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.

Ir para a instalação

Informações da origem

Repositório
weaties/imu4helmlog
Última atividade na origem
14 de abril de 2026 às 21:55
Idioma detectado do SKILL.md
inglês
Estrelas
0
Forks
0

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
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
Ver no GitHub