Added parameterized tests

This commit is contained in:
Snaipe 2015-09-17 17:44:47 +02:00
parent 84706900b4
commit 582fa18389
10 changed files with 161 additions and 11 deletions

View file

@ -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__, \

View 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_ */

View file

@ -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_;

View file

@ -17,6 +17,7 @@ set(SAMPLES
theories.c
timeout.c
redirect.c
parameterized.c
signal.cc
report.cc

13
samples/parameterized.c Normal file
View 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);
}

View file

@ -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;

View file

@ -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;

View file

@ -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, &param);
}
}
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;

View file

@ -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;

View file

@ -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_ */