"""End-to-end smoke test for the automation harness. Runs a scripted playthrough: load mission 0, place a rook, take screenshots, step forward, and validate state at each step. Fails hard on any anomaly. """ from __future__ import annotations import hashlib import json import sys from pathlib import Path from harness import Harness, HarnessError def sha256(path: Path) -> str: return hashlib.sha256(path.read_bytes()).hexdigest() def main() -> int: with Harness.launch(run_name="smoke") as h: print(f"\n[smoke] run dir: {h.root}\n") # --- 1. initial state --- print("[smoke] load_mission") state = h.load_mission("campaign_01", 0) assert state["width"] > 0 and state["height"] > 0, state assert state["phase"] == "Paused", f"expected Paused, got {state['phase']}" assert state["remainingStock"], "stock is empty" print(f" board {state['width']}x{state['height']}, phase={state['phase']}, stock={state['remainingStock']}") shot1 = h.screenshot("01_loaded") assert shot1.exists(), shot1 print(f" screenshot -> {shot1.name}") # --- 2. place a piece --- snap_before = h.state() stock_before = dict(snap_before["remainingStock"]) first_kind = next(iter(stock_before)) print(f"[smoke] try placing {first_kind} at (0,0)->(0,0)") # Find any legal placement. Simplest: for a Rook-ish piece, same cell start=end # isn't legal — try adjacent cells. We scan for one kind we have in stock and a # simple legal move. placed = None for kind in stock_before: for s in [(0, 0), (1, 0), (0, 1)]: for e in [(0, 1), (1, 1), (2, 0), (0, 2)]: if s == e: continue result = h.place(kind, s, e) if result.get("placed"): placed = (kind, s, e, result) break if placed: break if placed: break if not placed: print("[smoke] no legal placement found — inspect state dump:") print(json.dumps(snap_before, indent=2)) return 2 kind, start, end, result = placed print(f" placed {kind} {start}->{end}, pieceId={result.get('pieceId')}") h.screenshot("02_placed") snap_after = h.state() assert len(snap_after["pieces"]) == len(snap_before["pieces"]) + 1, "piece count didn't grow" assert snap_after["remainingStock"][kind] == stock_before[kind] - 1, "stock didn't decrement" # --- 3. determinism check: two screenshots of a paused state must match --- print("[smoke] determinism check") a = h.screenshot("det_a") b = h.screenshot("det_b") if sha256(a) != sha256(b): print(f" WARN: screenshots differ (hover cursor likely) — {sha256(a)[:8]} vs {sha256(b)[:8]}") else: print(" identical OK") # --- 4. stepping --- print("[smoke] stepping up to 10 turns") for i in range(10): step_info = h.step() h.screenshot(f"step_{i:02}") phase = step_info.get("phase") print(f" turn={step_info.get('turn')} phase={phase}") if phase == "MissionComplete": print(" mission complete!") break # --- 5. negative test --- print("[smoke] negative test: off-board placement") try: bad = h.place(kind, (-1, -1), (0, 0)) assert not bad.get("placed"), f"expected placed:false, got {bad}" assert bad.get("reason"), f"expected reason, got {bad}" print(f" rejected with: {bad['reason']}") except HarnessError as e: print(f" harness error (acceptable): {e}") # --- 6. responsive after negative --- print("[smoke] final state dump") final = h.state() print(f" phase={final['phase']} turn={final['turn']} pieces={len(final['pieces'])}") print("\n[smoke] PASS\n") return 0 if __name__ == "__main__": sys.exit(main())