import pytest from backend.services.caller_gen import CallerIdentity, parse_batch_response SAMPLE_JSON = """ { "callers": [ { "name": "Danny Ortega", "age": 47, "voice_suggestion": "Marcus", "location": "Silver City, NM", "identity": "A plumber who inherited his uncle's taxidermy shop...", "situation": "He's been getting calls from people...", "reason_calling": "Someone left a note in his mailbox tonight...", "opening_line": "Luke, I need to ask you something weird.", "secret_want": "Permission to just throw it all away", "specific_details": ["the elk head in the basement", "the note said 'she forgot'", "his uncle's Rolodex"], "emotional_register": "quietly unsettled, trying to sound casual" } ] } """ def test_parse_batch_response_returns_caller_list(): callers = parse_batch_response(SAMPLE_JSON) assert len(callers) == 1 assert callers[0].name == "Danny Ortega" assert callers[0].age == 47 assert "taxidermy" in callers[0].identity assert len(callers[0].specific_details) == 3 def test_parse_batch_response_rejects_missing_fields(): bad = '{"callers": [{"name": "Jim"}]}' with pytest.raises(ValueError, match="missing"): parse_batch_response(bad) def test_resolve_voice_matches_exact(): from backend.services.caller_gen import resolve_voice roster = ["Marcus", "Dennis", "Priya", "Edward"] assert resolve_voice("Marcus", roster) == "Marcus" def test_resolve_voice_case_insensitive(): from backend.services.caller_gen import resolve_voice roster = ["Marcus", "Dennis"] assert resolve_voice("marcus", roster) == "Marcus" def test_resolve_voice_falls_back_when_no_match(): from backend.services.caller_gen import resolve_voice roster = ["Marcus", "Dennis"] # Deterministic fallback: return first from roster assert resolve_voice("Santiago", roster) == "Marcus" def test_resolve_voice_empty_suggestion_falls_back(): from backend.services.caller_gen import resolve_voice assert resolve_voice("", ["Marcus"]) == "Marcus" def test_build_batch_prompt_includes_context(): from backend.services.caller_gen import build_batch_prompt ctx = { "date": "Saturday, April 5, 2026", "weather": "cool desert night, 48°F", "headlines": ["New Mexico legislature approves water bill"], "recent_caller_summaries": ["Jerry called about his neighbor's goat"], "regulars_included": [], "caller_count": 12, "voice_roster": ["Marcus", "Dennis", "Priya"], } prompt = build_batch_prompt(ctx) assert "Saturday, April 5, 2026" in prompt assert "water bill" in prompt assert "Jerry called about his neighbor's goat" in prompt assert "12 callers" in prompt assert "Marcus" in prompt # voice roster listed assert "Stern" in prompt assert "Coast to Coast" in prompt assert "Loveline" in prompt assert "Delilah" in prompt assert "Opie and Anthony" in prompt def test_build_batch_prompt_includes_silas_lore_when_present(): from backend.services.caller_gen import build_batch_prompt ctx = { "date": "...", "weather": "...", "headlines": [], "recent_caller_summaries": [], "regulars_included": [{"name": "Silas", "lore": "Silas leads a small desert cult...", "arc_state": "seeking new members"}], "caller_count": 12, "voice_roster": ["Marcus"], } prompt = build_batch_prompt(ctx) assert "Silas" in prompt assert "desert cult" in prompt assert "seeking new members" in prompt assert "DO NOT alter his voice, personality, or core traits" in prompt