elouann.dev
FR — version française

ProjectsLow-level & embedded

Libunit

A unit-testing framework in C

Period
Jan 2026
Context
42 rush
Team
group
Grade
117/100
  • C
  • Low-level
  • Imperative programming
  • Tester

View source

A unit-testing framework for C, written in C during a two-day rush. Its strength: a test that crashes does not take the others down with it.

batterytest 1test 2test 3fork()childruns the testparentwaitpid()exit(code)or signalOKKOSIG…WIFEXITED / WIFSIGNALEDrecognised signalsSIGSEGVSIGBUSSIGABRTSIGFPESIGPIPESIGILL
DiagramEach test runs in its own process. The parent reads how the child ended to work out the result.

How it works

Tests are grouped into “batteries”, one per tested function. Each test is a function that returns 0 when everything is fine. For each test, the framework calls fork(): the child runs the test and exits with its return code, and the parent waits for it with waitpid().

With the WIFEXITED and WIFSIGNALED macros, the parent knows whether the test passed, failed, or was killed by a signal: SIGSEGV, SIGBUS, SIGABRT, SIGFPE, SIGPIPE or SIGILL. Results are printed in colour, test by test.

The extras

A test can be flagged as “expected to crash”: for instance, we expect a SIGSEGV on a null pointer. A battery can also stop at the first error, and a test can be disabled without being deleted.

What I took away

  • The process is the best isolation Unix offers, and it only costs a fork().
  • A signal is information like any other: it can be read from the child’s status.
  • Writing the tool that tests your code makes you read your code differently.