thousand-token-wood-sim / tests /test_replay.py
AdmiralTaco's picture
v4 "The Wood Fights Back": adversarial adaptation + exposure meter
859f8bd
Raw
History Blame Contribute Delete
1.81 kB
"""Tests for attract/replay serialization. No GPU, no network, no Modal.
Run: python -m pytest tests/ -q
"""
import sys
from pathlib import Path
import pandas as pd
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from ttw.dummy import make_random_policy
from ttw.game import Game
from ttw.replay import FRAME_KEYS, frame_to_views, load_attract, record_frame, save_frames
def _game_after_a_turn() -> Game:
g = Game(make_random_policy(seed=7), deck_seed=7)
g.tempt_fate()
g.step()
return g
def test_record_frame_has_all_view_keys():
frame = record_frame(_game_after_a_turn())
assert sorted(frame.keys()) == sorted(FRAME_KEYS)
def test_frame_to_views_arity_and_chart_types():
frame = record_frame(_game_after_a_turn())
views = frame_to_views(frame)
assert len(views) == 15 # matches app._views (game_state added by the handler)
assert isinstance(views[1], pd.DataFrame) # prices
assert isinstance(views[2], pd.DataFrame) # gini
assert list(views[1].columns) == ["turn", "good", "price"]
assert list(views[2].columns) == ["turn", "gini"]
def test_roundtrip_save_load(tmp_path):
g = _game_after_a_turn()
frames = [record_frame(g)]
path = tmp_path / "attract.json"
save_frames(frames, path)
loaded = load_attract(path)
assert len(loaded) == 1
assert loaded[0]["town"] == frames[0]["town"]
def test_load_attract_missing_file_is_empty(tmp_path):
assert load_attract(tmp_path / "nope.json") == []
def test_frame_to_views_empty_frame_yields_valid_empty_plots():
# A defensive frame with no chart records must still build valid DataFrames.
views = frame_to_views({})
assert isinstance(views[1], pd.DataFrame) and views[1].empty
assert isinstance(views[2], pd.DataFrame) and views[2].empty