alexchilton Claude commited on
Commit
d87a3e7
·
1 Parent(s): 33b8813

Add inventory persistence test - PASSES ✅

Browse files

Test verifies:
- Buy rope → inventory updated, gold deducted
- Rope persists in inventory between commands
- Sell rope → inventory updated, gold increased

Findings:
- Inventory persistence works correctly in core systems
- Issue was shop reality check requiring merchant NPCs
- No bugs in CharacterState.inventory or GameMaster session

This isolates the Playwright test issue to Gradio/web layer

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

Files changed (1) hide show
  1. tests/test_inventory_persistence.py +138 -0
tests/test_inventory_persistence.py ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Test inventory persistence across multiple commands.
3
+
4
+ This test verifies that items added to character_state.inventory
5
+ are properly maintained between multiple GM interactions.
6
+ """
7
+
8
+ import sys
9
+ from pathlib import Path
10
+ sys.path.insert(0, str(Path(__file__).parent.parent))
11
+
12
+ from dnd_rag_system.core.chroma_manager import ChromaDBManager
13
+ from dnd_rag_system.systems.gm_dialogue_unified import GameMaster
14
+ from dnd_rag_system.systems.game_state import CharacterState
15
+
16
+
17
+ def test_inventory_persistence_across_commands():
18
+ """
19
+ Test that inventory persists correctly across multiple GM commands.
20
+
21
+ Simulates:
22
+ 1. Create character with initial inventory
23
+ 2. Buy rope (adds to inventory)
24
+ 3. Verify rope is in inventory
25
+ 4. Sell rope (removes from inventory)
26
+ 5. Verify rope is NOT in inventory
27
+ """
28
+ print("\n" + "=" * 80)
29
+ print("TEST: Inventory Persistence Across Commands")
30
+ print("=" * 80)
31
+
32
+ # Initialize systems
33
+ db = ChromaDBManager()
34
+ gm = GameMaster(db)
35
+
36
+ # Create character state with initial inventory
37
+ char_state = CharacterState(
38
+ character_name="Test Hero",
39
+ max_hp=30,
40
+ level=3,
41
+ gold=100
42
+ )
43
+ char_state.armor_class = 15
44
+
45
+ # Set initial equipment (simulating Thorin's setup)
46
+ char_state.inventory = {
47
+ 'Longsword': 1,
48
+ 'Shield': 1,
49
+ 'Plate Armor': 1,
50
+ 'Backpack': 1
51
+ }
52
+
53
+ # Attach character to GM session
54
+ gm.session.character_state = char_state
55
+ gm.set_context("Test Hero is in a marketplace")
56
+ gm.set_location("The Market Square", "A bustling marketplace")
57
+
58
+ # CRITICAL: Add merchant NPCs to enable shop transactions
59
+ # The shop system requires either has_shop=True on location OR merchant NPCs present
60
+ gm.session.npcs_present = ['Merchant', 'Shopkeeper']
61
+ print(f" Added NPCs for shop: {gm.session.npcs_present}")
62
+
63
+ print(f"\n1️⃣ Initial Setup:")
64
+ print(f" Character: {char_state.character_name}")
65
+ print(f" Gold: {char_state.gold} GP")
66
+ print(f" Inventory: {char_state.inventory}")
67
+ print(f" Session character_state ID: {id(char_state)}")
68
+ print(f" GM session character_state ID: {id(gm.session.character_state)}")
69
+
70
+ # Verify they're the same object
71
+ assert gm.session.character_state is char_state, "Session character_state should be same object"
72
+ print(" ✅ Character state attached correctly")
73
+
74
+ # Step 2: Buy rope
75
+ print(f"\n2️⃣ Buying rope...")
76
+ buy_response = gm.generate_response("/buy rope", use_rag=False)
77
+
78
+ print(f" Response: {buy_response[:200]}...")
79
+ print(f" Gold after buy: {gm.session.character_state.gold} GP")
80
+ print(f" Inventory after buy: {gm.session.character_state.inventory}")
81
+
82
+ # Verify purchase
83
+ assert "rope" in gm.session.character_state.inventory, "Rope should be in inventory after purchase"
84
+ assert gm.session.character_state.inventory["rope"] == 1, "Should have 1 rope"
85
+ assert gm.session.character_state.gold == 99, f"Expected 99 GP, got {gm.session.character_state.gold}"
86
+ print(" ✅ Rope successfully purchased and added to inventory")
87
+
88
+ # CRITICAL: Check if character_state object changed
89
+ print(f" Session character_state ID after buy: {id(gm.session.character_state)}")
90
+ if id(gm.session.character_state) != id(char_state):
91
+ print(" ⚠️ WARNING: character_state object was replaced!")
92
+ char_state = gm.session.character_state # Update reference
93
+
94
+ # Step 3: Verify rope persists before selling
95
+ print(f"\n3️⃣ Checking inventory before sell:")
96
+ print(f" Inventory: {gm.session.character_state.inventory}")
97
+ assert "rope" in gm.session.character_state.inventory, "Rope should still be in inventory"
98
+ print(" ✅ Rope persisted in inventory")
99
+
100
+ # Step 4: Sell rope
101
+ print(f"\n4️⃣ Selling rope...")
102
+ sell_response = gm.generate_response("/sell rope", use_rag=False)
103
+
104
+ print(f" Response: {sell_response[:200]}...")
105
+ print(f" Gold after sell: {gm.session.character_state.gold} GP")
106
+ print(f" Inventory after sell: {gm.session.character_state.inventory}")
107
+
108
+ # Verify sale
109
+ assert "rope" not in gm.session.character_state.inventory, "Rope should NOT be in inventory after sale"
110
+ assert gm.session.character_state.gold == 99.5, f"Expected 99.5 GP (sold for 0.5), got {gm.session.character_state.gold}"
111
+ print(" ✅ Rope successfully sold and removed from inventory")
112
+
113
+ # Step 5: Final verification
114
+ print(f"\n5️⃣ Final State:")
115
+ print(f" Gold: {gm.session.character_state.gold} GP")
116
+ print(f" Inventory: {gm.session.character_state.inventory}")
117
+ print(f" Session character_state ID: {id(gm.session.character_state)}")
118
+
119
+ print("\n" + "=" * 80)
120
+ print("✅ ALL INVENTORY PERSISTENCE TESTS PASSED!")
121
+ print("=" * 80)
122
+
123
+ return True
124
+
125
+
126
+ if __name__ == "__main__":
127
+ try:
128
+ test_inventory_persistence_across_commands()
129
+ except AssertionError as e:
130
+ print(f"\n❌ TEST FAILED: {e}")
131
+ import traceback
132
+ traceback.print_exc()
133
+ sys.exit(1)
134
+ except Exception as e:
135
+ print(f"\n❌ TEST ERROR: {e}")
136
+ import traceback
137
+ traceback.print_exc()
138
+ sys.exit(1)