import shutil import unittest from pathlib import Path from src.llm.models import CharacterStateUpdate, InventoryChange, LoreUpdate from src.persistence.characters import get_character_state, update_character_state from src.persistence.lore import update_lore class TestPersistence(unittest.TestCase): def setUp(self): # Clear data directories before each test if Path("data/lore").exists(): shutil.rmtree("data/lore") if Path("data/chars").exists(): shutil.rmtree("data/chars") def test_lore_update_npc(self): update = LoreUpdate( category="NPC", entity_name="Grog", content="Grog loves ale.", context="Conversation with Grog at the tavern.", ) path = update_lore(update) self.assertTrue(Path(path).exists()) with open(path, "r") as f: content = f.read() self.assertIn("- Grog loves ale.", content) def test_lore_update_location(self): update = LoreUpdate( category="Location", entity_name="Waterdeep", content="A bustling city of splendor.", context="General world info.", ) path = update_lore(update) self.assertTrue(Path(path).exists()) with open(path, "r") as f: content = f.read() self.assertIn("- A bustling city of splendor.", content) def test_lore_update_timeline(self): update = LoreUpdate( category="Plot", entity_name=None, content="The party defeated the goblins.", context="After the first encounter.", ) path = update_lore(update) self.assertTrue(Path(path).exists()) self.assertEqual(Path(path).name, "Timeline.md") with open(path, "r") as f: content = f.read() self.assertIn("- The party defeated the goblins.", content) def test_character_update_hp(self): update = CharacterStateUpdate( character_name="Grog", hp_change=-10, status_effects_added=[], status_effects_removed=[], inventory_changes=[], ) update_character_state(update) state = get_character_state("Grog") # Default HP is 0, so 0 - 10 = -10 self.assertEqual(state["stats"]["hp"], -10) def test_character_update_status_effects(self): update = CharacterStateUpdate( character_name="Grog", hp_change=None, status_effects_added=["Blinded"], status_effects_removed=[], inventory_changes=[], ) update_character_state(update) state = get_character_state("Grog") self.assertIn("Blinded", state["status_effects"]) update2 = CharacterStateUpdate( character_name="Grog", hp_change=None, status_effects_added=[], status_effects_removed=["Blinded"], inventory_changes=[], ) update_character_state(update2) state = get_character_state("Grog") self.assertNotIn("Blinded", state["status_effects"]) def test_character_update_inventory(self): update = CharacterStateUpdate( character_name="Grog", hp_change=None, status_effects_added=[], status_effects_removed=[], inventory_changes=[ InventoryChange(item="Health Potion", quantity=2, action="added"), InventoryChange(item="Greatsword", quantity=1, action="added"), ], ) update_character_state(update) state = get_character_state("Grog") inventory = state["inventory"] self.assertEqual(len(inventory), 2) self.assertEqual(inventory[0]["item"], "Health Potion") self.assertEqual(inventory[0]["quantity"], 2) # Add more of the same item update2 = CharacterStateUpdate( character_name="Grog", hp_change=None, status_effects_added=[], status_effects_removed=[], inventory_changes=[ InventoryChange(item="Health Potion", quantity=1, action="added") ], ) update_character_state(update2) state = get_character_state("Grog") inventory = state["inventory"] # Should still be 2 unique items self.assertEqual(len(inventory), 2) # Health Potion should now be 3 hp_potion = next(item for item in inventory if item["item"] == "Health Potion") self.assertEqual(hp_potion["quantity"], 3) if __name__ == "__main__": unittest.main()