"""Tests for the pf1e-sim command-line interface.""" from __future__ import annotations from pathlib import Path from typing import TYPE_CHECKING if TYPE_CHECKING: import pytest from pf1e_simulator.cli import main ROOT = Path(__file__).resolve().parents[1] MAP = ROOT / "data" / "maps" / "sample_arena.yaml" GOBLIN = ROOT / "data" / "monsters" / "goblin.json" ORC = ROOT / "data" / "monsters" / "orc.json" def test_cli_prints_balance_report(capsys: pytest.CaptureFixture[str]) -> None: rc = main( [ "--map", str(MAP), "--side", "players", str(GOBLIN), str(GOBLIN), str(GOBLIN), "--side", "monsters", str(ORC), str(ORC), "--runs", "50", "--seed", "1", ] ) out = capsys.readouterr().out assert rc == 0 assert "Rapport d'équilibrage" in out assert "Victoires players" in out assert "Victoires monsters" in out assert "bande 3σ" in out assert "Nuls" in out assert "Rounds moyens" in out assert "Attrition moyenne" in out assert "soins prodigués" in out def test_cli_rejects_side_not_in_deployment(capsys: pytest.CaptureFixture[str]) -> None: rc = main(["--map", str(MAP), "--side", "bogus", str(GOBLIN), "--runs", "10"]) assert rc == 2 assert "deployment" in capsys.readouterr().err def test_cli_rejects_missing_deployment_side(capsys: pytest.CaptureFixture[str]) -> None: rc = main(["--map", str(MAP), "--side", "players", str(GOBLIN), "--runs", "10"]) assert rc == 2 assert "monsters" in capsys.readouterr().err def test_cli_rejects_duplicate_side_names(capsys: pytest.CaptureFixture[str]) -> None: rc = main( [ "--map", str(MAP), "--side", "players", str(GOBLIN), "--side", "players", str(ORC), "--side", "monsters", str(ORC), "--runs", "10", ] ) assert rc == 2 err = capsys.readouterr().err assert "duplicate --side names" in err assert "players" in err def test_cli_transcript_prints_first_battle_log(capsys: pytest.CaptureFixture[str]) -> None: rc = main( [ "--map", str(MAP), "--side", "players", str(GOBLIN), "--side", "monsters", str(ORC), "--runs", "10", "--seed", "1", "--transcript", ] ) out = capsys.readouterr().out assert rc == 0 assert "Déroulé du premier combat" in out # X6: the transcript is rendered as a table (header + separator); engine # lines outside the "round N id: message" shape (initiative rolls) stay # visible as raw fallback rows. assert "Round" in out assert "Combattant" in out assert "Message" in out assert "initiative:" in out assert "goblin" in out # The balance report must still be printed after the transcript. assert "Rapport d'équilibrage" in out assert out.index("Déroulé du premier combat") < out.index("Rapport d'équilibrage")