diff --git a/doc/develop/test/ztest.rst b/doc/develop/test/ztest.rst index 31b90193785..5def69164f2 100644 --- a/doc/develop/test/ztest.rst +++ b/doc/develop/test/ztest.rst @@ -46,10 +46,13 @@ Below is an example of a test suite using a predicate: Adding tests to a suite *********************** -There are 4 macros used to add a test to a suite, they are: +There are 5 macros used to add a test to a suite, they are: * :c:macro:`ZTEST` ``(suite_name, test_name)`` - Which can be used to add a test by ``test_name`` to a given suite by ``suite_name``. +* :c:macro:`ZTEST_P` ``(suite_name, test_name)`` - Add a parameterized test to a given suite by specifying + the ``suite_name`` and ``test_name``. You can then access the passed parameter within + the body of the test using the ``data`` pointer. * :c:macro:`ZTEST_USER` ``(suite_name, test_name)`` - Which behaves the same as :c:macro:`ZTEST`, only that when :kconfig:option:`CONFIG_USERSPACE` is enabled, then the test will be run in a userspace thread. diff --git a/subsys/testsuite/ztest/include/zephyr/ztest_test.h b/subsys/testsuite/ztest/include/zephyr/ztest_test.h index ab693e53ce6..bec180965e1 100644 --- a/subsys/testsuite/ztest/include/zephyr/ztest_test.h +++ b/subsys/testsuite/ztest/include/zephyr/ztest_test.h @@ -342,9 +342,11 @@ void ztest_verify_all_test_suites_ran(void); * @param shuffle Shuffle tests * @param suite_iter Test suite repetitions. * @param case_iter Test case repetitions. + * @param param Parameter passing into test. * @return Negative value if the test suite never ran; otherwise, return the number of failures. */ -int z_ztest_run_test_suite(const char *name, bool shuffle, int suite_iter, int case_iter); +int z_ztest_run_test_suite(const char *name, bool shuffle, int suite_iter, + int case_iter, void *param); /** * @brief Returns next test within suite. @@ -404,6 +406,26 @@ void ztest_test_skip(void); void ztest_skip_failed_assumption(void); +#define Z_TEST_P(suite, fn, t_options) \ + struct ztest_unit_test_stats z_ztest_unit_test_stats_##suite##_##fn; \ + static void _##suite##_##fn##_wrapper(void *data); \ + static void suite##_##fn(void *data); \ + static STRUCT_SECTION_ITERABLE(ztest_unit_test, z_ztest_unit_test__##suite##__##fn) = { \ + .test_suite_name = STRINGIFY(suite), \ + .name = STRINGIFY(fn), \ + .test = (_##suite##_##fn##_wrapper), \ + .thread_options = t_options, \ + .stats = &z_ztest_unit_test_stats_##suite##_##fn \ + }; \ + static void _##suite##_##fn##_wrapper(void *wrapper_data) \ + { \ + suite##_##fn(wrapper_data); \ + } \ + static inline void suite##_##fn(void *data) + + +#define ZTEST_P(suite, fn) Z_TEST_P(suite, fn, 0) + #define Z_TEST(suite, fn, t_options, use_fixture) \ struct ztest_unit_test_stats z_ztest_unit_test_stats_##suite##_##fn; \ static void _##suite##_##fn##_wrapper(void *data); \ diff --git a/subsys/testsuite/ztest/src/ztest.c b/subsys/testsuite/ztest/src/ztest.c index a2b3c547cbb..279ca4d9ac0 100644 --- a/subsys/testsuite/ztest/src/ztest.c +++ b/subsys/testsuite/ztest/src/ztest.c @@ -789,7 +789,7 @@ static void z_ztest_shuffle(bool shuffle, void *dest[], intptr_t start, size_t n #endif static int z_ztest_run_test_suite_ptr(struct ztest_suite_node *suite, bool shuffle, int suite_iter, - int case_iter) + int case_iter, void *param) { struct ztest_unit_test *test = NULL; void *data = NULL; @@ -828,6 +828,9 @@ static int z_ztest_run_test_suite_ptr(struct ztest_suite_node *suite, bool shuff if (test_result != ZTEST_RESULT_SUITE_FAIL && suite->setup != NULL) { data = suite->setup(); } + if (param != NULL) { + data = param; + } for (int i = 0; i < case_iter; i++) { #ifdef CONFIG_ZTEST_SHUFFLE @@ -899,10 +902,11 @@ static int z_ztest_run_test_suite_ptr(struct ztest_suite_node *suite, bool shuff return fail; } -int z_ztest_run_test_suite(const char *name, bool shuffle, int suite_iter, int case_iter) +int z_ztest_run_test_suite(const char *name, bool shuffle, + int suite_iter, int case_iter, void *param) { return z_ztest_run_test_suite_ptr(ztest_find_test_suite(name), shuffle, suite_iter, - case_iter); + case_iter, param); } #ifdef CONFIG_USERSPACE @@ -1053,14 +1057,15 @@ static void __ztest_show_suite_summary(void) } static int __ztest_run_test_suite(struct ztest_suite_node *ptr, const void *state, bool shuffle, - int suite_iter, int case_iter) + int suite_iter, int case_iter, void *param) { struct ztest_suite_stats *stats = ptr->stats; int count = 0; for (int i = 0; i < suite_iter; i++) { if (ztest_api.should_suite_run(state, ptr)) { - int fail = z_ztest_run_test_suite_ptr(ptr, shuffle, suite_iter, case_iter); + int fail = z_ztest_run_test_suite_ptr(ptr, shuffle, + suite_iter, case_iter, param); count++; stats->run_count++; @@ -1076,7 +1081,7 @@ static int __ztest_run_test_suite(struct ztest_suite_node *ptr, const void *stat int z_impl_ztest_run_test_suites(const void *state, bool shuffle, int suite_iter, int case_iter) { int count = 0; - + void *param = NULL; if (test_status == ZTEST_STATUS_CRITICAL_ERROR) { return count; } @@ -1096,7 +1101,7 @@ int z_impl_ztest_run_test_suites(const void *state, bool shuffle, int suite_iter } for (size_t i = 0; i < ZTEST_SUITE_COUNT; ++i) { count += __ztest_run_test_suite(suites_to_run[i], state, shuffle, suite_iter, - case_iter); + case_iter, param); /* Stop running tests if we have a critical error or if we have a failure and * FAIL_FAST was set */ @@ -1109,7 +1114,7 @@ int z_impl_ztest_run_test_suites(const void *state, bool shuffle, int suite_iter for (struct ztest_suite_node *ptr = _ztest_suite_node_list_start; ptr < _ztest_suite_node_list_end; ++ptr) { __ztest_init_unit_test_result_for_suite(ptr); - count += __ztest_run_test_suite(ptr, state, shuffle, suite_iter, case_iter); + count += __ztest_run_test_suite(ptr, state, shuffle, suite_iter, case_iter, param); /* Stop running tests if we have a critical error or if we have a failure and * FAIL_FAST was set */ @@ -1322,10 +1327,10 @@ static int cmd_run_suite(const struct shell *sh, size_t argc, char **argv) int opt_index = 0; int val; int opt_num = 0; - + void *param = NULL; int repeat_iter = 1; - while ((opt = getopt_long(argc, argv, "r:", long_options, &opt_index)) != -1) { + while ((opt = getopt_long(argc, argv, "r:p:", long_options, &opt_index)) != -1) { state = getopt_state_get(); switch (opt) { case 'r': @@ -1338,6 +1343,10 @@ static int cmd_run_suite(const struct shell *sh, size_t argc, char **argv) repeat_iter = val; opt_num++; break; + case 'p': + param = state->optarg; + opt_num++; + break; default: shell_fprintf(sh, SHELL_ERROR, "Invalid option or option usage: %s\n", argv[opt_index + 1]); @@ -1349,10 +1358,10 @@ static int cmd_run_suite(const struct shell *sh, size_t argc, char **argv) const char *shell_command = argv[0]; /* - * This if statement sets the appropriate test argument for ztest_set_test_args. - * If the optional argument is used (opt_num == 1), it sets the test argument to the third element (argv[3]). - * If the optional argument is not used, it sets the test argument to the first element (argv[1]). - */ + * This if statement determines which argv contains the test name. + * If the optional argument is used, the test name is in the third + * argv instead of the first. + */ if (opt_num == 1) { ztest_set_test_args(argv[3]); } else { @@ -1363,9 +1372,9 @@ static int cmd_run_suite(const struct shell *sh, size_t argc, char **argv) ptr < _ztest_suite_node_list_end; ++ptr) { __ztest_init_unit_test_result_for_suite(ptr); if (strcmp(shell_command, "run-testcase") == 0) { - count += __ztest_run_test_suite(ptr, NULL, shuffle, 1, repeat_iter); + count += __ztest_run_test_suite(ptr, NULL, shuffle, 1, repeat_iter, param); } else if (strcmp(shell_command, "run-testsuite") == 0) { - count += __ztest_run_test_suite(ptr, NULL, shuffle, repeat_iter, 1); + count += __ztest_run_test_suite(ptr, NULL, shuffle, repeat_iter, 1, NULL); } if (test_status == ZTEST_STATUS_CRITICAL_ERROR || (test_status == ZTEST_STATUS_HAS_FAILURE && FAIL_FAST)) {