Skip to main content

tdd

Test-driven development for firmware logic using PlatformIO's native env. TRIGGER when adding or changing code under lib/sampler/, lib/packetizer/, lib/ringbuf/, lib/config/, or any pure-logic C++ in this repo. DO NOT trigger for docs, platformio.ini, scripts, or hardware-only modules (lib/imu/, lib/net/, lib/uploader/) where behavior can't be exercised without a board.

Zur Installation springen

Quellinformationen

Repository
weaties/imu4helmlog
Letzte Quellaktivität
14. April 2026 um 21:55
Erkannte Sprache von SKILL.md
Englisch
Sterne
0
Forks
0

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
tdd
description
Test-driven development for firmware logic using PlatformIO's native env. TRIGGER when adding or changing code under lib/sampler/, lib/packetizer/, lib/ringbuf/, lib/config/, or any pure-logic C++ in this repo. DO NOT trigger for docs, platformio.ini, scripts, or hardware-only modules (lib/imu/, lib/net/, lib/uploader/) where behavior can't be exercised without a board.
# TDD — host-side firmware loop Embedded TDD only works if you can run the code on the host. This project is structured so that every non-hardware module builds and tests under `pio test -e native` on the Mac in under a second. Use that ruthlessly. ## The cycle ### 1. Red — failing host test Add a test file under `test/test_native/test_<module>/test_<module>.cpp`. PlatformIO + Unity discovers one `void setup()` / `void loop()` per group. ```cpp #include <unity.h> #include "packetizer/Packetizer.h" void test_batch_respects_size_cap(void) { Packetizer p(/*cap=*/10); for (int i = 0; i < 15; i++) p.add(sample_at(i)); TEST_ASSERT_EQUAL(10, p.size()); TEST_ASSERT_EQUAL(5, p.dropped()); } void setup() { UNITY_BEGIN(); RUN_TEST(test_batch_respects_size_cap); UNITY_END(); } void loop() {} ``` Run it and confirm it **fails for the reason you expect**, not a link error: ```bash pio test -e native -f test_packetizer ``` ### 2. Green — minimum implementation Write the least code that makes it pass. No speculative generality. Sampler rate logic doesn't need a state machine if an `if` works. ```bash pio test -e native -f test_packetizer ``` ### 3. Refactor — run the whole host suite ```bash pio test -e native ``` All host tests must be green. If a refactor touches the interface between a pure-logic module and a hardware module, also verify the device build still links: ```bash pio run -e esp32c3 ``` ### 4. Format ```bash clang-format -i $(git ls-files 'src/*.cpp' 'src/*.h' 'lib/**/*.cpp' 'lib/**/*.h' 'test/**/*.cpp' 'test/**/*.h') ``` ### 5. Commit Test and implementation in the same commit. Conventional commit format, include issue number if applicable: `feat(packetizer): cap batch size (#12)`. ## What belongs in host tests - **Packetizer** — JSON shape, `seq` monotonicity, mount_quat application, batch boundaries, gzip framing, pre_sntp handling - **Sampler** — rate limiting, backpressure when ringbuf is full, clock skew detection, dropped-sample accounting - **Ringbuf** — wrap behavior, oldest-drop-on-overflow, segment recovery after simulated crash, size accounting - **Config** — NVS round-trip (use a fake NVS), schema version migration, default values - **Anything with math** — quaternion multiplication, frame transforms, heave integration — write a test with known-answer inputs ## What does NOT belong in host tests - `lib/imu/` device impl — needs `Wire` and `sh2`, use `ImuFake` in host tests - `lib/net/` — uses `WiFi.h`, mock at the interface boundary - `lib/uploader/` — uses `HTTPClient`, inject a fake HTTP sink - `main.cpp` — no logic lives there by convention; nothing to test If you catch yourself writing `#ifdef ARDUINO` inside a module that's supposed to be pure logic, stop — the hardware dependency needs to move behind an interface. ## Fake injection pattern ```cpp // lib/imu/Imu.h class Imu { public: virtual ~Imu() = default; virtual bool begin() = 0; virtual bool read(Sample& out) = 0; }; // lib/imu/ImuFake.h — host-only class ImuFake : public Imu { public: std::vector<Sample> canned; size_t idx = 0; bool begin() override { return true; } bool read(Sample& out) override { if (idx >= canned.size()) return false; out = canned[idx++]; return true; } }; ``` Sampler takes `Imu&`, not `Imu*` or a concrete type. Tests pass `ImuFake`. `main.cpp` passes the real one. ## Known gotchas - **Unity's `TEST_ASSERT_EQUAL_FLOAT` uses a fixed epsilon** — for quaternion math, use `TEST_ASSERT_FLOAT_WITHIN(1e-6f, expected, actual)` - **`pio test -e native` rebuilds slowly on cold cache** — first run takes ~15s, subsequent runs are sub-second. Don't conflate the two - **Arduino types leak in** — if a host test fails to compile because of `String` or `HardwareSerial`, the module under test has a hidden Arduino dependency. Move it behind an interface
Auf GitHub ansehen