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