Spaces:
Sleeping
Sleeping
| """Regression test for feature_cache content-based keying. | |
| Ensures cache doesn't collide when CPython reuses id() after GC. | |
| """ | |
| from __future__ import annotations | |
| from werewolftown.features.card_value import card_cluster_gain | |
| def test_cache_by_content_not_id(make_state): | |
| """Cache must key on state content, not id(). Different states must get different results.""" | |
| state_a = make_state( | |
| plots=frozenset({4, 5, 6}), | |
| built_on={4: "Happy", 5: "Happy"}, | |
| shops=(), | |
| ) | |
| state_b = make_state( | |
| plots=frozenset({4, 5, 7}), | |
| built_on={4: "Happy", 5: "Happy"}, | |
| shops=("Happy",), | |
| ) | |
| gain_a = card_cluster_gain(state_a, "Happy") | |
| gain_b = card_cluster_gain(state_b, "Happy") | |
| # state_a: empty 6 adjacent to Happy 2-cluster, 0 cards → gain=20000 | |
| # state_b: empty 7 not adjacent, 1 card already → gain=0 | |
| assert gain_a != gain_b, "Cache polluted: different states returned same result" | |
| assert gain_a == 20000 | |
| assert gain_b == 0 | |
| def test_cache_same_state_reuses(make_state): | |
| """Same state instance called twice must return cached result (no recompute).""" | |
| state = make_state( | |
| plots=frozenset({4, 5, 6}), | |
| built_on={4: "Happy", 5: "Happy"}, | |
| shops=(), | |
| ) | |
| # Clear cache first | |
| card_cluster_gain._cache.clear() | |
| gain1 = card_cluster_gain(state, "Happy") | |
| assert len(card_cluster_gain._cache) == 1 | |
| gain2 = card_cluster_gain(state, "Happy") | |
| assert gain1 == gain2 | |
| assert len(card_cluster_gain._cache) == 1 # No new entry | |
| def test_cache_survives_gc(make_state): | |
| """Cache must not break when intermediate states are GC'd.""" | |
| import gc | |
| state_main = make_state( | |
| plots=frozenset({4, 5, 6}), | |
| built_on={4: "Happy", 5: "Happy"}, | |
| shops=(), | |
| ) | |
| # Create and discard many states to trigger id reuse | |
| for i in range(100): | |
| _ = make_state(plots=frozenset({i}), round=i) | |
| gc.collect() | |
| # Original state should still return correct result | |
| gain = card_cluster_gain(state_main, "Happy") | |
| assert gain == 20000 | |