from character import INTRO_CARDS, INTRO_SEQUENCES, build_system_prompt def test_intro_cards_and_sequences(): # four lore beats + a tester-only condensed teaching card (index 4) assert len(INTRO_CARDS) == 5 assert all(isinstance(c, str) and c.strip() for c in INTRO_CARDS) # tester is the short 3-card arc, full is the 4-card arc assert INTRO_SEQUENCES["tester"] == [0, 4, 3] assert INTRO_SEQUENCES["full"] == [0, 1, 2, 3] # every index points at a real card for seq in INTRO_SEQUENCES.values(): assert all(0 <= i < len(INTRO_CARDS) for i in seq) # the short tester arc must still teach the loop — a card that names "memory" assert any("memory" in INTRO_CARDS[i].lower() for i in INTRO_SEQUENCES["tester"]) class TestMimicry: def test_always_present(self): assert "mirror the visitor's writing style" in build_system_prompt(20, []) def test_present_with_recall_too(self): p = build_system_prompt(60, ["had a dog"], recall_memory="had a dog") assert "mirror the visitor's writing style" in p class TestToneBands: def test_warm_band_at_15(self): assert "gentle with you" in build_system_prompt(50, [], tone=15) def test_no_band_when_neutral(self): p = build_system_prompt(50, [], tone=0) assert "gentle with you" not in p assert "words have hurt you" not in p assert "curdled" not in p def test_no_band_at_minus_14(self): p = build_system_prompt(50, [], tone=-14) assert "words have hurt you" not in p def test_wounded_band_at_minus_15(self): assert "words have hurt you" in build_system_prompt(50, [], tone=-15) def test_wounded_band_at_minus_21(self): assert "words have hurt you" in build_system_prompt(50, [], tone=-21) def test_hostile_band_at_minus_22(self): assert "curdled" in build_system_prompt(50, [], tone=-22) class TestWoundEcho: def test_hostile_injects_last_two_wounds(self): p = build_system_prompt(50, [], tone=-50, wounds=["one", "two", "three"]) assert '"two"' in p and '"three"' in p assert '"one"' not in p def test_wounded_band_does_not_inject(self): p = build_system_prompt(50, [], tone=-20, wounds=["one"]) assert '"one"' not in p def test_hostile_without_wounds_safe(self): p = build_system_prompt(50, [], tone=-50, wounds=[]) assert "curdled" in p class TestBackwardCompat: def test_old_call_signature_still_works(self): p = build_system_prompt(60, ["had a dog"], "had a dog") assert "claim this one specific memory" in p class TestVarietyDirective: def test_variety_directive_present(self): p = build_system_prompt(30, []) assert "ONE or TWO short lines" in p assert "at most every other turn" in p class TestStayInWood: def test_injection_hardening_always_present(self): assert "not from the wood" in build_system_prompt(20, []) class TestAskForMemory: def test_nudge_when_asked(self): p = build_system_prompt(30, [], memory_plea=1) assert "one small true thing" in p def test_no_nudge_by_default(self): p = build_system_prompt(30, []) assert "one small true thing" not in p class TestMemoryPlea: def test_memory_plea_levels_escalate(self): p0 = build_system_prompt(20, [], memory_plea=0) p1 = build_system_prompt(20, [], memory_plea=1) p2 = build_system_prompt(20, [], memory_plea=2) p3 = build_system_prompt(20, [], memory_plea=3) # no plea at level 0 assert "memory" not in p0.lower() or "claim this one" in p0.lower() # each higher level adds a distinct, more explicit instruction assert p1 != p0 and p2 != p1 and p3 != p2 assert "a person they loved" in p3 and "a moment they can still see" in p3 def test_own_fragments_caor_arc(): from character import OWN_FRAGMENTS assert len(OWN_FRAGMENTS) == 5 joined = " ".join(OWN_FRAGMENTS).lower() assert "caor" in joined and "gaunt" in joined and "brother" in joined assert "hunger" in OWN_FRAGMENTS[0].lower() # arc still opens on hunger def test_system_prompt_carries_world(): from character import build_system_prompt p = build_system_prompt(20, [], recall_memory=None, tone=0, wounds=None, memory_plea=0, own_fragment=None, style="concise", aware_memory=None) assert "Caor" in p and "Gaunt" in p