paavohtl Claude Opus 4.6 (1M context) commited on
Commit
72b45ce
Β·
1 Parent(s): eb3bec7

docs: update replay testing docs for new test runner

Browse files

- CLAUDE.md: rewrite Replay Testing section with test runner as primary,
add openwa-test-runner to crate architecture, document env vars and
instructions for adding new replay tests
- run-tests.ps1: use cargo run to ensure binary is up-to-date
- SKILL.md: rewrite with test runner quick start, updated paths and options

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Files changed (3) hide show
  1. .claude/skills/replay-test/SKILL.md +76 -29
  2. CLAUDE.md +40 -15
  3. run-tests.ps1 +1 -1
.claude/skills/replay-test/SKILL.md CHANGED
@@ -7,56 +7,103 @@ description: Run automated replay-based testing - builds, launches WA.exe with a
7
 
8
  Run the replay-based automated testing pipeline.
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  ## Modes
11
 
12
- ### Headful (default) β€” graphics, sound, validation
13
- Tests hooks, struct layouts, and game state with the full rendering pipeline active.
 
14
 
15
  ```bash
16
- powershell -ExecutionPolicy Bypass -File replay-test.ps1
 
 
 
 
17
  ```
18
 
19
- ### Headless β€” pure simulation, log comparison
20
- Uses WA's built-in `/getlog` mode: no window, no rendering, pure CPU simulation. Compares the output log byte-for-byte against an expected log to verify replay determinism. An order of magnitude faster than headful mode.
 
21
 
22
  ```bash
23
- powershell -ExecutionPolicy Bypass -File replay-test.ps1 -Headless
24
  ```
25
 
26
- ## Steps
27
 
28
- 1. Run the replay test script (headful or headless as appropriate).
29
 
30
  2. Read the output and present results:
31
 
32
- **Both modes:**
33
- - If `testdata/logs/errorlog_latest.txt` exists, WA.exe crashed. Read it and report the crash (exception type, address, registers)
 
 
 
 
 
 
34
 
35
  **Headful mode:**
36
- - Read `testdata/logs/validation_latest.log` and check two categories:
37
- - **Static checks** (`[STATIC PASS]`/`[STATIC FAIL]`): vtable addresses, struct offsets, function prologues. These verify memory layout correctness but NOT that the game actually ran.
38
- - **Gameplay checks** (`[GAMEPLAY PASS]`/`[GAMEPLAY FAIL]`): milestone-based detection of game initialization, match start (multiple alive teams), and match completion (winner decided). These confirm the replay actually played through.
 
39
  - Quote any FAIL lines exactly
40
- - Note whether safety timeout triggered
41
- - If `testdata/logs/openwa_latest.log` exists, check for errors or interesting hook activity
42
-
43
- **Headless mode:**
44
- - The script compares the output log to `testdata/replays/bots_expected.log`
45
- - PASS means byte-identical output -- replay is deterministic
46
- - FAIL shows the diff lines between expected and actual
47
 
48
  ## Environment Variables
49
 
50
- - `OPENWA_VALIDATE=1` β€” (headful) Enables validation module
51
- - `OPENWA_REPLAY_TEST=1` β€” (headful) Enables fast-forward mode (50x speed)
52
- - `OPENWA_HEADLESS=1` β€” (headless) Hooks MessageBoxA to auto-dismiss, enabling unattended /getlog
 
 
 
 
 
 
 
 
 
 
 
 
 
53
 
54
- All are set automatically by `replay-test.ps1`.
 
 
 
55
 
56
  ## Notes
57
 
58
- - Headful replay typically completes in ~15-30s; headless in ~5s
59
- - Custom replay: `powershell -File replay-test.ps1 [-Headless] path\to\other.WAgame`
60
- - Expected log convention: `<replay>_expected.log` next to `<replay>.WAgame`
61
- - If no expected log exists, headless mode saves the first output as the expected log
62
- - The launcher uses named event synchronization to ensure all hooks are installed before WA.exe's main thread runs
 
7
 
8
  Run the replay-based automated testing pipeline.
9
 
10
+ ## Quick Start β€” Run All Tests
11
+
12
+ The fastest way to run all replay tests:
13
+
14
+ ```bash
15
+ .\run-tests.ps1
16
+ ```
17
+
18
+ This builds and runs the `openwa-test` binary via `cargo run`, which then builds the DLL + launcher, discovers all `testdata/replays/*.WAgame` files with matching `*_expected.log`, and runs them concurrently (default 4 workers) in headless mode. Output:
19
+
20
+ ```
21
+ Building... done (2.1s)
22
+ Running 7 tests (4 concurrent)...
23
+
24
+ PASS bots (5.2s)
25
+ PASS longbow (4.9s)
26
+ ...
27
+
28
+ 7 tests: all passed (wall 12.0s, cpu 40.3s)
29
+ ```
30
+
31
+ Options:
32
+ - `.\run-tests.ps1 longbow` β€” filter by name
33
+ - `.\run-tests.ps1 -j 1` β€” serial mode (for debugging)
34
+ - `.\run-tests.ps1 --no-build` β€” skip internal DLL/launcher build (assumes already built)
35
+
36
  ## Modes
37
 
38
+ ### Headless test runner (primary)
39
+
40
+ Uses WA's built-in `/getlog` mode: no rendering, pure CPU simulation. Compares the output log byte-for-byte against an expected baseline.
41
 
42
  ```bash
43
+ # All tests:
44
+ .\run-tests.ps1
45
+
46
+ # Single replay via old script:
47
+ powershell -ExecutionPolicy Bypass -File replay-test.ps1 -Headless testdata/replays/longbow.WAgame
48
  ```
49
 
50
+ ### Headful (interactive) β€” graphics, sound, validation
51
+
52
+ Tests hooks, struct layouts, and game state with the full rendering pipeline active. Use for debugging specific replays.
53
 
54
  ```bash
55
+ powershell -ExecutionPolicy Bypass -File replay-test.ps1
56
  ```
57
 
58
+ ## Steps (for Claude)
59
 
60
+ 1. Run the appropriate test command.
61
 
62
  2. Read the output and present results:
63
 
64
+ **Headless (test runner):**
65
+ - PASS/FAIL summary is printed directly
66
+ - Per-run logs stored in `testdata/runs/<timestamp>/`
67
+ - FAIL shows first differing lines between expected and actual
68
+
69
+ **Headless (single replay via script):**
70
+ - PASS means byte-identical output to `<replay>_expected.log`
71
+ - FAIL shows the diff lines
72
 
73
  **Headful mode:**
74
+ - If `testdata/logs/errorlog_latest.txt` exists, WA.exe crashed. Read it and report the crash
75
+ - Read `testdata/logs/validation_latest.log`:
76
+ - **Static checks** (`[STATIC PASS]`/`[STATIC FAIL]`): vtable addresses, struct offsets
77
+ - **Gameplay checks** (`[GAMEPLAY PASS]`/`[GAMEPLAY FAIL]`): game init, match start, match completion
78
  - Quote any FAIL lines exactly
79
+ - Check `testdata/logs/openwa_latest.log` for `[PANIC]` errors
 
 
 
 
 
 
80
 
81
  ## Environment Variables
82
 
83
+ - `OPENWA_HEADLESS=1` β€” Headless mode: auto-dismiss MessageBoxA, SW_HIDE window, file isolation
84
+ - `OPENWA_VALIDATE=1` β€” (headful) Enable validation module
85
+ - `OPENWA_REPLAY_TEST=1` β€” (headful) Enable fast-forward mode (50x speed)
86
+ - `OPENWA_LOG_PATH=<path>` β€” Override OpenWA.log location (per-instance isolation)
87
+
88
+ All are set automatically by the test runner / replay-test.ps1.
89
+
90
+ ## Key Paths
91
+
92
+ - Replay files + expected logs: `testdata/replays/*.WAgame` + `*_expected.log`
93
+ - Per-run output: `testdata/runs/<timestamp>/` (gitignored)
94
+ - Test runner: `crates/openwa-test-runner/` (`openwa-test` binary)
95
+ - Convenience script: `run-tests.ps1`
96
+ - Single-replay script: `replay-test.ps1`
97
+
98
+ ## Adding New Replay Tests
99
 
100
+ 1. Record a game in WA.exe (replay `.WAgame` saved automatically)
101
+ 2. Copy to `testdata/replays/`
102
+ 3. Run `.\run-tests.ps1` β€” auto-generates `*_expected.log` on first run
103
+ 4. Subsequent runs compare against the baseline
104
 
105
  ## Notes
106
 
107
+ - Headful replay: ~15-30s; headless: ~5s per test
108
+ - Concurrent headless tests use per-PID event names, log paths, and temp files (CreateFileA hook)
109
+ - Named event: `OpenWA_HooksReady_{pid}` β€” ensures hooks installed before WA main thread runs
 
 
CLAUDE.md CHANGED
@@ -34,30 +34,54 @@ It used to be necessary to copy the built DLLs to the game directory and launch
34
 
35
  ## Replay Testing
36
 
37
- Use the `/replay-test` skill to automatically build, deploy, launch WA.exe with a replay file, capture validation logs, and present results. This is the fastest way to validate struct layouts, hooks, and game state against live WA.exe.
38
 
39
- **Use replay testing to validate assumptions and test theories!** You don't have to figure out everything from disassembly and static analysis. Make a hypothesis, implement it in the DLL, then use replay testing to see if it holds up against the real game. This iterative approach is much faster than trying to get everything right on the first try.
 
 
40
 
41
  ```bash
42
- # Manual invocation (skill runs this automatically):
43
- powershell -ExecutionPolicy Bypass -File replay-test.ps1
 
 
 
 
 
44
  ```
45
 
46
- How it works:
47
- 1. `replay-test.ps1` builds the unified DLL, deploys to game dir, sets `OPENWA_VALIDATE=1` and `OPENWA_REPLAY_TEST=1`, launches `WA.exe` minimized with a replay file
48
- 2. The DLL restores the window after 2s via FindWindowA + ShowWindow(SW_RESTORE), then hooks TurnManager_ProcessFrame and sets DDGame+0x98B0=1 each frame to enable 50x fast-forward (same mechanism as spacebar during replay). Validation runs at 5s. The replay typically finishes in ~15-30s
49
- 3. Script copies logs to `testdata/logs/` and prints a PASS/FAIL summary
50
 
51
  Key paths:
52
- - Replay files: `testdata/replays/*.WAgame`
53
- - Captured logs: `testdata/logs/` (gitignored, `validation_latest.log` / `openwa_latest.log` / `errorlog_latest.txt`)
54
- - Crash log: WA writes `ERRORLOG.TXT` to game dir on crash -- script clears it before each run and copies to `testdata/logs/` if present
55
- - Script: `replay-test.ps1`
56
- - Skill: `.claude/skills/replay-test/SKILL.md`
 
57
 
58
- Environment variables:
 
 
 
 
 
 
 
 
 
 
 
59
  - `OPENWA_VALIDATE=1` β€” Enable validation module (struct checks, vtable validation, memory dumps)
60
- - `OPENWA_REPLAY_TEST=1` β€” Fast-forward mode: hooks TurnManager_ProcessFrame and sets DDGame+0x98B0=1 each frame (50x speed). Restores window at 2s, runs validation at 5s, 120s safety timeout. Without this, validation runs interactively with hotkeys (F9=team blocks, F10=landscape)
 
 
 
 
 
 
 
 
61
 
62
  ## Debug CLI
63
 
@@ -93,6 +117,7 @@ Key env vars:
93
  - **`openwa-core`** β€” Types, addresses, parsers, ASLR rebasing, and typed WA function wrappers. The source of truth for all reverse-engineered type layouts and known addresses (`address.rs`). Contains `rebase` (ASLR delta), `wa_call` (calling convention helpers), and `wa/` (typed handle wrappers like `DDGameWrapperHandle`, `CWndHandle`).
94
  - **`openwa-wormkit`** β€” Unified WormKit cdylib that replaces WA functions with Rust and optionally validates types against live memory. Logs to `OpenWA.log` (hooks) and `OpenWA_validation.log` (validation). Uses MinHook for inline hooking. Validation is enabled via `OPENWA_VALIDATE=1` env var.
95
  - **`openwa-harness`** β€” Offline test harness that loads WA.exe into process memory via `LoadLibraryExA(DONT_RESOLVE_DLL_REFERENCES)` for testing without running the game.
 
96
  - **`openwa-debug-cli`** β€” CLI tool for live memory inspection (`openwa-debug` binary). Connects to the debug server in the DLL.
97
  - **`openwa-debug-proto`** β€” Shared protocol types (Request/Response enums, MessagePack framing) between CLI and server.
98
 
 
34
 
35
  ## Replay Testing
36
 
37
+ **Use replay testing to validate assumptions and test theories!** Make a hypothesis, implement it in the DLL, then run replay tests to see if it holds up against the real game. This iterative approach is much faster than trying to get everything right from static analysis alone.
38
 
39
+ ### Headless test runner (primary)
40
+
41
+ The `openwa-test-runner` crate (`openwa-test` binary) runs all replay tests automatically with concurrent execution:
42
 
43
  ```bash
44
+ # Run all tests (builds everything, default 4 concurrent):
45
+ .\run-tests.ps1
46
+
47
+ # Filter by name, control parallelism:
48
+ .\run-tests.ps1 longbow # only tests matching "longbow"
49
+ .\run-tests.ps1 -j 1 # serial mode
50
+ .\run-tests.ps1 --no-build # skip internal DLL/launcher build
51
  ```
52
 
53
+ Each test runs WA.exe in headless `/getlog` mode (pure CPU simulation, no rendering) and compares the output log byte-for-byte against an expected baseline. Tests are isolated for concurrent execution via per-PID event names, log paths, and landscape temp files (`CreateFileA` hook).
 
 
 
54
 
55
  Key paths:
56
+ - Replay files + expected logs: `testdata/replays/*.WAgame` + `*_expected.log`
57
+ - Per-run output: `testdata/runs/<timestamp>/` (gitignored)
58
+ - Test runner: `crates/openwa-test-runner/`
59
+ - Convenience script: `run-tests.ps1`
60
+
61
+ ### Headful replay testing (interactive)
62
 
63
+ Use the `/replay-test` skill for interactive testing with graphics, sound, and validation module:
64
+
65
+ ```bash
66
+ powershell -ExecutionPolicy Bypass -File replay-test.ps1
67
+ powershell -ExecutionPolicy Bypass -File replay-test.ps1 -Headless testdata/replays/longbow.WAgame
68
+ ```
69
+
70
+ Headful mode enables fast-forward (50x via DDGame+0x98B0) and runs struct validation at 5s. Use for debugging specific replays or testing visual/audio hooks.
71
+
72
+ ### Environment variables
73
+
74
+ - `OPENWA_HEADLESS=1` β€” Headless mode: hooks MessageBoxA to auto-dismiss, launcher uses SW_HIDE, file isolation hook active
75
  - `OPENWA_VALIDATE=1` β€” Enable validation module (struct checks, vtable validation, memory dumps)
76
+ - `OPENWA_REPLAY_TEST=1` β€” Fast-forward mode for headful testing (50x speed, 120s safety timeout)
77
+ - `OPENWA_LOG_PATH=<path>` β€” Override OpenWA.log location (used by test runner for per-instance isolation)
78
+
79
+ ### Adding new replay tests
80
+
81
+ 1. Record a game in WA.exe (the replay `.WAgame` file is saved automatically)
82
+ 2. Copy the replay to `testdata/replays/`
83
+ 3. Run once with the headless test runner β€” it auto-generates the `*_expected.log` baseline
84
+ 4. Subsequent runs compare against this baseline
85
 
86
  ## Debug CLI
87
 
 
117
  - **`openwa-core`** β€” Types, addresses, parsers, ASLR rebasing, and typed WA function wrappers. The source of truth for all reverse-engineered type layouts and known addresses (`address.rs`). Contains `rebase` (ASLR delta), `wa_call` (calling convention helpers), and `wa/` (typed handle wrappers like `DDGameWrapperHandle`, `CWndHandle`).
118
  - **`openwa-wormkit`** β€” Unified WormKit cdylib that replaces WA functions with Rust and optionally validates types against live memory. Logs to `OpenWA.log` (hooks) and `OpenWA_validation.log` (validation). Uses MinHook for inline hooking. Validation is enabled via `OPENWA_VALIDATE=1` env var.
119
  - **`openwa-harness`** β€” Offline test harness that loads WA.exe into process memory via `LoadLibraryExA(DONT_RESOLVE_DLL_REFERENCES)` for testing without running the game.
120
+ - **`openwa-test-runner`** β€” Headless replay test runner (`openwa-test` binary). Discovers replay tests, runs them concurrently via WA.exe's `/getlog` mode, compares output logs. See "Replay Testing" section.
121
  - **`openwa-debug-cli`** β€” CLI tool for live memory inspection (`openwa-debug` binary). Connects to the debug server in the DLL.
122
  - **`openwa-debug-proto`** β€” Shared protocol types (Request/Response enums, MessagePack framing) between CLI and server.
123
 
run-tests.ps1 CHANGED
@@ -5,4 +5,4 @@
5
  # .\run-tests.ps1 longbow # only tests matching "longbow"
6
  # .\run-tests.ps1 -j 1 # serial mode
7
 
8
- & "$PSScriptRoot\target\i686-pc-windows-msvc\release\openwa-test.exe" @args
 
5
  # .\run-tests.ps1 longbow # only tests matching "longbow"
6
  # .\run-tests.ps1 -j 1 # serial mode
7
 
8
+ cargo run -p openwa-test-runner --release -- @args