diff options
author | Andreas Schneider <asn@cryptomilk.org> | 2013-12-23 19:05:14 +0100 |
---|---|---|
committer | Andreas Schneider <asn@cryptomilk.org> | 2014-04-11 15:08:45 +0200 |
commit | a046988ac4135ec63f6b19172cdcdae7ef123869 (patch) | |
tree | 88637e6eae0b688b9c780e5a3f67c3d969b8f1a8 | |
parent | 93cd14ba4cd46626313ced8582f76a1b1bceb349 (diff) | |
download | cmocka-a046988ac4135ec63f6b19172cdcdae7ef123869.tar.gz cmocka-a046988ac4135ec63f6b19172cdcdae7ef123869.tar.bz2 cmocka-a046988ac4135ec63f6b19172cdcdae7ef123869.zip |
cmocka: Add support for test groups.
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-rw-r--r-- | include/cmocka.h | 18 | ||||
-rw-r--r-- | src/cmocka.c | 144 |
2 files changed, 162 insertions, 0 deletions
diff --git a/include/cmocka.h b/include/cmocka.h index b107f9f..db1d74a 100644 --- a/include/cmocka.h +++ b/include/cmocka.h @@ -1344,6 +1344,12 @@ static inline void _unit_test_dummy(void **state) { unit_test(test), \ _unit_test_teardown(test, teardown) +#define group_test_setup(setup) \ + { "group_" #setup, setup, UNIT_TEST_FUNCTION_TYPE_GROUP_SETUP } + +#define group_test_teardown(teardown) \ + { "group_" #teardown, teardown, UNIT_TEST_FUNCTION_TYPE_GROUP_TEARDOWN } + /** * Initialize an array of UnitTest structures with a setup function for a test * and a teardown function. Either setup or teardown can be NULL. @@ -1404,6 +1410,8 @@ int run_tests(const UnitTest tests[]); #define run_tests(tests) _run_tests(tests, sizeof(tests) / sizeof(tests)[0]) #endif +#define run_group_tests(tests) _run_group_tests(tests, sizeof(tests) / sizeof(tests)[0]) + /** @} */ /** @@ -1608,6 +1616,8 @@ typedef enum UnitTestFunctionType { UNIT_TEST_FUNCTION_TYPE_TEST = 0, UNIT_TEST_FUNCTION_TYPE_SETUP, UNIT_TEST_FUNCTION_TYPE_TEARDOWN, + UNIT_TEST_FUNCTION_TYPE_GROUP_SETUP, + UNIT_TEST_FUNCTION_TYPE_GROUP_TEARDOWN, } UnitTestFunctionType; /* @@ -1621,6 +1631,12 @@ typedef struct UnitTest { UnitTestFunctionType function_type; } UnitTest; +typedef struct GroupTest { + UnitTestFunction setup; + UnitTestFunction teardown; + const UnitTest *tests; + const size_t number_of_tests; +} GroupTest; /* Location within some source code. */ typedef struct SourceLocation { @@ -1759,6 +1775,8 @@ int _run_test( void ** const volatile state, const UnitTestFunctionType function_type, const void* const heap_check_point); int _run_tests(const UnitTest * const tests, const size_t number_of_tests); +int _run_group_tests(const UnitTest * const tests, + const size_t number_of_tests); /* Standard output and error print methods. */ void print_message(const char* const format, ...) CMOCKA_PRINTF_ATTRIBUTE(1, 2); diff --git a/src/cmocka.c b/src/cmocka.c index 23abf7e..78bd5d9 100644 --- a/src/cmocka.c +++ b/src/cmocka.c @@ -1900,3 +1900,147 @@ int _run_tests(const UnitTest * const tests, const size_t number_of_tests) { fail_if_blocks_allocated(check_point, "run_tests"); return (int)total_failed; } + +int _run_group_tests(const UnitTest * const tests, const size_t number_of_tests) +{ + UnitTestFunction setup = NULL; + const char *setup_name; + size_t num_setups = 0; + UnitTestFunction teardown = NULL; + const char *teardown_name; + size_t num_teardowns = 0; + size_t current_test = 0; + size_t i; + + /* Number of tests executed. */ + size_t tests_executed = 0; + /* Number of failed tests. */ + size_t total_failed = 0; + /* Check point of the heap state. */ + const ListNode * const check_point = check_point_allocated_blocks(); + const char** failed_names = (const char**)malloc(number_of_tests * + sizeof(*failed_names)); + void **current_state = NULL; + TestState group_state; + + /* Find setup and teardown function */ + for (i = 0; i < number_of_tests; i++) { + const UnitTest * const test = &tests[i]; + + if (test->function_type == UNIT_TEST_FUNCTION_TYPE_GROUP_SETUP) { + if (setup == NULL) { + setup = test->function; + setup_name = test->name; + num_setups = 1; + } else { + print_error("[ ERROR ] More than one group setup function detected\n"); + exit_test(1); + } + } + + if (test->function_type == UNIT_TEST_FUNCTION_TYPE_GROUP_TEARDOWN) { + if (teardown == NULL) { + teardown = test->function; + teardown_name = test->name; + num_teardowns = 1; + } else { + print_error("[ ERROR ] More than one group teardown function detected\n"); + exit_test(1); + } + } + } + + print_message("[==========] Running %"PRIdS " test(s).\n", + number_of_tests - num_setups - num_teardowns); + + if (setup != NULL) { + int failed; + + group_state.check_point = check_point_allocated_blocks(); + current_state = &group_state.state; + *current_state = NULL; + failed = _run_test(setup_name, + setup, + current_state, + UNIT_TEST_FUNCTION_TYPE_SETUP, + group_state.check_point); + if (failed) { + failed_names[total_failed] = setup_name; + } + + total_failed += failed; + tests_executed++; + } + + while (current_test < number_of_tests) { + int run_test = 0; + const UnitTest * const test = &tests[current_test++]; + if (test->function == NULL) { + continue; + } + + switch (test->function_type) { + case UNIT_TEST_FUNCTION_TYPE_TEST: + run_test = 1; + break; + case UNIT_TEST_FUNCTION_TYPE_SETUP: + case UNIT_TEST_FUNCTION_TYPE_TEARDOWN: + case UNIT_TEST_FUNCTION_TYPE_GROUP_SETUP: + case UNIT_TEST_FUNCTION_TYPE_GROUP_TEARDOWN: + break; + default: + print_error("Invalid unit test function type %d\n", + test->function_type); + break; + } + + if (run_test) { + int failed; + + failed = _run_test(test->name, + test->function, + current_state, + test->function_type, + NULL); + if (failed) { + failed_names[total_failed] = test->name; + } + + total_failed += failed; + tests_executed++; + } + } + + if (teardown != NULL) { + int failed; + + failed = _run_test(teardown_name, + teardown, + current_state, + UNIT_TEST_FUNCTION_TYPE_GROUP_TEARDOWN, + group_state.check_point); + if (failed) { + failed_names[total_failed] = teardown_name; + } + + total_failed += failed; + tests_executed++; + } + + print_message("[==========] %"PRIdS " test(s) run.\n", tests_executed); + print_error("[ PASSED ] %"PRIdS " test(s).\n", tests_executed - total_failed); + + if (total_failed) { + print_error("[ FAILED ] %"PRIdS " test(s), listed below:\n", total_failed); + for (i = 0; i < total_failed; i++) { + print_error("[ FAILED ] %s\n", failed_names[i]); + } + } else { + print_error("\n %"PRIdS " FAILED TEST(S)\n", total_failed); + } + + free((void*)failed_names); + fail_if_blocks_allocated(check_point, "run_group_tests"); + + return (int)total_failed; +} |