Added parameterized tests
This commit is contained in:
parent
84706900b4
commit
582fa18389
10 changed files with 161 additions and 11 deletions
|
@ -48,6 +48,8 @@
|
|||
TEST_PROTOTYPE_(Category, Name); \
|
||||
struct criterion_test_extra_data IDENTIFIER_(Category, Name, extra) = \
|
||||
CR_EXPAND(CRITERION_MAKE_STRUCT(struct criterion_test_extra_data, \
|
||||
.kind_ = CR_TEST_NORMAL, \
|
||||
.param_ = (struct criterion_test_params(*)(void)) NULL, \
|
||||
.identifier_ = #Category "/" #Name, \
|
||||
.file_ = __FILE__, \
|
||||
.line_ = __LINE__, \
|
||||
|
|
48
include/criterion/parameterized.h
Normal file
48
include/criterion/parameterized.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
#ifndef CRITERION_PARAMETERIZED_H_
|
||||
# define CRITERION_PARAMETERIZED_H_
|
||||
|
||||
# include "criterion.h"
|
||||
|
||||
# ifdef __cplusplus
|
||||
# define CR_PARAM_TEST_PROTOTYPE_(Param, Category, Name) \
|
||||
extern "C" void IDENTIFIER_(Category, Name, impl)(Param)
|
||||
# else
|
||||
# define CR_PARAM_TEST_PROTOTYPE_(Param, Category, Name) \
|
||||
void IDENTIFIER_(Category, Name, impl)(Param)
|
||||
# endif
|
||||
|
||||
# define ParameterizedTest(...) \
|
||||
CR_EXPAND(ParameterizedTest_(__VA_ARGS__, .sentinel_ = 0))
|
||||
|
||||
# define ParameterizedTest_(Param, Category, Name, ...) \
|
||||
CR_PARAM_TEST_PROTOTYPE_(Param, Category, Name); \
|
||||
struct criterion_test_extra_data IDENTIFIER_(Category, Name, extra) = \
|
||||
CR_EXPAND(CRITERION_MAKE_STRUCT(struct criterion_test_extra_data, \
|
||||
.kind_ = CR_TEST_PARAMETERIZED, \
|
||||
.param_ = IDENTIFIER_(Category, Name, param), \
|
||||
.identifier_ = #Category "/" #Name, \
|
||||
.file_ = __FILE__, \
|
||||
.line_ = __LINE__, \
|
||||
__VA_ARGS__ \
|
||||
)); \
|
||||
SECTION_("cr_tst") \
|
||||
struct criterion_test IDENTIFIER_(Category, Name, meta) = { \
|
||||
#Name, \
|
||||
#Category, \
|
||||
(void(*)(void)) IDENTIFIER_(Category, Name, impl), \
|
||||
&IDENTIFIER_(Category, Name, extra) \
|
||||
} SECTION_SUFFIX_; \
|
||||
CR_PARAM_TEST_PROTOTYPE_(Param, Category, Name)
|
||||
|
||||
# define ParameterizedTestParameters(Category, Name) \
|
||||
static struct criterion_test_params IDENTIFIER_(Category, Name, param)(void)
|
||||
|
||||
# ifdef __cplusplus
|
||||
# define cr_make_param_array(Type, Array, Length) \
|
||||
criterion_test_params(sizeof (Type), (Array), (Length))
|
||||
# else
|
||||
# define cr_make_param_array(Type, Array, Length) \
|
||||
(struct criterion_test_params) { sizeof (Type), (void**)(Array), (Length) }
|
||||
# endif
|
||||
|
||||
#endif /* !CRITERION_PARAMETERIZED_H_ */
|
|
@ -33,8 +33,29 @@ using std::size_t;
|
|||
# endif
|
||||
# include "common.h"
|
||||
|
||||
enum criterion_test_kind {
|
||||
CR_TEST_NORMAL,
|
||||
CR_TEST_PARAMETERIZED,
|
||||
};
|
||||
|
||||
struct criterion_test_params {
|
||||
size_t size;
|
||||
void **params;
|
||||
size_t length;
|
||||
|
||||
# ifdef __cplusplus
|
||||
constexpr criterion_test_params(size_t size, void **params, size_t length)
|
||||
: size(size)
|
||||
, params(params)
|
||||
, length(length)
|
||||
{}
|
||||
# endif
|
||||
};
|
||||
|
||||
struct criterion_test_extra_data {
|
||||
int sentinel_;
|
||||
enum criterion_test_kind kind_;
|
||||
struct criterion_test_params (*param_)(void);
|
||||
const char *identifier_;
|
||||
const char *file_;
|
||||
unsigned line_;
|
||||
|
|
|
@ -17,6 +17,7 @@ set(SAMPLES
|
|||
theories.c
|
||||
timeout.c
|
||||
redirect.c
|
||||
parameterized.c
|
||||
|
||||
signal.cc
|
||||
report.cc
|
||||
|
|
13
samples/parameterized.c
Normal file
13
samples/parameterized.c
Normal file
|
@ -0,0 +1,13 @@
|
|||
#include <criterion/parameterized.h>
|
||||
|
||||
ParameterizedTestParameters(params, str) {
|
||||
static const char *strings[] = {
|
||||
"foo", "bar", "baz"
|
||||
};
|
||||
|
||||
return cr_make_param_array(const char *, strings, sizeof (strings) / sizeof (const char *));
|
||||
}
|
||||
|
||||
ParameterizedTest(const char *str, params, str) {
|
||||
cr_assert(0, "Parameter: %s", str);
|
||||
}
|
|
@ -99,6 +99,7 @@ struct full_context {
|
|||
struct criterion_test_extra_data suite_data;
|
||||
f_worker_func func;
|
||||
struct pipe_handle pipe;
|
||||
struct test_single_param param;
|
||||
volatile int resumed;
|
||||
};
|
||||
|
||||
|
@ -186,11 +187,22 @@ int resume_child(void) {
|
|||
exit(-1);
|
||||
|
||||
local_ctx = *ctx;
|
||||
struct test_single_param *param = NULL;
|
||||
if (local_ctx.param.size != 0) {
|
||||
param = malloc(sizeof (struct test_single_param) + local_ctx.param->size);
|
||||
*param = (struct test_single_param) {
|
||||
.size = local_ctx.param->size,
|
||||
.ptr = param + 1,
|
||||
};
|
||||
memcpy(param + 1, local_ctx.param->ptr, param->size);
|
||||
}
|
||||
|
||||
g_worker_context = (struct worker_context) {
|
||||
&local_ctx.test,
|
||||
&local_ctx.suite,
|
||||
local_ctx.func,
|
||||
&local_ctx.pipe
|
||||
.test = &local_ctx.test,
|
||||
.suite = &local_ctx.suite,
|
||||
.func = local_ctx.func,
|
||||
.pipe = &local_ctx.pipe,
|
||||
.param = param,
|
||||
};
|
||||
|
||||
local_ctx.test.data = &local_ctx.test_data;
|
||||
|
@ -204,6 +216,7 @@ int resume_child(void) {
|
|||
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
|
||||
|
||||
run_worker(&g_worker_context);
|
||||
free(param);
|
||||
return 1;
|
||||
#else
|
||||
# if defined(__unix__) || defined(__APPLE__)
|
||||
|
@ -266,6 +279,11 @@ s_proc_handle *fork_process() {
|
|||
.resumed = 0,
|
||||
};
|
||||
|
||||
if (g_worker_context.param) {
|
||||
ctx->param = *g_worker_context.param,
|
||||
memcpy(ctx + 1, g_worker_context.param->ptr, g_worker_context.param->size);
|
||||
}
|
||||
|
||||
if (g_worker_context.suite->data)
|
||||
ctx->suite_data = *g_worker_context.suite->data;
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ struct worker_context {
|
|||
struct criterion_suite *suite;
|
||||
f_worker_func func;
|
||||
struct pipe_handle *pipe;
|
||||
struct test_single_param *param;
|
||||
};
|
||||
|
||||
extern struct worker_context g_worker_context;
|
||||
|
|
|
@ -59,6 +59,7 @@ TestSuite();
|
|||
Test(,) {};
|
||||
|
||||
static INLINE void nothing(void) {}
|
||||
static INLINE void nothing_ptr(UNUSED void* ptr) {}
|
||||
|
||||
int cmp_suite(void *a, void *b) {
|
||||
struct criterion_suite *s1 = a, *s2 = b;
|
||||
|
@ -186,7 +187,11 @@ static void run_test_child(struct criterion_test *test,
|
|||
struct timespec_compat ts;
|
||||
if (!setjmp(g_pre_test)) {
|
||||
timer_start(&ts);
|
||||
(test->test ? test->test : nothing)();
|
||||
if (!test->data->param_)
|
||||
(test->test ? test->test : nothing)();
|
||||
else
|
||||
(test->test ? (void(*)(void*)) test->test
|
||||
: nothing_ptr)(g_worker_context.param->ptr);
|
||||
}
|
||||
|
||||
double elapsed_time;
|
||||
|
@ -297,7 +302,8 @@ static void handle_worker_terminated(struct event *ev,
|
|||
static void run_test(struct criterion_global_stats *stats,
|
||||
struct criterion_suite_stats *suite_stats,
|
||||
struct criterion_test *test,
|
||||
struct criterion_suite *suite) {
|
||||
struct criterion_suite *suite,
|
||||
struct test_single_param *param) {
|
||||
|
||||
struct criterion_test_stats *test_stats = test_stats_init(test);
|
||||
struct process *proc = NULL;
|
||||
|
@ -310,7 +316,7 @@ static void run_test(struct criterion_global_stats *stats,
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
proc = spawn_test_worker(test, suite, run_test_child, g_worker_pipe);
|
||||
proc = spawn_test_worker(test, suite, run_test_child, g_worker_pipe, param);
|
||||
if (proc == NULL && !is_runner())
|
||||
goto cleanup;
|
||||
|
||||
|
@ -370,6 +376,38 @@ cleanup:
|
|||
sfree(proc);
|
||||
}
|
||||
|
||||
static void run_test_param(struct criterion_global_stats *stats,
|
||||
struct criterion_suite_stats *suite_stats,
|
||||
struct criterion_test *test,
|
||||
struct criterion_suite *suite) {
|
||||
|
||||
if (!test->data->param_)
|
||||
return;
|
||||
|
||||
struct criterion_test_params params = test->data->param_();
|
||||
for (size_t i = 0; i < params.length; ++i) {
|
||||
struct test_single_param param = { params.size, params.params[i] };
|
||||
|
||||
run_test(stats, suite_stats, test, suite, ¶m);
|
||||
}
|
||||
}
|
||||
|
||||
static void run_test_switch(struct criterion_global_stats *stats,
|
||||
struct criterion_suite_stats *suite_stats,
|
||||
struct criterion_test *test,
|
||||
struct criterion_suite *suite) {
|
||||
|
||||
switch (test->data->kind_) {
|
||||
case CR_TEST_NORMAL:
|
||||
run_test(stats, suite_stats, test, suite, NULL);
|
||||
break;
|
||||
case CR_TEST_PARAMETERIZED:
|
||||
run_test_param(stats, suite_stats, test, suite);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_PCRE
|
||||
void disable_unmatching(struct criterion_test_set *set) {
|
||||
FOREACH_SET(struct criterion_suite_set *s, set->suites) {
|
||||
|
@ -414,7 +452,7 @@ static int criterion_run_all_tests_impl(struct criterion_test_set *set) {
|
|||
abort();
|
||||
|
||||
struct criterion_global_stats *stats = stats_init();
|
||||
map_tests(set, stats, run_test);
|
||||
map_tests(set, stats, run_test_switch);
|
||||
|
||||
int result = is_runner() ? stats->tests_failed == 0 : -1;
|
||||
|
||||
|
|
|
@ -77,12 +77,14 @@ void run_worker(struct worker_context *ctx) {
|
|||
struct process *spawn_test_worker(struct criterion_test *test,
|
||||
struct criterion_suite *suite,
|
||||
f_worker_func func,
|
||||
s_pipe_handle *pipe) {
|
||||
s_pipe_handle *pipe,
|
||||
struct test_single_param *param) {
|
||||
g_worker_context = (struct worker_context) {
|
||||
.test = test,
|
||||
.suite = suite,
|
||||
.func = func,
|
||||
.pipe = pipe
|
||||
.pipe = pipe,
|
||||
.param = param,
|
||||
};
|
||||
|
||||
struct process *ptr = NULL;
|
||||
|
|
|
@ -47,6 +47,11 @@ struct worker_status {
|
|||
struct process_status status;
|
||||
};
|
||||
|
||||
struct test_single_param {
|
||||
size_t size;
|
||||
void *ptr;
|
||||
};
|
||||
|
||||
void run_worker(struct worker_context *ctx);
|
||||
void set_runner_process(void);
|
||||
void unset_runner_process(void);
|
||||
|
@ -56,7 +61,8 @@ struct process_status get_status(int status);
|
|||
struct process *spawn_test_worker(struct criterion_test *test,
|
||||
struct criterion_suite *suite,
|
||||
f_worker_func func,
|
||||
s_pipe_handle *pipe);
|
||||
s_pipe_handle *pipe,
|
||||
struct test_single_param *param);
|
||||
struct event *worker_read_event(struct process *proc);
|
||||
|
||||
#endif /* !PROCESS_H_ */
|
||||
|
|
Loading…
Add table
Reference in a new issue