portersky 701c644408 feat: add log levels to logger
Replace log_message with log_debug/info/warn/err and a level filter
controlled by logger_set_level. Extract the printf sink into
log_write so CMock can intercept it in test_logger. Add 9 tests
covering emit and suppression behaviour per level.
2026-05-09 20:43:32 +02:00
2026-05-09 20:43:32 +02:00
2026-05-09 20:32:55 +02:00
2026-05-09 20:43:32 +02:00
2026-05-09 20:32:55 +02:00
2026-05-09 20:32:55 +02:00
2026-05-09 20:43:32 +02:00
2026-05-09 20:43:32 +02:00
2026-05-09 20:43:32 +02:00
2026-05-09 20:32:55 +02:00

ctdd

A C23 project wired for test-driven development using Unity and CMock.

All dependencies are fetched automatically via CMake FetchContent — no manual installation required beyond the tools listed below.

Requirements

Tool Purpose
CMake ≥ 3.21 Build system
Ninja Build backend
C23 compiler GCC 14+, Clang 18+
Ruby ≥ 3.0 CMock mock generation

Build

cmake -S . -B build -G Ninja
ninja -C build

Test

ninja -C build test          # summary output
ctest --test-dir build -V    # verbose (shows each test name)

Run a single suite directly for the clearest output:

./build/tests/test_str.exe
./build/tests/test_report.exe

Run

./build/main.exe             # Windows
./build/main                 # Linux / macOS

Adding a new module (TDD workflow)

1. Write the header

// ctdd/counter.h
#pragma once
int counter_increment(int value);

2. Write a failing test

// tests/test_counter.c
#include "unity.h"
#include "ctdd/counter.h"

void setUp(void) {}
void tearDown(void) {}

void test_increment_adds_one(void) {
    TEST_ASSERT_EQUAL_INT(2, counter_increment(1));
}

int main(void) {
    UNITY_BEGIN();
    RUN_TEST(test_increment_adds_one);
    return UNITY_END();
}

3. Register the test in tests/CMakeLists.txt

add_executable(test_counter test_counter.c)
target_include_directories(test_counter PRIVATE "${CMAKE_SOURCE_DIR}")
target_link_libraries(test_counter PRIVATE ctdd_counter Unity::Unity)
target_compile_features(test_counter PRIVATE c_std_23)
add_test(NAME test_counter COMMAND test_counter)

4. Add a stub, confirm RED, then implement GREEN

Stub ctdd/counter.c with return 0;, run tests to see the failure, then implement the real logic and confirm they pass.

Mocking a dependency

If your module calls an external function (e.g. log_message), generate a mock from its header and add it to the test target:

# tests/CMakeLists.txt
add_executable(test_mymodule test_mymodule.c)
target_link_libraries(test_mymodule PRIVATE ctdd_mymodule Unity::Unity CMock::CMock)
target_compile_features(test_mymodule PRIVATE c_std_23)
cmock_generate_mock(test_mymodule "${CMAKE_SOURCE_DIR}/ctdd/logger.h")
add_test(NAME test_mymodule COMMAND test_mymodule)

CMock generates Mocklogger.h into the build directory. Include it and use the generated API in your test:

#include "Mocklogger.h"

void setUp(void)    { Mocklogger_Init(); }
void tearDown(void) { Mocklogger_Verify(); Mocklogger_Destroy(); }

void test_something_logs(void) {
    log_message_Expect("expected string");
    my_function_under_test();
}

The _Expect call records the expected argument. CMock verifies the actual argument matches at call time using string comparison, and Mocklogger_Verify confirms the expected number of calls were made.

S
Description
No description provided
Readme MIT 71 KiB
Languages
C 58.8%
CMake 41.2%