From e9bdd3bff53c9e9f03e66abaeec1f280c4856e77 Mon Sep 17 00:00:00 2001 From: portersky <24420859+portersky@users.noreply.github.com> Date: Sun, 14 Jun 2026 19:35:26 +0200 Subject: [PATCH] chore: add TDD workflow, behavioral guidelines, and ASan support Add deps/Sanitizers.cmake for AddressSanitizer support (ENABLE_ASAN). Add TDD workflow and behavioral guidelines to AGENTS.md. --- AGENTS.md | 84 +++++++++++++++++++++++++++++++++++++++++++ CLAUDE.md | 1 + deps/Sanitizers.cmake | 28 +++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 CLAUDE.md create mode 100644 deps/Sanitizers.cmake diff --git a/AGENTS.md b/AGENTS.md index 08d4239..50aeb5d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -164,6 +164,90 @@ deps/ FindCMock.cmake Fetches CMock v2.6.0 via ZIP ``` +## TDD Workflow + +This project follows Red-Green-Refactor. All changes to testable source +files under `ctdd/` should be test-driven: write a failing test first, +then implement. + +### Adding a new module + +1. Create `ctdd/.h` with the public prototype. +2. Create `tests/test_.c`. Set CMock expectations for any +dependency calls, then assert the result. +3. Register the test in `tests/CMakeLists.txt`: + +```cmake +add_executable(test_module test_module.c) +target_include_directories(test_module PRIVATE "${CMAKE_SOURCE_DIR}") +target_link_libraries(test_module PRIVATE ctdd_module Unity::Unity CMock::CMock) +target_compile_features(test_module PRIVATE c_std_23) +cmock_generate_mock(test_module "${CMAKE_SOURCE_DIR}/ctdd/dep.h") +add_test(NAME test_module COMMAND test_module) +list(APPEND TEST_TARGETS test_module) +``` + +4. Stub `ctdd/.c` with a dummy return, confirm RED, implement, +confirm GREEN: + +```sh +ninja -C build check +``` + +### Mocking a dependency + +Use `cmock_generate_mock` in the test target to generate a mock from a +header. Include `Mock.h` in the test and use the generated API: + +```c +#include "Mockdep.h" + +void setUp(void) { Mockdep_Init(); } +void tearDown(void) { Mockdep_Verify(); Mockdep_Destroy(); } + +void test_something(void) { + dep_fn_ExpectAndReturn(arg, expected); + TEST_ASSERT_TRUE(module_do_thing()); +} +``` + +## Behavioral Guidelines + +Reduce common LLM coding mistakes. Bias toward caution over speed. +For trivial tasks, use judgment. + +### Think Before Coding + +- State assumptions explicitly. If uncertain, ask. +- If multiple interpretations exist, present them, don't pick silently. +- If something is unclear, stop. Name what's confusing. Ask. + +### Simplicity First + +Minimum code that solves the problem. Nothing speculative. + +- No features beyond what was asked. +- No abstractions for single-use code. +- If you write 200 lines and it could be 50, rewrite it. + +### Surgical Changes + +Touch only what you must. Clean up only your own mess. + +- Don't "improve" adjacent code, comments, or formatting. +- Don't refactor things that aren't broken. +- Match existing style, even if you'd do it differently. +- Remove imports/variables/functions that YOUR changes made unused. +- Don't remove pre-existing dead code unless asked. + +### Goal-Driven Execution + +Transform tasks into verifiable goals: + +- "Add validation" means: write tests for invalid inputs, then pass. +- "Fix the bug" means: write a test that reproduces it, then pass. +- "Refactor X" means: ensure tests pass before and after. + ## Platform Support The project supports Windows, Linux, macOS, Emscripten, and Android via diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..43c994c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/deps/Sanitizers.cmake b/deps/Sanitizers.cmake new file mode 100644 index 0000000..d793dcd --- /dev/null +++ b/deps/Sanitizers.cmake @@ -0,0 +1,28 @@ +# ============================================================================== +# Sanitizers +# ============================================================================== +# AddressSanitizer (ASan) support. +# Works with GCC/Clang on Linux and macOS, Clang on Windows (requires +# compiler-rt with sanitizers), and MSVC on Windows (/fsanitize=address). +# +# Usage: cmake -DENABLE_ASAN=ON ... +# ============================================================================== + +option(ENABLE_ASAN "Build with AddressSanitizer" OFF) + +if (ENABLE_ASAN) + if (ENABLE_COVERAGE) + message(FATAL_ERROR "ENABLE_ASAN and ENABLE_COVERAGE cannot be used together") + endif() + + if (MSVC) + add_compile_options(/fsanitize=address) + message(STATUS "ASan: enabled (MSVC)") + elseif (CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") + add_compile_options(-fsanitize=address -fno-omit-frame-pointer) + add_link_options(-fsanitize=address) + message(STATUS "ASan: enabled (${CMAKE_C_COMPILER_ID})") + else() + message(FATAL_ERROR "ENABLE_ASAN: unsupported compiler ${CMAKE_C_COMPILER_ID}") + endif() +endif()