Skip to content

Commit ca6197c

Browse files
committed
You can dynamic register test cases by cutest_register_case()
1 parent 3530097 commit ca6197c

File tree

4 files changed

+143
-122
lines changed

4 files changed

+143
-122
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88

99
### Features
1010
1. Automatic disable thread support if `Threads` not found.
11-
2. Test case can be unregistered by `cutest_unregister_case()`.
11+
2. You can dynamic register test cases by `cutest_register_case()`.
12+
3. Test case can be unregistered by `cutest_unregister_case()`.
1213

1314

1415
## v3.0.3 (2024/04/23)

include/cutest.h

Lines changed: 119 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ extern "C" {
115115
/**
116116
* @brief Development version.
117117
*/
118-
#define CUTEST_VERSION_PREREL 4
118+
#define CUTEST_VERSION_PREREL 5
119119

120120
/**
121121
* @brief Ensure the api is exposed as C function.
@@ -222,14 +222,10 @@ extern "C" {
222222
const unsigned long number_of_parameterized_data = sizeof(s_tests) / sizeof(s_tests[0]);\
223223
unsigned long i = 0;\
224224
for (i = 0; i < number_of_parameterized_data; i++) {\
225-
s_tests[i].node = CUTEST_MAP_NODE_INIT;\
226-
s_tests[i].info.fixture_name = #fixture;\
227-
s_tests[i].info.case_name = #test;\
228-
s_tests[i].stage.setup = s_cutest_fixture_setup_##fixture;\
229-
s_tests[i].stage.teardown = s_cutest_fixture_teardown_##fixture;\
230-
s_tests[i].stage.body = (void(*)(void*, unsigned long))cb;\
231-
s_tests[i].data.mask = 0;\
232-
s_tests[i].data.randkey = 0;\
225+
cutest_case_init(&s_tests[i], #fixture, #test,\
226+
s_cutest_fixture_setup_##fixture,\
227+
s_cutest_fixture_teardown_##fixture,\
228+
(void(*)(void*, unsigned long))cb);\
233229
s_tests[i].parameterized.type_name = #TYPE;\
234230
s_tests[i].parameterized.test_data_cstr = TEST_STRINGIFY(__VA_ARGS__);\
235231
s_tests[i].parameterized.param_data = s_parameterized_userdata;\
@@ -299,31 +295,12 @@ extern "C" {
299295
cutest_usertest_body_##fixture##_##test();\
300296
}\
301297
TEST_INITIALIZER(cutest_usertest_interface_##fixture##_##test) {\
302-
static cutest_case_t _case_##fixture##_##test = {\
303-
{\
304-
NULL, NULL, NULL,\
305-
}, /* .node */\
306-
{\
307-
#fixture,\
308-
#test,\
309-
}, /* .info */\
310-
{\
311-
s_cutest_fixture_setup_##fixture,\
312-
s_cutest_fixture_teardown_##fixture,\
313-
s_cutest_proxy_##fixture##_##test,\
314-
}, /* .stage */\
315-
{\
316-
0, 0,\
317-
}, /* .data */\
318-
{\
319-
NULL, NULL, NULL, 0,\
320-
}, /* .parameterized */\
321-
};\
322-
static unsigned char s_token = 0;\
323-
if (s_token == 0) {\
324-
s_token = 1;\
325-
cutest_register_case(&_case_##fixture##_##test);\
326-
}\
298+
static cutest_case_t _case_##fixture##_##test;\
299+
cutest_case_init(&_case_##fixture##_##test, #fixture, #test,\
300+
s_cutest_fixture_setup_##fixture,\
301+
s_cutest_fixture_teardown_##fixture,\
302+
s_cutest_proxy_##fixture##_##test);\
303+
cutest_register_case(&_case_##fixture##_##test);\
327304
}\
328305
TEST_C_API void cutest_usertest_body_##fixture##_##test(void)
329306

@@ -345,30 +322,10 @@ extern "C" {
345322
cutest_usertest_body_##fixture##_##test();\
346323
}\
347324
TEST_INITIALIZER(cutest_usertest_interface_##fixture##_##test) {\
348-
static cutest_case_t _case_##fixture##_##test = {\
349-
{\
350-
NULL, NULL, NULL,\
351-
}, /* .node */\
352-
{\
353-
#fixture,\
354-
#test,\
355-
}, /* .info */\
356-
{\
357-
NULL, NULL,\
358-
s_cutest_proxy_##fixture##_##test,\
359-
}, /* .stage */\
360-
{\
361-
0, 0,\
362-
}, /* .data */\
363-
{\
364-
NULL, NULL, NULL, 0,\
365-
}, /* parameterized */\
366-
};\
367-
static unsigned char s_token = 0;\
368-
if (s_token == 0) {\
369-
s_token = 1;\
370-
cutest_register_case(&_case_##fixture##_##test);\
371-
}\
325+
static cutest_case_t _case_##fixture##_##test;\
326+
cutest_case_init(&_case_##fixture##_##test, #fixture,#test,\
327+
NULL, NULL, s_cutest_proxy_##fixture##_##test);\
328+
cutest_register_case(&_case_##fixture##_##test);\
372329
}\
373330
TEST_C_API void cutest_usertest_body_##fixture##_##test(void)
374331

@@ -487,69 +444,6 @@ extern "C" {
487444
#define TEST_JOIN(a, b) TEST_JOIN2(a, b)
488445
#define TEST_JOIN2(a, b) a##b
489446

490-
typedef struct cutest_map_node
491-
{
492-
struct cutest_map_node* __rb_parent_color; /**< father node | color */
493-
struct cutest_map_node* rb_right; /**< right child node */
494-
struct cutest_map_node* rb_left; /**< left child node */
495-
} cutest_map_node_t;
496-
497-
#if defined(__cplusplus)
498-
# define CUTEST_MAP_NODE_INIT { NULL, NULL, NULL }
499-
#else
500-
# define CUTEST_MAP_NODE_INIT (cutest_map_node_t){ NULL, NULL, NULL }
501-
#endif
502-
503-
typedef struct cutest_case
504-
{
505-
cutest_map_node_t node;
506-
507-
struct
508-
{
509-
const char* fixture_name; /**< suit name */
510-
const char* case_name; /**< case name */
511-
} info;
512-
513-
struct
514-
{
515-
void (*setup)(void); /**< setup */
516-
void (*teardown)(void); /**< teardown */
517-
void (*body)(void*, unsigned long); /**< test body */
518-
} stage;
519-
520-
struct
521-
{
522-
unsigned long mask; /**< Internal mask */
523-
unsigned long randkey; /**< Random key */
524-
} data;
525-
526-
struct
527-
{
528-
const char* type_name; /**< User type name. */
529-
const char* test_data_cstr; /**< The C string of user test data. */
530-
void* param_data; /**< Data passed to #cutest_case_t::stage::body */
531-
unsigned long param_idx; /**< Index passed to #cutest_case_t::stage::body */
532-
} parameterized;
533-
} cutest_case_t;
534-
535-
/**
536-
* @brief Register test case.
537-
*
538-
* A registered test case will be automatically executed by #cutest_run_tests().
539-
*
540-
* @note A registered test case can not be unregistered during #cutest_run_tests().
541-
* @see #cutest_unregister_case().
542-
* @param[in,out] tc - Test case.
543-
*/
544-
void cutest_register_case(cutest_case_t* tc);
545-
546-
/**
547-
* @brief Unregister test case.
548-
* @see #cutest_register_case().
549-
* @param[in,out] tc - Test case.
550-
*/
551-
void cutest_unregister_case(cutest_case_t* tc);
552-
553447
/** @endcond */
554448

555449
/**
@@ -739,6 +633,110 @@ void cutest_unregister_case(cutest_case_t* tc);
739633
* @}
740634
*/
741635

636+
/**
637+
* @defgroup TEST_DYNAMIC_REGISTRATION Dynamic register test
638+
*
639+
* Of course, you can also register your test dynamically without using any of #TEST_F(), #TEST_P() or #TEST().
640+
*
641+
* To dynamically register test, you need to register your test case by #cutest_register_case() before #cutest_run_tests(),
642+
* and unregister by #cutest_unregister_case() after all test cases are run.
643+
*
644+
* @warning You cannot unregister test case during #cutest_run_tests().
645+
*
646+
* @{
647+
*/
648+
649+
typedef struct cutest_map_node
650+
{
651+
struct cutest_map_node* __rb_parent_color; /**< father node | color */
652+
struct cutest_map_node* rb_right; /**< right child node */
653+
struct cutest_map_node* rb_left; /**< left child node */
654+
} cutest_map_node_t;
655+
656+
/**
657+
* @brief Test case setup function.
658+
*/
659+
typedef void (*cutest_test_case_setup_fn)(void);
660+
661+
/**
662+
* @brief Test case teardown function.
663+
*/
664+
typedef void (*cutest_test_case_teardown_fn)(void);
665+
666+
/**
667+
* @brief Test case body function.
668+
* @param[in] dat - Data passed to #cutest_case_t::stage::body
669+
* @param[in] idx - Index passed to #cutest_case_t::stage::body
670+
*/
671+
typedef void (*cutest_test_case_body_fn)(void* dat, unsigned long idx);
672+
673+
typedef struct cutest_case
674+
{
675+
cutest_map_node_t node; /**< Node in rbtree. */
676+
677+
struct
678+
{
679+
const char* fixture_name; /**< suit name. */
680+
const char* case_name; /**< case name. */
681+
} info;
682+
683+
struct
684+
{
685+
cutest_test_case_setup_fn setup; /**< setup. */
686+
cutest_test_case_teardown_fn teardown; /**< teardown. */
687+
cutest_test_case_body_fn body; /**< test body. */
688+
} stage;
689+
690+
struct
691+
{
692+
unsigned long mask; /**< Internal mask. */
693+
unsigned long randkey; /**< Random key. */
694+
} data;
695+
696+
struct
697+
{
698+
const char* type_name; /**< User type name. */
699+
const char* test_data_cstr; /**< The C string of user test data. */
700+
void* param_data; /**< Data passed to #cutest_case_t::stage::body */
701+
unsigned long param_idx; /**< Index passed to #cutest_case_t::stage::body */
702+
} parameterized;
703+
} cutest_case_t;
704+
705+
/**
706+
* @brief Initialize test case as normal test.
707+
* @param[out] tc - Test case.
708+
* @param[in] fixture_name - Fixture name.
709+
* @param[in] case_name - Test name.
710+
* @param[in] setup - Setup function.
711+
* @param[in] teardown - Teardown function.
712+
* @param[in] body - Test body function.
713+
*/
714+
void cutest_case_init(cutest_case_t* tc, const char* fixture_name, const char* case_name,
715+
cutest_test_case_setup_fn setup, cutest_test_case_teardown_fn teardown, cutest_test_case_body_fn body);
716+
717+
/**
718+
* @brief Register test case.
719+
*
720+
* A registered test case will be automatically executed by #cutest_run_tests().
721+
*
722+
* @note A registered test case can not be unregistered during #cutest_run_tests().
723+
* @see #cutest_unregister_case().
724+
* @param[in,out] tc - Test case.
725+
*/
726+
void cutest_register_case(cutest_case_t* tc);
727+
728+
/**
729+
* @brief Unregister test case.
730+
* @see #cutest_register_case().
731+
* @param[in,out] tc - Test case.
732+
*/
733+
void cutest_unregister_case(cutest_case_t* tc);
734+
735+
/**
736+
* Group: TEST_DYNAMIC_REGISTRATION
737+
* @}
738+
*/
739+
742740
/**
743741
* @defgroup TEST_ASSERTION Assertion
744742
*

src/cutest.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3347,6 +3347,25 @@ void cutest_unregister_case(cutest_case_t* tc)
33473347
cutest_map_erase(&g_test_ctx.case_table, &tc->node);
33483348
}
33493349

3350+
void cutest_case_init(cutest_case_t* tc, const char* fixture_name, const char* case_name,
3351+
cutest_test_case_setup_fn setup, cutest_test_case_teardown_fn teardown, cutest_test_case_body_fn body)
3352+
{
3353+
const cutest_case_t s_empty_tc = {
3354+
{ NULL, NULL, NULL }, /* .node */
3355+
{ NULL, NULL }, /* .info */
3356+
{ NULL, NULL, NULL }, /* .stage */
3357+
{ 0,0 }, /* .data */
3358+
{ NULL, NULL, NULL, 0 }, /* .parameterized */
3359+
};
3360+
*tc = s_empty_tc;
3361+
3362+
tc->info.fixture_name = fixture_name;
3363+
tc->info.case_name = case_name;
3364+
tc->stage.setup = setup;
3365+
tc->stage.teardown = teardown;
3366+
tc->stage.body = body;
3367+
}
3368+
33503369
int cutest_run_tests(int argc, char* argv[], FILE* out, const cutest_hook_t* hook)
33513370
{
33523371
int ret = 0;

test/unit/case/feature_manual_register.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#define TEST_INITIALIZER(f) \
2+
void f(void)
3+
14
#include "test.h"
25

36
///////////////////////////////////////////////////////////////////////////////

0 commit comments

Comments
 (0)