ue-mcp-plugin-voxel-plugin 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/Tests.md ADDED
@@ -0,0 +1,280 @@
1
+ # VoxelTests — What's in It, What It's Worth Borrowing
2
+
3
+ > Audience: a senior UE5 engineer evaluating whether the plugin's testing approach is worth borrowing for their own project.
4
+
5
+ ## Overview
6
+
7
+ Phyronnaz's `VoxelTests` module is split into two surfaces:
8
+
9
+ - a **content-driven integration layer** — 23 test maps and 127 supporting assets under `Plugins/Voxel/Tests/`
10
+ - a **header include-safety harness** — 96 source files under `Plugins/Voxel/Source/VoxelTests/Private/`
11
+
12
+ The framework is lightweight and **eschews UE Automation** (`IMPLEMENT_SIMPLE_AUTOMATION_TEST`) entirely. Instead, it implements a custom **Blueprint-callable test harness** that loads maps in sequence, tracks pass/fail state, captures screenshots, and emits a JSON report suitable for CI. A separate startup hook auto-generates one `.cpp` per public header to verify every header compiles in isolation.
13
+
14
+ ## Layout
15
+
16
+ ### `Plugins/Voxel/Tests/` — content integration tests
17
+
18
+ - 23 `.umap` test maps covering gameplay, rendering, stamping, navigation
19
+ - 127 supporting assets (materials, graphs, meshes)
20
+ - Total: 150 files
21
+ - Folders: `Assets/`, `BasicGameplay/`, `BasicSplines/`, `CurveNode/`, `DistanceFields/`, `GradientTest/`, `Lumen/`, `MaterialRendering/{CurveMaterial,Gravel,MuddyLeaves}/`, `Metadata/`, `MetadataQueries/`, `Navigation/`, `OverrideGraphs/`, `PCGWorld/`, `Queries/`, `RVT/`, `Sculpting/`, `SmoothBlendsAndSmartSurfaces/`, `TangentNormals/`, `Velocity/`, `WPO/`
22
+
23
+ ### `Plugins/Voxel/Source/VoxelTests/` — native infrastructure
24
+
25
+ - 96 source files (90 `.cpp` + 6 headers)
26
+ - 85 auto-generated include-test stubs in `VoxelCoreIncludeTest/` — one `.cpp` per `VoxelMinimal/` header
27
+ - 6 manual infrastructure files:
28
+ - `VoxelTestsModule.cpp` — module entry, CLI flag handling (`-VoxelTests`, `-RunVoxelTests`)
29
+ - `VoxelTestManager.h/.cpp` — singleton: map sequencing, JSON serialization
30
+ - `VoxelTestLibrary.h/.cpp` — Blueprint-exposed test API
31
+ - `VoxelTestPCH.h` — lightweight include guard for `VoxelCoreMinimal.h`
32
+ - `VoxelCoreIncludeTestGenerator.cpp` — startup hook that creates the stubs
33
+
34
+ The `Build.cs` is intentionally tiny:
35
+
36
+ ```csharp
37
+ public VoxelTests(ReadOnlyTargetRules Target) : base(Target)
38
+ {
39
+ if (new VoxelConfig(this).DevWorkflow)
40
+ {
41
+ // Needed by include testing
42
+ PrivatePCHHeaderFile = "Private/VoxelTestPCH.h";
43
+ }
44
+
45
+ PublicDependencyModuleNames.AddRange(new string[] { "Json" });
46
+ PrivateDependencyModuleNames.AddRange(new string[] { "NavigationSystem" });
47
+ }
48
+ ```
49
+
50
+ ## Framework
51
+
52
+ ### Custom Blueprint-driven, not UE Automation
53
+
54
+ There are **no `IMPLEMENT_SIMPLE_AUTOMATION_TEST` macros**. Instead:
55
+
56
+ 1. **Blueprint layer:** call `UVoxelTestLibrary::StartTest(Name)` → returns `FVoxelTestHandle`.
57
+ 2. **State machine:** each test transitions `Started → Succeeded | Failed`.
58
+ 3. **Manager orchestration** (`FVoxelTestManager` singleton):
59
+ - Sequentially loads test maps from `/Game/VoxelTests/`.
60
+ - Collects pass/fail results, warnings, errors, screenshot GUIDs.
61
+ - Writes JSON to `Saved/VoxelTests/VoxelTests.json`.
62
+ - Captures high-res screenshots on demand.
63
+
64
+ Activation: console command `voxel.tests.Start` or CLI flag `-RunVoxelTests` (non-editor mode only).
65
+
66
+ ### Naming
67
+
68
+ | Surface | Convention |
69
+ |---|---|
70
+ | Test maps | `TEST_<Feature>.umap` (`TEST_BasicGameplay.umap`, `TEST_Gradient.umap`) |
71
+ | Assets | `TEST_<Type>_<Name>.uasset` (`TEST_VHG_Gradient.uasset`, `TEST_MI_Gravel_Red.uasset`) |
72
+ | Include-test stubs | `VoxelCoreIncludeTest_<Category>_<HeaderName>.cpp` |
73
+
74
+ ### Custom assertion macros: none
75
+
76
+ No `VOXEL_TEST_*` macros. The Blueprint-callable surface is the API:
77
+
78
+ ```cpp
79
+ UFUNCTION(BlueprintCallable, Category = "Voxel|Tests")
80
+ static FVoxelTestHandle StartTest(const FString& Name);
81
+
82
+ UFUNCTION(BlueprintCallable, Category = "Voxel|Tests")
83
+ static void PassTest(const FVoxelTestHandle& Handle);
84
+
85
+ UFUNCTION(BlueprintCallable, Category = "Voxel|Tests")
86
+ static void FailTest(const FVoxelTestHandle& Handle, const FString& Reason);
87
+
88
+ UFUNCTION(BlueprintCallable, Category = "Voxel|Tests")
89
+ static void TakeScreenshot(const FGuid& Guid);
90
+ ```
91
+
92
+ Tests call these from Blueprint event graphs (typically on a timer or completion callback). Standard `check()` / `ensure()` are intercepted by `FVoxelTestsOutputDevice` for logging.
93
+
94
+ ### No BDD / spec layer
95
+
96
+ Purely imperative, map-and-actor-driven: an actor in the map handles setup/teardown on `BeginPlay`, the BP graph waits for a completion condition, then calls `FailTest` or `PassTest`.
97
+
98
+ ## Fixture and runtime setup
99
+
100
+ ### Minimal `VoxelRuntime` bootstrapping
101
+
102
+ Tests do **not** spawn an in-memory `AVoxelWorld` CDO. Instead:
103
+
104
+ 1. **Editor-mounted content:** the module registers `Plugins/Voxel/Tests/` as a game path at startup:
105
+ ```cpp
106
+ FPackageName::RegisterMountPoint("/Game/VoxelTests/", DiskPath);
107
+ ```
108
+ 2. **Per-map setup:** each test map ships a custom test actor (e.g. `TEST_BasicGameplayActor.uasset`) that:
109
+ - executes on `BeginPlay`,
110
+ - configures nav generation (`SetNavMeshGeneration(bRuntime)`),
111
+ - spawns the runtime objects under test (VoxelWorld refs, stamps, AI pawns),
112
+ - calls `StartTest` and monitors for completion.
113
+ 3. **World lifespan:** entire map persists for the test; teardown destroys all actors after reporting.
114
+
115
+ ### Asset loading
116
+
117
+ - No transient CDOs — all test assets are pre-authored, disk-resident under `Plugins/Voxel/Tests/Assets/`.
118
+ - Graphs are pre-built `UVoxelHeightGraph` / `UVoxelVolumeGraph` `.uasset`s.
119
+ - Meshes & materials are standard UE5 content.
120
+
121
+ ### No explicit mocking
122
+
123
+ - GPU / render targets: used as-is.
124
+ - Navigation: gated via `SetNavMeshGeneration(bool bRuntime)` which flips `ERuntimeGenerationType` and triggers a rebuild.
125
+ - Threading / task graph: no abstraction; tests run synchronously or wait on async callbacks.
126
+
127
+ ## Coverage map
128
+
129
+ ### What's tested
130
+
131
+ | Area | Maps | Notes |
132
+ |---|---|---|
133
+ | Graph evaluation | `GradientTest`, `CurveNode` | Height/volume graph outputs, curve sampling. |
134
+ | Stamping & blending | `PCGWorld`, `OverrideGraphs`, `SmoothBlendsAndSmartSurfaces` | Procedural stamp application, blend-mode overrides. |
135
+ | Voxel rendering | `MaterialRendering/*`, `Lumen`, `Metadata` | Material slots, translucency, emissive, per-voxel metadata. |
136
+ | Serialization & I/O | `DistanceFields` | Distance-field bake + round-trip. |
137
+ | Gameplay integration | `BasicGameplay`, `Navigation` | Voxel-aware AI, character movement, navmesh. |
138
+ | Advanced rendering | `TangentNormals`, `WPO`, `RVT`, `Velocity` | Tangent normals, world-position offset, runtime VT, motion vectors. |
139
+ | Splines | `BasicSplines` | Spline-driven voxel deformation. |
140
+
141
+ ### What's NOT tested
142
+
143
+ - Editor UI (menus, property panels).
144
+ - Networking / replication / multiplayer integration.
145
+ - Cross-module plugin build sanity beyond compile.
146
+ - Performance — maps exist but no automated perf gates; manual profiling only.
147
+
148
+ Maps are **functional full-stack integration tests**: spawn a VoxelWorld (or load a pre-baked one), run a gameplay loop, assert the final state from Blueprint. No unit tests for individual containers or utilities — those are guarded by the include-testing layer below.
149
+
150
+ ## Include self-containment checks
151
+
152
+ **File:** `Plugins/Voxel/Source/VoxelTests/Private/VoxelCoreIncludeTestGenerator.cpp`
153
+
154
+ On startup (when `VOXEL_DEV_WORKFLOW && VOXEL_DEBUG`) the module:
155
+
156
+ 1. Scans `VoxelCore/Public/VoxelMinimal/` for every `.h`.
157
+ 2. Generates one `.cpp` stub per header, including it in isolation:
158
+ ```cpp
159
+ // Example: VoxelCoreIncludeTest_Containers_VoxelArray.cpp
160
+ #include "VoxelCoreMinimal.h"
161
+ #if VOXEL_DEV_WORKFLOW && VOXEL_DEBUG
162
+ #include "VoxelMinimal/Containers/VoxelArray.h" // the real include
163
+ #endif
164
+ ```
165
+ 3. Forces the PCH to `VoxelTestPCH.h` only when dev-workflow is on, so the linker compiles all 85+ stubs.
166
+ 4. Any header that fails standalone (missing transitive include, circular dep) breaks the build.
167
+
168
+ Why it matters: this catches the classic "works in unity build, fails in incremental compile" failure mode without anyone writing a manual test. Header hygiene is enforced by the build, not by code review.
169
+
170
+ ## Honest assessment
171
+
172
+ ### Strengths
173
+
174
+ 1. **Include-testing discipline is best-in-class.** The auto-generated stub generator is the standout pattern.
175
+ 2. **Lightweight infrastructure** — no Catch2, no GoogleTest, no UE Automation boilerplate.
176
+ 3. **Blueprint-testable gameplay** — designers can write integration tests in maps + event graphs.
177
+ 4. **JSON output for CI** — pipeline-friendly result format.
178
+ 5. **Built-in screenshot capture** — visual regression hook is in place even if not fully automated.
179
+
180
+ ### Weaknesses
181
+
182
+ 1. **Sparse unit-test coverage.** 91 `VoxelMinimal/` headers but only compile-validation, not runtime assertions on container ops.
183
+ 2. **No spec / BDD language.** Test intent is implicit in map names.
184
+ 3. **Content-heavy and fragile.** 23 maps × dozens of assets is a big footprint and renames silently break tests.
185
+ 4. **Limited documentation.** No README per map explaining what it validates.
186
+ 5. **Sequential map loading.** No parallelization for CI time savings.
187
+ 6. **Manual failure diagnosis.** Errors go to log + JSON; reading logs is required to debug.
188
+
189
+ ### Verdict
190
+
191
+ Solid but narrowly-focused. The include-testing pattern is excellent and worth lifting wholesale. The content-map integration layer is a workable smoke-test layer but not a template for comprehensive TDD.
192
+
193
+ ## Patterns worth borrowing
194
+
195
+ ### 1. Auto-generated header compliance tests
196
+
197
+ **Source:** `Plugins/Voxel/Source/VoxelTests/Private/VoxelCoreIncludeTestGenerator.cpp`
198
+
199
+ A startup hook that scans a module's `Public/` tree, generates one `.cpp` per `.h` including it standalone, and gates the PCH so the linker compiles them all. Catches transitive-include bugs and missing forward decls without writing manual tests.
200
+
201
+ Wire it up by gating a dedicated test PCH on a dev flag:
202
+
203
+ ```csharp
204
+ if (bIsDevBuild)
205
+ {
206
+ PrivatePCHHeaderFile = "Private/YourModuleTestPCH.h";
207
+ }
208
+ ```
209
+
210
+ ### 2. Blueprint-callable test harness
211
+
212
+ **Source:** `Plugins/Voxel/Source/VoxelTests/Private/VoxelTestLibrary.h`
213
+
214
+ Expose `StartTest(Name)`, `PassTest(Handle)`, `FailTest(Handle, Reason)` as `UFUNCTION(BlueprintCallable)`. Pairs naturally with map-driven testing — designers can author tests without touching C++.
215
+
216
+ Add gameplay-specific assertion helpers alongside:
217
+
218
+ ```cpp
219
+ UCLASS()
220
+ class YOURMODULE_API UYourTestLibrary : public UBlueprintFunctionLibrary
221
+ {
222
+ public:
223
+ UFUNCTION(BlueprintCallable, Category = "YourModule|Tests")
224
+ static void AssertActorCount(const FString& TestName, int32 Expected, int32 Actual);
225
+
226
+ UFUNCTION(BlueprintCallable, Category = "YourModule|Tests")
227
+ static void AssertFloatAlmostEqual(const FString& TestName, float Expected, float Actual, float Tolerance = 0.01f);
228
+ };
229
+ ```
230
+
231
+ ### 3. Automated screenshot capture for visual regression
232
+
233
+ **Source:** `Plugins/Voxel/Source/VoxelTests/Private/VoxelTestLibrary.cpp` (~lines 81–113)
234
+
235
+ `TakeScreenshot(FGuid)` wraps `HighResShot` and saves to `Saved/VoxelTests/<MapName>/<Guid>.png`. Adding hash- or perceptual-diff comparison turns it into a real visual baseline system.
236
+
237
+ ### 4. Custom `FOutputDevice` for warning / error tracking
238
+
239
+ **Source:** `Plugins/Voxel/Source/VoxelTests/Private/VoxelTestManager.cpp` (~lines 22–100, `FVoxelTestsOutputDevice`)
240
+
241
+ Subclass `FOutputDevice`, register with `GLog`, intercept warnings/errors with stack traces, serialize to JSON. Detects silent failures — `ensure()` firing without an explicit `FailTest`.
242
+
243
+ ### 5. Explicit test state machine
244
+
245
+ **Source:** `Plugins/Voxel/Source/VoxelTests/Private/VoxelTestManager.h` (~lines 9–14, `EVoxelTestState`)
246
+
247
+ `{ Started, Succeeded, Failed }` enum with transition validation. Catches double-pass / double-fail bugs in the test code itself.
248
+
249
+ ### 6. Per-map JSON serialization for CI
250
+
251
+ **Source:** `Plugins/Voxel/Source/VoxelTests/Private/VoxelTestManager.cpp` (~lines 123–181)
252
+
253
+ Per-test pass/fail, screenshots, warnings, errors, raytracing status. Pipelines (Gitea Actions, Jenkins, GitHub Actions) parse this directly to fail the build and link to detailed reports.
254
+
255
+ ## Recommended adoption order
256
+
257
+ 1. **Include-testing pattern first.** Lowest friction, highest immediate value. Start with your smallest-surface module, then expand.
258
+ 2. **Project test library** with gameplay-specific assertions: fuzzy compare, actor count, component state, GAS attribute equality.
259
+ 3. **Visual baseline on top of screenshot capture** — hash or perceptual diff in CI.
260
+ 4. **Document test maps** with a README per map (goal, expected result, manual verification).
261
+ 5. **Defer parallelization** — sequential map loading is fine until tests exceed ~50.
262
+ 6. **Add perf gates separately:** log frame time, draw calls, memory per map; fail on delta thresholds. Voxel doesn't do this and probably should.
263
+
264
+ ## Summary
265
+
266
+ | Aspect | Voxel approach | Notes |
267
+ |---|---|---|
268
+ | Framework | Custom Blueprint + manager | Low overhead, gameplay-friendly. |
269
+ | Coverage | Content maps + include stubs | Integration-focused; unit coverage thin. |
270
+ | Assertion macros | None (UE `check`/`ensure` + custom output device) | No DSL to learn. |
271
+ | Fixtures | Disk-resident assets, per-map actors | Reusable, but fragile to refactor. |
272
+ | CI integration | JSON output | Parse anywhere. |
273
+ | Header safety | Auto-generated stubs | Best-in-class — adopt as-is. |
274
+ | BDD / spec | None | Consider adding for docs. |
275
+ | Mocking | Minimal (real GPU, threading) | May need expansion for subsystem tests. |
276
+
277
+ ## Cross-references
278
+
279
+ - The headers being include-tested live in [VoxelCore](VoxelCore.md).
280
+ - `FVoxelTestsOutputDevice` integrates with the [VoxelCore message system](VoxelCore.md#messages).