You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- **Shutdown orchestration tests:** `tests/test_shutdown.cpp` tests the `DMK_Shutdown()` function from `DetourModKit.hpp`, verifying idempotent shutdown, hot-reload re-initialization, and correct teardown ordering across all subsystems.
224
224
- **Integration tests:** `tests/test_hook_integration.cpp` tests cross-module hooking against `tests/fixtures/hook_target_lib.cpp` (built as a DLL). The DLL exports `extern "C"` functions with volatile magic constants for stable AOB patterns. Includes hot-reload integration tests that exercise full hook/teardown/re-hook cycles, multi-type reload, enable/disable toggling, and repeated cycle stress.
225
225
- **Platform tests:** `tests/test_platform.cpp` tests internal loader-lock detection and module pinning utilities from `src/platform.hpp`.
226
+
- **Decoder tests:** `tests/test_x86_decode.cpp` tests the internal header `src/x86_decode.hpp` (RIP-relative E9 / EB / FF25 resolvers consumed by `Scanner`). The test file adds `src/` to its include path and drives each decoder with hand-crafted byte buffers.
227
+
- **Worker tests:** `tests/test_worker.cpp` covers the `StoppableWorker` RAII `std::jthread` wrapper, including the empty-body early return, swallowed `std::exception` and unknown-exception paths, and idempotent `request_stop()` / `shutdown()`. The loader-lock detach arm is untestable from user code (only reached under DllMain) and is accepted as such.
226
228
- **Test fixture pattern:** Each suite uses a `::testing::Test` subclass with `SetUp()`/`TearDown()` for temp file cleanup. Temp file paths must include the process ID (`_getpid()`) and a counter to avoid collisions when CTest runs tests in parallel as separate processes.
227
229
- **VMT hook test lifetime:** GoogleTest destroys test-body locals *before* calling `TearDown()`. VMT tests must explicitly call `remove_all_vmt_hooks()` (or `remove_vmt_hook`) before target objects go out of scope. Do not rely on `TearDown()` for VMT cleanup when the hooked object is a test-body local.
228
230
- **Coverage gate:** 80% minimum line coverage enforced in CI. All PRs must pass.
Copy file name to clipboardExpand all lines: docs/tests/README.md
+20-1Lines changed: 20 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -280,6 +280,21 @@ This is expected when casting `FARPROC` from `GetProcAddress` to a typed functio
280
280
281
281
These tests enable the test-only `debug_snapshot_use_count()` accessor via `#define DMK_EVENT_DISPATCHER_INTERNAL_TESTING 1` at the top of the translation unit. The macro is not part of the public API and must not be defined in consumer code.
282
282
283
+
## x86 Control-Flow Decoder Tests
284
+
285
+
`tests/test_x86_decode.cpp` exercises the internal header `src/x86_decode.hpp`, which is consumed by `Scanner` for RIP-relative jump/call resolution. The decoders are small and pure, so each branch is driven by crafting a byte buffer and calling the decoder directly:
286
+
287
+
| Test | What it proves |
288
+
| ---- | -------------- |
289
+
|`DecodeE9Rel32_WrongOpcodeRejected` / `DecodeEbRel8_WrongOpcodeRejected`| Opcode-mismatch short-circuit returns `std::nullopt` without reading the displacement. |
290
+
|`DecodeE9Rel32_ValidForwardDisplacement` / `DecodeE9Rel32_ValidBackwardDisplacement`|`base + 5 + disp32` is computed for both positive and negative displacements. |
291
+
|`DecodeEbRel8_NegativeDisplacementSignExtended`|`0xFE` on the displacement byte decodes as `-2`, proving the `std::int8_t` cast sign-extends correctly. |
292
+
|`DecodeFf25Indirect_WrongFirstByteRejected` / `DecodeFf25Indirect_WrongSecondByteRejected`| Both halves of the compound `FF 25` opcode predicate are rejected independently. |
293
+
|`DecodeFf25Indirect_UnreadableSlotRejected`| A displacement that places the indirect slot outside the user address range returns `std::nullopt`. |
294
+
|`DecodeFf25Indirect_SlotProducesDestination`| Happy path: the slot pointer is materialised and returned verbatim. An aligned struct lays out the instruction and slot so the RIP-relative displacement is independent of padding. |
295
+
296
+
The decoder header lives under `src/` (not the public include tree), so the test file adds `src/` to its include path and uses `DetourModKit::detail::` directly.
297
+
283
298
## Benchmark Harness
284
299
285
300
`tests/bench_event_dispatcher.cpp` is a standalone microbenchmark executable. It is deliberately not a gtest binary so it can run under any build configuration (release, release+PGO, ASAN, etc.) without dragging in the gtest runtime.
0 commit comments