2023
C Asserts
c_asserts is a compact C assertion and unit-test helper library. It provides a small framework for writing test functions, running them, reporting pass/fail status, and printing a summary at the end of a test suite. Instead of requiring a large external testing framework, it gives C projects a lightweight way to structure tests around simple macros and a small runtime implementation.
The library is organized around two main parts: a public header, c_asserts.h, and an implementation file, c_asserts.c. The header defines the central result type, unit_test_result_t, with outcomes for passed, failed, and not-implemented tests. It also defines test_environment_t, which stores aggregate counts for passed, failed, not-implemented, and total tests. Tests are normally declared with TEST_JIG, initialized with UT_BUILDUP, cleaned up with UT_TEARDOWN, executed with TEST, and wrapped between UT_START() and UT_END().
Assertions are implemented as macros that call internal helper functions while automatically passing __func__, __FILE__, __LINE__, and the string form of the tested expression. This lets the library print useful diagnostics showing where a failure occurred and what expression failed. Hard assertions such as ASSERT_TRUE, ASSERT_FALSE, ASSERT_INT, ASSERT_UINT, ASSERT_UINT64, ASSERT_UINT_RANGE, ASSERT_PTR, ASSERT_MEMORY, and ASSERT_SUBTEST set the current test result to failed and jump to a cleanup label when they fail. This cleanup label is supplied by UT_TEARDOWN, so tests can still release resources before returning. The header also exposes soft assertion variants, which report failures but do not immediately abort the current test.
The implementation file contains the actual comparison logic and formatted output. It uses ANSI color codes for passed, failed, not-implemented, and summary messages. Integer assertions print expected and actual values, unsigned checks include hexadecimal output, range checks clamp the accepted bounds safely, pointer checks print addresses, and memory checks compare byte buffers with memcmp, report the first differing offset, and print a limited byte-by-byte dump. There are also bit-reading helpers for extracting single bits or bit ranges from 32-bit values.
The intended use case is embedded systems, where unit testing often needs to be simple, portable, and easy to integrate into existing firmware projects. c_asserts is designed to make it very quick to add unit tests around embedded C modules, such as register handling, driver logic, protocol encoders, parsers, state machines, and byte-buffer operations. Its only dependency is stdio.h and printf, which keeps it lightweight and easy to port. In embedded targets where standard console output is unavailable or undesirable, the printf calls can be redirected or replaced with a target-specific output method such as UART logging or SEGGER RTT.
