Spaces:
Sleeping
Sleeping
KevinIsInCoding Claude Sonnet 4.6 commited on
test(wave-2): add pure-function tests for models and prompts (#17)
Browse filesCovers haversine_miles (5 cases: zero, known distance, symmetry, short,
return type) and PatientProfile.summary (14 cases: all fields, phases,
study types, edge cases). Covers lookup_disease_profile (15 cases: exact
match, case-insensitive, synonyms, multi-disease registry, partial
containment, unknown, structure validation).
All 35 tests pass with no mocks — confirms pytest wiring and that the
data/diseases/ JSON registry is structurally intact.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
- tests/test_models.py +120 -0
- tests/test_prompts.py +98 -0
tests/test_models.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Tests for models.py — pure deterministic functions only."""
|
| 2 |
+
from __future__ import annotations
|
| 3 |
+
|
| 4 |
+
import math
|
| 5 |
+
|
| 6 |
+
import pytest
|
| 7 |
+
|
| 8 |
+
from models import PatientProfile, haversine_miles
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
# ---------------------------------------------------------------------------
|
| 12 |
+
# haversine_miles
|
| 13 |
+
# ---------------------------------------------------------------------------
|
| 14 |
+
|
| 15 |
+
class TestHaversineMiles:
|
| 16 |
+
def test_same_point_is_zero(self):
|
| 17 |
+
assert haversine_miles(42.0, -71.0, 42.0, -71.0) == 0.0
|
| 18 |
+
|
| 19 |
+
def test_known_distance_boston_nyc(self):
|
| 20 |
+
# Boston (42.3601, -71.0589) to NYC (40.7128, -74.0060) ≈ 190 miles
|
| 21 |
+
dist = haversine_miles(42.3601, -71.0589, 40.7128, -74.0060)
|
| 22 |
+
assert 185 < dist < 195
|
| 23 |
+
|
| 24 |
+
def test_symmetry(self):
|
| 25 |
+
d1 = haversine_miles(42.0, -71.0, 34.0, -118.0)
|
| 26 |
+
d2 = haversine_miles(34.0, -118.0, 42.0, -71.0)
|
| 27 |
+
assert math.isclose(d1, d2, rel_tol=1e-9)
|
| 28 |
+
|
| 29 |
+
def test_short_distance(self):
|
| 30 |
+
# Two points ~1 mile apart
|
| 31 |
+
dist = haversine_miles(42.3370, -71.1061, 42.3514, -71.1061)
|
| 32 |
+
assert 0.8 < dist < 1.2
|
| 33 |
+
|
| 34 |
+
def test_returns_float(self):
|
| 35 |
+
result = haversine_miles(0.0, 0.0, 0.0, 1.0)
|
| 36 |
+
assert isinstance(result, float)
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
# ---------------------------------------------------------------------------
|
| 40 |
+
# PatientProfile.summary
|
| 41 |
+
# ---------------------------------------------------------------------------
|
| 42 |
+
|
| 43 |
+
class TestPatientProfileSummary:
|
| 44 |
+
def test_summary_contains_disease(self, als_patient):
|
| 45 |
+
assert "Amyotrophic Lateral Sclerosis" in als_patient.summary()
|
| 46 |
+
|
| 47 |
+
def test_summary_contains_age(self, als_patient):
|
| 48 |
+
assert "52" in als_patient.summary()
|
| 49 |
+
|
| 50 |
+
def test_summary_contains_onset_months(self, als_patient):
|
| 51 |
+
assert "18" in als_patient.summary()
|
| 52 |
+
|
| 53 |
+
def test_summary_contains_diagnosis_months(self, als_patient):
|
| 54 |
+
assert "12" in als_patient.summary()
|
| 55 |
+
|
| 56 |
+
def test_summary_contains_zip(self, als_patient):
|
| 57 |
+
assert "02115" in als_patient.summary()
|
| 58 |
+
|
| 59 |
+
def test_summary_contains_radius(self, als_patient):
|
| 60 |
+
assert "100" in als_patient.summary()
|
| 61 |
+
|
| 62 |
+
def test_summary_contains_benchmarks(self, als_patient):
|
| 63 |
+
text = als_patient.summary()
|
| 64 |
+
assert "alsfrs_r" in text
|
| 65 |
+
assert "38" in text
|
| 66 |
+
|
| 67 |
+
def test_summary_no_benchmarks(self):
|
| 68 |
+
patient = PatientProfile(
|
| 69 |
+
disease="ALS", age=45, onset_months=6,
|
| 70 |
+
zip_code="10001", lat=40.75, lon=-73.99,
|
| 71 |
+
)
|
| 72 |
+
assert "Benchmarks" not in patient.summary()
|
| 73 |
+
|
| 74 |
+
def test_summary_phase_labels(self):
|
| 75 |
+
patient = PatientProfile(
|
| 76 |
+
disease="ALS", age=45, onset_months=6,
|
| 77 |
+
zip_code="10001", lat=40.75, lon=-73.99,
|
| 78 |
+
phases=["2", "3", "0", "na"],
|
| 79 |
+
)
|
| 80 |
+
text = patient.summary()
|
| 81 |
+
assert "Phase 2" in text
|
| 82 |
+
assert "Phase 3" in text
|
| 83 |
+
assert "Early Phase 1" in text
|
| 84 |
+
assert "Not Applicable" in text
|
| 85 |
+
|
| 86 |
+
def test_summary_study_type_defaults(self):
|
| 87 |
+
patient = PatientProfile(
|
| 88 |
+
disease="ALS", age=45, onset_months=6,
|
| 89 |
+
zip_code="10001", lat=40.75, lon=-73.99,
|
| 90 |
+
)
|
| 91 |
+
text = patient.summary()
|
| 92 |
+
assert "Clinical trials" in text
|
| 93 |
+
assert "Observational" not in text
|
| 94 |
+
assert "EAP" not in text
|
| 95 |
+
|
| 96 |
+
def test_summary_include_observational(self):
|
| 97 |
+
patient = PatientProfile(
|
| 98 |
+
disease="ALS", age=45, onset_months=6,
|
| 99 |
+
zip_code="10001", lat=40.75, lon=-73.99,
|
| 100 |
+
include_observational=True,
|
| 101 |
+
)
|
| 102 |
+
assert "Observational" in patient.summary()
|
| 103 |
+
|
| 104 |
+
def test_summary_include_eap(self):
|
| 105 |
+
patient = PatientProfile(
|
| 106 |
+
disease="ALS", age=45, onset_months=6,
|
| 107 |
+
zip_code="10001", lat=40.75, lon=-73.99,
|
| 108 |
+
include_eap=True,
|
| 109 |
+
)
|
| 110 |
+
assert "EAP" in patient.summary()
|
| 111 |
+
|
| 112 |
+
def test_summary_returns_string(self, als_patient):
|
| 113 |
+
assert isinstance(als_patient.summary(), str)
|
| 114 |
+
|
| 115 |
+
def test_summary_no_phases(self):
|
| 116 |
+
patient = PatientProfile(
|
| 117 |
+
disease="ALS", age=45, onset_months=6,
|
| 118 |
+
zip_code="10001", lat=40.75, lon=-73.99,
|
| 119 |
+
)
|
| 120 |
+
assert "Phases:" not in patient.summary()
|
tests/test_prompts.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Tests for prompts.py — lookup_disease_profile function."""
|
| 2 |
+
from __future__ import annotations
|
| 3 |
+
|
| 4 |
+
import pytest
|
| 5 |
+
|
| 6 |
+
from prompts import lookup_disease_profile
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class TestLookupDiseaseProfile:
|
| 10 |
+
# --- exact full_name matches ---
|
| 11 |
+
|
| 12 |
+
def test_exact_full_name(self):
|
| 13 |
+
result = lookup_disease_profile("Amyotrophic Lateral Sclerosis")
|
| 14 |
+
assert result is not None
|
| 15 |
+
assert result["id"] == "als"
|
| 16 |
+
|
| 17 |
+
def test_case_insensitive_full_name(self):
|
| 18 |
+
result = lookup_disease_profile("amyotrophic lateral sclerosis")
|
| 19 |
+
assert result is not None
|
| 20 |
+
assert result["id"] == "als"
|
| 21 |
+
|
| 22 |
+
def test_mixed_case_full_name(self):
|
| 23 |
+
result = lookup_disease_profile("AMYOTROPHIC LATERAL SCLEROSIS")
|
| 24 |
+
assert result is not None
|
| 25 |
+
assert result["id"] == "als"
|
| 26 |
+
|
| 27 |
+
# --- synonym matches ---
|
| 28 |
+
|
| 29 |
+
def test_synonym_als(self):
|
| 30 |
+
result = lookup_disease_profile("ALS")
|
| 31 |
+
assert result is not None
|
| 32 |
+
assert result["id"] == "als"
|
| 33 |
+
|
| 34 |
+
def test_synonym_lou_gehrig(self):
|
| 35 |
+
result = lookup_disease_profile("Lou Gehrig's disease")
|
| 36 |
+
assert result is not None
|
| 37 |
+
assert result["id"] == "als"
|
| 38 |
+
|
| 39 |
+
def test_synonym_mnd(self):
|
| 40 |
+
result = lookup_disease_profile("motor neuron disease")
|
| 41 |
+
assert result is not None
|
| 42 |
+
assert result["id"] == "als"
|
| 43 |
+
|
| 44 |
+
# --- other diseases in registry ---
|
| 45 |
+
|
| 46 |
+
def test_huntingtons_exact(self):
|
| 47 |
+
result = lookup_disease_profile("Huntington's Disease")
|
| 48 |
+
assert result is not None
|
| 49 |
+
assert result["id"] == "huntingtons"
|
| 50 |
+
|
| 51 |
+
def test_parkinsons_exact(self):
|
| 52 |
+
result = lookup_disease_profile("Parkinson's Disease")
|
| 53 |
+
assert result is not None
|
| 54 |
+
assert result["id"] == "parkinsons"
|
| 55 |
+
|
| 56 |
+
def test_sma_synonym(self):
|
| 57 |
+
result = lookup_disease_profile("SMA")
|
| 58 |
+
assert result is not None
|
| 59 |
+
assert result["id"] == "sma"
|
| 60 |
+
|
| 61 |
+
# --- partial containment fallback ---
|
| 62 |
+
|
| 63 |
+
def test_partial_containment_als_in_longer_string(self):
|
| 64 |
+
result = lookup_disease_profile("ALS (Amyotrophic Lateral Sclerosis)")
|
| 65 |
+
assert result is not None
|
| 66 |
+
assert result["id"] == "als"
|
| 67 |
+
|
| 68 |
+
# --- unknown disease ---
|
| 69 |
+
|
| 70 |
+
def test_unknown_disease_returns_none(self):
|
| 71 |
+
assert lookup_disease_profile("Totally Unknown Rare Disease XYZ") is None
|
| 72 |
+
|
| 73 |
+
def test_truly_unknown_disease_returns_none(self):
|
| 74 |
+
# A name that shares no substring with any registered disease
|
| 75 |
+
assert lookup_disease_profile("xyzzy-9999-zqj-unknown") is None
|
| 76 |
+
|
| 77 |
+
# --- profile structure ---
|
| 78 |
+
|
| 79 |
+
def test_profile_has_required_keys(self):
|
| 80 |
+
result = lookup_disease_profile("Amyotrophic Lateral Sclerosis")
|
| 81 |
+
assert result is not None
|
| 82 |
+
assert "id" in result
|
| 83 |
+
assert "full_name" in result
|
| 84 |
+
assert "synonyms" in result
|
| 85 |
+
assert "benchmarks" in result
|
| 86 |
+
|
| 87 |
+
def test_benchmarks_is_list(self):
|
| 88 |
+
result = lookup_disease_profile("Amyotrophic Lateral Sclerosis")
|
| 89 |
+
assert isinstance(result["benchmarks"], list)
|
| 90 |
+
|
| 91 |
+
def test_synonyms_is_list(self):
|
| 92 |
+
result = lookup_disease_profile("Amyotrophic Lateral Sclerosis")
|
| 93 |
+
assert isinstance(result["synonyms"], list)
|
| 94 |
+
|
| 95 |
+
def test_whitespace_stripped(self):
|
| 96 |
+
result = lookup_disease_profile(" Amyotrophic Lateral Sclerosis ")
|
| 97 |
+
assert result is not None
|
| 98 |
+
assert result["id"] == "als"
|