"""Parsing tests — the structured-output contract is the riskiest part with a small VLM, so it's the part worth testing without a model in the loop. Run: uv run pytest (single test: uv run pytest tests/test_parsing.py::test_clean_json) """ from tempercheck.prompt import parse_verdict def test_clean_json(): v = parse_verdict( '{"score": 73, "verdict": "Mildly thorny", ' '"rationale": "Crossed arms.", "signals": ["frown", "caps lock"]}' ) assert v.score == 73 assert v.verdict == "Mildly thorny" assert v.signals == ["frown", "caps lock"] def test_json_with_surrounding_prose(): v = parse_verdict('Sure! Here is the read:\n{"score": 10}\nHope that helps.') assert v.score == 10 assert v.band # falls back to defaults without raising def test_score_clamped_and_coerced(): assert parse_verdict('{"score": 250}').score == 100 assert parse_verdict('{"score": -5}').score == 0 assert parse_verdict('{"score": "88 out of 100"}').score == 88 def test_garbage_never_raises(): v = parse_verdict("the model said nothing useful") assert 0 <= v.score <= 100 assert v.verdict assert v.rationale def test_signals_non_list_is_normalized(): assert parse_verdict('{"signals": "grumpy"}').signals == ["grumpy"]