Build: CMake with Conan for dependencies; a Debug build with sanitizers for development and
tests, a Release build for delivery.
Unit tests: Catch2, structured by GIVEN, WHEN, THEN.
Acceptance tests: pytest-bdd reads the scenarios from test/bdd/features/ and drives the
built binary. C++ has no maintained Gherkin runner of its own, and Behave cannot separate the
feature files from the step definitions.
Lint: clang-format and clang-tidy, whose naming and const-correctness checks fail the build.
Rationale: tests run against the Debug build, so sanitizers catch memory and undefined
behavior errors early; the Release build is tested again at merge to main.
Structure: hand-written code in src/, the CubeMX output in vendor/cubemx/, the target
build in firmware/, a mocked HAL in test/mocks/, and the manual test template in
test/manual/.
Vendor boundary: CubeMX regenerates its output at any time; keeping it in vendor/ gives
each directory one owner and one reason to change.
Target build: a static CMake toolchain file for arm-none-eabi; Conan builds only the host
tests, since a second toolchain mechanism for the target adds nothing yet.
Tests: Catch2 runs host-side against the mocked HAL; acceptance scenarios drive a host
harness wired to the same mocked HAL. On-target tests are left out until a concrete need
exists; they test timing and peripherals, not the logic the host tests cover.
Pipeline: host tests as for every C++ profile, plus the target build, make firmware-build;
no container image. make flash writes the firmware to the board.