Chessistics/tools/automation/test_undo.py
Samuel Bouchet 97bca7d7df Add Undo (Ctrl+Z) backed by the WorldSave checkpoint mechanism
GameSim snapshots the state before each undoable command
(PlacePiece / RemovePiece / MovePiece) into a bounded LinkedList stack
(max 32). Undo() pops the last checkpoint and emits StateRestoredEvent,
reusing the presentation rebuild path already wired for QuickLoad.

Ctrl+Z in Main triggers the engine method; the harness exposes undo()
for tests. QuickLoad clears the stack (fresh timeline). Seven unit tests
cover empty stack, place/remove/move undo, reverse-order multiple undos,
rejected commands not checkpointing, and post-simulation rewind.
2026-04-17 22:14:06 +02:00

44 lines
1.2 KiB
Python

"""End-to-end smoke test for Undo."""
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
from tools.automation.harness import Harness
def main():
with Harness.launch(run_name="undo") as h:
h.load_mission("campaign_01", 0)
h.screenshot("01_loaded")
initial = h.state()
assert len(initial['pieces']) == 0
h.place("Pawn", (0, 0), (0, 1))
h.place("Pawn", (1, 0), (1, 1))
h.screenshot("02_two_pieces")
s = h.state()
assert len(s['pieces']) == 2, f"expected 2 pieces, got {len(s['pieces'])}"
r = h.undo()
print(f"[undo] {r}")
h.screenshot("03_after_first_undo")
s = h.state()
assert len(s['pieces']) == 1, f"expected 1 piece, got {len(s['pieces'])}"
r = h.undo()
print(f"[undo] {r}")
h.screenshot("04_after_second_undo")
s = h.state()
assert len(s['pieces']) == 0
assert s['remainingStock']['Pawn'] == 4
r = h.undo()
print(f"[undo empty] {r}")
assert r['undone'] is False
print("OK — Undo works")
if __name__ == "__main__":
main()