dental-soap / tests /test_interview_extract.py
DrZayed's picture
Adaptive ODIPARA guided interview, dental-specific question bank, age-extraction safety guard
f3def38
Raw
History Blame Contribute Delete
3.07 kB
"""ExtractedIntake → (PatientProfile, StructuredIntake) bridge and its safety guards."""
from __future__ import annotations
import pytest
from pydantic import ValidationError
from app import CHECK_MAP
from interview_schema import (
INTAKE_BOOL_FIELDS,
ExtractedIntake,
extracted_to_intake,
intake_json_schema,
next_question_json_schema,
)
from schema import StructuredIntake
def test_bool_fields_match_structured_intake_and_check_map():
"""The bridge must cover exactly the StructuredIntake booleans the UI exposes."""
assert set(INTAKE_BOOL_FIELDS) == set(CHECK_MAP.values())
for field in INTAKE_BOOL_FIELDS:
assert field in StructuredIntake.model_fields, field
assert field in ExtractedIntake.model_fields, field
def test_full_round_trip_into_intake():
extracted = ExtractedIntake(
chief_concern="Crown feels high",
tooth_or_area="Upper left molar",
recent_dental_work="Root canal and crown",
symptom_duration="Three weeks",
pain_score=6,
biting_pain=True,
hot_cold_sensitivity=True,
age=38,
meds="Ibuprofen",
allergies="Penicillin rash",
goals="Understand the crown fit",
language="Bilingual",
)
profile, intake = extracted_to_intake(extracted)
assert intake.chief_concern == "Crown feels high"
assert intake.biting_pain is True
assert intake.hot_cold_sensitivity is True
assert intake.pain_score == 6
assert profile.age == 38
assert profile.meds == "Ibuprofen"
assert profile.language == "Bilingual"
def test_pain_score_and_age_are_bounded():
with pytest.raises(ValidationError):
ExtractedIntake(pain_score=55)
with pytest.raises(ValidationError):
ExtractedIntake(age=999)
def test_diagnosis_language_in_extracted_text_is_blanked():
"""The extractor is model output: a diagnosis-flavored string must not flow
into the intake as if the patient had said it."""
extracted = ExtractedIntake(
chief_concern="Patient has an abscess and needs a root canal",
tooth_or_area="Upper left molar",
)
_profile, intake = extracted_to_intake(extracted)
assert intake.chief_concern == ""
assert intake.tooth_or_area == "Upper left molar"
def test_unknown_extractor_keys_are_ignored():
extracted = ExtractedIntake.model_validate(
{"chief_concern": "Crown feels high", "made_up_field": "x"}
)
assert extracted.chief_concern == "Crown feels high"
def test_intake_schema_is_strict_for_xgrammar():
schema = intake_json_schema()
assert schema["additionalProperties"] is False
assert "pain_score" in schema["properties"]
for field in INTAKE_BOOL_FIELDS:
assert field in schema["properties"]
def test_next_question_schema_is_strict():
schema = next_question_json_schema()
assert schema["additionalProperties"] is False
assert "question" in schema["properties"]
assert "covered_axes" in schema["properties"]
assert "covered_details" in schema["properties"]