85 lines
2.2 KiB
Python
85 lines
2.2 KiB
Python
"""Unit tests for seat structured output + one-shot repair."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from app.maf_roundtable.seat_output import (
|
|
build_repair_prompt,
|
|
parse_seat_output,
|
|
validate_or_repair_seat_output,
|
|
)
|
|
|
|
|
|
def test_parse_valid_seat_output():
|
|
text = '{"summary":"ok","findings":["f1"],"proposed_actions":["do x"]}'
|
|
model, errors = parse_seat_output(text)
|
|
assert errors == []
|
|
assert model is not None
|
|
assert model.summary == "ok"
|
|
assert model.findings == ["f1"]
|
|
|
|
|
|
def test_parse_fenced_json():
|
|
text = '说明\n```json\n{"summary":"s"}\n```\n'
|
|
model, errors = parse_seat_output(text)
|
|
assert model is not None
|
|
assert errors == []
|
|
|
|
|
|
def test_parse_invalid_missing_summary():
|
|
model, errors = parse_seat_output('{"findings":[]}')
|
|
assert model is None
|
|
assert errors
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_validate_ok_no_repair():
|
|
result = await validate_or_repair_seat_output(
|
|
raw_content='{"summary":"fine"}',
|
|
repair_runner=None,
|
|
)
|
|
assert result["schema_status"] == "ok"
|
|
assert result["repair_attempted"] is False
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_one_shot_repair_success():
|
|
calls = {"n": 0}
|
|
|
|
async def _repair(prompt: str) -> str:
|
|
calls["n"] += 1
|
|
assert "SeatTurnOutput" in prompt or "校验" in prompt
|
|
return '{"summary":"repaired","findings":["x"]}'
|
|
|
|
result = await validate_or_repair_seat_output(
|
|
raw_content="not json at all",
|
|
repair_runner=_repair,
|
|
)
|
|
assert calls["n"] == 1
|
|
assert result["schema_status"] == "repaired"
|
|
assert result["output"]["summary"] == "repaired"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_repair_still_invalid_stops():
|
|
calls = {"n": 0}
|
|
|
|
async def _repair(prompt: str) -> str:
|
|
calls["n"] += 1
|
|
return "still not json"
|
|
|
|
result = await validate_or_repair_seat_output(
|
|
raw_content="garbage",
|
|
repair_runner=_repair,
|
|
)
|
|
assert calls["n"] == 1
|
|
assert result["schema_status"] == "schema_invalid"
|
|
assert result["repair_attempted"] is True
|
|
|
|
|
|
def test_build_repair_prompt_includes_errors():
|
|
prompt = build_repair_prompt("raw", ["summary: Field required"])
|
|
assert "summary: Field required" in prompt
|
|
assert "raw" in prompt
|