[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Support for test groups


Hi,

I've started to hack on test groups. Here is an unfinished patch for test 
group support.


Comments are welcome.


	-- andreas
From 14a3ec7d2c6f4577bcd1734eff4c2974681c594b Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn@xxxxxxxxxxxxxx>
Date: Mon, 23 Dec 2013 19:05:14 +0100
Subject: [PATCH 1/2] WIP: Add support for test groups.

Signed-off-by: Andreas Schneider <asn@xxxxxxxxxxxxxx>
---
 include/cmocka.h |  18 +++++++
 src/cmocka.c     | 144 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 162 insertions(+)

diff --git a/include/cmocka.h b/include/cmocka.h
index 960bf6b..96bef94 100644
--- a/include/cmocka.h
+++ b/include/cmocka.h
@@ -1337,6 +1337,12 @@ int run_test(#function);
     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.
@@ -1397,6 +1403,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])
+
 /** @} */
 
 /**
@@ -1601,6 +1609,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;
 
 /*
@@ -1614,6 +1624,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 {
@@ -1752,6 +1768,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, ...) PRINTF_ATTRIBUTE(1, 2);
diff --git a/src/cmocka.c b/src/cmocka.c
index b4de262..602cd94 100644
--- a/src/cmocka.c
+++ b/src/cmocka.c
@@ -1895,3 +1895,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;
+}
-- 
1.8.5.2


Follow-Ups:
Re: Support for test groupsJames Grenning <james@xxxxxxxxxxxx>