You are browsing as a guest. Sign up (or log in) to start making projects!

4h 33m 45s logged

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) to Logger that 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 EXPECT and ASSERT checks 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 test target, which compiles all source files EXCLUDING main.c (as I have a custom test_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.

0
2

Comments 0

No comments yet. Be the first!