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>
- .claude/skills/replay-test/SKILL.md +76 -29
- CLAUDE.md +40 -15
- 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 |
-
###
|
| 13 |
-
|
|
|
|
| 14 |
|
| 15 |
```bash
|
| 16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
```
|
| 18 |
|
| 19 |
-
###
|
| 20 |
-
|
|
|
|
| 21 |
|
| 22 |
```bash
|
| 23 |
-
powershell -ExecutionPolicy Bypass -File replay-test.ps1
|
| 24 |
```
|
| 25 |
|
| 26 |
-
## Steps
|
| 27 |
|
| 28 |
-
1. Run the
|
| 29 |
|
| 30 |
2. Read the output and present results:
|
| 31 |
|
| 32 |
-
**
|
| 33 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
|
| 35 |
**Headful mode:**
|
| 36 |
-
-
|
| 37 |
-
|
| 38 |
-
- **
|
|
|
|
| 39 |
- Quote any FAIL lines exactly
|
| 40 |
-
-
|
| 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 |
-
- `
|
| 51 |
-
- `
|
| 52 |
-
- `
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
|
| 54 |
-
|
|
|
|
|
|
|
|
|
|
| 55 |
|
| 56 |
## Notes
|
| 57 |
|
| 58 |
-
- Headful replay
|
| 59 |
-
-
|
| 60 |
-
-
|
| 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
|
| 38 |
|
| 39 |
-
|
|
|
|
|
|
|
| 40 |
|
| 41 |
```bash
|
| 42 |
-
#
|
| 43 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
```
|
| 45 |
|
| 46 |
-
|
| 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 |
-
-
|
| 54 |
-
-
|
| 55 |
-
-
|
| 56 |
-
|
|
|
|
| 57 |
|
| 58 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
- `OPENWA_VALIDATE=1` β Enable validation module (struct checks, vtable validation, memory dumps)
|
| 60 |
-
- `OPENWA_REPLAY_TEST=1` β Fast-forward mode
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
|
|
|
| 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
|