from pathlib import Path import pytest from dojo.rules import RulesConfig from dojo.sim import BoardFiles, Scenario, matrix, run BOARD = Path(__file__).parent.parent / "board" FILES = BoardFiles(BOARD / "quadrant.txt", BOARD / "legend.toml") LINEUP = ("balanced", "random") def test_matrix_crosses_every_axis() -> None: scenarios = matrix(["none", "acd"], [3, 4], [2, 1], [0], [LINEUP]) assert len(scenarios) == 8 assert scenarios[0].name == "exam:none p3 kiai+2 start0 balanced,random" assert scenarios[0].config == RulesConfig(exam_defender_black=False) assert scenarios[-1].config == RulesConfig( exam_ties_to_defender=True, exam_defender_black=True, exam_rounds=3, kiai_bonus=1 ) @pytest.mark.parametrize( ("exam", "ties", "black", "rounds"), [ ("none", False, False, 1), ("a", True, False, 1), ("c", False, True, 1), ("d", False, False, 3), ("cd", False, True, 3), ], ) def test_exam_options_map_to_rules(exam: str, ties: bool, black: bool, rounds: int) -> None: config = Scenario(exam, 4, 2, 0, LINEUP).config assert (config.exam_ties_to_defender, config.exam_defender_black) == (ties, black) assert config.exam_rounds == rounds def test_lineup_fills_the_seats_and_rotates_each_game() -> None: scenario = Scenario("none", 3, 2, 0, LINEUP) assert scenario.seating(0) == ("balanced", "random", "balanced") assert scenario.seating(1) == ("random", "balanced", "balanced") assert scenario.seating(3) == scenario.seating(0) @pytest.mark.parametrize( ("exam", "players", "lineup", "message"), [ ("b", 4, LINEUP, "unknown Exam options"), ("aa", 4, LINEUP, "unknown Exam options"), ("", 4, LINEUP, "unknown Exam options"), ("none", 4, ("balanced", "cheater"), "unknown bots"), ("none", 4, (), "unknown bots"), ("none", 9, LINEUP, "supported range"), ], ) def test_invalid_scenarios_are_rejected( exam: str, players: int, lineup: tuple[str, ...], message: str ) -> None: with pytest.raises(ValueError, match=message): Scenario(exam, players, 2, 0, lineup) def test_runs_are_reproducible_and_independent_of_worker_count() -> None: scenarios = matrix(["none", "acd"], [3], [2], [0], [LINEUP]) serial = run(FILES, scenarios, games=2, seed=5, jobs=1) parallel = run(FILES, scenarios, games=2, seed=5, jobs=2) assert serial == parallel assert [(g.scenario, g.seed) for g in serial] == [ (scenarios[0].name, 5), (scenarios[0].name, 6), (scenarios[1].name, 5), (scenarios[1].name, 6), ] assert serial[1].lineup == "random,balanced,balanced"