Repository navigation
Native Tests
Note
This Wiki page is generated from test/README.md. Edit the repository source rather than the Wiki directly.
pio test -e nativeThis is the developer-facing Native entry point. The suite deliberately makes timing, musical behavior, persistence, UI, and physical-control contracts visible instead of presenting only the 44-case mathematical core. PlatformIO executes twelve conventionally named suites:
| Suite | Named cases | What it proves |
|---|---|---|
test_clock_core |
44 | hardware-independent clock mathematics and exhaustive invariants |
test_realtime |
35 | deterministic scheduler/GPIO/SYNC/RST integration, bounded Sequencer step-expression gates and stress behavior |
test_sync_behavior |
116 | exact/changing external clocks plus configurable INPUT 1/2 roles (SYNC/RESET/RUN/START/STOP/RESTART/TAP), role reassignment, RUN baselining, jitter/glitches/loss, PPQN/edge semantics and nominal analogue-front-end behavior |
test_sequencer2 |
20 | Sequencer 2.0 128-step pattern model, traversal/loop modes, bank migration and sparse Probability/Gate/Tie/Ratchet persistence/defensive boundaries |
test_swing |
40 | Swing/Groove mathematics, exhaustive Custom-Groove sweeps, TAP Recorder capture/Count-In/One-Shot/Endless behavior, and observable engine timing invariants |
test_humanize |
12 | deterministic One Clock timing displacement, bounds, repeatability and isolation |
test_tap_tempo |
24 | tap estimator acquisition, rolling average, clamps, invalid intervals, jitter and timestamp wrap |
test_controls |
51 | TIM4 encoder quadrature, detent-phase recovery after missed/coalesced transitions and encoder-push phase shifts, first-detent and immediate direction-reversal behavior, NORMAL/REVERSED direction mapping, fast-turn backlog/drain and saturation, debounce, bounce, hold and simultaneous button behavior |
test_settings |
89 | settings boundaries, configurable inputs, grouped channel settings, Groove Editor/Recorder menus, Custom Groove slot management, Info overflow/popover, device preferences and invalid-input invariants |
test_screensavers |
19 | all screensaver renderers, deterministic/rewind behavior and long frame sweeps |
test_easter_eggs |
36 | intro launch gating, reset state, output safety and game-specific controls |
test_host_firmware |
39 | complete firmware/UI/HAL/persistence behavior, Groove Editor/Record workflows, schema migrations and framebuffer/navigation contracts using deterministic host fakes |
| Total | 525 | public Native inventory |
The default Native configuration executes more than 433,000 assertions. scripts/check_test_inventory.py enforces the visible-suite inventory contract so a broad test-count increase cannot hide a regression in one focused suite.
test_swing verifies classic Swing plus the deterministic Groove layer used by Clock, Euclid, Sequencer and One Clock. It sweeps Custom Groove lengths 1-64 and Amount 0-100%, exercises representative BPM/rate/grid combinations, signed early/late offsets, rotation, bounds and Swing interaction, and covers Groove Record Count-In, One-Shot/Endless wrap, targeted overwrite and shared draft behavior. Event order and gate-off safety remain bounded by the same scheduler invariants as straight timing.
test_humanize treats Humanize as a separate timing contract. OFF must keep all eight One Clock outputs coincident; 250/500/1000/2000 us settings must remain inside their configured scheduler-quantized windows; a fresh run must reproduce the same offsets; outputs must exhibit channel spread; and a stored One Clock Humanize value must have no timing effect in Independent mode. Humanize combined with maximum current Swing is also exercised for ordering safety.
test_tap_tempo exposes the estimator independently of the broad UI integration scenarios. It verifies 30/60/120/240 BPM-class intervals, the 999 BPM ceiling, the MIN-BPM-derived sequence timeout, exact slowest-valid boundaries, timestamp zero, reset behavior, too-fast/duplicate intervals, rolling four-interval averaging, small jitter, alternating fast/slow taps and unsigned timestamp wrap. The host-firmware suite separately verifies that the first TAP is visually silent, the second and following TAPs restart the four-frame 8×8 shrinking indicator, and a timeout returns the UI to first-tap state.
test_controls drives the production ControlPanel against GPIO fakes. It verifies both Gray-code directions, device-level NORMAL/REVERSED semantic mapping, partial cycles, contact bounce, six detents accumulated while foreground polling is absent, 1000-detent fast turns in either direction, repeated burst/drain cycles, deliberate signed backlog saturation without wrap, the +/-127 report bound with remainder preservation, idle sampling without gratuitous global interrupt masking, active-low button press/release debounce, no hold-repeat, bounce restart, simultaneous buttons and encoder activity during button debounce. The broader host-firmware suite continues to test how these samples drive the UI state machine.
test_sync_behavior intentionally targets the failure modes most likely to matter musically:
- exact 1, 20, 30, 60, 120, 240, 300, 600, 900 and 999 BPM boundaries;
- 1/2/4/24 PPQN interpretation and rising/falling-edge selection;
- duplicate timestamps, sub-filter glitches, glitch storms and opposite-polarity noise;
- deterministic jitter from +/-50 us through +/-20%, alternating 400/600 ms and 250/750 ms periods, and chaotic-but-valid periods;
- continuous tempo movement: linear 60->180 and 180->60 BPM ramps, slow drift around 120 BPM, repeated tempo steps, acceleration with alternating jitter and a 24-PPQN tempo ramp;
- abrupt 60<->180 BPM changes, adaptive timeout boundaries and STOP/FREEWHEEL/INTERNAL/AUTO loss behavior;
- timestamp wrap, queue-overflow continuity and explicit lock reacquisition;
- a permanently HIGH SYNC input: one selected edge only, natural timeout after a previous lock, and no manufactured falling-edge pulse train;
- runtime PPQN and selected-edge changes, including the beta.4 regression that previously allowed an old period filter to contaminate a newly interpreted clock.
The suite also contains a host-only nominal electrical model of the documented Rev-1 LM393 input resistor network. It calculates the nominal ~1.79 V rising and ~1.46 V falling thresholds and drives the production digital SYNC estimator from modelled 2.5 V, 3 V and 4 V inputs at 20, 120 and 999 BPM. This validates intended nominal design behavior and hysteresis logic; resistor tolerance, clamp-diode behavior, LM393 common-mode/propagation effects, noise, PCB parasitics and actual switching thresholds remain physical HIL requirements.
test_settings turns the Settings editor into an explicit behavioral contract rather than relying only on broad UI scenarios. It covers master tempo/min/max coupling, meter and Pre-Count limits, configurable INPUT 1/2 roles and exclusivity, external timing settings, persistent encoder direction/OLED orientation, screensaver timing invariants, grouped channel settings, rate/Swing/Groove/output limits, Euclid and Sequencer bounds, Custom Groove Editor/Recorder menus, 10-slot load/rename/delete flows, long read-only Info truncation/popover behavior, One Clock Humanize choices and Divider Bank settings.
test_screensavers executes every renderer, checks expected framebuffer activity, deterministic/rewind behavior where applicable, and sweeps frames long enough to exercise stateful animations. test_easter_eggs verifies the shipped BEATKNECHT compile-time default, that each boot game waits for explicit launch input, starts in a defined reset state, keeps Eurorack outputs safe in the host path, and obeys its game-specific controls, including BEATKNECHT PLAY/PAUSE/STOP transport, encoder tempo, and TAP style selection. These are state-machine tests; graphical appearance is still covered separately by framebuffer/simulator regression assets.
python scripts/run_host_tests.pyThis is the authoritative coverage gate. It compiles the complete project-owned firmware against deterministic framework fakes in I2C, SPI and fixed-address/reset-pin configurations.
Current validated 1.1 development baseline (r26 production source):
Executable lines: 9258 / 9665 95.79%
Functions: 805 / 819 98.29%
Decision branches: 5639 / 6246 90.28%
Compiler branches: 5640 / 7322 77.03% (informational)
The hard gates remain >=95% executable lines, >=95% functions and >=90% non-throw decision branches.
For change-local analysis, the same runner also exposes focused coverage slices without pretending that a partial run replaces the repository-wide gate:
python scripts/run_host_tests.py --focus swing
python scripts/run_host_tests.py --focus sync
python scripts/run_host_tests.py --focus swing --source src/engine/clock_engine_timing.cppAvailable focuses are core, realtime, sync, swing, settings, controls, screensavers, and easter-eggs. Focus reports are diagnostic only and are written as coverage/focus_<name>_coverage.{txt,json}. --source can be repeated to restrict the report to the exact production files changed in a patch. Full CI/release quality gates continue to use the unfiltered repository-wide run.
The three largest Native suites are physically split into themed include fragments under their local cases/ directories. The suite runner and RUN_TEST registration remain centralized, preserving one deterministic translation unit per PlatformIO suite while keeping persistence, timing, rendering, UI/game and input-role cases in readable files.
The script writes coverage/full_coverage.txt and coverage/full_coverage.json. The configured coverage thresholds are hard gates; uncovered production functions, lines, and non-throw decisions remain listed in the report.
Sanitizers run separately with:
python scripts/run_host_tests.py --sanitizers-onlyBoth AddressSanitizer and UndefinedBehaviorSanitizer are hard CI gates.
test/support/fake_framework/ contains intentionally small host implementations of the Arduino, Wire, SPI, HardwareTimer and Unity API surfaces used by this project. They exist to execute HAL logic deterministically; they are not substitutes for hardware-in-the-loop timing tests.
The simulator integration suite is maintained under sim/ and uses CMake/CTest rather than PlatformIO:
cmake --preset simulator-headless
cmake --build --preset simulator-headless
ctest --preset simulator-headlessIt executes the complete firmware above the simulator HAL and validates boot, real debounced controls, scheduler/gate activity, OLED framebuffer output, and file-backed persistence. SDL is deliberately not required for these integration tests.
Electrical gate timing, comparator behavior, real bus signaling, boot pulse safety, External Sync capture and physical Groove-Record TAP latency/jitter remain a separate HIL layer because those properties cannot be proven by host mocks.
CLOCK 1.1.0
- 01 Start here
- 02 Panel, power and boot
- 03 Two-minute quick start
- 04 The control language
- 05 Read the Performance screen
- 06 Select channels and change functions
- 07 Transport and tempo
- 08 Independent channels
- 09 Clock mode
- 10 Euclid mode
- 11 Sequencer mode
- 12 One Clock
- 13 Grooves and Custom Groove Record
- 14 Divider Bank
- 15 Settings map
- 16 Configurable external inputs
- 17 Presets, autosave and templates
- 18 Screensaver and display protection
- 19 Gate outputs and LEDs
- 20 Hidden boot features
- 21 Practical recipes
- 22 Troubleshooting
- 23 Firmware installation and updates
- 24 Technical status and specifications