#ifndef XTEST_XTEST_H #define XTEST_XTEST_H #if defined(XTEST_XASSERT) #error "do not include xtest.h before assert.h. If your tests make use of standard library assertions, include first xtest.h and then assert.h" #endif #if defined(__GNUC__) || defined(__clang__) #define XTEST_UNUSED __attribute__((unused)) #else #define XTEST_UNUSED #endif #include #include typedef void (*xtest_test_fn)(void *fixture, void **params); typedef void (*xtest_setup_fn)(void **fixture); typedef void (*xtest_teardown_fn)(void *fixture); typedef struct xtest_param_s xtest_param; typedef void *xtest_param_values[]; struct xtest_param_s { const char *name; xtest_param_values *values; }; enum xtest_type { xtest_type_bool, xtest_type_char, xtest_type_short, xtest_type_unsigned_short, xtest_type_int, xtest_type_unsigned_int, xtest_type_long, xtest_type_unsigned_long, xtest_type_long_long, xtest_type_unsigned_long_long, xtest_type_float, xtest_type_double, xtest_type_long_double, xtest_type_string, xtest_type_void_pointer, xtest_type_other, }; void xtest_init(int argc, char **argv); void xtest_fail_assert(const char *expression, const char *file, int line, void *expected, void *actual, _Bool invert, enum xtest_type type); void xtest_assert_float(double expected, double actual, int precision, _Bool invert, const char *expression, const char *file, int line); void xtest_assert_mem(const char *expected, const char *actual, size_t length, _Bool invert, const char *expression, const char *file, int line); void xtest_internal_run(xtest_test_fn fn, const char *name, xtest_param *params, xtest_setup_fn setup, xtest_teardown_fn teardown); void xtest_internal_start_group(const char *name); void xtest_internal_end_group(void); void xtest_skip(const char *reason); void xtest_expect_assertion_failure(void); int xtest_complete(void); #ifdef XTEST_PRNG void xtest_rand_fill(char *buf, size_t len); double xtest_rand_double(void); double xtest_rand_double_range(double min, double max); int xtest_rand_int(void); int xtest_rand_int_range(int min, int max); uint8_t xtest_rand_8(void); uint16_t xtest_rand_16(void); uint32_t xtest_rand_32(void); uint64_t xtest_rand_64(void); #endif #define xtest_run(fn) xtest_internal_run(fn, #fn, (void*)0, (void*)0, (void*)0) #define xtest_run_parameterized(fn, params) xtest_internal_run(fn, #fn, params, (void*)0, (void*)0) #define xtest_run_with_fixture(fn, setup, teardown) xtest_internal_run(fn, #fn, (void*)0, setup, teardown) #define xtest_run_parameterized_with_fixture(fn, params, setup, teardown) xtest_internal_run(fn, #fn, params, setup, teardown) #define xtest_group(name) xtest_internal_start_group(#name) #define xtest_end_group() xtest_internal_end_group() #define xtest_run_group(fn) do { \ xtest_group(fn); \ fn(); \ xtest_end_group(); \ } while (0) #define xtest_get_param(type, idx, params) *((type*)(params)[idx]) #define xtest_get_param_ptr(type, idx, params) (type)(params)[idx] #define xtest_get_type(val) _Generic(val, \ _Bool: xtest_type_bool, \ char: xtest_type_char, \ signed char: xtest_type_char, \ unsigned char: xtest_type_char, \ short: xtest_type_short, \ unsigned short: xtest_type_unsigned_short,\ int: xtest_type_int,\ unsigned int: xtest_type_unsigned_int,\ long: xtest_type_long,\ unsigned long: xtest_type_unsigned_long,\ long long: xtest_type_long_long,\ unsigned long long: xtest_type_unsigned_long_long,\ float: xtest_type_float,\ double: xtest_type_double,\ long double: xtest_type_long_double,\ const char *: xtest_type_string,\ void*:xtest_type_void_pointer,\ default: xtest_type_other) #define force_types_equal(a, b) (void) _Generic(a, \ __typeof__(b): (void*)0 \ ) #define xtest_assert_(expr, s, actual, expected, invert) do { \ force_types_equal(expected, actual); \ int _xtest_res = (expr); \ if (!(_xtest_res)) { \ __typeof__(actual) _xtest_a = actual; \ __typeof__(expected) _xtest_e = expected; \ enum xtest_type _xtest_type = xtest_get_type(actual); \ xtest_fail_assert(s, __FILE__, __LINE__, &_xtest_e, &_xtest_a, invert, _xtest_type); \ } \ } while(0) #define xtest_assert(e) xtest_assert_(!!(e), #e, (_Bool)(e), (_Bool)1, 0) #define xtest_assert_is(actual, expected) xtest_assert_((actual) == (expected), #actual " is " #expected, actual, expected, 0) #define xtest_assert_is_not(actual, expected) xtest_assert_((actual) != (expected), #actual " is not " #expected, actual, expected, 1) #define xtest_assert_float_is(actual, expected, precision) xtest_assert_float(expected, actual, precision, 0, #actual " is " #expected, __FILE__, __LINE__) #define xtest_assert_float_is_not(actual, expected, precision) xtest_assert_float(expected, actual, precision, 1, #actual " is not " #expected, __FILE__, __LINE__) #define xtest_assert_str_is(actual, expected) xtest_assert_(strcmp(actual, expected) == 0, #actual " is " #expected, (const char*)(actual), (const char*)(expected), 0) #define xtest_assert_str_is_not(actual, expected) xtest_assert_(strcmp(actual, expected) != 0, #actual " is not " #expected, (const char*)(actual), (const char*)(expected), 1) #define xtest_assert_mem_is(actual, expected, len) xtest_assert_mem(expected, actual, len, 0, #actual " is " #expected " (" #len " bytes)", __FILE__, __LINE__) #define xtest_assert_mem_is_not(actual, expected, len) xtest_assert_mem(expected, actual, len, 1, #actual " is not " #expected " (" #len " bytes)", __FILE__, __LINE__) #define XTEST_RUN_MAIN(fn) int main(int argc, char ** argv) { \ xtest_init(argc, argv); \ fn(); \ return xtest_complete(); \ } #define XTEST_MAIN void __xtest_main(); \ XTEST_RUN_MAIN(__xtest_main) \ void __xtest_main() #endif //XTEST_XTEST_H