"""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)