dental-soap / tests /test_interview_api.py
DrZayed's picture
Fabricated-negative guard, stateless interview API, handoff badge design
5754a1e
Raw
History Blame Contribute Delete
2.44 kB
"""Stateless REST endpoint for the guided interview.
Raw HTTP callers can't satisfy Gradio's hidden gr.State input on the UI
endpoints (/info advertises 2 params, the REST validator wants 3 — upstream
inconsistency, found in the June 6 live API check). interview_api carries the
state as an opaque JSON string instead, so a plain curl works end to end.
"""
from __future__ import annotations
import json
import pytest
import app as app_mod
def test_interview_api_starts_fresh_and_returns_state():
result = app_mod.interview_api("Sam, 34")
assert result["reply"].endswith("?")
assert not result["done"]
assert not result["early_exit"]
state = json.loads(result["state"])
assert state["user_turns"] == ["Sam, 34"]
assert state["patient_age"] == 34
def test_interview_api_round_trip_continues_interview():
first = app_mod.interview_api("Sam, 34")
second = app_mod.interview_api("My crown feels high when I bite.", first["state"])
state = json.loads(second["state"])
assert state["user_turns"] == ["Sam, 34", "My crown feels high when I bite."]
assert not second["done"]
def test_interview_api_runs_deterministic_sentinel():
"""The emergency interrupt must fire over the raw API exactly as in the UI."""
result = app_mod.interview_api(
"I have no pain but I cannot breathe properly and my throat is swelling"
)
assert result["early_exit"]
assert result["done"]
assert result["hard_findings"]
assert "urgent" in result["reply"].lower() or "emergency" in result["reply"].lower()
def test_interview_api_rejects_malformed_state():
with pytest.raises(ValueError):
app_mod.interview_api("hello", "{not valid json")
def test_interview_api_rejects_state_with_wrong_fields():
with pytest.raises(ValueError):
app_mod.interview_api("hello", json.dumps({"phase": "demographics", "bogus": 1}))
def test_interview_api_rejects_unknown_phase():
"""Crafted phase must raise a clean ValueError, not 500 via KeyError in step()."""
with pytest.raises(ValueError):
app_mod.interview_api("hello", json.dumps({"phase": "hacked"}))
def test_interview_api_rejects_oversized_turn_history():
"""Replayed token may not exceed the interview's own turn cap (prompt inflation)."""
bloated = json.dumps({"user_turns": ["tooth hurts"] * 1000})
with pytest.raises(ValueError):
app_mod.interview_api("hello", bloated)