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