# Criterion: a C and C++ test framework that registers tests at declaration

> No main, no registration boilerplate, and every test in its own process so crashes are reportable. The 2.5.0 release candidates are about exotic architectures and a forced ABI break.

**Snaipe/Criterion** — A cross-platform C and C++ unit testing framework for the 21st century

- Repository: https://github.com/Snaipe/Criterion
- Stars: 2,304 · Forks: 190
- Language: C
- License: MIT
- Published: 2026-10-07 · Updated: 2026-10-07 · Language: en
- Canonical page: https://hysenlabs.com/projects/snaipe-criterion

## Registering tests by declaring them

The argument the README makes is about boilerplate, and it is a fair one. Most C test frameworks want you to write a main, register test suites, register tests inside those suites, and then call the right functions to run them. Criterion's answer is that a declaration should be enough. Tests are registered when they are declared, a default entry point is provided so you do not need to write a main unless you want special handling, and the framework implements an xUnit structure so suites and tests still nest the way people expect.

GitHub reports the language as C with an MIT license, 2,304 stars, 190 forks and 58 open issues. The language field says C even though the framework is explicitly a C and C++ library, which is a metadata simplification rather than a contradiction: C is what the core is written in and what the header targets first.

The samples directory is the fastest way to see the ergonomics, and the README links each one by name: `samples/simple.c`, `samples/suites.c`, `samples/asserts.c`, `samples/fixtures.c`, `samples/signal.c` and `samples/report.c`. Each of those has a C++ twin alongside it, which is the practical demonstration of the unified interface claim. You include the criterion header and the same test code works in both languages.

## Process isolation as a feature rather than a detail

Every test runs in its own process. The README lists the consequence directly: crashes and signals can be reported and tested. This is the single largest technical difference from the in-process assertion libraries most C projects use, and it changes what a failing run looks like.

With in-process assertions, a segfault takes down the runner and you lose the rest of the suite. With Criterion, the child process dies, the parent framework captures the signal and exit status, and the run continues. The other direction works too: `samples/signal.c` exists precisely so you can write a test that expects a signal. That is a capability you cannot express in a framework where the assertion and the subject share an address space.

The cost is real and worth naming. Process per test means process startup cost per test, so a suite with thousands of trivial tests will feel slower than one running in-process. Criterion also relies on libffi to make the cross-language call into the test function work, and libffi appears in the credits alongside boxfort, debugbreak, klib, libcsptr, nanomsg and nanopb. Those dependencies are the price of the isolation and the unified C and C++ surface.

## Install paths across six distributions

The README's package table is the practical part of the page, and Criterion is packaged widely enough that you probably do not need to build it. The listed commands are:

```bash
apt-get install libcriterion-dev
emerge -a dev-libs/criterion
pacman -S criterion
brew install criterion
nix-shell -p criterion
pkg install criterion
```

That covers Ubuntu and Debian, Gentoo, Arch, macOS, Nix and FreeBSD. The README also asks that if your distribution is missing you reach out to its maintainers, which tells you how the project handles packaging: it does not ship the packages itself, it lobbies.

For anything else, binary archives for Linux x86 are on the release page, and the README points to the setup section of the online documentation for building from source. The repository confirms the build system, since the tree has `meson.build` and `meson_options.txt` at the root alongside `include/`, `src/` and `test/`. Meson rather than autotools, though an autotools skeleton is offered as a separate resource for projects that need it.

## Parameterized tests, theories and TAP output

Beyond the basics, the README's feature list names three things that separate Criterion from the minimal assert libraries. Parameterized tests and theories let one test body run against many inputs, which is how you avoid the copy-paste pattern that appears the moment a function has six interesting arguments. `samples/parameterized.c` is the example to read.

The second is report hooks, which let progress and statistics be followed in real time. `samples/report.c` covers it, and the mechanism is a documented extension point rather than a fixed output format, which means an IDE or a CI reporter can be written without patching the framework.

The third is TAP output, enabled with an option rather than being the default. That matters for integration: if your CI already aggregates TAP from other languages in the project, Criterion can join them instead of producing a second, incompatible report format.

Platform support is stated as Linux, FreeBSD, macOS and Windows, where Windows is compiled with MinGW GCC and Visual Studio 2015 or newer. The stated language floors are C99 and C++11.

## Release candidates, an ABI break and an unusual default branch

The three most recent releases are all 2.5.0 release candidates, published 2026-09-05, 2026-09-07 and 2026-09-09, and the last push to the repository matches the newest one. Two facts about that deserve attention before you pin anything.

First, the release notes state plainly that 2.5.0 is ABI incompatible with prior versions and that you must recompile your tests. That is a normal cost for a library with a stable C ABI, but it means an upgrade is not a drop-in library bump if you ship prebuilt test binaries anywhere.

Second, the repository's default branch is `bleeding`, not `master`. The README's own badges are split on this point, with the license badge linking to a LICENSE file on master and the coverage badge explicitly targeting the bleeding branch. So the branch you get when you clone is the development branch, while the badge pointing at LICENSE is not. Read the tree on bleeding and expect unreleased work.

The 2.5.0 feature list itself is mostly about correctness on unusual targets: fixes for SIGILL crashes on riscv64, support for the LoongArch architecture, and support for a 39-bit address space. Alongside that, `--default-timeout` sets a fallback timeout for tests that have none while leaving explicitly timed tests alone, which is a different behaviour from `--timeout` capping everything. `--show-skipped` adds skipped counts to the synthesis line. The redirected standard stream functions changed ownership: `cr_get_redirected_stdout()`, `cr_get_redirected_stderr()` and `cr_get_redirected_stdin()` now return a stream the caller must close, and the standard stream assertions now flush before comparing.

## Picking between Criterion and the alternatives

For a C or C++ project the realistic comparison is against Google Test, Catch2 and the plain assert macro. Catch2 shares Criterion's xUnit shape and has a much larger feature surface, including matchers and benchmarking, so it is the choice when you want the framework to grow with you. Google Test brings gmock, which is the reason to pick it when mocking is the actual requirement.

Criterion's specific case is process isolation plus the same test source working as C and C++. If you have a codebase where a portion is C and a portion is C++ and you want one runner and one test binary, that is a real constraint and Criterion is built for it. The signal testing story is the other one: if you are writing a library with a parser that is supposed to reject malformed input, being able to assert on the crash is worth more than matchers.

Documentation is on ReadTheDocs in stable and bleeding variants, with PDF, zip and epub downloads, and help goes through GitHub discussions or a mailing list on freelists.org. That is an unusually complete documentation setup for a C library of this size, and it is where you should go for the setup-from-source details the README defers.

## Conclusion

Criterion is the framework to reach for when you want Google Test style ergonomics in a language that Google Test does not target, and its process isolation is not a gimmick: a segfault in one test becomes a reported failure instead of a lost run. The catch is in the release channel. The most recent artifacts are 2.5.0 release candidates that break the ABI and require recompiling every test, and the default branch is bleeding rather than a release branch. Install a distribution package if you want stability, read the 2.5.0 changelog before pinning a version, and start from the samples directory, which has a simple test and a signal test that show the two things this framework does that the alternatives do not.

## FAQ

### What is Criterion used for in C and C++ projects?

It is a unit testing framework for both languages. Tests are registered when they are declared rather than through a manual registration step, a default entry point is provided so you do not have to write a main, and each test runs in its own process so a crash or signal becomes a reported result instead of ending the run.

### How does Criterion compare with Catch2?

Both use an xUnit style structure with suites and tests, and both support parameterized tests. Catch2 has a much larger feature surface, including expressive matchers and benchmarking, so it suits projects that want the framework to cover more ground. Criterion distinguishes itself on process isolation, on the same test source compiling as both C and C++, and on being able to assert that code crashes or receives a signal.

### Does Criterion 2.5.0 require recompiling my tests?

Yes. The 2.5.0 release notes state that the release is ABI incompatible with prior versions and that you must recompile your tests. The redirected stream functions also changed ownership in this version, with cr_get_redirected_stdout and its stderr and stdin counterparts returning a stream the caller now has to close.

### How do I install Criterion?

It is packaged for most major distributions. The README lists apt-get install libcriterion-dev for Debian and Ubuntu, emerge -a dev-libs/criterion for Gentoo, pacman -S criterion for Arch, brew install criterion for macOS, nix-shell -p criterion for Nix and pkg install criterion for FreeBSD. Binary archives for Linux x86 are on the release page, and the project builds with Meson from source.

### Can Criterion test code that is expected to crash?

Yes, because each test runs in its own process. The README lists crashes and signals among the things that can be reported and tested, and the repository includes samples/signal.c as the worked example. A segfault in a test is captured by the parent process and reported as a result, and the run continues with the next test.

## Sources

- [Issues](https://github.com/Snaipe/Criterion/issues)
- [License: MIT](https://github.com/Snaipe/Criterion/blob/bleeding/LICENSE)
- [README](https://github.com/Snaipe/Criterion/blob/bleeding/README.md)
- [Releases](https://github.com/Snaipe/Criterion/releases)
- [Snaipe/Criterion on GitHub](https://github.com/Snaipe/Criterion)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/snaipe-criterion
