From 4a75af27b81429204703f9d17f8cab6b3828aa89 Mon Sep 17 00:00:00 2001 From: Filipe Brandenburger Date: Tue, 12 Jun 2018 10:08:07 -0700 Subject: [PATCH] Fix START_TEST to look like valid C code. Instead of exporting the defined name as a bare function, export a struct that has a pointer to the function, but also its name, file and line number where it is defined. Store that information into a new `struct TTest`. After this commit, START_TEST() will create three definitions: - _fn: The actual function; - _ttest: A `struct TTest` with the information about it; - : A pointer to _ttest. Functions `tcase_add_test()` and friends are updated to take a `TTest *` argument rather than a `TFun` and separate name. The runners are updated to find that information inside the linked `tc->ttest`. The call to `tcase_fn_start()` is moved from the defined functions to the runners (both the "fork" and the "nofork" one) which call it just before invoking the test function. A nice side-effect is that END_TEST is now optional, though the empty `#define` is kept for backwards compability. v2: Initialize the struct TTest by position to be compatible with older compilers that do not recognize named fields (e.g. VS 2010, VS 2012.) Tested: - `make check` still passes. - Removing END_TEST from test cases still produces valid code that builds and passes tests. --- src/check.c | 10 +++++----- src/check.h.in | 51 +++++++++++++++++++++++++++++++----------------- src/check_impl.h | 3 +-- src/check_log.c | 2 +- src/check_run.c | 10 ++++++---- 5 files changed, 46 insertions(+), 30 deletions(-) diff --git a/src/check.c b/src/check.c index e42636ed..9f9b251c 100644 --- a/src/check.c +++ b/src/check.c @@ -247,21 +247,21 @@ void suite_add_tcase(Suite * s, TCase * tc) check_list_add_end(s->tclst, tc); } -void _tcase_add_test(TCase * tc, TFun fn, const char *name, int _signal, - int allowed_exit_value, int start, int end) +void _tcase_add_test(TCase * tc, const TTest * ttest, + int _signal, int allowed_exit_value, + int start, int end) { TF *tf; - if(tc == NULL || fn == NULL || name == NULL) + if(tc == NULL || ttest == NULL) return; tf = (TF *)emalloc(sizeof(TF)); /* freed in tcase_free */ - tf->fn = fn; + tf->ttest = ttest; tf->loop_start = start; tf->loop_end = end; tf->signal = _signal; /* 0 means no signal expected */ tf->allowed_exit_value = (WEXITSTATUS_MASK & allowed_exit_value); /* 0 is default successful exit */ - tf->name = name; check_list_add_end(tc->tflst, tf); } diff --git a/src/check.h.in b/src/check.h.in index 9e03d206..0152c725 100644 --- a/src/check.h.in +++ b/src/check.h.in @@ -121,6 +121,16 @@ typedef void (*SFun) (void); */ typedef struct Suite Suite; +/** + * Type for a test, which wraps a test function + */ +typedef struct TTest { + const char *name; + TFun fn; + const char *file; + int line; +} TTest; + /** * Creates a test suite with the given name. * @@ -214,8 +224,8 @@ CK_DLL_EXP void CK_EXPORT tcase_set_tags(TCase * tc, * * @since 0.9.2 * */ -#define tcase_add_test_raise_signal(tc,tf,signal) \ - _tcase_add_test((tc),(tf),"" # tf "",(signal), 0, 0, 1) +#define tcase_add_test_raise_signal(tc,ttest,signal) \ + _tcase_add_test((tc),(ttest),(signal), 0, 0, 1) /** * Add a test function with an expected exit value to a test case @@ -229,8 +239,8 @@ CK_DLL_EXP void CK_EXPORT tcase_set_tags(TCase * tc, * * @since 0.9.7 */ -#define tcase_add_exit_test(tc, tf, expected_exit_value) \ - _tcase_add_test((tc),(tf),"" # tf "",0,(expected_exit_value),0,1) +#define tcase_add_exit_test(tc, ttest, expected_exit_value) \ + _tcase_add_test((tc),(ttest),0,(expected_exit_value),0,1) /** * Add a looping test function to a test case @@ -246,8 +256,8 @@ CK_DLL_EXP void CK_EXPORT tcase_set_tags(TCase * tc, * * @since 0.9.4 */ -#define tcase_add_loop_test(tc,tf,s,e) \ - _tcase_add_test((tc),(tf),"" # tf "",0,0,(s),(e)) +#define tcase_add_loop_test(tc,ttest,s,e) \ + _tcase_add_test((tc),(ttest),0,0,(s),(e)) /** * Add a looping test function with signal handling to a test case @@ -267,8 +277,8 @@ CK_DLL_EXP void CK_EXPORT tcase_set_tags(TCase * tc, * * @since 0.9.5 */ -#define tcase_add_loop_test_raise_signal(tc,tf,signal,s,e) \ - _tcase_add_test((tc),(tf),"" # tf "",(signal),0,(s),(e)) +#define tcase_add_loop_test_raise_signal(tc,ttest,signal,s,e) \ + _tcase_add_test((tc),(ttest),(signal),0,(s),(e)) /** * Add a looping test function with an expected exit value to a test case @@ -288,16 +298,15 @@ CK_DLL_EXP void CK_EXPORT tcase_set_tags(TCase * tc, * * @since 0.9.7 */ -#define tcase_add_loop_exit_test(tc,tf,expected_exit_value,s,e) \ - _tcase_add_test((tc),(tf),"" # tf "",0,(expected_exit_value),(s),(e)) +#define tcase_add_loop_exit_test(tc,ttest,expected_exit_value,s,e) \ + _tcase_add_test((tc),(ttest),0,(expected_exit_value),(s),(e)) /* Add a test function to a test case (function version -- use this when the macro won't work */ -CK_DLL_EXP void CK_EXPORT _tcase_add_test(TCase * tc, TFun tf, - const char *fname, int _signal, - int allowed_exit_value, int start, - int end); +CK_DLL_EXP void CK_EXPORT _tcase_add_test(TCase * tc, const TTest * ttest, + int _signal, int allowed_exit_value, + int start, int end); /** * Add unchecked fixture setup/teardown functions to a test case @@ -400,16 +409,22 @@ CK_DLL_EXP const char* CK_EXPORT tcase_name(void); * @since 0.6.0 */ #define START_TEST(__testname)\ -static void __testname (int _i CK_ATTRIBUTE_UNUSED)\ -{\ - tcase_fn_start (""# __testname, __FILE__, __LINE__); +static void __testname ## _fn (int _i CK_ATTRIBUTE_UNUSED);\ +static const TTest __testname ## _ttest = {\ + .name = ""# __testname,\ + .fn = __testname ## _fn,\ + .file = __FILE__,\ + .line = __LINE__,\ +};\ +static const TTest * __testname = & __testname ## _ttest;\ +static void __testname ## _fn (int _i CK_ATTRIBUTE_UNUSED) /** * End a unit test * * @since 0.6.0 */ -#define END_TEST } +#define END_TEST /* * Fail the test case unless expr is false diff --git a/src/check_impl.h b/src/check_impl.h index bddd1868..f4e8c590 100644 --- a/src/check_impl.h +++ b/src/check_impl.h @@ -36,10 +36,9 @@ typedef struct TF { - TFun fn; + const TTest * ttest; int loop_start; int loop_end; - const char *name; int signal; signed char allowed_exit_value; } TF; diff --git a/src/check_log.c b/src/check_log.c index 2af83210..c785b33c 100644 --- a/src/check_log.c +++ b/src/check_log.c @@ -152,7 +152,7 @@ void log_test_start(SRunner * sr, TCase * tc, TF * tfun) { char buffer[100]; - snprintf(buffer, 99, "%s:%s", tc->name, tfun->name); + snprintf(buffer, 99, "%s:%s", tc->name, tfun->ttest->name); srunner_send_evt(sr, buffer, CLSTART_T); } diff --git a/src/check_run.c b/src/check_run.c index da1f40f1..7e212e02 100644 --- a/src/check_run.c +++ b/src/check_run.c @@ -415,11 +415,12 @@ static TestResult *tcase_run_tfun_nofork(SRunner * sr, TCase * tc, TF * tfun, clock_gettime(check_get_clockid(), &ts_start); if(0 == setjmp(error_jmp_buffer)) { - tfun->fn(i); + tcase_fn_start(tfun->ttest->name, tfun->ttest->file, tfun->ttest->line); + tfun->ttest->fn(i); } clock_gettime(check_get_clockid(), &ts_end); tcase_run_checked_teardown(tc); - return receive_result_info_nofork(tc->name, tfun->name, i, + return receive_result_info_nofork(tc->name, tfun->ttest->name, i, DIFF_IN_USEC(ts_start, ts_end)); } @@ -491,7 +492,8 @@ static TestResult *tcase_run_tfun_fork(SRunner * sr, TCase * tc, TF * tfun, tr = tcase_run_checked_setup(sr, tc); free(tr); clock_gettime(check_get_clockid(), &ts_start); - tfun->fn(i); + tcase_fn_start(tfun->ttest->name, tfun->ttest->file, tfun->ttest->line); + tfun->ttest->fn(i); clock_gettime(check_get_clockid(), &ts_end); tcase_run_checked_teardown(tc); send_duration_info(DIFF_IN_USEC(ts_start, ts_end)); @@ -535,7 +537,7 @@ static TestResult *tcase_run_tfun_fork(SRunner * sr, TCase * tc, TF * tfun, killpg(pid, SIGKILL); /* Kill remaining processes. */ - return receive_result_info_fork(tc->name, tfun->name, i, status, + return receive_result_info_fork(tc->name, tfun->ttest->name, i, status, tfun->signal, tfun->allowed_exit_value); }