1 /*
2 * Copyright (c) 2022 Google LLC
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include "cmdline.h" /* native_posix command line options header */
11 #include "soc.h"
12 #include <zephyr/tc_util.h>
13 #include <zephyr/ztest_test_new.h>
14
15 static const char *test_args;
16 static bool list_tests;
17
add_test_filter_option(void)18 static void add_test_filter_option(void)
19 {
20 static struct args_struct_t test_filter_s[] = {
21 /*
22 * Fields:
23 * manual, mandatory, switch,
24 * option_name, var_name ,type,
25 * destination, callback,
26 * description
27 */
28 { false, false, true, "list", NULL, 'b', (void *)&list_tests, NULL,
29 "List all suite and test cases" },
30 { false, false, false, "test", "suite::test", 's', (void *)&test_args, NULL,
31 "Name of tests to run. Comma separated list formatted as "
32 "\'suiteA::test1,suiteA::test2,suiteB::*\'. An * can be used "
33 "as a wildcard to run all tests within a suite." },
34 ARG_TABLE_ENDMARKER
35 };
36
37 native_add_command_line_opts(test_filter_s);
38 }
39
40 NATIVE_TASK(add_test_filter_option, PRE_BOOT_1, 10);
41
42 /**
43 * @brief Try to shorten a filename by removing the current directory
44 *
45 * This helps to reduce the very long filenames in assertion failures. It
46 * removes the current directory from the filename and returns the rest.
47 * This makes assertions a lot more readable, and sometimes they fit on one
48 * line.
49 *
50 * Overrides implementation in ztest_new.c
51 *
52 * @param file Filename to check
53 * @returns Shortened filename, or @file if it could not be shortened
54 */
ztest_relative_filename(const char * file)55 const char *ztest_relative_filename(const char *file)
56 {
57 const char *cwd;
58 char buf[200];
59
60 cwd = getcwd(buf, sizeof(buf));
61 if (cwd && strlen(file) > strlen(cwd) && !strncmp(file, cwd, strlen(cwd))) {
62 return file + strlen(cwd) + 1; /* move past the trailing '/' */
63 }
64 return file;
65 }
66
67 /**
68 * @brief Helper function to set list_tests
69 *
70 * @param value - Sets list_tests to value
71 */
ztest_set_list_test(bool value)72 void ztest_set_list_test(bool value)
73 {
74 list_tests = value;
75 }
76
77 /**
78 * @brief Helper function to get command line argument for listing tests
79 *
80 * @return true
81 * @return false
82 */
z_ztest_get_list_test(void)83 bool z_ztest_get_list_test(void)
84 {
85 return list_tests;
86 }
87
88 /**
89 * @brief Helper function to get command line test arguments
90 *
91 * @return const char*
92 */
ztest_get_test_args(void)93 const char *ztest_get_test_args(void)
94 {
95 return test_args;
96 }
97
98 /**
99 * @brief Lists registered unit tests in this binary, one per line
100 *
101 * @return int Number of tests in binary
102 */
z_ztest_list_tests(void)103 int z_ztest_list_tests(void)
104 {
105 struct ztest_suite_node *ptr;
106 struct ztest_unit_test *test = NULL;
107 int test_count = 0;
108 static bool list_once = true;
109
110 if (list_once) {
111 for (ptr = _ztest_suite_node_list_start; ptr < _ztest_suite_node_list_end; ++ptr) {
112 test = NULL;
113 while ((test = z_ztest_get_next_test(ptr->name, test)) != NULL) {
114 TC_PRINT("%s::%s\n", test->test_suite_name, test->name);
115 test_count++;
116 }
117 }
118 list_once = false;
119 }
120
121 return test_count;
122 }
123
124 /**
125 * Default entry point for running or listing registered unit tests.
126 *
127 * @param state The current state of the machine as it relates to the test executable.
128 */
z_ztest_run_all(const void * state)129 void z_ztest_run_all(const void *state)
130 {
131 if (z_ztest_get_list_test()) {
132 z_ztest_list_tests();
133 } else {
134 ztest_run_test_suites(state);
135 }
136 }
137
138 /**
139 * @brief Checks if the test_args contains the suite/test name.
140 *
141 * @param suite_name
142 * @param test_name
143 * @return true
144 * @return false
145 */
z_ztest_testargs_contains(const char * suite_name,const char * test_name)146 static bool z_ztest_testargs_contains(const char *suite_name, const char *test_name)
147 {
148 bool found = false;
149 char *test_args_local = strdup(test_args);
150 char *suite_test_pair;
151 char *last_suite_test_pair;
152 char *suite_arg;
153 char *test_arg;
154 char *last_arg;
155
156 suite_test_pair = strtok_r(test_args_local, ",", &last_suite_test_pair);
157
158 while (suite_test_pair && !found) {
159 suite_arg = strtok_r(suite_test_pair, ":", &last_arg);
160 test_arg = strtok_r(NULL, ":", &last_arg);
161
162 found = !strcmp(suite_arg, suite_name);
163 if (test_name) {
164 found &= !strcmp(test_arg, "*") ||
165 !strcmp(test_arg, test_name);
166 }
167
168 suite_test_pair = strtok_r(NULL, ",", &last_suite_test_pair);
169 }
170
171 free(test_args_local);
172 return found;
173 }
174
175 /**
176 * @brief Determines if the test case should run based on test cases listed
177 * in the command line argument.
178 *
179 * Overrides implementation in ztest_new.c
180 *
181 * @param suite - name of test suite
182 * @param test - name of unit test
183 * @return true
184 * @return false
185 */
z_ztest_should_test_run(const char * suite,const char * test)186 bool z_ztest_should_test_run(const char *suite, const char *test)
187 {
188 bool run_test = false;
189
190 run_test = (test_args == NULL ||
191 z_ztest_testargs_contains(suite, test));
192
193 return run_test;
194 }
195
196 /**
197 * @brief Determines if the test suite should run based on test cases listed
198 * in the command line argument.
199 *
200 * Overrides implementation in ztest_new.c
201 *
202 * @param state The current state of the machine as it relates to the test
203 * executable.
204 * @param suite Pointer to ztest_suite_node
205 * @return true
206 * @return false
207 */
z_ztest_should_suite_run(const void * state,struct ztest_suite_node * suite)208 bool z_ztest_should_suite_run(const void *state, struct ztest_suite_node *suite)
209 {
210 bool run_suite = true;
211
212 if (test_args != NULL && !z_ztest_testargs_contains(suite->name, NULL)) {
213 run_suite = false;
214 suite->stats->run_count++;
215 } else if (suite->predicate != NULL) {
216 run_suite = suite->predicate(state);
217 }
218
219 return run_suite;
220 }
221
222 ZTEST_DMEM const struct ztest_arch_api ztest_api = {
223 .run_all = z_ztest_run_all,
224 .should_suite_run = z_ztest_should_suite_run,
225 .should_test_run = z_ztest_should_test_run
226 };
227