Merge branch 'features/cpp-compat-2' into bleeding

This commit is contained in:
Snaipe 2015-09-07 10:35:43 +02:00
commit f5eefba060
84 changed files with 859 additions and 200 deletions

1
.gitignore vendored
View file

@ -6,6 +6,7 @@
!.ci/*
!*.c
!*.cc
!*.h
!*.rst
!samples/tests/*.sh

View file

@ -2,13 +2,25 @@ language: c
os:
- linux
- osx
compiler:
- gcc
- gcc-4.9
sudo: false
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-4.9
- g++-4.9
before_install:
- export LOCAL_INSTALL="$HOME"
- export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/lib
- export CFLAGS="-g -O0"
- export CXX="g++-4.9"
script:
- mkdir -p build
- cd build

View file

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 2.8)
project(Criterion C)
project(Criterion C CXX)
set(MODULE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/.cmake/Modules")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${MODULE_DIR})

View file

@ -8,7 +8,7 @@
[![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/Snaipe/Criterion/blob/master/LICENSE)
[![Version](https://img.shields.io/github/tag/Snaipe/Criterion.svg?label=version&style=flat)](https://github.com/Snaipe/Criterion/releases)
A dead-simple, yet extensible, C unit testing framework.
A dead-simple, yet extensible, C and C++ unit testing framework.
![Screencast](./doc/screencast.gif)
@ -24,12 +24,14 @@ This gives the user great control, at the unfortunate cost of simplicity.
Criterion follows the KISS principle, while keeping the control
the user would have with other frameworks:
* [x] C99 and C++11 compatible.
* [x] Tests are automatically registered when declared.
* [x] Implements a xUnit framework structure.
* [x] A default entry point is provided, no need to declare a main
unless you want to do special handling.
* [x] Test are isolated in their own process, crashes and signals can be
reported and tested.
* [x] Unified interface between C and C++: include the criterion header and it *just* works.
* [x] There is a support for theories alongside tests
* [x] Progress and statistics can be followed in real time with report hooks.
* [x] TAP output format can be enabled with an option.
@ -89,7 +91,7 @@ be merged.
## F.A.Q.
**Q. What's wrong with other test frameworks?**
**Q. What's wrong with other C test frameworks?**
A. I worked with CUnit and Check, and I must say that they do their job
very well -- the only thing that bugs me is that setting up a test
suite from scratch is a pain, it should really be simpler. Most

View file

@ -4,7 +4,7 @@ os: Visual Studio 2015
init:
- git config --global core.autocrlf input
- 'SET PATH=%PATH%;C:\MinGW\msys\1.0\bin;C:\MinGW\bin;%APPVEYOR_BUILD_FOLDER%\bin;%APPVEYOR_BUILD_FOLDER%\build'
- 'SET PATH=C:\MinGW\bin;%PATH%;C:\MinGW\msys\1.0\bin;%APPVEYOR_BUILD_FOLDER%\bin;%APPVEYOR_BUILD_FOLDER%\build'
environment:
COVERALLS_REPO_TOKEN:
@ -27,9 +27,6 @@ environment:
clone_depth: 5
matrix:
fast_finish: true # set this flag to immediately finish build once one of the jobs fails.
platform:
- x86_64

View file

@ -26,6 +26,10 @@
# include "common.h"
CR_BEGIN_C_API
CR_API NORETURN void criterion_abort_test(void);
CR_END_C_API
#endif /* !CRITERION_ABORT_H_ */

View file

@ -24,9 +24,17 @@
#ifndef CRITERION_ASSERT_H_
# define CRITERION_ASSERT_H_
# include <string.h>
# include <stdlib.h>
# include <stdbool.h>
# ifdef __cplusplus
# include <cstring>
# include <cstdlib>
using std::strcmp;
using std::memcmp;
# else
# include <string.h>
# include <stdlib.h>
# include <stdbool.h>
# endif
# include "designated-initializer-compat.h"
# include "types.h"
# include "stats.h"
# include "hooks.h"
@ -40,47 +48,66 @@ enum criterion_assert_kind {
struct criterion_assert_args {
const char *msg;
const char *default_msg;
int sentinel_;
#ifdef __cplusplus
constexpr criterion_assert_args(const char *msg) : msg(msg), sentinel_(0) {}
constexpr criterion_assert_args(const char *msg, int sentinel_) : msg(msg), sentinel_(sentinel_) {}
#endif
};
# define cr_assert_impl(Kind, Condition, ...) \
do { \
struct criterion_assert_args args = { \
__VA_ARGS__ \
}; \
int passed = !!(Condition); \
struct criterion_assert_stats stat = { \
.kind = (Kind), \
.condition = #Condition, \
.message = args.msg ? args.msg \
: (args.default_msg ? args.default_msg : ""), \
.passed = passed, \
.file = __FILE__, \
.line = __LINE__, \
}; \
send_event(ASSERT, &stat, sizeof (stat)); \
if (!passed && (Kind) == FATAL) \
criterion_abort_test(); \
# define CR_GET_CONDITION(Condition, ...) Condition
# define CR_GET_CONDITION_STR(Condition, ...) #Condition
# define CR_VA_SKIP(_, ...) __VA_ARGS__
# ifndef __cplusplus
# define CR_ZERO_FILL(Arg) memset(&(Arg), 0, sizeof (Arg))
# else
# define CR_ZERO_FILL(Arg) std::memset(&(Arg), 0, sizeof (Arg))
# endif
# define cr_assert_impl(Kind, ...) \
do { \
struct criterion_assert_args args = { \
CR_EXPAND(CR_VA_SKIP(__VA_ARGS__)) \
}; \
bool passed = !!(CR_EXPAND(CR_GET_CONDITION(__VA_ARGS__))); \
struct criterion_assert_stats stat; \
CR_ZERO_FILL(stat); \
stat.kind = (Kind); \
stat.condition = CR_EXPAND(CR_GET_CONDITION_STR(__VA_ARGS__)); \
stat.message = args.msg ? args.msg : ""; \
stat.passed = passed; \
stat.file = __FILE__; \
stat.line = __LINE__; \
send_event(ASSERT, &stat, sizeof (stat)); \
if (!passed && (Kind) == FATAL) \
criterion_abort_test(); \
} while (0)
// Common asserts
# define cr_abort_test(Message) \
cr_assert(0, \
.default_msg = "The conditions for this test were not met.", \
.msg = (Message) \
)
# define cr_abort_test(Message) \
do { \
const char *msg = (Message); \
cr_assert(0, msg ? msg : "The conditions for this test were not met.");\
} while (0)
# define cr_assert(...) CR_EXPAND(cr_assert_(__VA_ARGS__, .sentinel_ = 0))
# ifdef __cplusplus
# define CR_SENTINEL 0
# else
# define CR_SENTINEL .sentinel_ = 0
# endif
# define cr_expect(...) CR_EXPAND(cr_expect_(__VA_ARGS__, .sentinel_ = 0))
# define cr_assert(...) CR_EXPAND(cr_assert_(__VA_ARGS__, CR_SENTINEL))
# define cr_expect(...) CR_EXPAND(cr_expect_(__VA_ARGS__, CR_SENTINEL))
# define cr_assert_(Condition, ...) CR_EXPAND(cr_assert_impl(FATAL, Condition, __VA_ARGS__))
# define cr_expect_(Condition, ...) CR_EXPAND(cr_assert_impl(NORMAL, Condition, __VA_ARGS__))
# define cr_assert_not(...) CR_EXPAND(cr_assert_not_(__VA_ARGS__, .sentinel_ = 0))
# define cr_expect_not(...) CR_EXPAND(cr_expect_not_(__VA_ARGS__, .sentinel_ = 0))
# define cr_assert_not(...) CR_EXPAND(cr_assert_not_(__VA_ARGS__, CR_SENTINEL))
# define cr_expect_not(...) CR_EXPAND(cr_expect_not_(__VA_ARGS__, CR_SENTINEL))
# define cr_assert_not_(Condition, ...) \
CR_EXPAND(cr_assert_impl(FATAL, !(Condition), __VA_ARGS__))
@ -94,46 +121,46 @@ struct criterion_assert_args {
# define cr_expect_op_(Op, Actual, Expected, ...) \
CR_EXPAND(cr_assert_impl(NORMAL, (Actual) Op (Expected), __VA_ARGS__))
# define cr_assert_eq(...) CR_EXPAND(cr_assert_op_(==, __VA_ARGS__, .sentinel_ = 0))
# define cr_expect_eq(...) CR_EXPAND(cr_expect_op_(==, __VA_ARGS__, .sentinel_ = 0))
# define cr_assert_eq(...) CR_EXPAND(cr_assert_op_(==, __VA_ARGS__, CR_SENTINEL))
# define cr_expect_eq(...) CR_EXPAND(cr_expect_op_(==, __VA_ARGS__, CR_SENTINEL))
# define cr_assert_neq(...) CR_EXPAND(cr_assert_op_(!=, __VA_ARGS__, .sentinel_ = 0))
# define cr_expect_neq(...) CR_EXPAND(cr_expect_op_(!=, __VA_ARGS__, .sentinel_ = 0))
# define cr_assert_neq(...) CR_EXPAND(cr_assert_op_(!=, __VA_ARGS__, CR_SENTINEL))
# define cr_expect_neq(...) CR_EXPAND(cr_expect_op_(!=, __VA_ARGS__, CR_SENTINEL))
# define cr_assert_lt(...) CR_EXPAND(cr_assert_op_(<, __VA_ARGS__, .sentinel_ = 0))
# define cr_expect_lt(...) CR_EXPAND(cr_expect_op_(<, __VA_ARGS__, .sentinel_ = 0))
# define cr_assert_lt(...) CR_EXPAND(cr_assert_op_(<, __VA_ARGS__, CR_SENTINEL))
# define cr_expect_lt(...) CR_EXPAND(cr_expect_op_(<, __VA_ARGS__, CR_SENTINEL))
# define cr_assert_gt(...) CR_EXPAND(cr_assert_op_(>, __VA_ARGS__, .sentinel_ = 0))
# define cr_expect_gt(...) CR_EXPAND(cr_expect_op_(>, __VA_ARGS__, .sentinel_ = 0))
# define cr_assert_gt(...) CR_EXPAND(cr_assert_op_(>, __VA_ARGS__, CR_SENTINEL))
# define cr_expect_gt(...) CR_EXPAND(cr_expect_op_(>, __VA_ARGS__, CR_SENTINEL))
# define cr_assert_leq(...) CR_EXPAND(cr_assert_op_(<=, __VA_ARGS__, .sentinel_ = 0))
# define cr_expect_leq(...) CR_EXPAND(cr_expect_op_(<=, __VA_ARGS__, .sentinel_ = 0))
# define cr_assert_leq(...) CR_EXPAND(cr_assert_op_(<=, __VA_ARGS__, CR_SENTINEL))
# define cr_expect_leq(...) CR_EXPAND(cr_expect_op_(<=, __VA_ARGS__, CR_SENTINEL))
# define cr_assert_geq(...) CR_EXPAND(cr_assert_op_(>=, __VA_ARGS__, .sentinel_ = 0))
# define cr_expect_geq(...) CR_EXPAND(cr_expect_op_(>=, __VA_ARGS__, .sentinel_ = 0))
# define cr_assert_geq(...) CR_EXPAND(cr_assert_op_(>=, __VA_ARGS__, CR_SENTINEL))
# define cr_expect_geq(...) CR_EXPAND(cr_expect_op_(>=, __VA_ARGS__, CR_SENTINEL))
# define cr_assert_null_(Value, ...) \
CR_EXPAND(cr_assert_impl(FATAL, (Value) == NULL, __VA_ARGS__))
# define cr_expect_null_(Value, ...) \
CR_EXPAND(cr_assert_impl(NORMAL, (Value) == NULL, __VA_ARGS__))
# define cr_assert_null(...) CR_EXPAND(cr_assert_null_(__VA_ARGS__, .sentinel_ = 0))
# define cr_expect_null(...) CR_EXPAND(cr_expect_null_(__VA_ARGS__, .sentinel_ = 0))
# define cr_assert_null(...) CR_EXPAND(cr_assert_null_(__VA_ARGS__, CR_SENTINEL))
# define cr_expect_null(...) CR_EXPAND(cr_expect_null_(__VA_ARGS__, CR_SENTINEL))
# define cr_assert_not_null_(Value, ...) \
CR_EXPAND(cr_assert_impl(FATAL, (Value) != NULL, __VA_ARGS__))
# define cr_expect_not_null_(Value, ...) \
CR_EXPAND(cr_assert_impl(NORMAL, (Value) != NULL, __VA_ARGS__))
# define cr_assert_not_null(...) CR_EXPAND(cr_assert_not_null_(__VA_ARGS__, .sentinel_ = 0))
# define cr_expect_not_null(...) CR_EXPAND(cr_expect_not_null_(__VA_ARGS__, .sentinel_ = 0))
# define cr_assert_not_null(...) CR_EXPAND(cr_assert_not_null_(__VA_ARGS__, CR_SENTINEL))
# define cr_expect_not_null(...) CR_EXPAND(cr_expect_not_null_(__VA_ARGS__, CR_SENTINEL))
// Floating-point asserts
# define cr_assert_float_eq(...) \
CR_EXPAND(cr_assert_float_eq_(__VA_ARGS__, .sentinel_ = 0))
CR_EXPAND(cr_assert_float_eq_(__VA_ARGS__, CR_SENTINEL))
# define cr_expect_float_eq(...) \
CR_EXPAND(cr_expect_float_eq_(__VA_ARGS__, .sentinel_ = 0))
CR_EXPAND(cr_expect_float_eq_(__VA_ARGS__, CR_SENTINEL))
# define cr_assert_float_eq_(Actual, Expected, Epsilon, ...) \
CR_EXPAND(cr_assert_impl(FATAL, (Expected) - (Actual) <= (Epsilon) \
@ -145,9 +172,9 @@ struct criterion_assert_args {
__VA_ARGS__))
# define cr_assert_float_neq(...) \
CR_EXPAND(cr_assert_float_neq_(__VA_ARGS__, .sentinel_ = 0))
CR_EXPAND(cr_assert_float_neq_(__VA_ARGS__, CR_SENTINEL))
# define cr_expect_float_neq(...) \
CR_EXPAND(cr_expect_float_neq_(__VA_ARGS__, .sentinel_ = 0))
CR_EXPAND(cr_expect_float_neq_(__VA_ARGS__, CR_SENTINEL))
# define cr_assert_float_neq_(Actual, Expected, Epsilon, ...) \
CR_EXPAND(cr_assert_impl(FATAL, (Expected) - (Actual) > (Epsilon) \
@ -166,55 +193,51 @@ struct criterion_assert_args {
CR_EXPAND(cr_assert_impl(NORMAL, strcmp((Actual), (Expected)) Op 0, __VA_ARGS__))
# define cr_assert_strings_eq(...) \
CR_EXPAND(cr_assert_strings_(==, __VA_ARGS__, .sentinel_ = 0))
CR_EXPAND(cr_assert_strings_(==, __VA_ARGS__, CR_SENTINEL))
# define cr_expect_strings_eq(...) \
CR_EXPAND(cr_expect_strings_(==, __VA_ARGS__, .sentinel_ = 0))
CR_EXPAND(cr_expect_strings_(==, __VA_ARGS__, CR_SENTINEL))
# define cr_assert_strings_neq(...) \
CR_EXPAND(cr_assert_strings_(!=, __VA_ARGS__, .sentinel_ = 0))
CR_EXPAND(cr_assert_strings_(!=, __VA_ARGS__, CR_SENTINEL))
# define cr_expect_strings_neq(...) \
CR_EXPAND(cr_expect_strings_(!=, __VA_ARGS__, .sentinel_ = 0))
CR_EXPAND(cr_expect_strings_(!=, __VA_ARGS__, CR_SENTINEL))
# define cr_assert_strings_gt(...) CR_EXPAND(cr_assert_strings_(>, __VA_ARGS__, .sentinel_ = 0))
# define cr_expect_strings_gt(...) CR_EXPAND(cr_expect_strings_(>, __VA_ARGS__, .sentinel_ = 0))
# define cr_assert_strings_gt(...) CR_EXPAND(cr_assert_strings_(>, __VA_ARGS__, CR_SENTINEL))
# define cr_expect_strings_gt(...) CR_EXPAND(cr_expect_strings_(>, __VA_ARGS__, CR_SENTINEL))
# define cr_assert_strings_lt(...) CR_EXPAND(cr_assert_strings_(<, __VA_ARGS__, .sentinel_ = 0))
# define cr_expect_strings_lt(...) CR_EXPAND(cr_expect_strings_(<, __VA_ARGS__, .sentinel_ = 0))
# define cr_assert_strings_lt(...) CR_EXPAND(cr_assert_strings_(<, __VA_ARGS__, CR_SENTINEL))
# define cr_expect_strings_lt(...) CR_EXPAND(cr_expect_strings_(<, __VA_ARGS__, CR_SENTINEL))
# define cr_assert_strings_leq(...) CR_EXPAND(cr_assert_strings_(<=, __VA_ARGS__, .sentinel_ = 0))
# define cr_expect_strings_leq(...) CR_EXPAND(cr_expect_strings_(<=, __VA_ARGS__, .sentinel_ = 0))
# define cr_assert_strings_leq(...) CR_EXPAND(cr_assert_strings_(<=, __VA_ARGS__, CR_SENTINEL))
# define cr_expect_strings_leq(...) CR_EXPAND(cr_expect_strings_(<=, __VA_ARGS__, CR_SENTINEL))
# define cr_assert_strings_geq(...) CR_EXPAND(cr_assert_strings_(>=, __VA_ARGS__, .sentinel_ = 0))
# define cr_expect_strings_geq(...) CR_EXPAND(cr_expect_strings_(>=, __VA_ARGS__, .sentinel_ = 0))
# define cr_assert_strings_geq(...) CR_EXPAND(cr_assert_strings_(>=, __VA_ARGS__, CR_SENTINEL))
# define cr_expect_strings_geq(...) CR_EXPAND(cr_expect_strings_(>=, __VA_ARGS__, CR_SENTINEL))
// Array asserts
# define cr_assert_arrays_eq(...) \
CR_EXPAND(cr_assert_arrays_eq_(__VA_ARGS__, .sentinel_ = 0))
CR_EXPAND(cr_assert_arrays_eq_(__VA_ARGS__, CR_SENTINEL))
# define cr_expect_arrays_eq(...) \
CR_EXPAND(cr_expect_arrays_eq_(__VA_ARGS__, .sentinel_ = 0))
CR_EXPAND(cr_expect_arrays_eq_(__VA_ARGS__, CR_SENTINEL))
# define cr_assert_arrays_neq(...) \
CR_EXPAND(cr_assert_arrays_neq_(__VA_ARGS__, .sentinel_ = 0))
CR_EXPAND(cr_assert_arrays_neq_(__VA_ARGS__, CR_SENTINEL))
# define cr_expect_arrays_neq(...) \
CR_EXPAND(cr_expect_arrays_neq_(__VA_ARGS__, .sentinel_ = 0))
CR_EXPAND(cr_expect_arrays_neq_(__VA_ARGS__, CR_SENTINEL))
# define cr_assert_arrays_eq_(A, B, Size, ...) \
# define cr_assert_arrays_eq_(A, B, Size, ...) \
CR_EXPAND(cr_assert_impl(FATAL, !memcmp((A), (B), (Size)), \
.default_msg = "Arrays are not equal.", \
__VA_ARGS__))
# define cr_expect_arrays_eq_(A, B, Size, ...) \
# define cr_expect_arrays_eq_(A, B, Size, ...) \
CR_EXPAND(cr_assert_impl(NORMAL, !memcmp((A), (B), (Size)), \
.default_msg = "Arrays are not equal.", \
__VA_ARGS__))
# define cr_assert_arrays_neq_(A, B, Size, ...) \
# define cr_assert_arrays_neq_(A, B, Size, ...) \
CR_EXPAND(cr_assert_impl(FATAL, memcmp((A), (B), (Size)), \
.default_msg = "Arrays are equal", \
__VA_ARGS__))
# define cr_expect_arrays_neq_(A, B, Size, ...) \
# define cr_expect_arrays_neq_(A, B, Size, ...) \
CR_EXPAND(cr_assert_impl(NORMAL, memcmp((A), (B), (Size)), \
.default_msg = "Arrays are equal", \
__VA_ARGS__))
# ifdef __GNUC__
@ -230,7 +253,6 @@ struct criterion_assert_args {
do { \
CRIT_ARR_COMPARE_(A, B, Size, Cmp, equals); \
cr_assert_impl(FATAL, equals, \
.default_msg = "Arrays are not equal", \
__VA_ARGS__); \
} while (0)
@ -238,20 +260,18 @@ struct criterion_assert_args {
do { \
CRIT_ARR_COMPARE_(A, B, Size, Cmp, equals); \
cr_assert_impl(NORMAL, equals, \
.default_msg = "Arrays are not equal", \
__VA_ARGS__); \
} while (0)
# define cr_assert_arrays_eq_cmp(...) \
cr_assert_arrays_eq_cmp_(__VA_ARGS__, .sentinel_ = 0)
cr_assert_arrays_eq_cmp_(__VA_ARGS__, CR_SENTINEL)
# define cr_expect_arrays_eq_cmp(...) \
cr_expect_arrays_eq_cmp_(__VA_ARGS__, .sentinel_ = 0)
cr_expect_arrays_eq_cmp_(__VA_ARGS__, CR_SENTINEL)
# define cr_assert_arrays_neq_cmp_(A, B, Size, Cmp, ...) \
do { \
CRIT_ARR_COMPARE_(A, B, Size, Cmp, equals); \
cr_assert_impl(FATAL, !equals, \
.default_msg = "Arrays not equal", \
__VA_ARGS__); \
} while (0)
@ -259,14 +279,13 @@ struct criterion_assert_args {
do { \
CRIT_ARR_COMPARE_(A, B, Size, Cmp, equals); \
cr_assert_impl(NORMAL, equals, \
.default_msg = "Arrays not equal", \
__VA_ARGS__); \
} while (0)
# define cr_assert_arrays_neq_cmp(...) \
cr_assert_arrays_eq_cmp_(__VA_ARGS__, .sentinel_ = 0)
cr_assert_arrays_eq_cmp_(__VA_ARGS__, CR_SENTINEL)
# define cr_expect_arrays_neq_cmp(...) \
cr_expect_arrays_eq_cmp_(__VA_ARGS__, .sentinel_ = 0)
cr_expect_arrays_eq_cmp_(__VA_ARGS__, CR_SENTINEL)
# endif /* !__GNUC__ */
// The section below is here for backward compatibility purposes.

View file

@ -43,12 +43,22 @@
# endif
# endif
# ifdef __cplusplus
# define CR_ATTRIBUTE(Arg) [[gnu::Arg]]
# define CR_BEGIN_C_API extern "C" {
# define CR_END_C_API }
# else
# define CR_ATTRIBUTE(Arg) __attribute__((Arg))
# define CR_BEGIN_C_API
# define CR_END_C_API
# endif
# ifdef __APPLE__
# define SECTION_START_PREFIX __first
# define SECTION_END_PREFIX __last
# define SECTION_START_SUFFIX(Name) __asm("section$start$__DATA$" Name)
# define SECTION_END_SUFFIX(Name) __asm("section$end$__DATA$" Name)
# define SECTION_(Name) __attribute__((section("__DATA," Name)))
# define SECTION_(Name) CR_ATTRIBUTE(section("__DATA," Name))
# define SECTION_SUFFIX_
# elif CR_IS_MSVC
# define SECTION_START_PREFIX __start
@ -66,7 +76,7 @@
# define SECTION_END_PREFIX __stop
# define SECTION_START_SUFFIX(Name)
# define SECTION_END_SUFFIX(Name)
# define SECTION_(Name) __attribute__((section(Name)))
# define SECTION_(Name) CR_ATTRIBUTE(section(Name))
# define SECTION_SUFFIX_
# endif
@ -89,8 +99,8 @@
Type *const SECTION_END(Name) = &SECTION_END_(Name)
# ifdef __GNUC__
# define UNUSED __attribute__((unused))
# define NORETURN __attribute__((noreturn))
# define UNUSED CR_ATTRIBUTE(unused)
# define NORETURN CR_ATTRIBUTE(noreturn)
# elif CR_IS_MSVC
# define UNUSED
# define NORETURN __declspec(noreturn)
@ -106,7 +116,7 @@
# endif
# ifdef __GNUC__
# define FORMAT(Archetype, Index, Ftc) __attribute__((format(Archetype, Index, Ftc)))
# define FORMAT(Archetype, Index, Ftc) CR_ATTRIBUTE(format(Archetype, Index, Ftc))
# else
# define FORMAT(Archetype, Index, Ftc)
# endif
@ -114,13 +124,13 @@
# if defined _WIN32 || defined __CYGWIN__
# ifdef CRITERION_BUILDING_DLL
# ifdef __GNUC__
# define CR_API __attribute__ ((dllexport))
# define CR_API CR_ATTRIBUTE(dllexport)
# else
# define CR_API __declspec(dllexport)
# endif
# else
# ifdef __GNUC__
# define CR_API __attribute__ ((dllimport))
# define CR_API CR_ATTRIBUTE(dllimport)
# else
# define CR_API __declspec(dllimport)
# endif
@ -128,8 +138,8 @@
# define CR_LOCAL
# else
# if __GNUC__ >= 4
# define CR_API __attribute__ ((visibility ("default")))
# define CR_LOCAL __attribute__ ((visibility ("hidden")))
# define CR_API CR_ATTRIBUTE(visibility("default"))
# define CR_LOCAL CR_ATTRIBUTE(visibility("hidden"))
# else
# define CR_API
# define CR_LOCAL

View file

@ -24,14 +24,21 @@
#ifndef CRITERION_H_
# define CRITERION_H_
# include "designated-initializer-compat.h"
# include "common.h"
# include "assert.h"
# include "types.h"
# include "assert.h"
# define IDENTIFIER_(Category, Name, Suffix) \
Category ## _ ## Name ## _ ## Suffix
# define TEST_PROTOTYPE_(Category, Name) \
# ifdef __cplusplus
# define TEST_PROTOTYPE_(Category, Name) \
extern "C" void IDENTIFIER_(Category, Name, impl)(void)
# else
# define TEST_PROTOTYPE_(Category, Name) \
void IDENTIFIER_(Category, Name, impl)(void)
# endif
# define SUITE_IDENTIFIER_(Name, Suffix) \
suite_ ## Name ## _ ## Suffix
@ -39,34 +46,40 @@
# define Test(...) CR_EXPAND(Test_(__VA_ARGS__, .sentinel_ = 0))
# define Test_(Category, Name, ...) \
TEST_PROTOTYPE_(Category, Name); \
struct criterion_test_extra_data IDENTIFIER_(Category, Name, extra) = { \
.identifier_ = #Category "/" #Name, \
.file_ = __FILE__, \
.line_ = __LINE__, \
__VA_ARGS__ \
}; \
struct criterion_test_extra_data IDENTIFIER_(Category, Name, extra) = \
CR_EXPAND(CRITERION_MAKE_STRUCT(struct criterion_test_extra_data, \
.identifier_ = #Category "/" #Name, \
.file_ = __FILE__, \
.line_ = __LINE__, \
__VA_ARGS__ \
)); \
SECTION_("cr_tst") \
const struct criterion_test IDENTIFIER_(Category, Name, meta) = { \
.name = #Name, \
.category = #Category, \
.test = IDENTIFIER_(Category, Name, impl), \
.data = &IDENTIFIER_(Category, Name, extra) \
struct criterion_test IDENTIFIER_(Category, Name, meta) = { \
#Name, \
#Category, \
IDENTIFIER_(Category, Name, impl), \
&IDENTIFIER_(Category, Name, extra) \
} SECTION_SUFFIX_; \
TEST_PROTOTYPE_(Category, Name)
# define TestSuite(...) CR_EXPAND(TestSuite_(__VA_ARGS__, .sentinel_ = 0))
# define TestSuite_(Name, ...) \
struct criterion_test_extra_data SUITE_IDENTIFIER_(Name, extra) = { \
.file_ = __FILE__, \
.line_ = 0, \
__VA_ARGS__ \
}; \
struct criterion_test_extra_data SUITE_IDENTIFIER_(Name, extra) = \
CR_EXPAND(CRITERION_MAKE_STRUCT(struct criterion_test_extra_data, \
.file_ = __FILE__, \
.line_ = 0, \
__VA_ARGS__ \
)); \
SECTION_("cr_sts") \
const struct criterion_suite SUITE_IDENTIFIER_(Name, meta) = { \
.name = #Name, \
.data = &SUITE_IDENTIFIER_(Name, extra), \
struct criterion_suite SUITE_IDENTIFIER_(Name, meta) = { \
#Name, \
&SUITE_IDENTIFIER_(Name, extra), \
} SECTION_SUFFIX_
CR_BEGIN_C_API
CR_API int criterion_run_all_tests(void);
CR_END_C_API
#endif /* !CRITERION_H_ */

View file

@ -0,0 +1,125 @@
/*
* The MIT License (MIT)
*
* Copyright © 2015 Franklin "Snaipe" Mathieu <http://snai.pe/>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CRITERION_DESIGNATED_INITIALIZER_COMPAT_HH_
# define CRITERION_DESIGNATED_INITIALIZER_COMPAT_HH_
# include "common.h"
# define CRITERION_ARG_LENGTH(...) CR_EXPAND(CRITERION_ARG_LENGTH_(__VA_ARGS__,\
63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45,\
44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26,\
25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6,\
5, 4, 3, 2, 1, 0))
# define CRITERION_ARG_LENGTH_(_63, _62, _61, _60, _59, _58, _57, _56, _55, _54, _53, \
_52, _51, _50, _49, _48, _47, _46, _45, _44, _43, _42, _41, _40, _39, _38, \
_37, _36, _35, _34, _33, _32, _31, _30, _29, _28, _27, _26, _25, _24, _23, \
_22, _21, _20, _19, _18, _17, _16, _15, _14, _13, _12, _11, _10, _9, _8, \
_7, _6, _5, _4, _3, _2, _1, count, ...) count
# define CRITERION_APPLY_1(Macro, ...)
# define CRITERION_APPLY_2(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_1(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_3(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_2(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_4(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_3(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_5(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_4(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_6(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_5(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_7(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_6(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_8(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_7(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_9(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_8(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_10(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_9(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_11(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_10(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_12(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_11(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_13(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_12(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_14(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_13(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_15(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_14(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_16(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_15(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_17(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_16(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_18(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_17(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_19(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_18(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_20(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_19(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_21(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_20(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_22(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_21(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_23(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_22(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_24(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_23(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_25(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_24(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_26(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_25(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_27(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_26(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_28(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_27(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_29(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_28(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_30(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_29(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_31(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_30(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_32(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_31(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_33(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_32(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_34(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_33(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_35(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_34(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_36(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_35(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_37(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_36(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_38(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_37(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_39(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_38(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_40(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_39(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_41(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_40(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_42(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_41(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_43(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_42(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_44(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_43(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_45(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_44(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_46(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_45(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_47(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_46(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_48(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_47(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_49(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_48(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_50(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_49(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_51(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_50(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_52(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_51(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_53(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_52(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_54(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_53(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_55(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_54(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_56(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_55(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_57(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_56(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_58(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_57(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_59(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_58(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_60(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_59(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_61(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_60(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_62(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_61(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_63(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_62(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_64(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_63(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY_65(Macro, Prefix, Head, ...) Macro(Prefix, Head) CR_EXPAND(CRITERION_APPLY_64(Macro, Prefix, __VA_ARGS__))
# define CRITERION_APPLY__(Macro, Prefix, n, ...) CR_EXPAND(CRITERION_APPLY_##n(Macro, Prefix, __VA_ARGS__,))
# define CRITERION_APPLY_(Macro, n, Prefix, ...) CR_EXPAND(CRITERION_APPLY__(Macro, Prefix, n, __VA_ARGS__))
# define CRITERION_APPLY(Macro, ...) CR_EXPAND(CRITERION_APPLY_(Macro, CRITERION_ARG_LENGTH(__VA_ARGS__), __VA_ARGS__))
# define CRITERION_ADD_PREFIX_ONCE(Prefix, Field) Prefix Field;
# define CRITERION_ADD_PREFIX(...) \
CR_EXPAND(CRITERION_APPLY(CRITERION_ADD_PREFIX_ONCE, __VA_ARGS__))
# ifdef __cplusplus
# define CRITERION_MAKE_STRUCT(Type, ...) [&]() { \
Type t; \
std::memset(&t, 0, sizeof (t)); \
CR_EXPAND(CRITERION_ADD_PREFIX(t, __VA_ARGS__)) \
return t; \
}()
# else
# define CRITERION_MAKE_STRUCT(Type, ...) { __VA_ARGS__ }
# endif
#endif /* !CRITERION_DESIGNATED_INITIALIZER_COMPAT_HH_ */

View file

@ -24,12 +24,21 @@
#ifndef CRITERION_EVENT_H_
# define CRITERION_EVENT_H_
# include <stddef.h>
# include <stdio.h>
# ifdef __cplusplus
# include <cstddef>
# include <cstdio>
# else
# include <stddef.h>
# include <stdio.h>
# endif
# include "common.h"
CR_BEGIN_C_API
extern FILE *g_event_pipe;
CR_API void send_event(int kind, void *data, size_t size);
CR_END_C_API
#endif /* !CRITERION_EVENT_H_ */

View file

@ -25,6 +25,7 @@
# define CRITERION_HOOKS_H_
# include "common.h"
# include "types.h"
typedef enum {
PRE_ALL,
@ -46,8 +47,13 @@ typedef void (*f_report_hook)();
# define HOOK_IDENTIFIER__(Line, Suffix) HOOK_IDENTIFIER___(Line, Suffix)
# define HOOK_IDENTIFIER___(Line, Suffix) hook_l ## Line ## _ ## Suffix
# define HOOK_PROTOTYPE_ \
# ifdef __cplusplus
# define HOOK_PROTOTYPE_ \
extern "C" void HOOK_IDENTIFIER_(impl)
# else
# define HOOK_PROTOTYPE_ \
void HOOK_IDENTIFIER_(impl)
# endif
// Section abbreviations
# define HOOK_SECTION_PRE_ALL cr_pra
@ -68,10 +74,26 @@ typedef void (*f_report_hook)();
# define HOOK_SECTION_STRINGIFY_(Sec) HOOK_SECTION_STRINGIFY__(Sec)
# define HOOK_SECTION_STRINGIFY(Kind) HOOK_SECTION_STRINGIFY_(HOOK_SECTION(Kind))
# define HOOK_PARAM_TYPE_PRE_ALL struct criterion_test_set *
# define HOOK_PARAM_TYPE_PRE_SUITE struct criterion_suite_set *
# define HOOK_PARAM_TYPE_PRE_INIT struct criterion_test *
# define HOOK_PARAM_TYPE_PRE_TEST struct criterion_test *
# define HOOK_PARAM_TYPE_ASSERT struct criterion_assert_stats *
# define HOOK_PARAM_TYPE_THEORY_FAIL struct criterion_theory_stats *
# define HOOK_PARAM_TYPE_TEST_CRASH struct criterion_test_stats *
# define HOOK_PARAM_TYPE_POST_TEST struct criterion_test_stats *
# define HOOK_PARAM_TYPE_POST_FINI struct criterion_test_stats *
# define HOOK_PARAM_TYPE_POST_SUITE struct criterion_suite_stats *
# define HOOK_PARAM_TYPE_POST_ALL struct criterion_global_stats *
# define HOOK_PARAM_TYPE(Kind) HOOK_PARAM_TYPE_ ## Kind
# define ReportHook(Kind) \
HOOK_PROTOTYPE_(); \
HOOK_PROTOTYPE_(HOOK_PARAM_TYPE(Kind)); \
SECTION_(HOOK_SECTION_STRINGIFY(Kind)) \
const f_report_hook HOOK_IDENTIFIER_(func) = HOOK_IDENTIFIER_(impl); \
f_report_hook HOOK_IDENTIFIER_(func) = \
(f_report_hook) HOOK_IDENTIFIER_(impl) \
SECTION_SUFFIX_; \
HOOK_PROTOTYPE_
#endif /* !CRITERION_HOOKS_H_ */

View file

@ -24,8 +24,13 @@
#ifndef CRITERION_LOGGING_H_
# define CRITERION_LOGGING_H_
# include <stdbool.h>
# include <stdarg.h>
# ifdef __cplusplus
# include <cstdarg>
using std::va_list;
# else
# include <stdbool.h>
# include <stdarg.h>
# endif
# include "common.h"
# include "ordered-set.h"
# include "stats.h"
@ -67,6 +72,8 @@ struct criterion_prefix_data {
# define RESET CRIT_COLOR_NORMALIZE(CRIT_RESET)
# endif
CR_BEGIN_C_API
extern const struct criterion_prefix_data g_criterion_logging_prefixes[];
# define CRITERION_PREFIX_DASHES (&g_criterion_logging_prefixes[CRITERION_LOGGING_PREFIX_DASHES])
@ -109,6 +116,8 @@ struct criterion_output_provider {
extern struct criterion_output_provider normal_logging;
extern struct criterion_output_provider tap_logging;
CR_END_C_API
#define NORMAL_LOGGING (&normal_logging)
#define TAP_LOGGING (&tap_logging)

View file

@ -38,6 +38,10 @@ struct criterion_options {
bool short_filename;
};
CR_BEGIN_C_API
extern struct criterion_options criterion_options;
CR_END_C_API
#endif /*!CRITERION_OPTIONS_H_ */

View file

@ -40,15 +40,7 @@ struct criterion_ordered_set_node {
char data[0];
};
struct criterion_suite_set {
struct criterion_suite suite;
struct criterion_ordered_set *tests;
};
struct criterion_test_set {
struct criterion_ordered_set *suites;
size_t tests;
};
CR_BEGIN_C_API
CR_API struct criterion_ordered_set *new_ordered_set(f_criterion_cmp cmp,
void (*dtor)(void *, void *));
@ -57,6 +49,8 @@ CR_API void *insert_ordered_set(struct criterion_ordered_set *l,
void *ptr,
size_t size);
CR_END_C_API
# define FOREACH_SET(Elt, Set) \
for (struct criterion_ordered_set_node *n = Set->first; n; n = n->next) \
for (int cond = 1; cond;) \

View file

@ -24,9 +24,24 @@
#ifndef CRITERION_THEORIES_H_
# define CRITERION_THEORIES_H_
# include <stddef.h>
# ifdef __cplusplus
# include <cstddef>
using std::size_t;
# else
# include <stddef.h>
# endif
# include "criterion.h"
# ifdef __cplusplus
template <typename... T>
constexpr size_t criterion_va_num__(const T &...) {
return sizeof...(T);
}
# endif
CR_BEGIN_C_API
struct criterion_theory_context;
CR_API struct criterion_theory_context* cr_theory_init(void);
@ -41,11 +56,19 @@ CR_API void cr_theory_call(struct criterion_theory_context *ctx, void (*fnptr)(v
# define TheoryDataPoints(Category, Name) \
static struct criterion_datapoints IDENTIFIER_(Category, Name, dps)[]
# ifdef __cplusplus
# define CR_TH_VA_NUM(Type, ...) criterion_va_num__(__VA_ARGS__)
# define CR_TH_TEMP_ARRAY(Type, ...) []() { static Type arr[] = { __VA_ARGS__ }; return &arr; }()
# else
# define CR_TH_VA_NUM(Type, ...) sizeof ((Type[]) { __VA_ARGS__ }) / sizeof (Type)
# define CR_TH_TEMP_ARRAY(Type, ...) &(Type[]) { __VA_ARGS__ }
# endif
# define DataPoints(Type, ...) { \
sizeof (Type), \
sizeof ((Type[]) { __VA_ARGS__ }) / sizeof (Type), \
CR_EXPAND(CR_TH_VA_NUM(Type, __VA_ARGS__)), \
#Type, \
&(Type[]) { __VA_ARGS__ }, \
CR_EXPAND(CR_TH_TEMP_ARRAY(Type, __VA_ARGS__)), \
}
struct criterion_datapoints {
@ -114,4 +137,6 @@ CR_API void cr_theory_main(struct criterion_datapoints *dps, size_t datapoints,
} \
void CR_EXPAND(CR_VAARG_ID(theory, __VA_ARGS__,))Args
CR_END_C_API
#endif /* !CRITERION_THEORIES_H_ */

View file

@ -24,8 +24,13 @@
#ifndef CRITERION_TYPES_H_
# define CRITERION_TYPES_H_
# include <stdbool.h>
# include <stddef.h>
# ifdef __cplusplus
# include <cstddef>
using std::size_t;
# else
# include <stdbool.h>
# include <stddef.h>
# endif
# include "common.h"
struct criterion_test_extra_data {
@ -54,6 +59,18 @@ struct criterion_suite {
struct criterion_test_extra_data *data;
};
struct criterion_ordered_set;
struct criterion_suite_set {
struct criterion_suite suite;
struct criterion_ordered_set *tests;
};
struct criterion_test_set {
struct criterion_ordered_set *suites;
size_t tests;
};
typedef void (*f_worker_func)(struct criterion_test *, struct criterion_suite *);
#endif /* !CRITERION_TYPES_H_ */

View file

@ -1,22 +1,36 @@
if (NOT MSVC)
set(CMAKE_C_FLAGS "-std=c99 -Wall -Wextra -pedantic")
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -pedantic")
endif ()
include_directories(../include)
set(SAMPLES
signal
exit
report
suites
fixtures
asserts
more-suites
long-messages
description
other-crashes
simple
theories
signal.c
exit.c
report.c
suites.c
fixtures.c
asserts.c
more-suites.c
long-messages.c
description.c
other-crashes.c
simple.c
theories.c
signal.cc
exit.cc
report.cc
suites.cc
fixtures.cc
asserts.cc
more-suites.cc
long-messages.cc
description.cc
other-crashes.cc
simple.cc
theories.cc
)
set(SCRIPTS
@ -33,15 +47,15 @@ if (HAVE_PCRE)
endif ()
foreach(sample ${SAMPLES})
add_executable(${sample} ${sample}.c)
target_link_libraries(${sample} criterion)
add_test(${sample} ${sample})
add_executable(${sample}.bin ${sample})
target_link_libraries(${sample}.bin criterion)
add_test(${sample} ${sample}.bin)
set_property(TEST ${sample} PROPERTY
ENVIRONMENT "CRITERION_ALWAYS_SUCCEED=1"
)
if (NOT MSVC) # we disable the scripted tests when building with MSVC
add_test(${sample}_compare sh ${CMAKE_CURRENT_LIST_DIR}/tests/run_test.sh "${CMAKE_CURRENT_LIST_DIR}" . . ${sample})
add_test(${sample}_compare sh ${CMAKE_CURRENT_LIST_DIR}/tests/run_test.sh "${CMAKE_CURRENT_LIST_DIR}" . . ${sample}.bin)
set_property(TEST ${sample}_compare PROPERTY
ENVIRONMENT "LC_ALL=en_US.utf8"
ENVIRONMENT "CRITERION_ALWAYS_SUCCEED=1"

View file

@ -6,8 +6,6 @@ Test(asserts, base) {
cr_assert(true, "Assertions may take failure messages");
cr_assert(true, .msg = "You can use explicit named arguments");
cr_expect(false, "assert is fatal, expect isn't");
cr_assert(false, "This assert runs");
cr_assert(false, "This does not");
@ -76,7 +74,7 @@ Test(asserts, array) {
s2[1].a = 2;
s2[1].b = 4;
cr_assert_arrays_neq(s1, s2, 2);
// cr_assert_arrays_eq(s1, s2, 2); not guaranteed to work on structs.
cr_assert_arrays_eq_cmp(s1, s2, 2, eq_dummy);
#endif
}

View file

@ -1,6 +1,6 @@
[----] asserts.c:11: Assertion failed: assert is fatal, expect isn't
[----] asserts.c:12: Assertion failed: This assert runs
[----] asserts.c:9: Assertion failed: assert is fatal, expect isn't
[----] asserts.c:10: Assertion failed: This assert runs
[FAIL] asserts::base: (0.00s)
[----] asserts.c:20: Assertion failed: The conditions for this test were not met.
[----] asserts.c:18: Assertion failed: The conditions for this test were not met.
[FAIL] asserts::old_school: (0.00s)
[====] Synthesis: Tested: 6 | Passing: 4 | Failing: 2 | Crashing: 0 

80
samples/asserts.cc Normal file
View file

@ -0,0 +1,80 @@
#include <criterion/criterion.h>
Test(asserts, base) {
cr_assert(true);
cr_expect(true);
cr_assert(true, "Assertions may take failure messages");
cr_expect(false, "assert is fatal, expect isn't");
cr_assert(false, "This assert runs");
cr_assert(false, "This does not");
}
Test(asserts, old_school) {
if (false)
cr_abort_test("You can abort the test with a message from anywhere");
cr_abort_test(NULL); // or without a message
}
Test(asserts, string) {
cr_assert_strings_eq("hello", "hello");
cr_assert_strings_neq("hello", "olleh");
cr_assert_strings_gt("hello", "hell");
cr_assert_strings_geq("hello", "hell");
cr_assert_strings_geq("hello", "hello");
cr_assert_strings_lt("hell", "hello");
cr_assert_strings_leq("hell", "hello");
cr_assert_strings_leq("hello", "hello");
}
Test(asserts, native) {
cr_assert_eq(1, 1);
cr_assert_neq(1, 2);
cr_assert_lt(1, 2);
cr_assert_leq(1, 2);
cr_assert_leq(2, 2);
cr_assert_gt(2, 1);
cr_assert_geq(2, 1);
cr_assert_geq(2, 2);
}
Test(asserts, float) {
cr_assert_neq(0.1 * 0.1, 0.01);
cr_assert_float_eq(0.1 * 0.1, 0.01, 0.001);
}
struct dummy_struct {
char a;
size_t b;
};
int eq_dummy(struct dummy_struct *a, struct dummy_struct *b) {
return a->a != b->a || a->b != b->b;
}
Test(asserts, array) {
int arr1[] = {1, 2, 3, 4};
int arr2[] = {4, 3, 2, 1};
cr_assert_arrays_eq(arr1, arr1, 4);
cr_assert_arrays_neq(arr1, arr2, 4);
#ifdef __GNUC__
struct dummy_struct s1[] = {{4, 2}, {2, 4}};
struct dummy_struct s2[2];
memset(s2, 0xFF, sizeof(s2));
s2[0].a = 4;
s2[0].b = 2;
s2[1].a = 2;
s2[1].b = 4;
// cr_assert_arrays_eq(s1, s2, 2); not guaranteed to work on structs.
cr_assert_arrays_eq_cmp(s1, s2, 2, eq_dummy);
#endif
}

View file

@ -0,0 +1,6 @@
[----] asserts.cc:9: Assertion failed: assert is fatal, expect isn't
[----] asserts.cc:10: Assertion failed: This assert runs
[FAIL] asserts::base: (0.00s)
[----] asserts.cc:18: Assertion failed: The conditions for this test were not met.
[FAIL] asserts::old_school: (0.00s)
[====] Synthesis: Tested: 6 | Passing: 4 | Failing: 2 | Crashing: 0 

8
samples/description.cc Normal file
View file

@ -0,0 +1,8 @@
#include <criterion/criterion.h>
Test(misc, failing, .description = "Just a failing test") {
cr_assert(0);
}
Test(misc, skipped, .description = "This one is skipped", .disabled = true) {
}

View file

@ -0,0 +1,3 @@
[----] description.cc:4: Assertion failed: 0
[FAIL] misc::failing: (0.00s)
[====] Synthesis: Tested: 1 | Passing: 0 | Failing: 1 | Crashing: 0 

24
samples/exit.cc Normal file
View file

@ -0,0 +1,24 @@
#include <stdio.h>
#include <stdlib.h>
#include <criterion/criterion.h>
Test(exit, normal, .exit_code = 0) {
}
Test(exit, expected_exit, .exit_code = 42) {
exit(42);
}
Test(exit, unexpected_exit) {
exit(127);
}
void do_exit (void) {
exit(127);
}
Test(exit_with_fixtures, init_exits, .init = do_exit) {
}
Test(exit_with_fixtures, fini_exits, .fini = do_exit) {
}

View file

@ -0,0 +1,4 @@
[----] Warning! The test `exit::unexpected_exit` exited during its setup or teardown.
[----] Warning! The test `exit_with_fixtures::fini_exits` exited during its setup or teardown.
[----] Warning! The test `exit_with_fixtures::init_exits` exited during its setup or teardown.
[====] Synthesis: Tested: 5 | Passing: 3 | Failing: 2 | Crashing: 2 

14
samples/fixtures.cc Normal file
View file

@ -0,0 +1,14 @@
#include <criterion/criterion.h>
#include <stdio.h>
void setup(void) {
puts("Runs before the test");
}
void teardown(void) {
puts("Runs after the test");
}
Test(simple, fixtures, .init = setup, .fini = teardown) {
cr_assert(1);
}

View file

@ -0,0 +1 @@
[====] Synthesis: Tested: 1 | Passing: 1 | Failing: 0 | Crashing: 0 

View file

@ -0,0 +1,2 @@
Runs before the test
Runs after the test

5
samples/long-messages.cc Normal file
View file

@ -0,0 +1,5 @@
#include <criterion/criterion.h>
Test(sample, long_msg) {
cr_assert(0, "This is\nA long message\nSpawning multiple lines.\n\nFormatting is respected.");
}

View file

@ -0,0 +1,6 @@
[----] long-messages.cc:4: Assertion failed: This is
[----] A long message
[----] Spawning multiple lines.
[----] Formatting is respected.
[FAIL] sample::long_msg: (0.00s)
[====] Synthesis: Tested: 1 | Passing: 0 | Failing: 1 | Crashing: 0 

21
samples/more-suites.cc Normal file
View file

@ -0,0 +1,21 @@
#include <criterion/criterion.h>
void setup_suite(void) {
}
void teardown_suite(void) {
}
TestSuite(suite1, .init = setup_suite, .fini = teardown_suite);
Test(suite1, test) {
cr_assert(1);
}
Test(suite2, test) {
cr_assert(1);
}
TestSuite(disabled, .disabled = true);
Test(disabled, test) {}

View file

View file

14
samples/other-crashes.cc Normal file
View file

@ -0,0 +1,14 @@
#include <criterion/criterion.h>
void crash(void) {
int *i = NULL;
*i = 42;
}
Test(misc, setup_crash, .init = crash) {
cr_assert(true);
}
Test(misc, teardown_crash, .fini = crash) {
cr_assert(true);
}

View file

@ -0,0 +1,3 @@
[----] Warning! The test `misc::setup_crash` crashed during its setup or teardown.
[----] Warning! The test `misc::teardown_crash` crashed during its setup or teardown.
[====] Synthesis: Tested: 2 | Passing: 1 | Failing: 1 | Crashing: 1 

View file

@ -15,10 +15,12 @@ ReportHook(POST_TEST)(struct criterion_test_stats *stats) {
stats->passed_asserts, stats->failed_asserts, stats->passed_asserts + stats->failed_asserts);
}
ReportHook(PRE_ALL)() {
ReportHook(PRE_ALL)(struct criterion_test_set *tests) {
(void) tests;
puts("criterion_init");
}
ReportHook(POST_ALL)() {
ReportHook(POST_ALL)(struct criterion_global_stats *stats) {
(void) stats;
puts("criterion_fini");
}

26
samples/report.cc Normal file
View file

@ -0,0 +1,26 @@
#include <stdio.h>
#include <criterion/criterion.h>
Test(sample, test) {
cr_expect(0);
cr_assert(1);
}
ReportHook(PRE_INIT)(struct criterion_test *test) {
printf("testing %s in category %s\n", test->name, test->category);
}
ReportHook(POST_TEST)(struct criterion_test_stats *stats) {
printf("Asserts: [%d passed, %d failed, %d total]\n",
stats->passed_asserts, stats->failed_asserts, stats->passed_asserts + stats->failed_asserts);
}
ReportHook(PRE_ALL)(struct criterion_test_set *tests) {
(void) tests;
puts("criterion_init");
}
ReportHook(POST_ALL)(struct criterion_global_stats *stats) {
(void) stats;
puts("criterion_fini");
}

View file

@ -0,0 +1,3 @@
[----] report.cc:5: Assertion failed: 0
[FAIL] sample::test: (0.00s)
[====] Synthesis: Tested: 1 | Passing: 0 | Failing: 1 | Crashing: 0 

View file

@ -0,0 +1,4 @@
criterion_init
testing test in category sample
Asserts: [1 passed, 1 failed, 2 total]
criterion_fini

View file

19
samples/signal.cc Normal file
View file

@ -0,0 +1,19 @@
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <criterion/criterion.h>
Test(simple, caught, .signal = SIGSEGV) {
int *i = NULL;
*i = 42;
}
Test(simple, wrong_signal, .signal = SIGINT) {
int *i = NULL;
*i = 42;
}
Test(simple, uncaught) {
int *i = NULL;
*i = 42;
}

View file

@ -0,0 +1,4 @@
[----] signal.cc:16: Unexpected signal caught below this line!
[FAIL] simple::uncaught: CRASH!
[FAIL] simple::wrong_signal: (0.00s)
[====] Synthesis: Tested: 3 | Passing: 1 | Failing: 2 | Crashing: 1 

View file

View file

9
samples/simple.cc Normal file
View file

@ -0,0 +1,9 @@
#include <criterion/criterion.h>
Test(misc, failing) {
cr_assert(0);
}
Test(misc, passing) {
cr_assert(1);
}

View file

@ -0,0 +1,3 @@
[----] simple.cc:4: Assertion failed: 0
[FAIL] misc::failing: (0.00s)
[====] Synthesis: Tested: 2 | Passing: 1 | Failing: 1 | Crashing: 0 

View file

View file

@ -0,0 +1 @@
[====] Synthesis: Tested: 2 | Passing: 2 | Failing: 0 | Crashing: 0 

View file

9
samples/suites.cc Normal file
View file

@ -0,0 +1,9 @@
#include <criterion/criterion.h>
Test(first_suite, test) {
cr_assert(1);
}
Test(second_suite, test) {
cr_assert(1);
}

View file

@ -0,0 +1 @@
[====] Synthesis: Tested: 2 | Passing: 2 | Failing: 0 | Crashing: 0 

View file

View file

@ -1,3 +1,3 @@
#!/bin/sh
./simple --no-early-exit --always-succeed
./theories --no-early-exit --always-succeed
./simple.c.bin --no-early-exit --always-succeed
./theories.c.bin --no-early-exit --always-succeed

View file

@ -1,2 +1,2 @@
#!/bin/sh
./simple --fail-fast --always-succeed
./simple.c.bin --fail-fast --always-succeed

View file

@ -1,3 +1,3 @@
#!/bin/sh
./simple --help
./simple --version
./simple.c.bin --help
./simple.c.bin --version

View file

@ -1,3 +1,3 @@
#!/bin/sh
./simple --list
./simple --list --ascii
./simple.c.bin --list
./simple.c.bin --list --ascii

View file

@ -1,10 +1,10 @@
#!/bin/sh -e
./simple --pattern '*/passing'
./simple --pattern '!(*/passing)'
./simple --pattern '[pf]a@(ss|il)ing'
./simple --pattern '@(+(nest)ed))'
./simple --pattern '?(*(a|b))'
! ./simple --pattern '?(malformed'
./simple --pattern '[!azerty]assing'
./simple --pattern '|pipe'
./simple --pattern '\!(escaped'
./simple.c.bin --pattern '*/passing'
./simple.c.bin --pattern '!(*/passing)'
./simple.c.bin --pattern '[pf]a@(ss|il)ing'
./simple.c.bin --pattern '@(+(nest)ed))'
./simple.c.bin --pattern '?(*(a|b))'
! ./simple.c.bin --pattern '?(malformed'
./simple.c.bin --pattern '[!azerty]assing'
./simple.c.bin --pattern '|pipe'
./simple.c.bin --pattern '\!(escaped'

View file

@ -1,7 +1,7 @@
#!/bin/sh
./simple --tap --always-succeed
./signal --tap --always-succeed
./asserts --tap --always-succeed
./more-suites --tap --always-succeed
./long-messages --tap --always-succeed
./description --tap --always-succeed
./simple.c.bin --tap --always-succeed
./signal.c.bin --tap --always-succeed
./asserts.c.bin --tap --always-succeed
./more-suites.c.bin --tap --always-succeed
./long-messages.c.bin --tap --always-succeed
./description.c.bin --tap --always-succeed

View file

@ -1,2 +1,2 @@
#!/bin/sh
./simple --verbose --always-succeed
./simple.c.bin --verbose --always-succeed

112
samples/theories.cc Normal file
View file

@ -0,0 +1,112 @@
#ifdef _MSC_VER
#pragma warning(disable : 4090)
#endif
#include <criterion/theories.h>
#ifdef __cplusplus
# include <climits>
#else
# include <limits.h>
#endif
# define INT_DATAPOINTS DataPoints(int, 0, 1, 2, -1, -2, INT_MAX, INT_MIN)
// Let's test the multiplicative properties of 32-bit integers:
int bad_mul(int a, int b) {
return a * b;
}
int bad_div(int a, int b) {
return a / b;
}
TheoryDataPoints(algebra, bad_divide_is_inverse_of_multiply) = {
INT_DATAPOINTS,
INT_DATAPOINTS,
};
Theory((int a, int b), algebra, bad_divide_is_inverse_of_multiply) {
cr_assume(b != 0);
cr_assert_eq(a, bad_div(bad_mul(a, b), b));
}
// The above implementation of mul & div fails the test because of overflows,
// let's try again:
long long good_mul(long long a, long long b) {
return a * b;
}
long long good_div(long long a, long long b) {
return a / b;
}
TheoryDataPoints(algebra, good_divide_is_inverse_of_multiply) = {
INT_DATAPOINTS,
INT_DATAPOINTS,
};
Theory((int a, int b), algebra, good_divide_is_inverse_of_multiply) {
cr_assume(b != 0);
cr_assert_eq(a, good_div(good_mul(a, b), b));
}
// For triangulation
Test(algebra, multiplication_by_integer) {
cr_assert_eq(10, good_mul(5, 2));
}
// Another property test
TheoryDataPoints(algebra, zero_is_absorbing) = {
INT_DATAPOINTS,
INT_DATAPOINTS,
};
Theory((int a, int b), algebra, zero_is_absorbing) {
cr_assume(a == 0 || b == 0);
cr_assert_eq(0, good_mul(a, b));
}
// Testing for various parameters
struct my_object {
int foo;
};
struct my_object o = {42};
char test_str[] = {'t', 'e', 's', 't', '\0'};
TheoryDataPoints(theory, misc) = {
DataPoints(char, 'a'),
DataPoints(bool, true),
DataPoints(short, 1),
DataPoints(int, 1),
DataPoints(long, 1),
DataPoints(long long, 1),
DataPoints(float, 3.14f),
DataPoints(double, 3.14),
DataPoints(char *, test_str),
DataPoints(const char *, "other test"),
DataPoints(struct my_object *, &o),
};
Theory((char c, bool b, short s, int i, long l, long long ll, float f, double d, char *str, const char *cstr, struct my_object *obj), theory, misc) {
cr_assert(b);
cr_assert_eq(c, 'a');
cr_assert_eq(s, 1);
cr_assert_eq(i, 1);
cr_assert_eq(l, 1);
cr_assert_eq(ll, 1);
cr_assert_eq(f, 3.14f);
cr_assert_eq(d, 3.14);
cr_assert_strings_eq(str, "test");
cr_assert_strings_eq(cstr, "other test");
cr_assert_eq(obj->foo, 42);
// abort to see the formatted string of all parameters
cr_abort_test(NULL);
}

View file

@ -83,15 +83,15 @@ IMPL_CALL_REPORT_HOOKS(POST_FINI);
IMPL_CALL_REPORT_HOOKS(POST_SUITE);
IMPL_CALL_REPORT_HOOKS(POST_ALL);
ReportHook(PRE_ALL)() {}
ReportHook(PRE_SUITE)() {}
ReportHook(PRE_INIT)() {}
ReportHook(PRE_TEST)() {}
ReportHook(ASSERT)() {}
ReportHook(THEORY_FAIL)() {}
ReportHook(TEST_CRASH)() {}
ReportHook(POST_TEST)() {}
ReportHook(POST_FINI)() {}
ReportHook(POST_SUITE)() {}
ReportHook(POST_ALL)() {}
ReportHook(PRE_ALL)(UNUSED struct criterion_test_set *arg) {}
ReportHook(PRE_SUITE)(UNUSED struct criterion_suite_set *arg) {}
ReportHook(PRE_INIT)(UNUSED struct criterion_test *arg) {}
ReportHook(PRE_TEST)(UNUSED struct criterion_test *arg) {}
ReportHook(ASSERT)(UNUSED struct criterion_assert_stats *arg) {}
ReportHook(THEORY_FAIL)(UNUSED struct criterion_theory_stats *arg) {}
ReportHook(TEST_CRASH)(UNUSED struct criterion_test_stats *arg) {}
ReportHook(POST_TEST)(UNUSED struct criterion_test_stats *arg) {}
ReportHook(POST_FINI)(UNUSED struct criterion_test_stats *arg) {}
ReportHook(POST_SUITE)(UNUSED struct criterion_suite_stats *arg) {}
ReportHook(POST_ALL)(UNUSED struct criterion_global_stats *arg) {}