Writing C is still king for OS development and many embedded systems. With that said there are no guardrails or safety features built into the language.

After looking into ADA, Zig and Rust I decided to for the moment stick with C until it’s no longer the best tool for my projects.

With all that said I still found myself wanting to find a way to push my C code closer to perfection if such a thing exists in programming. I ended up deciding to use TDD in C.

Finding the tooling

As with any exploration I started by looking into what existing tools for C TDD were in common use.

I kept coming across two, Unity from ThrowTheSwitch; and CppUTest. There are other tools but many of them were no longer worked on and often missing documentation.

The documentation for both Unity and CppUTest is pretty decent and is enough to get a small project built using them.

Dependency Hell

After trying out my new shiny tools I ran into several issues.

  1. Unity expects you to use “ceedling”
  2. ceedling expects you to use rake as the build system.
  3. ceedling is written in ruby
  4. As of 2023-06-19 only older versions of ruby work with release 31
  5. The documentation for plugins is….somewhat lacking
  6. Attempting to use the compile_commands_json plugin crashed every time.

I’m sure a lot of these are less of an issue for ruby developers, and people who already have multiple ruby environments setup.

Key issue is, I don’t spend a ton of time working with ruby and I really don’t like having my systems cluttered with multiple versions of ruby and python files.

It results in a very brittle system that ends up using multiple package managers and formats like gems, pips, wheels etc. All of which your normal system package manager won’t know about; so everything can be a single update away from implosion.

P.S. Yes nix is one possible solution but working with the language for the configuration often takes more time than I would like. Also spending all my time building flakes isn’t what I actually want to accomplish.

Shell Script Solutions

Armed with the knowledge of what ceedling was supposed to accomplish on behalf of it’s users I decided that most of it’s features could probably be emulated in a less complicated way.

So I wrote a shell script which is posix compliant at the moment. Here is a short list of what it does:

  • automates adding of new modules and module tests.
  • automates editing of the CMakeLists.txt files for testing
  • removes modules and their dirs when prompted.
  • builds and runs individual tests.
  • creates symlink to the compile_commands.json generated by CMake

Most of the editing is done through the use of the sed tool and some regex substitutions. Overall it’s a really simple way to approach the problem and makes use of built in Unix tooling.

remove_cmake_test_inc () {
    if [ -n "${1}" ]; then
        sed -i "s/add_subdirectory(${1})//g"
    fi
}

The script itself came out to less than 500 lines, most of which is embedded C source snippets and comments.

Test runs

After building up a nice little tdd template I’ve moved over my modbus project to using it.

so far it’s been working great and I think over time I’ll probably update it and add more features to further automate the generation of tests and such.