""" Test to ensure PlayerState slots are complete. This test prevents the class of bugs where dynamic attributes are lost during state copying because they aren't declared in __slots__. """ import numpy as np import pytest from engine.game.player_state import PlayerState class TestPlayerStateSlotCompleteness: """Verify all attributes are properly declared in __slots__.""" def test_no_dynamic_attributes_after_init(self): """PlayerState should have no __dict__ (pure __slots__ class).""" ps = PlayerState(0) # __slots__ classes should not have __dict__ unless explicitly added # However, if parent class doesn't use __slots__, __dict__ may exist but be empty if hasattr(ps, "__dict__"): assert len(ps.__dict__) == 0, f"PlayerState has dynamic attributes not in __slots__: {ps.__dict__}" def test_all_slots_have_default_values(self): """All slots should be initialized in __init__.""" ps = PlayerState(0) for slot in PlayerState.__slots__: assert hasattr(ps, slot), f"Slot '{slot}' not initialized in __init__" def test_copy_preserves_all_slots(self): """copy() should preserve all slot values.""" ps1 = PlayerState(0) # Modify some values to non-default ps1.hand = [1, 2, 3] ps1.tapped_members[0] = True ps1.rested_members[1] = True ps1.performance_abilities_processed = True ps1.revealed_hand = True ps1.deck_refreshed_this_turn = True ps1.baton_touch_count = 5 # Copy ps2 = ps1.copy() # Verify all values copied assert ps2.hand == [1, 2, 3] assert ps2.tapped_members[0] == True assert ps2.rested_members[1] == True assert ps2.performance_abilities_processed == True assert ps2.revealed_hand == True assert ps2.deck_refreshed_this_turn == True assert ps2.baton_touch_count == 5 # Verify copies are independent (deep copy for mutable types) ps2.hand.append(4) assert ps1.hand == [1, 2, 3], "hand should be deep copied" ps2.tapped_members[0] = False assert ps1.tapped_members[0] == True, "numpy arrays should be deep copied" def test_reset_clears_all_mutable_state(self): """_reset() should restore all slots to defaults.""" ps = PlayerState(0) # Modify state ps.hand = [1, 2, 3] ps.performance_abilities_processed = True ps.revealed_hand = True ps.rested_members[0] = True # Reset ps._reset(0) # Verify reset assert ps.hand == [] assert ps.performance_abilities_processed == False assert ps.revealed_hand == False assert not np.any(ps.rested_members) if __name__ == "__main__": pytest.main([__file__, "-v"])