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

[PATCH v2] cmocka: Allow to pass initial data to test cases


Sometimes multiple test cases share the same test function, running it
on different data. To pass this data to test functions we must define
setup function for each data set. It's not very convienient when there
are many states to test.

This commit introduce more elegant way to pass data to tests. The
initial_state field of CMUnitTest structure can be defined by user.
It will be either passed to setup function, which makes any preparation
needed, or it will be passed directly to test function when setup func is
NULL.

Signed-off-by: Pawel Szewczyk <p.szewczyk@xxxxxxxxxxx>
---
 include/cmocka.h            | 25 +++++++++++++++++++++----
 src/cmocka.c                |  3 +++
 tests/test_fixtures.c       | 37 +++++++++++++++++++++++++++++++++++++
 tests/test_group_fixtures.c |  2 ++
 4 files changed, 63 insertions(+), 4 deletions(-)

diff --git a/include/cmocka.h b/include/cmocka.h
index 797fbe2..e4aa5b2 100644
--- a/include/cmocka.h
+++ b/include/cmocka.h
@@ -1489,19 +1489,35 @@ static inline void _unit_test_dummy(void **state) {
 
 
 /** Initializes a CMUnitTest structure. */
-#define cmocka_unit_test(f) { #f, f, NULL, NULL }
+#define cmocka_unit_test(f) { #f, f, NULL, NULL, NULL }
 
 /** Initializes a CMUnitTest structure with a setup function. */
-#define cmocka_unit_test_setup(f, setup) { #f, f, setup, NULL }
+#define cmocka_unit_test_setup(f, setup) { #f, f, setup, NULL, NULL }
 
 /** Initializes a CMUnitTest structure with a teardown function. */
-#define cmocka_unit_test_teardown(f, teardown) { #f, f, NULL, teardown }
+#define cmocka_unit_test_teardown(f, teardown) { #f, f, NULL, teardown, NULL }
 
 /**
  * Initialize an array of CMUnitTest structures with a setup function for a test
  * and a teardown function. Either setup or teardown can be NULL.
  */
-#define cmocka_unit_test_setup_teardown(f, setup, teardown) { #f, f, setup, teardown }
+#define cmocka_unit_test_setup_teardown(f, setup, teardown) { #f, f, setup, teardown, NULL }
+
+/**
+ * Initialize a CMUnitTest structure with given initial state. It will be passed to test
+ * function as an argument later. It can be used when test state does not need special initialization
+ * or was initialized already.
+ * If group state was initialized for this unit test, it won't be overrided by initial state defined here.
+ */
+#define cmocka_unit_test_prestate(f, state) { #f, f, NULL, NULL, state }
+
+/**
+ * Initialize a CMUnitTest structure with given initial state, setup and teardown function. Any of
+ * these values can be NULL. Initial state is passed later to setup function, or directly to test if
+ * none was given.
+ * If group state was initialized for this unit test, it won't be overrided by initial state defined here.
+ */
+#define cmocka_unit_test_prestate_setup_teardown(f, setup, teardown, state) { #f, f, setup, teardown, state }
 
 #define run_tests(tests) _run_tests(tests, sizeof(tests) / sizeof(tests)[0])
 #define run_group_tests(tests) _run_group_tests(tests, sizeof(tests) / sizeof(tests)[0])
@@ -1894,6 +1910,7 @@ struct CMUnitTest {
     CMUnitTestFunction test_func;
     CMFixtureFunction setup_func;
     CMFixtureFunction teardown_func;
+    void *initial_state;
 };
 
 /* Location within some source code. */
diff --git a/src/cmocka.c b/src/cmocka.c
index 9790449..8e2d3ac 100644
--- a/src/cmocka.c
+++ b/src/cmocka.c
@@ -2549,7 +2549,10 @@ int _cmocka_run_group_tests(const char *group_name,
 
             if (group_state != NULL) {
                 cm_tests[i].state = group_state;
+            } else if (cm_tests[i].test->initial_state != NULL) {
+                cm_tests[i].state = cm_tests[i].test->initial_state;
             }
+
             rc = cmocka_run_one_tests(cmtest);
             total_executed++;
             total_runtime += cmtest->runtime;
diff --git a/tests/test_fixtures.c b/tests/test_fixtures.c
index 4597626..6d39487 100644
--- a/tests/test_fixtures.c
+++ b/tests/test_fixtures.c
@@ -31,7 +31,42 @@ static void malloc_teardown_test(void **state)
     assert_non_null(*state);
 }
 
+static int prestate_setup(void **state)
+{
+    int *val = (int *)*state, *a;
+
+    a = malloc(sizeof(int));
+    *a = *val + 1;
+    *state = a;
+
+    return 0;
+}
+
+static int prestate_teardown(void **state)
+{
+	free(*state);
+
+	return 0;
+}
+
+static void prestate_setup_test(void **state)
+{
+    int *a = (int *)*state;
+
+    assert_non_null(a);
+    assert_int_equal(*a, 43);
+}
+
+static void prestate_test(void **state)
+{
+    int *a = (int *)*state;
+
+    assert_non_null(a);
+    assert_int_equal(*a, 42);
+}
+
 int main(void) {
+    int prestate = 42;
     const struct CMUnitTest tests[] = {
         cmocka_unit_test_setup(malloc_setup_test, setup_only),
         cmocka_unit_test_setup(malloc_setup_test, setup_only),
@@ -39,6 +74,8 @@ int main(void) {
         cmocka_unit_test_teardown(malloc_teardown_test, teardown_only),
         cmocka_unit_test_teardown(malloc_teardown_test, teardown_only),
         cmocka_unit_test_teardown(malloc_teardown_test, teardown_only),
+        cmocka_unit_test_prestate(prestate_test, &prestate),
+        cmocka_unit_test_prestate_setup_teardown(prestate_setup_test, prestate_setup, prestate_teardown, &prestate),
     };
 
     return cmocka_run_group_tests(tests, NULL, NULL);
diff --git a/tests/test_group_fixtures.c b/tests/test_group_fixtures.c
index 09f39b1..64f0ab7 100644
--- a/tests/test_group_fixtures.c
+++ b/tests/test_group_fixtures.c
@@ -39,9 +39,11 @@ static void test_value_range(void **state)
 }
 
 int main(void) {
+    int prestate = 1337;
     const struct CMUnitTest tests[] = {
         cmocka_unit_test(test_value_equal),
         cmocka_unit_test(test_value_range),
+	cmocka_unit_test_prestate(test_value_equal, &prestate),
     };
 
     return cmocka_run_group_tests(tests, group_setup, group_teardown);
-- 
1.9.1



Follow-Ups:
Re: [PATCH v2] cmocka: Allow to pass initial data to test casesAndreas Schneider <asn@xxxxxxxxxxxxxx>