summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Schneider <asn@cryptomilk.org>2013-12-23 19:05:14 +0100
committerAndreas Schneider <asn@cryptomilk.org>2014-04-11 15:08:45 +0200
commita046988ac4135ec63f6b19172cdcdae7ef123869 (patch)
tree88637e6eae0b688b9c780e5a3f67c3d969b8f1a8
parent93cd14ba4cd46626313ced8582f76a1b1bceb349 (diff)
downloadcmocka-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.h18
-rw-r--r--src/cmocka.c144
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;
+}