diff --git a/src/util-munit.c b/src/util-munit.c index cf8535e..29c2c8a 100644 --- a/src/util-munit.c +++ b/src/util-munit.c @@ -56,10 +56,42 @@ munit_tests_run(int argc, char **argv) _cleanup_free_ MunitTest *tests = calloc(count, sizeof(*tests)); size_t idx = 0; foreach_test(t) { + size_t nparams = 0; + MunitParameterEnum *parameters = calloc(MUNIT_TEST_MAX_PARAMS, sizeof(*parameters)); + + const char *name = NULL; + char **values = NULL; + for (size_t i = 0; t->params[i]; i++) { + if (t->params[i][0] == '@') { + if (name != NULL) { + assert(nparams < MUNIT_TEST_MAX_PARAMS); + assert(strv_len(values) > 0); + /* Not stripping the @! */ + parameters[nparams].name = xstrdup(name); + parameters[nparams].values = steal(&values); + ++nparams; + } + name = t->params[i]; + } else { + assert(i > 0); /* First one must be a name */ + values = strv_append_strdup(values, t->params[i]); + } + } + if (name != NULL) { + assert(nparams < MUNIT_TEST_MAX_PARAMS); + assert(strv_len(values) > 0); + /* Not stripping the @! */ + parameters[nparams].name = xstrdup(name); + parameters[nparams].values = steal(&values); + ++nparams; + } + MunitTest test = { .name = xaprintf("%s", t->name), .test = t->func, + .parameters = parameters, }; + tests[idx++] = test; } @@ -91,8 +123,10 @@ munit_tests_run(int argc, char **argv) int rc = munit_suite_main(&suite, setup.userdata, setup.argc, setup.argv); - for (idx = 0; idx < count; idx++) + for (idx = 0; idx < count; idx++) { free(tests[idx].name); + free(tests[idx].parameters); + } return rc; } diff --git a/src/util-munit.h b/src/util-munit.h index 26b111b..e57055e 100644 --- a/src/util-munit.h +++ b/src/util-munit.h @@ -41,6 +41,9 @@ #include +/* Random number, bumb if need be */ +#define MUNIT_TEST_MAX_PARAMS 64 + /** * Put at the top of the file somewhere, declares the start/stop for the test section we need. */ @@ -61,6 +64,7 @@ struct test_function { const char *name; /* function name */ const char *file; /* file name */ munit_test_func_t func; /* test function */ + const char *params[MUNIT_TEST_MAX_PARAMS]; } __attribute__((aligned(16))); /** @@ -104,9 +108,34 @@ __attribute__((section("test_functions_section"))) = { \ .name = #_func, \ .func = _func, \ .file = __FILE__, \ + .params = { NULL }, \ }; \ static MunitResult _func(const MunitParameter params[], void *user_data) +/** + * Same as MUNIT test but takes a list of strings that define parameters + * and their values. Parameter names must be prefixed with @, for example: + * MUNIT_TEST_WITH_PARAMS(test_foo, "@x", "1", "2", "@y", "100", "200") { + * const char *x = MUNIT_TEST_PARAM("@x"); + * const char *y = MUNIT_TEST_PARAM("@y"); + * } + */ +#define MUNIT_TEST_WITH_PARAMS(_func, ...) \ +static MunitResult _func(const MunitParameter params[], void *user_data); \ +static const struct test_function _test_##_func \ +__attribute__((used)) \ +__attribute__((section("test_functions_section"))) = { \ + .name = #_func, \ + .func = _func, \ + .file = __FILE__, \ + .params = { __VA_ARGS__, NULL }, \ +}; \ +static MunitResult _func(const MunitParameter params[], void *user_data) + +/* Retrieve the test parameter with the given name */ +#define MUNIT_TEST_PARAM(name_) \ + munit_parameters_get(params, name_) + /** * Defines a struct global_setup_function in a custom ELF section that we can * then find in munit_tests_run() to do setup based on argv and/or pass userdata