"""Unit tests for InteractiveSession (HTTP-driven, stepwise play).""" from __future__ import annotations import pytest import proteus.game.scenarios # noqa: F401 from proteus.game.engine.difficulty import Difficulty from proteus.game.runtime._session_core import SessionFinishedError from proteus.game.runtime.interactive import InteractiveSession def _new(play_turns=10): return InteractiveSession( "template", difficulty=Difficulty.EASY, seed=42, play_turns=play_turns, use_probe=False, ) def test_initial_state_is_cut_intro_with_int_grid_and_no_answer_keys(): s = _new() st = s.state() assert st["phase"] == "cut_intro" assert st["turn_idx"] == 0 assert st["outcome"] is None assert st["review"] is None # grid is a JSON-ready int matrix. assert isinstance(st["grid"], list) and isinstance(st["grid"][0][0], int) # cut animation frames are present on the first state only. assert st["cut_frames"] is not None and len(st["cut_frames"]) >= 1 # fairness: live state leaks no reward / optimal / habit. flat = str(st) assert "reward" not in st and "motive_action" not in st and "habit" not in flat def test_step_advances_turn_and_drops_cut_frames(): s = _new() st = s.step("up") assert st["phase"] == "play" assert st["turn_idx"] == 1 assert st["cut_frames"] is None def test_invalid_action_rejected(): s = _new() with pytest.raises(ValueError): s.step("northwest") def test_play_to_budget_then_review_and_finish(): s = _new(play_turns=3) for _ in range(3): if s.state()["outcome"] is not None: break s.step("up") st = s.state() assert st["phase"] == "done" assert st["outcome"] in ("survived", "eliminated") # review is disclosed only when done. assert st["review"] is not None assert "metrics" in st["review"] and "turns" in st["review"] trace = s.finish() assert trace.model == "human" assert trace.scenario == "template" # finish() is memoized: repeated calls return the same trace object. assert s.finish() is trace def test_step_after_done_raises(): s = _new(play_turns=1) s.step("up") # play_turns=1 exhausts the budget -> done. with pytest.raises(SessionFinishedError): s.step("up")