08 — Test coverage (behavioral)¶
No line/branch % claimed — no coverage tool is wired. This page is the definitive behavioral FEATURE × TEST matrix from the live tree: what is tested, where, and how. Gate wiring (lefthook, ctest registrations) lives on quality-gates.md and is only referenced, not repeated.
Dual harness (+ script gates)¶
| Harness | Source | Runner | Count (this refresh) |
|---|---|---|---|
| C++ Catch2 | src/Engine/tests/engine_tests.cpp |
ctest → NPSEngineTests |
90 TEST_CASEs (73 TEST_CASE + 17 TEST_CASE_METHOD) |
| C# xUnit | tests/NPSEngine.Tests/*.cs (10 files) |
dotnet test |
115 methods (111 [Fact] + 4 [Theory], all Theories in EngineBridgeTests.cs) |
| Script fitness | scripts/*.sh |
lefthook pre-push + ctest | layer-fitness (live), no-placeholder-scan (live), fixture-present (live), docs-deploy (live), structural-fitness (disabled), smoke-apps (disabled), production Test*-gate (ctest-only) |
HOW legend — golden = real Benchy fixture with hard asserts;
synthetic = embedded gcode/XML/temp files; crafted = byte-patched ZIP;
bridge = P/Invoke into the real libNPSEngine.so; headless =
Avalonia.Headless real controls; logic = pure managed math; ABI smoke =
entry-point call without semantic assert; structural = grep/nm/script scan.
Golden fixture¶
4-colors+Benchy+AMS+test-v2.3mf (repo root) = 1 plate / 16562 vertices /
33097 triangles / 4 palette colors (0xFFC12E1F, 0xFFFEC600,
0xFF00AE42, 0xFF0A2989). Constants pinned at engine_tests.cpp:93-95;
resolver ResolveBenchyPath() (:102), RAII BenchyFixture (:139). The
fixture-present pre-push hook (lefthook.yml:139-140) refuses to push
without it — there is no synthetic fallback for loader tests.
Consumers (hard golden asserts, not smoke):
| Harness | Tests |
|---|---|
| C++ | load :287/:1092; ZIP :339/:1102; mesh query :374; BenchyFixture suite :621/:630/:638 (exact palette)/:651 (first-vertex transforms)/:674 (bounds); metadata-only :706; missing-entry ZIP :1056; bounds overload :4390; viewport/warp :1674; perf :1812; render SHA :2437; gen+analyze :2538-:2915 |
| C# | EngineBridgeTests.cs:292 (full contract via Marshal.Copy), :601, :669, :744, :1008, :1059 (unsafe reads), :1772 (SHA parity); EngineSessionTests.cs:95,:142,:166,:185,:211; MeshControllerTests.cs:51,:91; ViewportControllerTests.cs:460,:509 |
Test-hook-gated exports (why they exist)¶
NPS_ENABLE_TEST_HOOKS (src/Engine/CMakeLists.txt:31, auto-ON when
BUILD_TESTING=ON at :50-60, defined at :212-213) compiles extra C ABI
entry points that let both harnesses drive internals without exposing them
in production: TestParseModelXmlForHarness, TestZipReaderExtractModelAndMetadata,
TestZipReaderDirectError, TestGetPlateThumbnailSize, GetMeshBounds
(abi/nps_c_api.h:247-274), TestGcodeParseForHarness,
TestThermalGridForHarness, TestStructuralScoreForHarness,
TestAnalysisManagerThermal (:398-411). GetMeshBounds is test-gated
because no app/C# consumer exists — production computes bounds from the
vertex stream. The production gate (nps-n1m-12-production-gate.sh) asserts
zero Test* symbols via nm -D; see
quality-gates.md for why that gate never runs inside
lefthook (hooks always build Debug+tests).
Feature × test matrix¶
C++/C# cells give line anchors (engine_tests.cpp / the named C# file).
Load / 3MF / ZIP¶
| Feature | Where | C++ | C# | Scripts | HOW | Verdict |
|---|---|---|---|---|---|---|
| 3MF load end-to-end | engine.cpp:540/550 |
:287,:1092,:621,:630 |
EngineBridgeTests:292,:601; EngineSessionTests:95 |
fixture-present | golden | covered |
| ZIP/OPC reader | engine_zip.cpp |
:339,:1102 |
indirect via load tests | — | golden + Test* hooks | covered (C++); partial C# (indirect only) |
| ZIP error paths (EOCD/truncated/sig/compression/deflate/missing/stored-size/null) | engine_zip.cpp |
Zip error suite :965-:1084 (8 cases: 7 ZipReaderFixture + null-args plain TEST_CASE at :1084) |
only EngineBridgeTests:465 (magic/empty/size) |
— | crafted byte-patched ZIPs | covered (C++); partial C# |
| 3MF XML parser | engine.cpp:2084/2325/2472 |
:1178,:1206,:1224,:1240 |
— | — | synthetic real-derived XML | covered (C++ only) |
| Mesh queries (verts/tris/colors/plates/unit) | engine.cpp:988-1109 |
:374,:651 |
EngineBridgeTests:292,:1059 |
— | golden, exact counts+samples | covered |
| Mesh bounds (AABB) | engine.cpp:1059/1077 |
:529,:674,:4390 |
— (test-gated export, by design) | — | golden via test-gated export | covered (C++); N/A C# |
| Palette decode (4-color AMS) | engine_color.cpp |
:638 exact hex |
EngineBridgeTests:292; MeshControllerTests:51 |
— | golden exact-hex | covered |
| Plate thumbnail | engine.cpp:1116 |
size>1000B inside :374 |
— | — | golden, SIZE-only | partial — PNG content never verified |
| Multi-plate / multi-object | engine.cpp:885 hardcodes plate_1 |
— | — | — | no multi-plate fixture exists | NOT TESTED (feature single-plate by design) |
| Loader error model | engine.cpp:550-970 |
:724,:743,:816 |
EngineBridgeTests:446,:465,:555; EngineSessionTests:127 |
— | synthetic temp files + C ABI | covered |
G-code generation & parsing¶
| Feature | Where | C++ | C# | Scripts | HOW | Verdict |
|---|---|---|---|---|---|---|
| GenerateGcode (demo toolpath, not slicing) | engine.cpp:1215 |
:2538,:2637,:2780 |
EngineBridgeTests:744; EngineSessionTests:166 |
— | golden + demo gen | covered (as demo toolpath) |
| Gen errors + C ABI buffer/file roundtrip | engine.cpp:1593/2947-3028 |
:2700,:2729 |
— | — | synthetic + golden + ABI | covered (C++); partial (no C# gen-error cases) |
Real slicing (slice/ module) |
does not exist (engine.h:155) |
— | — | — | — | N/A — feature not implemented |
| Text gcode parse (layers, M82/83, G92, M204, arcs, Bambu markers) | engine.cpp:3621 |
:1290,:1346,:1371,:1398,:1410,:3178 |
EngineBridgeTests:636 |
— | synthetic via Test*; optional real file | covered |
| bgcode binary parse | engine.cpp:3407/4049 |
:1509 (skips if fixture absent) |
EngineBridgeTests:823 (hard-requires, >1000 moves, maxL≥249) |
— | real test_cube_binary.bgcode |
covered (happy path); corrupt bgcode (bad CRC) NOT TESTED anywhere |
| Parsed/generated text split | engine.cpp:1436/1453 |
:1447 |
EngineBridgeTests:923 |
— | synthetic via C ABI, sentinels | covered |
| Move array (shared after gen or parse) | engine.cpp:1460/1464 |
inside :1447,:2538,:2729 |
EngineSessionTests:142,:166 |
— | bridge pointer+count | covered |
| Parser robustness (null/empty/long-line/malformed metadata/false banners) | engine.cpp:4011 |
:3368-:3516 (8 cases) |
EngineBridgeTests:1570 (Theory, empty only) |
— | synthetic adversarial | covered (C++ deep; C# one row) |
Analysis & material¶
| Feature | Where | C++ | C# | Scripts | HOW | Verdict |
|---|---|---|---|---|---|---|
| Thermal analyzer | engine.cpp:4320 |
:1550, perf :1755 |
EngineBridgeTests:650 |
— | synthetic; score>0, gridHeatSum==score only | partial — no golden thermal values |
| Structural analyzer | engine.cpp:4650 |
:1570 |
EngineBridgeTests:650 |
— | synthetic; score>0 only | partial |
| Motion analyzer (junction velocity) | engine.cpp:4803 |
only via E2E :1625 |
only via EngineBridgeTests:669 |
— | no analyzer-specific unit test; inferProfileFromGcode is a stub (:4851) |
partial |
| Hole findings | engine.cpp:6606 |
:2896 ("diameter" in message) |
indirect via :1468 |
— | golden + demo gen | covered |
| Retraction + stringing | engine.cpp:6839 |
:2940 |
— | — | synthetic gcode | covered (C++); NOT TESTED in C# |
| Flow + volumetric overlays | engine.cpp:6923 |
:2915,:3541 (108B POD, cap 7.5) |
EngineBridgeTests:1345 |
— | golden + synthetic + ABI | covered |
| Material catalog (10 rows, PLA fallback, key normalize) | material_catalog.cpp |
:3249 (11 GENERATE rows),:3276,:3286,:3310 |
— | — | unit | covered (C++); NOT TESTED in C# |
| Inferred profile (slicer/printer/material/FLAVOR/temp fallback) | engine.cpp:176 |
:3021,:3092,:3131,:3154,:3331 |
EngineBridgeTests:1129,:1204,:1261 (Theory),:1307 (Theory) |
— | synthetic headers, both harnesses | covered |
Findings / overlays / viewport¶
| Feature | Where | C++ | C# | Scripts | HOW | Verdict |
|---|---|---|---|---|---|---|
| Findings summary (16B) + detail (300B) contract | engine.cpp:1513/1538 |
via analysis tests only | EngineBridgeTests:1468 (count/row equality, id -1→InvalidArgument, past-end→NotFound),:1548; EngineSessionTests:185,:211,:233 |
— | bridge + synthetic | covered (C# owns the contract) |
| Per-move overlay values + supported ids | engine.cpp:1550/1557/5573 |
:2010,:1625,:3633 |
EngineSessionTests:253,:261 |
— | synthetic + ABI | covered — GetSupportedOverlayIds is a hardcoded stub (engine.cpp:5579), tested as-is |
| Overlay stats pipeline (Min/Max/Mean/SampleCount, zero-filter) | ViewportController.cs:564-640 |
:4065,:4107 |
ViewportControllerTests:460,:509 |
— | bridge + golden + demo gen | covered (controller level) |
| Heatmap colors (ramp/invert/vmax/null) | engine.cpp:6186 |
:2047 |
EngineBridgeTests:1642-:1686 (exact (0,1,0) mid) |
— | unit + ABI | covered |
| Warp grid (info + risk arrays) | engine.cpp:1572/1578 |
:1674 (size==gridW*gridH) |
EngineSessionTests:241 (null guard only) |
— | ABI shape only | partial — risk VALUES never content-asserted |
| Viewport buffers (layer buckets/offsets/extrude counts) | engine.cpp:5861 |
:1918 |
EngineBridgeTests:1008 (smoke, Assert.True(true) tail) |
— | synthetic; C# ABI smoke | covered (C++); C# smoke-only |
| Viewport MVP + camera | engine.cpp:6102/5761 |
:1976,:3998,:4372 |
ViewportControllerTests:84,:104 |
— | synthetic + mirror | covered |
| ProjectOrbitXY | engine.cpp:5400 |
:2078 (11 samples, 1e6 boundary) |
EngineBridgeTests:1697,:1741,:1753 |
— | golden math vs legacy oracle ±1e-4 | covered |
| Golden render parity (SHA-256) | tests/golden/g6_orbit_render.sha256 |
:2437 |
EngineBridgeTests:1772 |
— | golden + Bresenham oracle + SHA file | covered — caveat: baseline self-writes on first run; a corrupted baseline would be blessed |
| Viewport move ownership / D5 copy | engine.cpp:5714-5741 |
:4164,:4275 |
indirect ViewportControllerTests:138 |
— | bit-identical rebuild + sentinels | covered |
| Viewport colors (TYPE_COLORS port) | engine.cpp:5692/6152 |
:1895,:4427 |
— | — | unit | covered (C++ only) |
| Value types (Vec3/Color3/BedGeometry/CameraState/Position) | internal/engine_value_types.h |
:3949,:4351 |
— | — | unit + static_assert | covered |
| Viewport snapshot (applySnapshot) | engine.cpp:5840 |
:4035 |
— | — | synthetic | covered (C++ only) |
C# facades & UI¶
| Feature | Where | C++ | C# | Scripts | HOW | Verdict |
|---|---|---|---|---|---|---|
| EngineSession facade (lifecycle/load/gen/analyze/findings/warp/overlay/dispose) | src/Nps.EngineHost/EngineSession.cs |
— | EngineSessionTests:48-:261 (13 tests) |
— | bridge + golden | covered — gap: Analyze only with ("PLA",210,60); no full-profile override matrix |
| MeshController (snapshot/reload-replace/spans) | MeshController.cs |
— | MeshControllerTests:36,:51,:91,:132 |
— | bridge + golden | covered |
| ViewportController (lifecycle/moves/camera/sim/overlay/warp) | src/Nps.Shell/ViewportController.cs |
— | ViewportControllerTests:31-:218 |
— | bridge + guards | covered |
| Camera presets + Zoom to Fit math | ViewportController.cs:294-482 |
— | ViewportControllerTests:253,:305,:376,:415,:439 (exact values) |
— | bridge | covered (math) — toolbar button wiring NOT TESTED |
| GcodeToolpathPainter | Controls/GcodeToolpathPainter.cs |
— | GcodeToolpathPainterTests:19,:42 (no-op guards only) |
— | logic | partial — happy-path draw (lines/colors/markers) NOT TESTED |
| MeshCanvasPainter | Controls/MeshCanvasPainter.cs |
— | — | — | — | NOT TESTED |
| FindingsPanel (7 category chips, no search) | Controls/FindingsPanel.axaml(.cs) |
— | FindingsPanelTests:43-:248 + ShellChromeTests:209-:374 |
— | headless; chip clicks via reflection, not pointer events | covered (panel level); keyboard/a11y NOT TESTED |
| PlaybackPanel + timer logic | Controls/PlaybackPanel.axaml(.cs); SimulatorApp MainWindow.axaml.cs:510-658 |
— | existence only AppHeadlessSmokeTests:58,:141; math TimelineMarkerHelperTests (13 Facts) |
— | headless existence + logic | partial — scrubber press/release latch, DispatcherTimer stepping, speed→interval, auto-pause \|moveIndex-simIndex\|<2 (:645) have ZERO tests |
| SliceParams (Slicer VM) | src/SlicerApp/SliceParams.cs |
— | SliceParamsTests:17,:30,:49,:64 |
— | logic | covered (VM level) — ApplySliceButton chain NOT TESTED |
| Shell collapse + width memory | MainWindowShell.axaml.cs:294-412 |
— | AppHeadlessSmokeTests:152 (250/350 restore) |
— | headless | covered |
| Activity bar + panel host + tabs | ActivityBarHost.cs; PanelHost.cs |
— | ShellChromeTests:130-:188 |
— | logic | covered — per-app OnActivityTabClick handlers are dead code, untested |
| Keybindings (P / Ctrl+L / Left / Right — the only 4 that exist) | ShellKeybindings.cs:82-113 |
— | ShellChromeTests:50,:69,:89,:114 |
— | logic | covered |
| ViewportToolbar (10 code-built buttons) | Controls/ViewportToolbar.cs |
— | — | — | — | NOT TESTED — zero tests enumerate/click its buttons |
| Viewport pointer gestures (drag orbit/pan) | SlicerApp MainWindow.axaml.cs:560-593; SimulatorApp :661-692 |
— | — | — | — | NOT TESTED — math covered, event chain not |
| App wiring (Load+Gen+Analyze, ApplySliceButton, overlay radios incl "None"→"motion-type", layer slider, finding navigation) | SlicerApp :155-318; SimulatorApp :205-314 |
— | existence only AppHeadlessSmokeTests:58,:141 |
— | headless existence | NOT TESTED at behavior level |
| App boot (Program.cs, ABI gate, window load) | src/SlicerApp/Program.cs; src/SimulatorApp/Program.cs |
— | AppHeadlessSmokeTests:58,:141; EngineBridgeTests:194 (ABI==1) |
smoke-apps.sh (disabled, lefthook.yml:131-132) |
headless + bridge | partial — Sim raw-ABI boot smoke only in the disabled script |
| StatusSink stderr dual-write | StatusSink.cs:57 |
— | status TextBlock substring only (:58/:141) |
_smoke_scan.py via disabled script |
headless (visible bar only) | partial — stderr path only covered by disabled script |
Errors, ABI, scripts, perf¶
| Feature | Where | C++ | C# | Scripts | HOW | Verdict |
|---|---|---|---|---|---|---|
| Error paths: engine overall | engine.cpp lastErrorMessage_ |
:724,:743,:816,:1240,:2700, ZIP suite |
:446,:465,:555,:127,:233,:1548 |
— | synthetic/crafted | covered |
| Error paths: UI (load-fail status, fixture-missing, no-moves, session-invalid guards) | SlicerApp :157-167; SimulatorApp :207-217 |
— | — | — | — | NOT TESTED — no failure driven through an app handler |
| C ABI surface contract (POD sizes, string-out, null-handle, enum/wire-id mirrors) | abi/nps_c_api.h |
static_asserts nps_c_api.h:215-222; tests :3633,:3541 |
EngineBridgeTests:230 (Theory 7 rows),:255,:279 |
— | marshal sizeof + synthetic, both sides | covered |
| layer-fitness gate | scripts/layer-fitness.sh |
— | — | LIVE pre-push + ctest + mutation ctest | structural + adversarial fixtures | covered |
| structural-fitness gate | scripts/structural-fitness.sh |
— | — | commented out (lefthook.yml:165-166) |
structural | partial — disabled by design; mutation suite manual-only |
| closure-integrity | scripts/closure-integrity.sh |
— | — | manual close protocol | fail-closed branch tests, manual | partial (manual-only) |
| no-placeholder-scan | scripts/no-placeholder-scan.sh |
— | — | LIVE pre-push (:135-136) |
structural | covered (gate live; no self-test) |
| Production Test*-export hygiene | scripts/nps-n1m-12-production-gate.sh |
— | — | ctest only when BUILD_TESTING=OFF + header grep ctest | nm -D scan | covered — caveat: never runs in the lefthook path (always Debug+tests) |
| debug-mixed.sh launcher | scripts/debug-mixed.sh |
:3843 (popen smoke) |
— | 4 ctest syntax/content tests | popen + structural | covered (bash); debug-mixed.ps1 NOT TESTED |
| docs-deploy | scripts/deploy-docs.sh |
— | — | LIVE pre-push on docs/guide/** |
fail-closed wrangler/zensical | covered (gate live; no self-test) |
| Perf (parse/analyze/load/build timings) | — | :1755 (<5000ms),:1812 |
— | — | synthetic 20k moves + golden | covered (smoke thresholds only) |
| FixtureLocator walk | src/Nps.Shell/FixtureLocator.cs:60-90 |
— | — | fixture-present hook | implicit in every bridge/golden test | partial (no walk-order unit test) |
Zero-coverage rows (brutally honest)¶
- ViewportToolbar — no test enumerates or clicks any of its 10 code-built buttons.
- Playback runtime — scrubber pointer latch, DispatcherTimer stepping, speed→interval, auto-pause rule: zero tests.
- App event handlers — OnLoadAnalyzeClick, OnApplySliceClick, OnOverlayModeChanged, OnLayerSliderChanged, OnFindingSelected: existence-only.
- Pointer-drag orbit/pan + Zoom-to-Fit button — math covered, event chain not.
- UI error paths — no failure ever driven through an app handler.
- MeshCanvasPainter + GcodeToolpathPainter happy path — only no-op guards.
- Warp grid risk values — ABI shape only, content never asserted.
- Analyzer value correctness — thermal/structural/motion scores asserted
>0, never against golden expected values; motion profile inference is a stub. - Retraction analyzer + MaterialCatalog C# parity, corrupt-bgcode, multi-plate fixtures, debug-mixed.ps1 — all absent.
How to run each harness¶
# C++ Catch2 (Debug build auto-enables NPS_ENABLE_TEST_HOOKS):
cmake -S src/Engine -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build --parallel
ctest --test-dir build --output-on-failure
# C# xUnit (build the engine first; lib must be on the loader path):
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 $HOME/.dotnet/dotnet test tests/NPSEngine.Tests
# (lefthook.yml:110 — place libNPSEngine.so next to the test binary or set LD_LIBRARY_PATH)
# Script fitness gates:
./scripts/layer-fitness.sh # live in pre-push
./scripts/no-placeholder-scan.sh # live in pre-push
./scripts/structural-fitness.sh # manual (gate disabled by design)
./scripts/closure-integrity.sh <beadId> # manual close protocol
Re-count baselines:
grep -c 'TEST_CASE(' src/Engine/tests/engine_tests.cpp # 73 (+17 TEST_CASE_METHOD)
grep -rnE '^\s*\[Fact' tests/NPSEngine.Tests/*.cs | wc -l # 111 (+4 [Theory])
Optional future: gcov/llvm-cov + coverlet for true % — not wired today.
Full test inventory (every name)¶
Mechanically extracted from the live tree (same grep the re-count one-liners use). The matrix above groups them by feature; this list is the complete checklist the refresh gate diffs against.
C++ Catch2 — all 90 TEST_CASEs (engine_tests.cpp)
Bead nps-f8v.5: Retraction events parsing and analysis on custom G-code—engine_tests.cpp:2940Bead nps-f8v.8: Bambu comments parsing and override detection—engine_tests.cpp:3021Bead nps-f8v.8: Bambu proprietary commands are tolerated without crash—engine_tests.cpp:3178Bead nps-f8v.8: Malformed / boundary inputs are tolerated without crash /—engine_tests.cpp:3368Bead nps-f8v.8: Malformed / boundary inputs are tolerated without crash / ;—engine_tests.cpp:3425Bead nps-f8v.8: Malformed / boundary inputs are tolerated without crash / ;FLAVOR: with—engine_tests.cpp:3454Bead nps-f8v.8: Malformed / boundary inputs are tolerated without crash / ParseGcode—engine_tests.cpp:3385Bead nps-f8v.8: Malformed / boundary inputs are tolerated without crash / Very long—engine_tests.cpp:3401Bead nps-f8v.8: Marlin + Klipper firmware detection via FLAVOR comment / Klipper flavor—engine_tests.cpp:3154Bead nps-f8v.8: Marlin + Klipper firmware detection via FLAVOR comment / Marlin flavor—engine_tests.cpp:3131Bead nps-f8v.8: NpsMaterialProfile POD layout is 108 bytes and round-trips via C ABI—engine_tests.cpp:3541Bead nps-f8v.8: OrcaSlicer comments parsing—engine_tests.cpp:3092Bead nps-f8v.8: Slicer detection rejects non-banner CURA/BAMBU substrings / Comment—engine_tests.cpp:3474Bead nps-f8v.8: Slicer detection rejects non-banner CURA/BAMBU substrings / Comment—engine_tests.cpp:3495Bead nps-f8v.8: Slicer detection rejects non-banner CURA/BAMBU substrings / Real banner—engine_tests.cpp:3516Benchy analysis populates flow overlays—engine_tests.cpp:2915Benchy analysis reports hole findings—engine_tests.cpp:2896Benchy parse + viewport build timing smoke (nps-n1m.40 G16)—engine_tests.cpp:1812Benchy validation exposes transformed mesh data—engine_tests.cpp:651Benchy validation keeps bounds and indices consumable—engine_tests.cpp:674Benchy validation loads the primary fixture—engine_tests.cpp:621Benchy validation preserves golden mesh counts—engine_tests.cpp:630Benchy validation preserves the four-color palette—engine_tests.cpp:638Benchy validation supports metadata-only reload—engine_tests.cpp:706C ABI string-output contract (nps-n1m.27): null/zero-cap no-op + UTF-8 NUL + truncation—engine_tests.cpp:3633Default material profiles are parameterized by material key—engine_tests.cpp:3249E2E: mesh load + synthetic gcode parse/analyze + overlay data assert (nps-f8v.11)—engine_tests.cpp:1625Engine GetLastParsedGcode split semantics (nps-n1m.32)—engine_tests.cpp:1447Engine LoadModelFromFile error cases for robustness (nps-l7k.14)—engine_tests.cpp:743Engine LoadModelFromFile returns failure for missing file—engine_tests.cpp:724Engine LoadModelFromFile wires parser via ZIP/OPC reader (nps-l7k.3) on real Benchy—engine_tests.cpp:287Engine ZipArchiveReader extracts model XML + metadata on primary Benchy (nps-l7k.3)—engine_tests.cpp:339Engine basic lifecycle and version—engine_tests.cpp:272Engine core mesh and plate data structures + append/combine (nps-l7k.4)—engine_tests.cpp:474Engine mesh prep for scalar fields & shared viewport (nps-l7k.11)—engine_tests.cpp:529Engine mesh query API surface (nps-l7k.2 design)—engine_tests.cpp:374Gcode bgcode basic header + optional full decode (nps-f8v.4)—engine_tests.cpp:1509Gcode gen + C ABI buffer + file roundtrip (nps-f8v.10 interop)—engine_tests.cpp:2729Gcode generation error cases and defaults (nps-f8v.10)—engine_tests.cpp:2700Gcode generation from loaded mesh + params (nps-f8v.10 basic)—engine_tests.cpp:2538Gcode generation non-planar + roundtrip validate structure (nps-f8v.10)—engine_tests.cpp:2637Gcode generation real geometry and scalar fields (nps-f8v.7.1)—engine_tests.cpp:2780Gcode parse + analyze roundtrip via C ABI harness hooks (integration)—engine_tests.cpp:1592Gcode parse from real test_cube + roundtrip structure (nps-f8v.4 + Gcode files)—engine_tests.cpp:1410Gcode parser multi-format layers + Bambu markers (nps-f8v.4)—engine_tests.cpp:1346Gcode parser relative E + M82/M83 + G92 + accel M204 (nps-f8v.4)—engine_tests.cpp:1371Gcode parser section types + G2/G3 arcs (nps-f8v.4)—engine_tests.cpp:1398Gcode parser state machine + moves (nps-f8v.11 + f8v.9 model)—engine_tests.cpp:1290LoadModelFromFile ABI forwarder rejects null engine handle (nps-n1m.32)—engine_tests.cpp:816M104 metadata fallback is parameterized by hotend temperature—engine_tests.cpp:3331MaterialCatalog table exposes expected entry count + PLA fallback at index 0—engine_tests.cpp:3286MaterialCatalog::forType normalizes key (case + underscore-to-dash) and falls back to PLA—engine_tests.cpp:3310ModelXMLParser direct nps::Parse populates full result incl triangles—engine_tests.cpp:1224ModelXMLParser handles object/component graph, unit, build items—engine_tests.cpp:1206ModelXMLParser reports PARSE_ERROR on bad data (integrates .14 model)—engine_tests.cpp:1240ModelXMLParser streams vertices + triangles from real 3MF sample—engine_tests.cpp:1178Performance: large G-code parse + analysis time (nps-f8v.11)—engine_tests.cpp:1755Primary Benchy ZIP hook extracts model and metadata—engine_tests.cpp:1102Primary Benchy ZIP load preserves golden counts—engine_tests.cpp:1092ProjectOrbitXY C ABI parity with previous UI math (nps-n1m.30 G6)—engine_tests.cpp:2078Structural score analyzer with GcodeMove (nps-f8v.11 + f8v.9)—engine_tests.cpp:1570Thermal grid analyzer math with GcodeMove (nps-f8v.11 + f8v.9)—engine_tests.cpp:1550Unknown material profile falls back to PLA—engine_tests.cpp:3276Viewport camera MVP + layer vis + sim offsets (nps-f8v.3)—engine_tests.cpp:1976Viewport color logic matches TYPE_COLORS port (nps-f8v.3)—engine_tests.cpp:1895Viewport harness integration: moves from parse + analyze feed (nps-f8v.3 + f8v.11)—engine_tests.cpp:2010Viewport layer buffers + move offsets from GcodeMove (nps-f8v.3 + f8v.9)—engine_tests.cpp:1918ViewportGetHeatmapColor C ABI matches GcodeViewport::GetHeatmapColor (nps-n1m.30 G6)—engine_tests.cpp:2047Visual/golden render parity via engine C ABI (nps-n1m.30 G6)—engine_tests.cpp:2437WarpGrid ABI + viewport render smoke (nps-f8v.6.1)—engine_tests.cpp:1674Zip reader rejects a bad deflate stream—engine_tests.cpp:1032Zip reader rejects a bad local header signature—engine_tests.cpp:995Zip reader rejects a corrupt EOCD—engine_tests.cpp:965Zip reader rejects a truncated archive—engine_tests.cpp:982Zip reader rejects null arguments—engine_tests.cpp:1084Zip reader rejects stored-size mismatches—engine_tests.cpp:1067Zip reader rejects unsupported compression—engine_tests.cpp:1014Zip reader reports a missing entry—engine_tests.cpp:1056nps-580 scripts/debug-mixed.sh --help and print-modes—engine_tests.cpp:3843nps-n1m.18 D5: Viewport SetGcodeMoves copies (engine buffer mutation after Set does not—engine_tests.cpp:4275nps-n1m.18 D5: Viewport survives engine Load/Parse after SetGcodeMoves (no UAF)—engine_tests.cpp:4164nps-n1m.41 G17: ApplyOverlay(OverlayState) collapses the three-setter sequence—engine_tests.cpp:4065nps-n1m.41 G17: GetExtrudeColorForType Color3* overload matches float[3] overload—engine_tests.cpp:4427nps-n1m.41 G17: GetMeshBounds Position* overload matches float[3] overload—engine_tests.cpp:4390nps-n1m.41 G17: Mat4LookAt now takes three Vec3—engine_tests.cpp:4372nps-n1m.41 G17: Position alias exists and is a Vec3—engine_tests.cpp:4351nps-n1m.41 G17: SetCamera(CameraState) overload forwards all five floats—engine_tests.cpp:3998nps-n1m.41 G17: Vec3/Color3/BedGeometry/CameraState aggregate value types—engine_tests.cpp:3949nps-n1m.41 G17: ViewportApplyOverlay C ABI aggregate equals three-setter sequence—engine_tests.cpp:4107nps-n1m.41 G17: applySnapshot(EngineSnapshot) feeds moves to viewport—engine_tests.cpp:4035
C# xUnit — all 115 Facts/Theories (tests/NPSEngine.Tests)
MainWindowShell_Collapse_Width_Memory_Smoke—AppHeadlessSmokeTests.cs:150SimulatorApp_MainWindow_Loads_Layout_And_Bindings—AppHeadlessSmokeTests.cs:139SlicerApp_MainWindow_Loads_Layout_And_Bindings—AppHeadlessSmokeTests.cs:57AbiPODLayout_Frozen—EngineBridgeTests.cs:227CreateInitializeVersionDestroy_Works—EngineBridgeTests.cs:167E2E_MeshLoadPlusGcodeAnalyze_AssertsOverlays—EngineBridgeTests.cs:667EnumMirrors_MatchFrozenAbiInts—EngineBridgeTests.cs:254GcodeGenerate_RoundtripAndNonplanar_Validates—EngineBridgeTests.cs:742GcodeParse_RoundtripViaTestHook_Works—EngineBridgeTests.cs:634GetAbiVersion_MatchesExpectedAtStartup—EngineBridgeTests.cs:193GetLastParsedGcode_SplitSemantics_RoundTripViaCAbi—EngineBridgeTests.cs:922LoadModelFromFile_ErrorCasesAndOptions_Robustness—EngineBridgeTests.cs:463LoadModelFromFile_MissingFile_ReturnsSpecificErrorAndMessage—EngineBridgeTests.cs:444LoadModelFromFile_NullEngineHandle_ReturnsInvalidArgument—EngineBridgeTests.cs:554LoadModelFromFile_OnBenchy3Mf_SucceedsWithAssertion—EngineBridgeTests.cs:290Loader_IntegratesViaEngineHost_Succeeds—EngineBridgeTests.cs:600ParseBgcode_RealTestCubeBinary_FullRoundtripAssertsMovesAndLayers—EngineBridgeTests.cs:821ProjectOrbitXY_IdentityRotation_ZContributesToScreenXY—EngineBridgeTests.cs:1739ProjectOrbitXY_MatchesLegacyUiMath—EngineBridgeTests.cs:1695ProjectOrbitXY_NullOutIsNoop—EngineBridgeTests.cs:1751TestAnalysisFindingsSummary_BeforeAnalyze_ReportsNoData—EngineBridgeTests.cs:1547TestAnalysisFindingsSummary_RoundTripsThroughDetail—EngineBridgeTests.cs:1467TestInferredMaterialTemperatureFallback—EngineBridgeTests.cs:1302TestInferredPropertiesFromGcode—EngineBridgeTests.cs:1127TestInferredSlicerFlavor—EngineBridgeTests.cs:1257TestInferredSlicerOrcaSlicer—EngineBridgeTests.cs:1203TestMaterialProfilePODRoundTrip—EngineBridgeTests.cs:1344TestParseGcodeMalformedInputs—EngineBridgeTests.cs:1568ThermalAndStructural_AnalyzerInterop_ReturnsData—EngineBridgeTests.cs:648ViewportGetHeatmapColor_InvertFlipsRamp—EngineBridgeTests.cs:1659ViewportGetHeatmapColor_MidValue_IsGreen—EngineBridgeTests.cs:1640ViewportGetHeatmapColor_NullOutIsNoop—EngineBridgeTests.cs:1684ViewportGetHeatmapColor_VmaxMapsToRedEnd—EngineBridgeTests.cs:1673ViewportMeshRender_BenchyFixture_Validates—EngineBridgeTests.cs:1057ViewportRenderLogic_Smoke_BridgeCalls_NoCrash—EngineBridgeTests.cs:1007VisualGolden_RenderOrbit_BytesMatchCppBaseline—EngineBridgeTests.cs:1771WireIdMirrors_MatchFrozenAbiIds—EngineBridgeTests.cs:278CreateAndInitialize_ProducesValidSession—EngineSessionTests.cs:47Dispose_MakesSessionInvalid—EngineSessionTests.cs:58Dispose_Twice_IsIdempotent—EngineSessionTests.cs:67Findings_AreEmptyBeforeAnalyze_AndPopulatedAfter—EngineSessionTests.cs:183GenerateDemoToolpath_AfterBenchyLoad_ReturnsMoves—EngineSessionTests.cs:164GetFindingDetail_ReturnsFullRecordForKnownId—EngineSessionTests.cs:209GetFindingDetail_StaleId_ReturnsNull—EngineSessionTests.cs:231GetOverlayValue_BeforeLoad_ReturnsZero—EngineSessionTests.cs:259GetOverlayValue_ThrowsAfterDispose—EngineSessionTests.cs:251GetWarpGrid_BeforeAnalyze_ReturnsNull—EngineSessionTests.cs:239LoadModel_ClearsPriorMoveBuffer—EngineSessionTests.cs:140LoadModel_MissingFile_ReturnsFailureWithMessage—EngineSessionTests.cs:125LoadModel_OnBenchy3Mf_ReturnsStructuredPlatesAndPalette—EngineSessionTests.cs:93FindingsPanel_AllChip_RestoresBothAxes—FindingsPanelTests.cs:154FindingsPanel_CategoryFilter_AlsoUnchecksAll—FindingsPanelTests.cs:128FindingsPanel_DefaultChips_AllChecked—FindingsPanelTests.cs:42FindingsPanel_Selection_RaisesFindingSelected_WithItem—FindingsPanelTests.cs:187FindingsPanel_SetFindings_RebuildsItemsSource_And_Count—FindingsPanelTests.cs:71FindingsPanel_SeverityFilter_ShrinksVisibleCount—FindingsPanelTests.cs:92FindingsPanel_TryGetCachedItem_ReturnsNull_ForUnknownFindingId—FindingsPanelTests.cs:246FindingsPanel_UpdateDetail_PopulatesStyledProperties—FindingsPanelTests.cs:216RenderTo_FreshViewport_ZeroMoves_IsNoOp—GcodeToolpathPainterTests.cs:40RenderTo_NullViewport_IsNoOp—GcodeToolpathPainterTests.cs:18Constructor_BeforeReload_HasZeroPlatesAndEmptyPalette—MeshControllerTests.cs:35PlateMesh_EmptyArrays_ReportZeroCountsAndEmptySpans—MeshControllerTests.cs:130Reload_AfterSecondLoad_ReplacesSnapshotInPlace—MeshControllerTests.cs:89Reload_OnBenchy_SnapshotsOnePlateWithGoldenCounts—MeshControllerTests.cs:49ActivityBarHost_FiresTabClicked_ForRegisteredKey—ShellChromeTests.cs:145ActivityBarHost_NoTabClicked_When_Button_Tag_Unregistered—ShellChromeTests.cs:129FindingFormatter_CategoryLabel_And_Brush_For_All_Known_Categories—ShellChromeTests.cs:243FindingFormatter_FromSummaryAndDetail_Stamps_Category_From_Detail—ShellChromeTests.cs:333FindingItem_DefaultShape_Mirrors_Api_Contract—ShellChromeTests.cs:208FindingsFilterState_Default_Matches_All_Rows—ShellChromeTests.cs:288PanelHost_Show_FlipsExactlyOneVisible_And_FiresOnShown—ShellChromeTests.cs:163PanelHost_Show_UnknownKey_NoOp_NoOnShown—ShellChromeTests.cs:187SeverityPalette_Resolves_Fallback_Brushes—ShellChromeTests.cs:373ShellKeybindings_Left_Right_Step_And_Handle—ShellChromeTests.cs:88ShellKeybindings_Mod_L_TogglesInspector_Only_With_Ctrl—ShellChromeTests.cs:68ShellKeybindings_P_TogglesPlay_And_Handles—ShellChromeTests.cs:49ShellKeybindings_Unhandled_Key_FallsThrough—ShellChromeTests.cs:113CreateDefaults_Matches_HardCoded_Demo_Toolpath_Options—SliceParamsTests.cs:16PropertyChanged_Does_Not_Fire_On_Same_Value—SliceParamsTests.cs:62PropertyChanged_Fires_On_Mutation—SliceParamsTests.cs:47ToGcodeGenOptions_Reflects_Mutated_Fields—SliceParamsTests.cs:28BuildMarkers_EmptyFindings_ReturnsEmpty—TimelineMarkerHelperTests.cs:108BuildMarkers_EmptyTimeline_ReturnsEmpty—TimelineMarkerHelperTests.cs:116BuildMarkers_ExcludesMoveIndexMinusOne—TimelineMarkerHelperTests.cs:136BuildMarkers_NullFindings_ReturnsEmpty—TimelineMarkerHelperTests.cs:100BuildMarkers_PreservesInputOrder—TimelineMarkerHelperTests.cs:182BuildMarkers_ProjectOffsetsAcrossFullTimeline—TimelineMarkerHelperTests.cs:161Fraction_EmptyTimeline_ReturnsZero—TimelineMarkerHelperTests.cs:62Fraction_FirstMove_ReturnsZero—TimelineMarkerHelperTests.cs:40Fraction_LastMove_ReturnsOne—TimelineMarkerHelperTests.cs:46Fraction_Midpoint_ReturnsHalf—TimelineMarkerHelperTests.cs:54Fraction_MoveBeyondEnd_ClampsToOne—TimelineMarkerHelperTests.cs:88Fraction_NegativeMoveIndex_ClampsToZero—TimelineMarkerHelperTests.cs:80Fraction_SingleMove_ReturnsZero—TimelineMarkerHelperTests.cs:72ApplyOverlay_FromSession_ComputesStatsAndAppliesOverlay—ViewportControllerTests.cs:458ApplyOverlay_MirrorsMode_AndDoesNotThrow—ViewportControllerTests.cs:166ApplyOverlay_NonThermal_LastOverlayMeanMatchesStatsMeanAndSampleCountExcludesZeros—ViewportControllerTests.cs:507ApplyOverlay_NullValues_Throws—ViewportControllerTests.cs:194BuildBuffers_IsCallableAndDoesNotThrow—ViewportControllerTests.cs:126CameraPresets_ProduceNonCollapsedProjectedBoundsAndDistinctOrientations—ViewportControllerTests.cs:303ComputeZoomFit_ReturnsPlacingContentAtApproximately90PercentFill—ViewportControllerTests.cs:413ComputeZoomFit_WithMoves_ReturnsExpectedZoomAndPan—ViewportControllerTests.cs:374ComputeZoomFit_WithNonSquareViewportAndContent_ReturnsExpectedZoomAndFill—ViewportControllerTests.cs:437CreateAndInitialize_ProducesValidViewport—ViewportControllerTests.cs:30Dispose_MakesViewportInvalid—ViewportControllerTests.cs:39Dispose_Twice_IsIdempotent—ViewportControllerTests.cs:48MovesSpan_EmptyBeforeSetMoves—ViewportControllerTests.cs:209MovesSpan_ReflectsSetMovesCount—ViewportControllerTests.cs:216SetCameraPreset_UpdatesCameraRotationAndZeroPan—ViewportControllerTests.cs:251SetCamera_FiveArgOverload_MirrorsCameraState—ViewportControllerTests.cs:102SetCamera_RecordOverload_MirrorsCameraState—ViewportControllerTests.cs:82SetLayerVisibility_MirrorsMaxLayer—ViewportControllerTests.cs:74SetMoves_MirrorsCountAndPointer—ViewportControllerTests.cs:136SetSimulationState_MirrorsSimMoveIndex—ViewportControllerTests.cs:118SetWarpParams_DoesNotThrow—ViewportControllerTests.cs:201
See also¶
- quality-gates.md — lefthook/ctest wiring for every gate named here
- overview.md — golden fixture in the architecture context
- c-abi.md — the ABI surface the bridge tests pin