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 |
93 TEST_CASEs (76 TEST_CASE + 17 TEST_CASE_METHOD) |
| C# xUnit | tests/NPSEngine.Tests/*.cs (12 files) |
dotnet test |
158 attributes (154 [Fact] + 4 [Theory], all Theories in EngineBridgeTests.cs) → 163 test cases after Theory row expansion |
| 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:97-98;
resolver ResolveBenchyPath() (:106), RAII BenchyFixture (:143). 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 :291/:1096; ZIP :343/:1106; mesh query :378; BenchyFixture suite :625/:634/:642 (exact palette)/:655 (first-vertex transforms)/:678 (bounds); metadata-only :710; missing-entry ZIP :1060; bounds overload :4760; viewport/warp :1798; perf :2025; render SHA :2650; gen+analyze :2772-:3149 |
| C# | EngineBridgeTests.cs:298 (full contract via Marshal.Copy), :607, :675, :750, :1014, :1065 (unsafe reads), :2214 (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 |
:291,:1096,:625,:634 |
EngineBridgeTests:298,:607; EngineSessionTests:95 |
fixture-present | golden | covered |
| ZIP/OPC reader | engine_zip.cpp |
:343,:1106 |
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 :969-:1088 (8 cases: 7 ZipReaderFixture + null-args plain TEST_CASE at :1088) |
only EngineBridgeTests:471 (magic/empty/size) |
— | crafted byte-patched ZIPs | covered (C++); partial C# |
| 3MF XML parser | engine.cpp:2084/2325/2472 |
:1182,:1210,:1228,:1244 |
— | — | synthetic real-derived XML | covered (C++ only) |
| Mesh queries (verts/tris/colors/plates/unit) | engine.cpp:988-1109 |
:378,:655 |
EngineBridgeTests:298,:1065 |
— | golden, exact counts+samples | covered |
| Mesh bounds (AABB) | engine.cpp:1059/1077 |
:533,:678,:4760 |
— (test-gated export, by design) | — | golden via test-gated export | covered (C++); N/A C# |
| Palette decode (4-color AMS) | engine_color.cpp |
:642 exact hex |
EngineBridgeTests:298; MeshControllerTests:51 |
— | golden exact-hex | covered |
| Plate thumbnail | engine.cpp:1116 |
size>1000B inside :378 |
— | — | 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; deferred — tracked by bead nps-ai2.3, documented per nps-oro.6) |
| Loader error model | engine.cpp:550-970 |
:728,:747,:820 |
EngineBridgeTests:452,:471,:561; 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 |
:2772,:2871,:3014 |
EngineBridgeTests:750; EngineSessionTests:166 |
— | golden + demo gen | covered (as demo toolpath) |
| Gen errors + C ABI buffer/file roundtrip | engine.cpp:1593/2947-3028 |
:2934,:2963 |
— | — | 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 |
:1294,:1350,:1375,:1402,:1414,:3412 |
EngineBridgeTests:642 |
— | synthetic via Test*; optional real file | covered |
| bgcode binary parse | engine.cpp:3407/4049 |
:1513 (skips if fixture absent) |
EngineBridgeTests:829 (hard-requires, >1000 moves, maxL≥249) |
— | real test_cube_binary.bgcode |
covered — happy path + corrupt block CRC (byte-patched real fixture → warn-and-continue, EngineBridgeTests:1904, nps-oro.6) |
| Parsed/generated text split | engine.cpp:1436/1453 |
:1451 |
EngineBridgeTests:929 |
— | synthetic via C ABI, sentinels | covered |
| Move array (shared after gen or parse) | engine.cpp:1460/1464 |
inside :1451,:2772,:2963 |
EngineSessionTests:142,:166 |
— | bridge pointer+count | covered |
| Parser robustness (null/empty/long-line/malformed metadata/false banners) | engine.cpp:4011 |
:3602-:3750 (8 cases) |
EngineBridgeTests:1576 (Theory, empty only) |
— | synthetic adversarial | covered (C++ deep; C# one row) |
Analysis & material¶
| Feature | Where | C++ | C# | Scripts | HOW | Verdict |
|---|---|---|---|---|---|---|
| Thermal analyzer | engine.cpp:4323 |
:1554 (golden: score == totHeat == 0.04, findingCount == 1 on pinned 3-move input, nps-oro.5), perf :1968 |
EngineBridgeTests:656 |
— | synthetic; golden derived from ThermalAnalyzer::analyze math |
covered |
| Structural analyzer | engine.cpp:4653 |
:1594 (golden values on pinned 10-move input, nps-oro.5) |
EngineBridgeTests:656 |
— | synthetic; golden derived from StructuralAnalyzer::analyze math |
covered |
| Motion analyzer (junction velocity) | engine.cpp:4806 |
:1640 (golden: tiny 2-move + cube junction-clamp at 14.4, nps-oro.5), E2E :1749; inferProfileFromGcode real M204 P/T/S inference :4096 (nps-ai2.2) |
via EngineBridgeTests:675 |
— | golden analyzer unit tests | covered |
| Hole findings | engine.cpp:6724 |
:3130 ("diameter" in message) |
indirect via EngineBridgeTests:1474 |
— | golden + demo gen | covered |
| Retraction + stringing | engine.cpp:6957 |
:3174 |
EngineBridgeTests:1639 (parity with C++ fixture: real messages + overlays, nps-oro.6) |
— | synthetic gcode | covered |
| Flow + volumetric overlays | engine.cpp:7041 |
:3149,:3775 (108B POD, cap 7.5) |
EngineBridgeTests:1351 |
— | golden + synthetic + ABI | covered |
| Material catalog (10 rows, PLA fallback, key normalize) | material_catalog.cpp |
:3483 (11 GENERATE rows),:3510,:3520,:3544 |
EngineBridgeTests:1770 (POD roundtrip, exact flow values, nps-oro.6) |
— | unit | covered |
| Inferred profile (slicer/printer/material/FLAVOR/temp fallback) | engine.cpp:176 |
:3255,:3326,:3365,:3388,:3565 |
EngineBridgeTests:1135,:1210,:1267 (Theory),:1313 (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:1474 (count/row equality, id -1→InvalidArgument, past-end→NotFound),:1554; EngineSessionTests:185,:211,:233 |
— | bridge + synthetic | covered (C# owns the contract) |
| Per-move overlay values + supported ids | engine.cpp:1550/1557/5652-5702 |
:2223,:1749,:3867 + SECTION :3969 (manager-derived 17-id list, exact content + order, nps-ai2.2) |
EngineSessionTests:253,:261,:464 (exact 17-id manager-derived list + order),:501 (tight-buffer truncation + pinned NUL),:533/:549 (null/zero-cap no-op) |
— | synthetic + ABI | covered — GetSupportedOverlayIds is manager-derived (un-stubbed nps-ai2.2), exact id order pinned |
| Overlay stats pipeline (Min/Max/Mean/SampleCount, zero-filter) | ViewportController.cs:564-640 |
:4435,:4477 |
ViewportControllerTests:460,:509 |
— | bridge + golden + demo gen | covered (controller level) |
| Heatmap colors (ramp/invert/vmax/null) | engine.cpp:6304 |
:2260 |
EngineBridgeTests:2084-:2128 (exact (0,1,0) mid) |
— | unit + ABI | covered |
| Warp grid (info + risk arrays) | engine.cpp:5711/5717 |
:1798 (size==gridW*gridH + full-array content guard), :1912 (risk VALUES golden on pinned input, nps-oro.5) |
EngineSessionTests:241 (null guard) |
— | ABI shape + content golden | covered |
| Viewport buffers (layer buckets/offsets/extrude counts) | engine.cpp:5861 |
:2131 |
EngineBridgeTests:1014 (smoke, Assert.True(true) tail) |
— | synthetic; C# ABI smoke | covered (C++); C# smoke-only |
| Viewport MVP + camera | engine.cpp:6102/5761 |
:2189,:4368,:4742 |
ViewportControllerTests:84,:104 |
— | synthetic + mirror | covered |
| ProjectOrbitXY | engine.cpp:5400 |
:2291 (11 samples, 1e6 boundary) |
EngineBridgeTests:2139,:2183,:2195 |
— | golden math vs legacy oracle ±1e-4 | covered |
| Golden render parity (SHA-256) | tests/golden/g6_orbit_render.sha256 |
:2650 |
EngineBridgeTests:2214 |
— | golden + Bresenham oracle + SHA file | covered — fail-closed (NPS_BLESS_GOLDEN=1 opt-in, see Golden blessing recipe) |
| Viewport move ownership / D5 copy | engine.cpp:5714-5741 |
:4534,:4645 |
indirect ViewportControllerTests:138 |
— | bit-identical rebuild + sentinels | covered |
| Viewport colors (TYPE_COLORS port) | engine.cpp:5692/6152 |
:2108,:4797 |
— | — | unit | covered (C++ only) |
| Value types (Vec3/Color3/BedGeometry/CameraState/Position) | internal/engine_value_types.h |
:4319,:4721 |
— | — | unit + static_assert | covered |
| Viewport snapshot (applySnapshot) | engine.cpp:5840 |
:4405 |
— | — | 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-:617 (24 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 covered by ViewportToolbarTests preset/zoom-fit→controller facts (ViewportToolbarTests:438,:464,:561,:598, nps-oro.2) |
| GcodeToolpathPainter | Controls/GcodeToolpathPainter.cs |
— | GcodeToolpathPainterTests:29,:52,:75 |
— | logic + native parser/viewport snapshot | covered — parsed moves emit travel/extrusion Lines with asserted colors, finding Ellipse markers, and max-layer filtering |
| MeshCanvasPainter | Controls/MeshCanvasPainter.cs |
— | MeshCanvasPainterTests:28,:47,:71,:106 |
— | logic + golden Benchy mesh snapshot | covered — null/empty guards, empty-palette white fallback, and Benchy Polygon output capped at MaxTrianglesPerPlate |
| 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 |
— | runtime AppHeadlessSmokeTests:1410-:1758 (6 Facts: play/pause+icon, step clamp, auto-pause \|Δ\|<2, scrubber latch press→pause release→resume-if-was-playing, speed→interval recompute, scrubber commit clamp) + math TimelineMarkerHelperTests (13 Facts) |
— | headless public panel-event surface (AvaloniaHeadless class fixture LoadedSimulatorWindow amortizes Benchy load across suite) |
covered — runtime/state observable contract end-to-end (panel events → MainWindow handlers → status/IconGeometry/timer.Interval/mirror) |
| 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:173 (250/350 restore) |
— | headless | covered |
| Activity bar + panel host + tabs | ActivityBarHost.cs; PanelHost.cs |
— | ShellChromeTests:130-:188 |
— | logic | covered — per-app OnActivityTabClick(object?, RoutedEventArgs) handlers were dead code (never wired in XAML, no callers); bead nps-ai2.4 deleted both copies; only OnActivityTabClicked (event subscriber) remains |
| 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 |
— | ViewportToolbarTests:100 (10 controls), :120 (tooltip text), :141 (toggle defaults), :155 (distinct refs), :194 (noop subscribers), :213/229/245/261/277/293/309/325 (8 *Clicked once), :341/:372 (toggle bool payload), :395 (multi-toggle), :438 (reset preset→controller), :464 (all-six orientations), :522 (toggle→app payload), :561 (zoom-fit→controller), :598 (non-square zoom-fit), :628 (layer up/down seam) |
— | headless click + bridge | covered — every button enumerated, click-dispatched exactly once per raise, preset/zoom-fit clicks reach ViewportController.Camera as the production apps wire |
| Viewport pointer gestures (drag orbit/pan) | SlicerApp MainWindow.axaml.cs:560-593; SimulatorApp :661-692 |
— | AppHeadlessSmokeTests:157,:165 |
— | Avalonia.Headless synthetic mouse events | covered — both apps exercise the viewport press latch, left-button orbit with RotationX clamp ±1.5, right-button pan scaling by zoom, and camera assertions |
| App wiring (Load+Gen+Analyze, ApplySliceButton, overlay radios incl "None"→"motion-type", layer slider, finding navigation) | SlicerApp :190-241 (seam LoadAndAnalyzeFromPath:208) + :244-263 + :440-450; SimulatorApp :241-256 (seam LoadAndAnalyzeFromPath:512) + :557-568 + :578-583 |
— | covered (nps-oro.3): 15 active Facts in AppHeadlessSmokeTests:367-:1115 drive every reachable handler through the real LoadAndAnalyzeFromPath seam + XAML button + public FindingsPanel.FindingSelected + reflected OverlayPanel.ModeChanged. The gen-failed (SlicerApp/MainWindow.axaml.cs:441-443; SimulatorApp/MainWindow.axaml.cs:557-559) and analyze-failed (SlicerApp/MainWindow.axaml.cs:503-506; SimulatorApp/MainWindow.axaml.cs:579-582) branches are unreachable from production today — Engine::GenerateGcode returns NPS_RESULT_SUCCESS unconditionally (src/Engine/engine.cpp:1433) and Engine::AnalyzeGcode is void (src/Engine/engine.cpp:1479-1488); 4 Skip facts with bead-cited reasons document the engine-side coverage (AppHeadlessSmokeTests.cs:1447-1467, wrapped in #pragma warning disable xUnit1004 / restore xUnit1004). Observable contract: Shell.StatusText substring, LayerSlider.Value → _maxLayer mirror, LayerLabel text, viewport.SimMoveIndex, playback.SimIndex. |
— | headless behaviour | covered (nps-oro.3, reachable paths); engine-side-only (gen-failed/analyze-failed, Skip facts cite EngineSessionTests coverage) |
| App boot (Program.cs, ABI gate, window load) | src/SlicerApp/Program.cs; src/SimulatorApp/Program.cs |
— | AppHeadlessSmokeTests:63,:146; EngineBridgeTests:200 (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 (AppHeadlessSmokeTests:63/:146) |
_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_ |
:728,:747,:820,:1244,:2934, ZIP suite |
EngineBridgeTests:452,:471,:561,:1554; EngineSessionTests:127,:233 |
— | synthetic/crafted | covered |
| Error paths: UI (load-fail status, fixture-missing, no-moves, session-invalid guards) | SlicerApp :210-219 (session guard + fixture-missing) + :222-226 (load-failed); SimulatorApp :514-520 (session guard + fixture-missing) + :528-534 (load-failed; seam at :512 shifts the handlers into LoadAndAnalyzeFromPath) |
— | covered (nps-oro.3): AppHeadlessSmokeTests:367 (Slicer missing-fixture → "ERROR: primary ..."), :420 (Slicer invalid-file → "Load failed: ..." + _modelLoaded==false), :791 (Simulator missing-fixture → same), :843 (Simulator invalid-file → "Load failed: ..." + _mesh.Reload() ran → PlateCount==0), :531 (Slicer Apply-before-load → "Load a model first"). Engine session stays valid in every error branch. |
— | headless + reflected private state | covered (nps-oro.3) |
| 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 :3867,:3775 |
EngineBridgeTests:236 (Theory 7 rows),:261,:285 |
— | 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 |
:4213 (popen smoke) |
— | 4 ctest syntax/content tests | popen + structural | covered (bash); debug-mixed.ps1 NOT TESTED — wont-fix (nps-oro.6): Windows-only twin launcher, no PowerShell on the Linux dev/CI host; behavior is pinned by the bash twin's coverage |
| 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) | — | :1968 (<5000ms),:2025 |
— | — | 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— CLOSED (nps-oro.2): 22 Facts inViewportToolbarTestsenumerate the 10 code-built controls + tooltips (ViewportToolbarTests.cs:99–:189), drive every button click throughButton.ClickEventand verify*Clickedfires exactly once (:193–:339), drive both toggles through flipped-IsChecked+Clickto verify the bool payload (:340–:436+:521–:559), and wire the toolbar to a realViewportControllerto verify preset clicks changevc.Cameraacross all six orientations (:437–:520) and zoom-fit clicks changevc.Camera.Zoom/PanX/PanY(:560–:626).Playback runtime— CLOSED (nps-oro.1): 6 Facts inAppHeadlessSmokeTests:1410-:1758drivePlayPauseClicked/StepClicked/AutoPause/ScrubberPointerPressed/Released/SpeedChanged/ScrubberChangedthrough the public panel surface into the real MainWindow handlers (SimulatorApp/MainWindow.axaml.cs:510-658). Observable contract:panel.IsPlaying, status substring,_simMoveIndexmirror,_playTimer.Interval.App event handlers— CLOSED (nps-oro.3) for all reachable branches:OnLoadAnalyzeClickdriven throughLoadAndAnalyzeFromPathseam with both fixture-missing and invalid-file paths (AppHeadlessSmokeTests:367,:420,:791,:843);OnApplySliceClickdriven via XAML button before/after load (:531,:572);OnOverlayModeChangeddriven via reflectedOverlayPanel.ModeChanged(:657,:998);OnLayerSliderChangeddriven viaSlider.Value(:615,:958);OnFindingSelecteddriven viaFindingsPanel.FindingSelectedfor both pinned and unpinned (-1) move indices (:727,:1052,:1115). Both apps covered. Engine-side-only (4 Skip facts,AppHeadlessSmokeTests:1447-:1467):RunGenerategen-failed (SlicerApp/MainWindow.axaml.cs:441-443;SimulatorApp/MainWindow.axaml.cs:557-559) and analyze-failed (SlicerApp/MainWindow.axaml.cs:503-506;SimulatorApp/MainWindow.axaml.cs:579-582) branches are unreachable from production today —Engine::GenerateGcodereturnsNPS_RESULT_SUCCESSunconditionally (src/Engine/engine.cpp:1433) andEngine::AnalyzeGcodeisvoid(src/Engine/engine.cpp:1479-1488); covered engine-side byEngineSessionTests.GenerateDemoToolpath_AfterBenchyLoad_ReturnsMoves(:166) andEngineSessionTests.Findings_AreEmptyBeforeAnalyze_AndPopulatedAfter(:185). The Skip facts cite these engine-side tests and flip to real asserts the moment a future engine revision makes either op return a failure code.Pointer-drag orbit/pan + Zoom-to-Fit button— CLOSED (nps-oro.4 / nps-oro.2): synthetic press/drag/release through Avalonia.Headless asserts camera fields for both apps — unarmed move is a no-op, left-drag orbit clampsRotationXRadiansat ±1.5 while applying the Z delta, right-drag pan scales by0.5 / max(0.1, Zoom)(AppHeadlessSmokeTests:157Slicer,:165Simulator via the sharedRunViewportPointerGestureSmoke:227). Zoom-to-Fit clicks reachViewportController.Camerawith aspect-preserving math (ViewportToolbarTests.cs:561,:598).UI error paths— CLOSED (nps-oro.3): 5 facts across both apps drive the load-failed / fixture-missing / Apply-before-load branches through the realOnLoadAnalyzeClick+OnApplySliceClickhandlers (AppHeadlessSmokeTests:367,:420,:531,:791,:843). Each error branch asserts the user-visibleShell.StatusTextsubstring and that the engine session stays valid (IsValid==true,_modelLoaded==false, no move buffer populated).MeshCanvasPainter + GcodeToolpathPainter happy path— CLOSED (nps-oro.4):GcodeToolpathPainterTests:75draws parsed moves and asserts travel/extrusion Lines, colors, finding Ellipse markers, and the max-layer filter;MeshCanvasPainterTests:71renders the golden Benchy mesh and asserts Polygon output stays withinMaxTrianglesPerPlate=2000,:106pins the empty-palette opaque-white fallback.Warp grid risk values— CLOSED (nps-oro.5):engine_tests.cpp:1912content-asserts the risk array cell-by-cell on a pinned synthetic input (values, not justsize==gridW*gridH).Analyzer value correctness— CLOSED (nps-oro.5 / nps-ai2.2): golden values pinned per analyzer — thermalengine_tests.cpp:1554(score == totHeat == 0.04, findingCount == 1), structural:1594, motion:1640(2-move tiny + cube junction clamp at 14.4). Motion profile inference is un-stubbed:inferProfileFromGcodeapplies real M204 P/T/S declarations (engine_tests.cpp:4096).Retraction analyzer + MaterialCatalog C# parity, corrupt-bgcode, multi-plate fixtures, debug-mixed.ps1— CLOSED (nps-oro.6): retraction C# parity (EngineBridgeTests:1639), MaterialCatalog POD roundtrip C# (:1770), corrupt-CRC bgcode warn-and-continue on the real fixture (:1904). Two gaps documented instead of tested: multi-plate stays untested by design (engine hardcodesplate_1, no fixture exists — tracked by feature bead nps-ai2.3) and debug-mixed.ps1 is wont-fix (Windows-only twin; bash twin covered atengine_tests.cpp:4213+ 4 ctest).
Golden blessing recipe (NPS_BLESS_GOLDEN)¶
The single visual-golden baseline (tests/golden/g6_orbit_render.sha256,
tests/golden/g6_orbit_render.ppm) is fail-closed:
- A missing baseline = hard FAIL (C++
TEST_CASE("Visual/golden render parity …")atengine_tests.cpp:2650; C#VisualGolden_RenderOrbit_BytesMatchCppBaselineatEngineBridgeTests.cs:2214). No auto-write. - A mismatch = hard FAIL +
.driftPPM next to the baseline (C++ side only — foreog/xdg-open/byte-diff inspection).
Regenerating the baseline is an explicit, gated, human-reviewed operation. To (re)bless the baseline after a deliberate ABI/render change:
# C++ Catch2:
NPS_BLESS_GOLDEN=1 ctest --test-dir build --output-on-failure \
-R "Visual/golden render parity"
# C# xUnit (mirrors the C++ test byte-for-byte):
NPS_BLESS_GOLDEN=1 dotnet test tests/NPSEngine.Tests \
--filter "FullyQualifiedName~VisualGolden_RenderOrbit_BytesMatchCppBaseline"
Both harnesses gate on NPS_BLESS_GOLDEN=="1" exactly. The bless run
WARNs in C++ (INFO log) and silently passes in C#; both write the new
.sha256 (C++ also rewrites the .ppm). Subsequent runs without the env
var then enforce the new baseline.
Mandatory review checklist before committing:
git diff tests/golden/g6_orbit_render.sha256— new SHA must match what the C++ side just wrote (C# bless is byte-identical because the Bresenham oracle is mirrored).- Visually inspect the new
.ppmagainst the previous one (eog tests/golden/g6_orbit_render.ppmor any image viewer). Drift should match the deliberate change (camera, color ramp, ABI). - If a mismatch run wrote
.drift, byte-diff it against the committed.ppmto confirm the diff is exactly the intended change.
The baseline is committed (tests/golden/g6_orbit_render.sha256) and MUST
NOT be deleted as a workaround for a missing baseline. If it's missing, run
the bless recipe above; do not git restore the previous SHA without
reviewing.
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 # 76 (+17 TEST_CASE_METHOD)
grep -rnE '^\s*\[Fact' tests/NPSEngine.Tests/*.cs | wc -l # 154 (+4 [Theory], 163 cases after Theory row expansion)
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 93 TEST_CASEs (engine_tests.cpp)
Bead nps-f8v.5: Retraction events parsing and analysis on custom G-code—engine_tests.cpp:3174Bead nps-f8v.8: Bambu comments parsing and override detection—engine_tests.cpp:3255Bead nps-f8v.8: Bambu proprietary commands are tolerated without crash—engine_tests.cpp:3412Bead nps-f8v.8: Malformed / boundary inputs are tolerated without crash /—engine_tests.cpp:3602Bead nps-f8v.8: Malformed / boundary inputs are tolerated without crash / ;—engine_tests.cpp:3659Bead nps-f8v.8: Malformed / boundary inputs are tolerated without crash / ;FLAVOR: with—engine_tests.cpp:3688Bead nps-f8v.8: Malformed / boundary inputs are tolerated without crash / ParseGcode—engine_tests.cpp:3619Bead nps-f8v.8: Malformed / boundary inputs are tolerated without crash / Very long—engine_tests.cpp:3635Bead nps-f8v.8: Marlin + Klipper firmware detection via FLAVOR comment / Klipper flavor—engine_tests.cpp:3388Bead nps-f8v.8: Marlin + Klipper firmware detection via FLAVOR comment / Marlin flavor—engine_tests.cpp:3365Bead nps-f8v.8: NpsMaterialProfile POD layout is 108 bytes and round-trips via C ABI—engine_tests.cpp:3775Bead nps-f8v.8: OrcaSlicer comments parsing—engine_tests.cpp:3326Bead nps-f8v.8: Slicer detection rejects non-banner CURA/BAMBU substrings / Comment—engine_tests.cpp:3708Bead nps-f8v.8: Slicer detection rejects non-banner CURA/BAMBU substrings / Comment—engine_tests.cpp:3729Bead nps-f8v.8: Slicer detection rejects non-banner CURA/BAMBU substrings / Real banner—engine_tests.cpp:3750Benchy analysis populates flow overlays—engine_tests.cpp:3149Benchy analysis reports hole findings—engine_tests.cpp:3130Benchy parse + viewport build timing smoke (nps-n1m.40 G16)—engine_tests.cpp:2025Benchy validation exposes transformed mesh data—engine_tests.cpp:655Benchy validation keeps bounds and indices consumable—engine_tests.cpp:678Benchy validation loads the primary fixture—engine_tests.cpp:625Benchy validation preserves golden mesh counts—engine_tests.cpp:634Benchy validation preserves the four-color palette—engine_tests.cpp:642Benchy validation supports metadata-only reload—engine_tests.cpp:710C ABI string-output contract (nps-n1m.27): null/zero-cap no-op + UTF-8 NUL + truncation—engine_tests.cpp:3867Default material profiles are parameterized by material key—engine_tests.cpp:3483E2E: mesh load + synthetic gcode parse/analyze + overlay data assert (nps-f8v.11)—engine_tests.cpp:1749Engine GetLastParsedGcode split semantics (nps-n1m.32)—engine_tests.cpp:1451Engine LoadModelFromFile error cases for robustness (nps-l7k.14)—engine_tests.cpp:747Engine LoadModelFromFile returns failure for missing file—engine_tests.cpp:728Engine LoadModelFromFile wires parser via ZIP/OPC reader (nps-l7k.3) on real Benchy—engine_tests.cpp:291Engine ZipArchiveReader extracts model XML + metadata on primary Benchy (nps-l7k.3)—engine_tests.cpp:343Engine basic lifecycle and version—engine_tests.cpp:276Engine core mesh and plate data structures + append/combine (nps-l7k.4)—engine_tests.cpp:478Engine mesh prep for scalar fields & shared viewport (nps-l7k.11)—engine_tests.cpp:533Engine mesh query API surface (nps-l7k.2 design)—engine_tests.cpp:378Gcode bgcode basic header + optional full decode (nps-f8v.4)—engine_tests.cpp:1513Gcode gen + C ABI buffer + file roundtrip (nps-f8v.10 interop)—engine_tests.cpp:2963Gcode generation error cases and defaults (nps-f8v.10)—engine_tests.cpp:2934Gcode generation from loaded mesh + params (nps-f8v.10 basic)—engine_tests.cpp:2772Gcode generation non-planar + roundtrip validate structure (nps-f8v.10)—engine_tests.cpp:2871Gcode generation real geometry and scalar fields (nps-f8v.7.1)—engine_tests.cpp:3014Gcode parse + analyze roundtrip via C ABI harness hooks (integration)—engine_tests.cpp:1708Gcode parse from real test_cube + roundtrip structure (nps-f8v.4 + Gcode files)—engine_tests.cpp:1414Gcode parser multi-format layers + Bambu markers (nps-f8v.4)—engine_tests.cpp:1350Gcode parser relative E + M82/M83 + G92 + accel M204 (nps-f8v.4)—engine_tests.cpp:1375Gcode parser section types + G2/G3 arcs (nps-f8v.4)—engine_tests.cpp:1402Gcode parser state machine + moves (nps-f8v.11 + f8v.9 model)—engine_tests.cpp:1294LoadModelFromFile ABI forwarder rejects null engine handle (nps-n1m.32)—engine_tests.cpp:820M104 metadata fallback is parameterized by hotend temperature—engine_tests.cpp:3565MaterialCatalog table exposes expected entry count + PLA fallback at index 0—engine_tests.cpp:3520MaterialCatalog::forType normalizes key (case + underscore-to-dash) and falls back to PLA—engine_tests.cpp:3544ModelXMLParser direct nps::Parse populates full result incl triangles—engine_tests.cpp:1228ModelXMLParser handles object/component graph, unit, build items—engine_tests.cpp:1210ModelXMLParser reports PARSE_ERROR on bad data (integrates .14 model)—engine_tests.cpp:1244ModelXMLParser streams vertices + triangles from real 3MF sample—engine_tests.cpp:1182Motion analyzer golden values on pinned synthetic gcode (nps-oro.5)—engine_tests.cpp:1640Performance: large G-code parse + analysis time (nps-f8v.11)—engine_tests.cpp:1968Primary Benchy ZIP hook extracts model and metadata—engine_tests.cpp:1106Primary Benchy ZIP load preserves golden counts—engine_tests.cpp:1096ProjectOrbitXY C ABI parity with previous UI math (nps-n1m.30 G6)—engine_tests.cpp:2291Structural score analyzer with GcodeMove (nps-f8v.11 + f8v.9)—engine_tests.cpp:1594Thermal grid analyzer math with GcodeMove (nps-f8v.11 + f8v.9)—engine_tests.cpp:1554Unknown material profile falls back to PLA—engine_tests.cpp:3510Viewport camera MVP + layer vis + sim offsets (nps-f8v.3)—engine_tests.cpp:2189Viewport color logic matches TYPE_COLORS port (nps-f8v.3)—engine_tests.cpp:2108Viewport harness integration: moves from parse + analyze feed (nps-f8v.3 + f8v.11)—engine_tests.cpp:2223Viewport layer buffers + move offsets from GcodeMove (nps-f8v.3 + f8v.9)—engine_tests.cpp:2131ViewportGetHeatmapColor C ABI matches GcodeViewport::GetHeatmapColor (nps-n1m.30 G6)—engine_tests.cpp:2260Visual/golden render parity via engine C ABI (nps-n1m.30 G6)—engine_tests.cpp:2650Warp grid risk contents golden on pinned synthetic input (nps-oro.5)—engine_tests.cpp:1912WarpGrid ABI + viewport render smoke (nps-f8v.6.1)—engine_tests.cpp:1798Zip reader rejects a bad deflate stream—engine_tests.cpp:1036Zip reader rejects a bad local header signature—engine_tests.cpp:999Zip reader rejects a corrupt EOCD—engine_tests.cpp:969Zip reader rejects a truncated archive—engine_tests.cpp:986Zip reader rejects null arguments—engine_tests.cpp:1088Zip reader rejects stored-size mismatches—engine_tests.cpp:1071Zip reader rejects unsupported compression—engine_tests.cpp:1018Zip reader reports a missing entry—engine_tests.cpp:1060nps-580 scripts/debug-mixed.sh --help and print-modes—engine_tests.cpp:4213nps-ai2.2: inferProfileFromGcode applies M204 P/T/S acceleration declarations—engine_tests.cpp:4096nps-n1m.18 D5: Viewport SetGcodeMoves copies (engine buffer mutation after Set does not—engine_tests.cpp:4645nps-n1m.18 D5: Viewport survives engine Load/Parse after SetGcodeMoves (no UAF)—engine_tests.cpp:4534nps-n1m.41 G17: ApplyOverlay(OverlayState) collapses the three-setter sequence—engine_tests.cpp:4435nps-n1m.41 G17: GetExtrudeColorForType Color3* overload matches float[3] overload—engine_tests.cpp:4797nps-n1m.41 G17: GetMeshBounds Position* overload matches float[3] overload—engine_tests.cpp:4760nps-n1m.41 G17: Mat4LookAt now takes three Vec3—engine_tests.cpp:4742nps-n1m.41 G17: Position alias exists and is a Vec3—engine_tests.cpp:4721nps-n1m.41 G17: SetCamera(CameraState) overload forwards all five floats—engine_tests.cpp:4368nps-n1m.41 G17: Vec3/Color3/BedGeometry/CameraState aggregate value types—engine_tests.cpp:4319nps-n1m.41 G17: ViewportApplyOverlay C ABI aggregate equals three-setter sequence—engine_tests.cpp:4477nps-n1m.41 G17: applySnapshot(EngineSnapshot) feeds moves to viewport—engine_tests.cpp:4405
C# xUnit — all 158 Facts/Theories (154 [Fact] + 4 [Theory], 163 test cases) (tests/NPSEngine.Tests)
MainWindowShell_Collapse_Width_Memory_Smoke—AppHeadlessSmokeTests.cs:173SimulatorApp_MainWindow_Loads_Layout_And_Bindings—AppHeadlessSmokeTests.cs:146SimulatorApp_ViewportPointerDrag_OrbitAndPan_UpdateCamera—AppHeadlessSmokeTests.cs:165SlicerApp_MainWindow_Loads_Layout_And_Bindings—AppHeadlessSmokeTests.cs:63SlicerApp_ViewportPointerDrag_OrbitAndPan_UpdateCamera—AppHeadlessSmokeTests.cs:157AbiPODLayout_Frozen—EngineBridgeTests.cs:236CreateInitializeVersionDestroy_Works—EngineBridgeTests.cs:174E2E_MeshLoadPlusGcodeAnalyze_AssertsOverlays—EngineBridgeTests.cs:675EnumMirrors_MatchFrozenAbiInts—EngineBridgeTests.cs:261GcodeGenerate_RoundtripAndNonplanar_Validates—EngineBridgeTests.cs:750GcodeParse_RoundtripViaTestHook_Works—EngineBridgeTests.cs:642GetAbiVersion_MatchesExpectedAtStartup—EngineBridgeTests.cs:200GetLastParsedGcode_SplitSemantics_RoundTripViaCAbi—EngineBridgeTests.cs:929LoadModelFromFile_ErrorCasesAndOptions_Robustness—EngineBridgeTests.cs:471LoadModelFromFile_MissingFile_ReturnsSpecificErrorAndMessage—EngineBridgeTests.cs:452LoadModelFromFile_NullEngineHandle_ReturnsInvalidArgument—EngineBridgeTests.cs:561LoadModelFromFile_OnBenchy3Mf_SucceedsWithAssertion—EngineBridgeTests.cs:298Loader_IntegratesViaEngineHost_Succeeds—EngineBridgeTests.cs:607MaterialProfilePod_FilamentDiameter_RoundTripsWithExactFlowValues—EngineBridgeTests.cs:1770ParseBgcode_CorruptBlockCrc_ValidContainer_WarnAndContinue—EngineBridgeTests.cs:1904ParseBgcode_RealTestCubeBinary_FullRoundtripAssertsMovesAndLayers—EngineBridgeTests.cs:829ProjectOrbitXY_IdentityRotation_ZContributesToScreenXY—EngineBridgeTests.cs:2183ProjectOrbitXY_MatchesLegacyUiMath—EngineBridgeTests.cs:2139ProjectOrbitXY_NullOutIsNoop—EngineBridgeTests.cs:2195RetractionFindings_ParityWithCppFixture_RealMessagesAndOverlays—EngineBridgeTests.cs:1639TestAnalysisFindingsSummary_BeforeAnalyze_ReportsNoData—EngineBridgeTests.cs:1554TestAnalysisFindingsSummary_RoundTripsThroughDetail—EngineBridgeTests.cs:1474TestInferredMaterialTemperatureFallback—EngineBridgeTests.cs:1313TestInferredPropertiesFromGcode—EngineBridgeTests.cs:1135TestInferredSlicerFlavor—EngineBridgeTests.cs:1267TestInferredSlicerOrcaSlicer—EngineBridgeTests.cs:1210TestMaterialProfilePODRoundTrip—EngineBridgeTests.cs:1351TestParseGcodeMalformedInputs—EngineBridgeTests.cs:1576ThermalAndStructural_AnalyzerInterop_ReturnsData—EngineBridgeTests.cs:656ViewportGetHeatmapColor_InvertFlipsRamp—EngineBridgeTests.cs:2103ViewportGetHeatmapColor_MidValue_IsGreen—EngineBridgeTests.cs:2084ViewportGetHeatmapColor_NullOutIsNoop—EngineBridgeTests.cs:2128ViewportGetHeatmapColor_VmaxMapsToRedEnd—EngineBridgeTests.cs:2117ViewportMeshRender_BenchyFixture_Validates—EngineBridgeTests.cs:1065ViewportRenderLogic_Smoke_BridgeCalls_NoCrash—EngineBridgeTests.cs:1014VisualGolden_RenderOrbit_BytesMatchCppBaseline—EngineBridgeTests.cs:2214WireIdMirrors_MatchFrozenAbiIds—EngineBridgeTests.cs:285Construction_AllControlsHaveExpectedTooltipText—ViewportToolbarTests.cs:120Construction_AllPublicButtonsAreDistinctInstances—ViewportToolbarTests.cs:155Construction_ExposesExactlyTenControls—ViewportToolbarTests.cs:100Construction_TravelsAndExtrudesToggle_StartChecked—ViewportToolbarTests.cs:141ExtrudesToggle_Click_PayloadReflectsPostToggleIsChecked—ViewportToolbarTests.cs:372FrontClick_RaisesFrontClickedExactlyOnce—ViewportToolbarTests.cs:245IsometricClick_RaisesIsometricClickedExactlyOnce—ViewportToolbarTests.cs:229LayerDownClick_RaisesLayerDownClickedExactlyOnce—ViewportToolbarTests.cs:325LayerUpClick_RaisesLayerUpClickedExactlyOnce—ViewportToolbarTests.cs:309LayerUpDownClick_SubscriptionPath_RaisesEventForHostLambda—ViewportToolbarTests.cs:628NoOpEventSubscription_DoesNotThrowAndDoesNotFire—ViewportToolbarTests.cs:194PresetClicks_ReachesController_AllSixOrientations—ViewportToolbarTests.cs:464ResetClick_RaisesResetClickedExactlyOnce—ViewportToolbarTests.cs:213ResetClick_ReachesController_AndAppliesResetPreset—ViewportToolbarTests.cs:438RightClick_RaisesRightClickedExactlyOnce—ViewportToolbarTests.cs:277ShowTravelsToggle_PayloadTracksIsChecked_ThroughMultipleToggles—ViewportToolbarTests.cs:395ToggleClicks_ReachAppSubscription_WithExpectedPayload—ViewportToolbarTests.cs:522TopClick_RaisesTopClickedExactlyOnce—ViewportToolbarTests.cs:261TravelsToggle_Click_PayloadReflectsPostToggleIsChecked—ViewportToolbarTests.cs:341ZoomFitClick_NonSquareViewport_PreservesAspectMath—ViewportToolbarTests.cs:598ZoomFitClick_RaisesZoomFitClickedExactlyOnce—ViewportToolbarTests.cs:293ZoomFitClick_ReachesController_AndAppliesZoomFitMath—ViewportToolbarTests.cs:561CreateAndInitialize_ProducesValidSession—EngineSessionTests.cs:48Dispose_MakesSessionInvalid—EngineSessionTests.cs:60Dispose_Twice_IsIdempotent—EngineSessionTests.cs:69Findings_AreEmptyBeforeAnalyze_AndPopulatedAfter—EngineSessionTests.cs:185GenerateDemoToolpath_AfterBenchyLoad_ReturnsMoves—EngineSessionTests.cs:166GetFindingDetail_ReturnsFullRecordForKnownId—EngineSessionTests.cs:211GetFindingDetail_StaleId_ReturnsNull—EngineSessionTests.cs:233GetOverlayValue_BeforeLoad_ReturnsZero—EngineSessionTests.cs:261GetOverlayValue_ThrowsAfterDispose—EngineSessionTests.cs:253GetSupportedOverlayIds_NullEngine_IsNoOp—EngineSessionTests.cs:533GetSupportedOverlayIds_ReturnsExactManagerDerivedList—EngineSessionTests.cs:464GetSupportedOverlayIds_TightBuffer_TruncatesAtCapMinusOneAndPinsNul—EngineSessionTests.cs:501GetSupportedOverlayIds_ZeroCapacity_IsNoOp—EngineSessionTests.cs:549GetWarpGrid_BeforeAnalyze_ReturnsNull—EngineSessionTests.cs:241LoadModel_ClearsPriorMoveBuffer—EngineSessionTests.cs:142LoadModel_MissingFile_ReturnsFailureWithMessage—EngineSessionTests.cs:127LoadModel_OnBenchy3Mf_ReturnsStructuredPlatesAndPalette—EngineSessionTests.cs:95ParseBgcode_AfterDispose_ThrowsObjectDisposedException—EngineSessionTests.cs:407ParseBgcode_InvalidBytes_ReturnsFailureWithParseError—EngineSessionTests.cs:362ParseGcode_AfterDispose_ThrowsObjectDisposedException—EngineSessionTests.cs:395ParseGcode_AsciiText_ReturnsSuccessWithMoves—EngineSessionTests.cs:288ParseGcode_CommandlessText_ReturnsSuccessWithoutMoves_AndClearsPriorSnapshot—EngineSessionTests.cs:335ParseGcode_EmptyText_ReturnsSuccessWithoutMoves_AndClearsPriorSnapshot—EngineSessionTests.cs:311ParseGcode_NoM204_LeavesReservedSlotZero—EngineSessionTests.cs:617FindingsPanel_AllChip_RestoresBothAxes—FindingsPanelTests.cs:156FindingsPanel_CategoryFilter_AlsoUnchecksAll—FindingsPanelTests.cs:130FindingsPanel_DefaultChips_AllChecked—FindingsPanelTests.cs:43FindingsPanel_Selection_RaisesFindingSelected_WithItem—FindingsPanelTests.cs:189FindingsPanel_SetFindings_RebuildsItemsSource_And_Count—FindingsPanelTests.cs:73FindingsPanel_SeverityFilter_ShrinksVisibleCount—FindingsPanelTests.cs:94FindingsPanel_TryGetCachedItem_ReturnsNull_ForUnknownFindingId—FindingsPanelTests.cs:248FindingsPanel_UpdateDetail_PopulatesStyledProperties—FindingsPanelTests.cs:218RenderTo_FreshViewport_ZeroMoves_IsNoOp—GcodeToolpathPainterTests.cs:52RenderTo_NullViewport_IsNoOp—GcodeToolpathPainterTests.cs:29RenderTo_WithParsedMoves_DrawsLinesColorsMarkers_AndHonorsLayerFilter—GcodeToolpathPainterTests.cs:75RenderTo_Benchy_EmitsPolygonsWithinPerPlateCap—MeshCanvasPainterTests.cs:71RenderTo_EmptyMeshController_IsNoOp—MeshCanvasPainterTests.cs:47RenderTo_EmptyPalette_UsesOpaqueWhiteFallback—MeshCanvasPainterTests.cs:106RenderTo_NullMesh_IsNoOp—MeshCanvasPainterTests.cs:28Constructor_BeforeReload_HasZeroPlatesAndEmptyPalette—MeshControllerTests.cs:36PlateMesh_EmptyArrays_ReportZeroCountsAndEmptySpans—MeshControllerTests.cs:132Reload_AfterSecondLoad_ReplacesSnapshotInPlace—MeshControllerTests.cs:91Reload_OnBenchy_SnapshotsOnePlateWithGoldenCounts—MeshControllerTests.cs:51ActivityBarHost_FiresTabClicked_ForRegisteredKey—ShellChromeTests.cs:146ActivityBarHost_NoTabClicked_When_Button_Tag_Unregistered—ShellChromeTests.cs:130FindingFormatter_CategoryLabel_And_Brush_For_All_Known_Categories—ShellChromeTests.cs:244FindingFormatter_FromSummaryAndDetail_Stamps_Category_From_Detail—ShellChromeTests.cs:334FindingItem_DefaultShape_Mirrors_Api_Contract—ShellChromeTests.cs:209FindingsFilterState_Default_Matches_All_Rows—ShellChromeTests.cs:289PanelHost_Show_FlipsExactlyOneVisible_And_FiresOnShown—ShellChromeTests.cs:164PanelHost_Show_UnknownKey_NoOp_NoOnShown—ShellChromeTests.cs:188SeverityPalette_Resolves_Fallback_Brushes—ShellChromeTests.cs:374ShellKeybindings_Left_Right_Step_And_Handle—ShellChromeTests.cs:89ShellKeybindings_Mod_L_TogglesInspector_Only_With_Ctrl—ShellChromeTests.cs:69ShellKeybindings_P_TogglesPlay_And_Handles—ShellChromeTests.cs:50ShellKeybindings_Unhandled_Key_FallsThrough—ShellChromeTests.cs:114CreateDefaults_Matches_HardCoded_Demo_Toolpath_Options—SliceParamsTests.cs:17PropertyChanged_Does_Not_Fire_On_Same_Value—SliceParamsTests.cs:64PropertyChanged_Fires_On_Mutation—SliceParamsTests.cs:49ToGcodeGenOptions_Reflects_Mutated_Fields—SliceParamsTests.cs:30BuildMarkers_EmptyFindings_ReturnsEmpty—TimelineMarkerHelperTests.cs:110BuildMarkers_EmptyTimeline_ReturnsEmpty—TimelineMarkerHelperTests.cs:118BuildMarkers_ExcludesMoveIndexMinusOne—TimelineMarkerHelperTests.cs:138BuildMarkers_NullFindings_ReturnsEmpty—TimelineMarkerHelperTests.cs:102BuildMarkers_PreservesInputOrder—TimelineMarkerHelperTests.cs:184BuildMarkers_ProjectOffsetsAcrossFullTimeline—TimelineMarkerHelperTests.cs:163Fraction_EmptyTimeline_ReturnsZero—TimelineMarkerHelperTests.cs:64Fraction_FirstMove_ReturnsZero—TimelineMarkerHelperTests.cs:42Fraction_LastMove_ReturnsOne—TimelineMarkerHelperTests.cs:48Fraction_Midpoint_ReturnsHalf—TimelineMarkerHelperTests.cs:56Fraction_MoveBeyondEnd_ClampsToOne—TimelineMarkerHelperTests.cs:90Fraction_NegativeMoveIndex_ClampsToZero—TimelineMarkerHelperTests.cs:82Fraction_SingleMove_ReturnsZero—TimelineMarkerHelperTests.cs:74ApplyOverlay_FromSession_ComputesStatsAndAppliesOverlay—ViewportControllerTests.cs:460ApplyOverlay_MirrorsMode_AndDoesNotThrow—ViewportControllerTests.cs:168ApplyOverlay_NonThermal_LastOverlayMeanMatchesStatsMeanAndSampleCountExcludesZeros—ViewportControllerTests.cs:509ApplyOverlay_NullValues_Throws—ViewportControllerTests.cs:196BuildBuffers_IsCallableAndDoesNotThrow—ViewportControllerTests.cs:128CameraPresets_ProduceNonCollapsedProjectedBoundsAndDistinctOrientations—ViewportControllerTests.cs:305ComputeZoomFit_ReturnsPlacingContentAtApproximately90PercentFill—ViewportControllerTests.cs:415ComputeZoomFit_WithMoves_ReturnsExpectedZoomAndPan—ViewportControllerTests.cs:376ComputeZoomFit_WithNonSquareViewportAndContent_ReturnsExpectedZoomAndFill—ViewportControllerTests.cs:439CreateAndInitialize_ProducesValidViewport—ViewportControllerTests.cs:31Dispose_MakesViewportInvalid—ViewportControllerTests.cs:41Dispose_Twice_IsIdempotent—ViewportControllerTests.cs:50MovesSpan_EmptyBeforeSetMoves—ViewportControllerTests.cs:211MovesSpan_ReflectsSetMovesCount—ViewportControllerTests.cs:218SetCameraPreset_UpdatesCameraRotationAndZeroPan—ViewportControllerTests.cs:253SetCamera_FiveArgOverload_MirrorsCameraState—ViewportControllerTests.cs:104SetCamera_RecordOverload_MirrorsCameraState—ViewportControllerTests.cs:84SetLayerVisibility_MirrorsMaxLayer—ViewportControllerTests.cs:76SetMoves_MirrorsCountAndPointer—ViewportControllerTests.cs:138SetSimulationState_MirrorsSimMoveIndex—ViewportControllerTests.cs:120SetWarpParams_DoesNotThrow—ViewportControllerTests.cs:203
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