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 "cmdline.h" /* native_sim command line options header */
10 #include "soc.h"
11 #include <zephyr/tc_util.h>
12 #include <zephyr/ztest_test.h>
13 #include "nsi_host_trampolines.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.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 = nsi_host_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
100 /**
101 * @brief Lists registered unit tests in this binary, one per line
102 *
103 * @return int Number of tests in binary
104 */
z_ztest_list_tests(void)105 int z_ztest_list_tests(void)
106 {
107 struct ztest_suite_node *ptr;
108 struct ztest_unit_test *test = NULL;
109 int test_count = 0;
110 static bool list_once = true;
111
112 if (list_once) {
113 for (ptr = _ztest_suite_node_list_start; ptr < _ztest_suite_node_list_end; ++ptr) {
114 test = NULL;
115 while ((test = z_ztest_get_next_test(ptr->name, test)) != NULL) {
116 TC_PRINT("%s::%s\n", test->test_suite_name, test->name);
117 test_count++;
118 }
119 }
120 list_once = false;
121 }
122
123 return test_count;
124 }
125
126 /**
127 * Default entry point for running or listing registered unit tests.
128 *
129 * @param state The current state of the machine as it relates to the test executable.
130 */
z_ztest_run_all(const void * state,bool shuffle,int suite_iter,int case_iter)131 void z_ztest_run_all(const void *state, bool shuffle, int suite_iter, int case_iter)
132 {
133 if (z_ztest_get_list_test()) {
134 z_ztest_list_tests();
135 } else {
136 ztest_run_test_suites(state, shuffle, suite_iter, case_iter);
137 }
138 }
139
140 /**
141 * @brief Checks if the test_args contains the suite/test name.
142 *
143 * @param suite_name
144 * @param test_name
145 * @return true
146 * @return false
147 */
z_ztest_testargs_contains(const char * suite_name,const char * test_name)148 static bool z_ztest_testargs_contains(const char *suite_name, const char *test_name)
149 {
150 bool found = false;
151 char *test_args_local = nsi_host_strdup(test_args);
152 char *suite_test_pair;
153 char *last_suite_test_pair;
154 char *suite_arg;
155 char *test_arg;
156 char *last_arg;
157
158 suite_test_pair = strtok_r(test_args_local, ",", &last_suite_test_pair);
159
160 while (suite_test_pair && !found) {
161 suite_arg = strtok_r(suite_test_pair, ":", &last_arg);
162 test_arg = strtok_r(NULL, ":", &last_arg);
163
164 found = !strcmp(suite_arg, suite_name);
165 if (test_name) {
166 found &= !strcmp(test_arg, "*") ||
167 !strcmp(test_arg, test_name);
168 }
169
170 suite_test_pair = strtok_r(NULL, ",", &last_suite_test_pair);
171 }
172
173 nsi_host_free(test_args_local);
174 return found;
175 }
176
177 /**
178 * @brief Determines if the test case should run based on test cases listed
179 * in the command line argument.
180 *
181 * Overrides implementation in ztest.c
182 *
183 * @param suite - name of test suite
184 * @param test - name of unit test
185 * @return true
186 * @return false
187 */
z_ztest_should_test_run(const char * suite,const char * test)188 bool z_ztest_should_test_run(const char *suite, const char *test)
189 {
190 bool run_test = false;
191
192 run_test = (test_args == NULL ||
193 z_ztest_testargs_contains(suite, test));
194
195 return run_test;
196 }
197
198 /**
199 * @brief Determines if the test suite should run based on test cases listed
200 * in the command line argument.
201 *
202 * Overrides implementation in ztest.c
203 *
204 * @param state The current state of the machine as it relates to the test
205 * executable.
206 * @param suite Pointer to ztest_suite_node
207 * @return true
208 * @return false
209 */
z_ztest_should_suite_run(const void * state,struct ztest_suite_node * suite)210 bool z_ztest_should_suite_run(const void *state, struct ztest_suite_node *suite)
211 {
212 bool run_suite = true;
213
214 if (test_args != NULL && !z_ztest_testargs_contains(suite->name, NULL)) {
215 run_suite = false;
216 suite->stats->run_count++;
217 } else if (suite->predicate != NULL) {
218 run_suite = suite->predicate(state);
219 }
220
221 return run_suite;
222 }
223
224 ZTEST_DMEM const struct ztest_arch_api ztest_api = {
225 .run_all = z_ztest_run_all,
226 .should_suite_run = z_ztest_should_suite_run,
227 .should_test_run = z_ztest_should_test_run
228 };
229