Unit Test Results¶
261 total | 261 passed | 0 failed — 2026-04-22 11:42
By complexity¶
| Level | Count | Description |
|---|---|---|
smoke |
13 | no-crash / lifecycle only |
format |
37 | string or schema format checks |
behavioral |
185 | actual module behavior: output, state, counts |
integration |
28 | multi-module pipeline or cross-device |
See Testing standards for the full classification guide.
test_artnet.cpp¶
✅ 7/7 passed — test_artnet.cpp
- ✅
smokeArtNetOutModule - lifecycle without layer (should not crash) - ✅
behavioralArtNetOutModule - sends packets when wired to a DriverLayer with pixels - ✅
behavioralArtNetOutModule - multi-universe: 170 pixels use 1 universe, 171 use 2 - ✅
behavioralArtNetOutModule - packet header bytes are correct Art-Net OpDmx - ✅
smokeArtNetInModule - lifecycle without layer (should not crash) - ✅
formatArtNetInModule - healthReport format - ✅
integrationArtNetOut loopback to ArtNetIn on 127.0.0.1
Brightness Modifier¶
✅ 8/8 passed — test_brightness_mod.cpp
- ✅
behavioralBrightnessModifierModule - setup registers frequency control - ✅
behavioralBrightnessModifierModule - setControl updates live frequency - ✅
behavioralBrightnessModifierModule - loop() output scales with brightness from KvStore - ✅
behavioralBrightnessModifierModule - loop() uses KvStore default when key absent - ✅
behavioralDriverLayer - setInput source2 registers a second producer - ✅
behavioralDriverLayer - setInput source only still works (single source) - ✅
behavioralSineEffectModule - loop() publishes amplitude as KvStore 'brightness' - ✅
integrationPhase 9 pipeline - SineEffectModule publishes brightness, BrightnessMod reads it
Controls and KV Store¶
✅ 26/26 passed — test_controls_and_kv.cpp
- ✅
behavioralStatefulModule - addControl registers controls correctly - ✅
behavioralStatefulModule - clearControls resets count - ✅
behavioralStatefulModule - setControl float writes through to field - ✅
behavioralStatefulModule - setControl uint8 writes through to field - ✅
behavioralStatefulModule - setControl uint32 writes through to field - ✅
behavioralStatefulModule - setControl bool writes through to field - ✅
behavioralStatefulModule - setControl unknown key is a no-op - ✅
behavioralStatefulModule - setControl JsonVariant writes through to field - ✅
behavioralStatefulModule - onUpdate is called after setControl - ✅
behavioralStatefulModule - onUpdate is NOT called for unknown key - ✅
formatStatefulModule - getSchema produces correct JSON structure - ✅
formatStatefulModule - getSchema reflects current field value after setControl - ✅
formatSineEffectModule - getSchema exposes frequency and amplitude - ✅
behavioralSineEffectModule - setControl updates live frequency - ✅
formatPreviewModule - getSchema exposes logEveryN - ✅
behavioralKvStore - setFloat / getFloat round-trip - ✅
behavioralKvStore - setUint8 / getUint8 round-trip - ✅
behavioralKvStore - setBool / getBool round-trip - ✅
behavioralKvStore - getFloat returns default for unknown key - ✅
behavioralKvStore - getUint8 returns default for unknown key - ✅
behavioralKvStore - getBool returns default for unknown key - ✅
behavioralKvStore - getFloat returns default when key holds different type - ✅
behavioralKvStore - exists returns true for present key, false for absent - ✅
behavioralKvStore - setFloat updates an existing entry - ✅
behavioralKvStore - setFloat returns false when table is full - ✅
behavioralKvStore - clear removes all entries
Coord3D and Pixel Addressing¶
✅ 7/7 passed — test_coord3d.cpp
- ✅
behavioralCoord3D - default construction is (0,0,0) - ✅
behavioralCoord3D - equality and inequality - ✅
behavioralcoords_to_index - flat 2D grid (depth=1) - ✅
behavioralcoords_to_index - 3D volume - ✅
behavioralindex_to_coords - flat 2D grid (depth=1) - ✅
behavioralindex_to_coords - 3D round-trip with coords_to_index - ✅
behavioralcoords_to_index - matches EffectsLayer pixel layout
test_effects_2d.cpp¶
✅ 7/7 passed — test_effects_2d.cpp
- ✅
behavioralGameOfLifeEffect - glider moves (+1,+1) after 4 generations - ✅
behavioralGameOfLifeEffect - extinction triggers re-seed - ✅
behavioralGameOfLifeEffect - renders non-zero pixels after loop - ✅
behavioralNoiseEffect2D - renders non-zero pixels - ✅
behavioralNoiseEffect2D - output varies with position (scale>0 produces spatial variation) - ✅
behavioralDistortionWaves2DEffect - renders non-zero pixels - ✅
behavioralDistortionWaves2DEffect - spatial variation across pixels
Health Checks¶
✅ 5/5 passed — test_health_checks.cpp
- ✅
formatSineEffectModule - healthReport format after one tick - ✅
formatPreviewModule - healthReport format after one tick - ✅
behavioralHealth check - SineEffectModule and Preview checksums match - ✅
behavioralHealth check - zero-residue: PreviewModule state reset after teardown - ✅
formatScheduler - printHealthReports fires for participating modules
HTTP Server¶
✅ 18/18 passed — test_http_server.cpp
- ✅
formatSineEffectModule - getSchema includes category 'effect' - ✅
formatBrightnessModifierModule - getSchema includes category 'modifier' - ✅
formatEffectsLayer - getSchema includes category 'layer' - ✅
formatDriverLayer - getSchema includes category 'layer' - ✅
behavioralSineEffectModule - setControl updates frequency live - ✅
behavioralSineEffectModule - setControl ignores unknown key - ✅
behavioralModuleManager - getModulesJson emits id + name + category + controls - ✅
behavioralModuleManager - setModuleControl returns true for valid id+key - ✅
behavioralModuleManager - setModuleControl returns false for unknown module id - ✅
behavioralModuleManager - setModuleControl returns false for unknown key - ✅
behavioralModuleManager - flushIfDirty does not flush before debounce window - ✅
behavioralModuleManager - getModulesJson reflects live value after setModuleControl - ✅
behavioralModuleManager - flushIfDirty writes state file when debounce is 0 - ✅
behavioralModuleManager - addModule creates a root module at runtime - ✅
behavioralModuleManager - addModule creates a child module with parent_id - ✅
behavioralModuleManager - removeModule returns HasChildren when children exist - ✅
behavioralModuleManager - removeModule returns NotFound for unknown id - ✅
behavioralModuleManager - validateControls: all slider controls have valid min < max
REST and WebSocket Integration¶
✅ 13/13 passed — test_integration.cpp
- ✅
integrationintegration/A: GET /api/modules returns 200 with a JSON array - ✅
integrationintegration/A: POST /api/control with valid id+key returns 200 ok:true - ✅
integrationintegration/A: POST /api/control with unknown module id returns 404 - ✅
integrationintegration/A: POST /api/control with unknown key returns 404 - ✅
integrationintegration/A: POST /api/control with malformed JSON returns 400 - ✅
integrationintegration/A: GET /api/types returns array of known type names - ✅
integrationintegration/B: pixel snapshot header is stable across consecutive ticks - ✅
integrationintegration/B: pixel snapshot contains non-zero pixels after SineEffectModule runs - ✅
integrationintegration/B: GET /api/modules + pixel snapshot are consistent - ✅
integrationintegration/D: POST /api/control value appears in WS state within 600 ms - ✅
integrationintegration/E: first WS connection receives a valid state frame within 3 s - ✅
integrationintegration/E: WS state frame contains expected module ids - ✅
integrationintegration/D4: binary WS frame header byte and size match pixelSnapshot
Effect and Driver Layers¶
✅ 29/29 passed — test_layers.cpp
- ✅
smokeEffectsLayer - zero residue after teardown - ✅
integrationDriverLayer - zero sources produces all-black blend - ✅
integrationDriverLayer - single producer passes through unchanged - ✅
integrationDriverLayer - two producers blend to pixel-wise saturating add - ✅
smokeDriverLayer - zero residue after teardown - ✅
integrationPreviewModule - reads blended output from DriverLayer - ✅
behavioralGridLayout - extent() returns configured dimensions - ✅
behavioralGridLayout - extent() via setProps - ✅
behavioralDriverLayer - props-only sizing (no Layout children, backward compat) - ✅
behavioralDriverLayer - GridLayout child overrides props size via onChildrenReady - ✅
behavioralDriverLayer - onChildrenReady called via addChild (addModule path) - ✅
behavioralEffectsLayer - onSizeChanged ignored when useDriverSize is false - ✅
behavioralEffectsLayer - full-extent driver sizing (start=0 end=1) - ✅
behavioralEffectsLayer - partial driver sizing via start/end props - ✅
behavioralEffectsLayer - resizes when driver resizes via onChildrenReady - ✅
behavioralEffectsLayer - EffectsLayer before DriverLayer setup ordering - ✅
behavioralGridLayout - saveState/loadState round-trips width/height/depth - ✅
integrationDriverLayer - partial EffectsLayer (startX=0.5) does not OOB blend - ✅
behavioralEffectsLayer - saveState/loadState round-trips start/end fractions - ✅
behavioralEffectsLayer - onUpdate resizes buffer when start/end slider changes - ✅
behavioralGridLayout - requestMappings straight (identity for non-serpentine) - ✅
behavioralGridLayout - requestMappings serpentine reverses odd rows - ✅
behavioralEffectsLayer preferredCore returns 0 - ✅
behavioralDriverLayer preferredCore returns 1 - ✅
formatDriverLayer healthReport contains expected fields - ✅
formatDriverLayer healthReport reports source count - ✅
behavioralStatefulModule timing_ accumulates self loop() time - ✅
behavioralStatefulModule parent self-timing excludes child time - ✅
behavioralStatefulModule timing resets on runSetup
Logger¶
✅ 6/6 passed — test_logger.cpp
- ✅
behavioralLogger - logLevelFromString parses all levels - ✅
behavioralLogger - logLevelFromString rejects unknown string - ✅
behavioralLogger - logLevelToString round-trips all levels - ✅
behavioralLogger - g_logLevel gate: LOG_SETUP suppressed below Setup level - ✅
behavioralLogger - WS push function receives stripped message - ✅
behavioralLogger - WS push not called when fn is null
Memory and Filesystem¶
✅ 3/3 passed — test_memory_stats.cpp
- ✅
behavioralMemoryStats - filesystem stats are available - ✅
behavioralMemoryStats - memory sanity checks - ✅
behavioralMemoryStats - multiple snapshots are consistent
Module Manager¶
✅ 25/25 passed — test_module_manager.cpp
- ✅
behavioralTypeRegistry - registered types are findable - ✅
behavioralTypeRegistry - create returns correct type - ✅
behavioralTypeRegistry - create returns nullptr for unknown type - ✅
behavioralEffectsLayer - setProps sets width and height - ✅
behavioralSineEffect - setProps and saveState/loadState round-trip - ✅
behavioralModuleManager - loads config and registers all modules - ✅
integrationModuleManager - wires modules correctly (pipeline runs without crash) - ✅
behavioralModuleManager - isPermanent returns true - ✅
behavioralModuleManager - addModule happy path - ✅
behavioralModuleManager - addModule duplicate id rejected - ✅
behavioralModuleManager - addModule unknown type rejected - ✅
behavioralModuleManager - removeModule happy path - ✅
behavioralModuleManager - removeModule not found returns NotFound - ✅
behavioralModuleManager - removeModule permanent module rejected - ✅
behavioralTypeRegistry - getTypes returns all registered type names - ✅
behavioralModuleManager - addModule with valid parent_id succeeds - ✅
behavioralModuleManager - addModule with invalid parent_id rejected - ✅
behavioralModuleManager - removeModule with children returns HasChildren - ✅
behavioralModuleManager - parent_id round-tripped through getModulesJson - ✅
behavioralModuleManager - child module NOT registered in Scheduler (roots-only) - ✅
behavioralModuleManager - child wired into parent's children_ list - ✅
behavioralModuleManager - addModule child: added to parent, not Scheduler - ✅
behavioralModuleManager - removeModule child: detached from parent, not Scheduler - ✅
integrationModuleManager - auto-creates default pipeline when no modules exist - ✅
integrationModuleManager - does NOT auto-create pipeline when DriverLayer+EffectsLayer exist
Network and WiFi¶
✅ 31/31 passed — test_network.cpp
- ✅
behavioralNetworkModule - default device_name on PC starts with MM- and has length 7 - ✅
behavioralNetworkModule - setProps overrides device_name - ✅
behavioralNetworkModule - loadState/saveState round-trip for device_name - ✅
formatNetworkModule - getSchema includes device_name and mac_address - ✅
formatNetworkModule - category is network - ✅
formatNetworkModule - healthReport contains device= and mac= - ✅
behavioralEditStr - setControl round-trip via JsonVariant - ✅
behavioralEditStr - setControl(float) returns false for EditStr type - ✅
formatEditStr - getSchema includes value for non-sensitive control - ✅
smokeWifiStaModule - lifecycle on PC does not crash - ✅
behavioralWifiStaModule - password absent from getControlValues (sensitive) - ✅
formatWifiStaModule - password in getSchema without value field - ✅
behavioralWifiStaModule - saveState/loadState round-trip for ssid - ✅
formatWifiStaModule - category is network - ✅
behavioralWifiStaModule - setControl ssid triggers pendingConnect via loop - ✅
behavioralWifiStaModule - password setLen is 0 when empty, actual length when set - ✅
behavioralWifiStaModule - password control uiType is password - ✅
smokeWifiApModule - lifecycle on PC does not crash - ✅
behavioralWifiApModule - setInput network accepted without crash - ✅
formatWifiApModule - category is network - ✅
smokeEthernetModule - lifecycle does not crash - ✅
behavioralEthernetModule - status is unsupported after setup - ✅
formatEthernetModule - category is network - ✅
formatEthernetModule - healthReport contains eth=unsupported - ✅
smokeDeviceDiscoveryModule - lifecycle on PC does not crash - ✅
formatDeviceDiscoveryModule - category is network - ✅
behavioralDeviceDiscoveryModule - setup registers broadcast_interval, status, and 8 device controls - ✅
formatDeviceDiscoveryModule - healthReport starts with devices=0 - ✅
behavioralDeviceDiscoveryModule - setInput network accepted without crash - ✅
behavioralDeviceDiscoveryModule - broadcast_interval saveState/loadState round-trip - ✅
behavioralDeviceDiscoveryModule - getControlValues includes status field
Preview Pipeline¶
✅ 3/3 passed — test_preview_e2e.cpp
- ✅
integrationPreview pipeline - non-zero output after 50 ticks - ✅
integrationPreview pipeline - checksum varies across ticks - ✅
integrationPreview pipeline - PreviewModule listed with fps>0 via HTTP
test_producer_consumer.cpp¶
✅ 7/7 passed — test_producer_consumer.cpp
- ✅
behavioralbuffer is null before setup - ✅
behavioraldeclareBuffer registers pointer, length and elemSize - ✅
behavioralbufferPtr gives read access to the underlying array - ✅
behavioralproducer_ is null before wiring - ✅
behavioralsetInput('producer', ...) wires the producer - ✅
behavioralsetInput ignores unknown keys - ✅
behavioralconsumer reads producer buffer after wiring
Scheduler¶
✅ 4/4 passed — test_scheduler.cpp
- ✅
integrationphase 1 sanity - ✅
behavioralScheduler loopCore runs only matching-core modules - ✅
behavioralScheduler loop() runs all modules via loopCore(0) then loopCore(1) - ✅
behavioralScheduler loopCore timing is tracked per module
Sine Effect¶
✅ 3/3 passed — test_sine_effect.cpp
- ✅
behavioralSineEffectModule - deterministic output for fixed frequency/amplitude - ✅
smokeSineEffectModule - zero residue after teardown - ✅
integrationPreviewModule - consumer sees producer frame checksum via layers
Stateful Module¶
✅ 18/20 passed — test_stateful_module.cpp
- ✅
behavioralsprint9/B: SystemStatusModule has 'progress' type controls - ✅
behavioralsprint9/B: SystemStatusModule progress controls have min=0 and max>0 - ✅
behavioralsprint9/C: SystemStatusModule has 'button' type control for reboot - ✅
behavioralsprint9/C: SystemStatusModule reboot button is sensitive (absent from getControlValues) - ✅
formatsprint9/D: SystemStatusModule string controls have string value in schema - ❓
behavioralsprint9/E: WifiApModule loadState/saveState round-trip for ap_password - ❓
behavioralsprint9/E: WifiApModule ap_password control is sensitive (not in getControlValues) - ✅
smokesprint9/F: ModuleManager with disableStatePersistence does not write state files - ✅
behavioralsprint9/G: SineEffectModule frequency and amplitude are uint8_t - ✅
formatsprint9/G: SineEffectModule getSchema includes integer=true for frequency - ✅
behavioralsprint9/G: SineEffectModule setControl with integer value clamps to uint8_t range - ✅
behavioralsprint9/G: SineEffectModule saveState/loadState round-trips integer frequency - ✅
behavioralsprint9/G: BrightnessModifierModule frequency is uint8_t - ✅
behavioralsprint9/G: BrightnessModifierModule setControl with integer value - ✅
behavioralsprint9: bool addControl with sensitive=true excludes value from getControlValues - ✅
behavioralsprint7/D: meta() const on uninitialised store returns empty document - ✅
behavioralsprint7/D: meta() stores and retrieves non-control fields - ✅
behavioralsprint7/D: meta() store survives teardown/runSetup cycle - ✅
behavioralR4S9/A: defVal captured from field initializer, not overwritten by setControl - ✅
behavioralR4S9/A: defVal is unchanged after saveState/loadState round-trip
System Status¶
✅ 14/14 passed — test_system_info.cpp
- ✅
behavioralLogLevel enum ordering is cumulative - ✅
behaviorallogLevelFromString parses all valid names - ✅
behaviorallogLevelFromString rejects unknown names and nullptr - ✅
behavioralEffectsLayer heapSize equals 2 * width * height * sizeof(RGB) - ✅
behavioralDriverLayer heapSize equals width * height * sizeof(RGB) - ✅
behavioralEffectsLayer heapSize is non-zero for default-constructed (10x10x10) instance - ✅
formathealthReport default writes empty string into buffer - ✅
formathealthReport respects buffer length limit - ✅
smokeSystemStatusModule lifecycle: setup / loop / teardown - ✅
behavioralSystemStatusModule exposes key controls by name - ✅
formatSystemStatusModule has no heap allocation - ✅
formatSystemStatusModule classSize is sizeof(SystemStatusModule) - ✅
formatSystemStatusModule healthReport writes non-empty string - ✅
formatSystemStatusModule healthReport contains expected keys after loop1s sampling
System Utility Modules¶
✅ 10/10 passed — test_system_utils.cpp
- ✅
smokeTasksModule - lifecycle does not crash - ✅
formatTasksModule - healthReport format contains task_count= - ✅
formatTasksModule - getSchema exposes tasks display and task_count display - ✅
behavioralTasksModule - task_count is non-negative after setup - ✅
smokeFileManagerModule - lifecycle does not crash - ✅
formatFileManagerModule - healthReport format contains state_dir= and file_count= - ✅
formatFileManagerModule - getSchema exposes files display, filename text, delete button - ✅
behavioralFileManagerModule - delete with empty filename sets error result - ✅
behavioralFileManagerModule - delete nonexistent file sets not-found result - ✅
behavioralFileManagerModule - delete existing file succeeds
WebSocket¶
✅ 17/17 passed — test_websocket.cpp
- ✅
behavioralgetControlValues returns empty object for module with no controls - ✅
behavioralgetControlValues reflects live field values - ✅
behavioralgetControlValues updates after second setControl - ✅
behavioralsnapshot returns false before first loop() - ✅
behavioralsnapshot returns true after first loop() and fills buffer - ✅
behavioralsnapshot header: byte 0 is 0x01 (pixel frame type) - ✅
behavioralsnapshot header: width and height encoded little-endian - ✅
behavioralsnapshot payload size matches width * height * 3 - ✅
behavioralsnapshot pixel values are non-zero after SineEffectModule runs - ✅
behavioralgetStateJson returns one entry per module - ✅
behavioralgetStateJson entries have id, controls, and timing fields - ✅
behavioralgetStateJson timing fps is positive after one tick - ✅
behavioralgetStateJson control values reflect live state - ✅
behavioralpixelSnapshot returns true for consumer1 after one tick - ✅
behavioralpixelSnapshot returns false for unknown module id - ✅
behavioralgetStateJson valid before and after runtime addModule (root) - ✅
behavioralgetStateJson valid before and after runtime removeModule (child)