Devlog #3: Test Suite (Commit: d1e7b17ad9)
8 changed files with 1264 additions and 30 deletions
The next priority wasn’t to build more features, but to ensure that the ones I have are unbreakable. Thus, I’ve implemented a custom, zero-dependency Unit Testing Framework and a comprehensive suite of 50 tests for the Logger module.
Why Build a Custom Test Suite?
Because of my ego in the way, I didn’t want to rely on heavy external libraries like GoogleTest or Check (or any external library, for that matter).
The result?
-
Isolated Singleton Management: I added a “Backdoor” (
_zinn_log_reset_internal) toLoggerthat allows the test suite to scrub the global state of the Logger between runs. This ensures that every test starts with a clean state, which prevents state-leakage bugs. -
Assertion Precision: Using C23 macros, I built
EXPECTandASSERTchecks that capture the exact file and line number of any failure. - Clean Output: The test runner provides colored feedback and a final summary.
I also updated the Makefile to add a
testtarget, which compiles all source files EXCLUDINGmain.c(as I have a customtest_main.c), test files, and runs the tests.
The Logger Unit Tests (50 tests)
Instead of being lazy, I decided to write a test for everything imaginable for the Logger. This may seem pointless, even redundant at times, but as I say, better be safe than sorry.
1. Lifecycle Verification
Proving that Init/Shutdown/Reset cycles don’t leak memory or leave the mutex in a deadlocked state. I verified that the Logger returns to a “Zero State” after shutdown, allowing it to be safely re-initialized later.
2. Boundary Protection & Buffer Safety
This was the most critical part. I wrote a “ruler” test to verify exactly what happens when the 1024-character message buffer is exceeded. By analyzing the memory buffer line-by-line, I proved that the logic correctly truncates and appends ... at the exact 1023rd byte without overflowing the stack.
3. Null-Pointer Safety
Every public function was tested with nullptr arguments.
Where applicable, of course.
4. Logic & Metadata Verification
Using fmemopen() to capture the logger’s output in memory, I verified the exact formatting of timestamps, ANSI colors, and source-location metadata.
Ajajaj, yet another POSIX-only function. Surely this won’t backfire…
What’s Next?
Now that the Test Suite is done, and Logger unit tests are written, it’s finally time to tackle yet another core component, this time it being a custom (minimalist) memory allocator.
Comments 0
No comments yet. Be the first!
Sign in to join the conversation.