blob: 3925a391de1bea1d97b0a4800266005099cacc1e [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0
Joe Hershberger11dd7cc2015-05-20 14:27:28 -05002/*
3 * (C) Copyright 2015
4 * Joe Hershberger, National Instruments, joe.hershberger@ni.com
Joe Hershberger11dd7cc2015-05-20 14:27:28 -05005 */
6
Joe Hershberger11dd7cc2015-05-20 14:27:28 -05007#include <command.h>
Simon Glass6db8ea52020-07-28 19:41:13 -06008#include <console.h>
Tom Rinidec7ea02024-05-20 13:35:03 -06009#include <vsprintf.h>
Simon Glass81cbe1c2017-11-25 11:57:29 -070010#include <test/test.h>
Simon Glass5722fb22021-03-07 17:34:47 -070011#include <test/ut.h>
Joe Hershberger11dd7cc2015-05-20 14:27:28 -050012
Simon Glass78fd76b2025-01-20 14:25:33 -070013/**
14 * struct suite - A set of tests for a certain topic
15 *
16 * All tests end up in a single 'struct unit_test' linker-list array, in order
17 * of the suite they are in
18 *
19 * @name: Name of suite
20 * @start: First test in suite
21 * @end: End test in suite (points to the first test in the next suite)
Simon Glass46093b32025-01-20 14:26:05 -070022 * @help: Help-string to show for this suite
Simon Glass78fd76b2025-01-20 14:25:33 -070023 */
24struct suite {
25 const char *name;
26 struct unit_test *start;
27 struct unit_test *end;
Simon Glass46093b32025-01-20 14:26:05 -070028 const char *help;
Simon Glass78fd76b2025-01-20 14:25:33 -070029};
30
Simon Glass6685ece2025-01-20 14:25:58 -070031static int do_ut_all(struct unit_test_state *uts, struct cmd_tbl *cmdtp,
32 int flag, int argc, char *const argv[]);
Joe Hershberger11dd7cc2015-05-20 14:27:28 -050033
Simon Glassfb998c22022-10-29 19:47:12 -060034static int do_ut_info(struct cmd_tbl *cmdtp, int flag, int argc,
35 char *const argv[]);
36
Simon Glass623e01c2025-02-07 11:30:55 -070037static int cmd_ut_category(struct unit_test_state *uts, const char *name,
38 const char *prefix, struct unit_test *tests,
39 int n_ents, int argc, char *const argv[])
Simon Glass81cbe1c2017-11-25 11:57:29 -070040{
Simon Glass85ba7c32022-10-29 19:47:13 -060041 const char *test_insert = NULL;
Simon Glass91a187b2022-08-01 07:58:45 -060042 int runs_per_text = 1;
Simon Glass1f1614b2022-10-20 18:22:50 -060043 bool force_run = false;
Simon Glass5722fb22021-03-07 17:34:47 -070044 int ret;
Simon Glass81cbe1c2017-11-25 11:57:29 -070045
Simon Glass1f1614b2022-10-20 18:22:50 -060046 while (argc > 1 && *argv[1] == '-') {
47 const char *str = argv[1];
48
49 switch (str[1]) {
50 case 'r':
51 runs_per_text = dectoul(str + 2, NULL);
52 break;
53 case 'f':
54 force_run = true;
55 break;
Simon Glass85ba7c32022-10-29 19:47:13 -060056 case 'I':
57 test_insert = str + 2;
58 break;
Simon Glass1f1614b2022-10-20 18:22:50 -060059 }
Simon Glass91a187b2022-08-01 07:58:45 -060060 argv++;
Simon Glass85ba7c32022-10-29 19:47:13 -060061 argc--;
Simon Glass91a187b2022-08-01 07:58:45 -060062 }
63
Simon Glass6685ece2025-01-20 14:25:58 -070064 ret = ut_run_list(uts, name, prefix, tests, n_ents,
Simon Glass793a98e2023-11-18 14:05:20 -070065 cmd_arg1(argc, argv), runs_per_text, force_run,
Simon Glass85ba7c32022-10-29 19:47:13 -060066 test_insert);
Simon Glass81cbe1c2017-11-25 11:57:29 -070067
Simon Glass5722fb22021-03-07 17:34:47 -070068 return ret ? CMD_RET_FAILURE : 0;
Simon Glass81cbe1c2017-11-25 11:57:29 -070069}
70
Simon Glass78fd76b2025-01-20 14:25:33 -070071/* declare linker-list symbols for the start and end of a suite */
72#define SUITE_DECL(_name) \
73 ll_start_decl(suite_start_ ## _name, struct unit_test, ut_ ## _name); \
74 ll_end_decl(suite_end_ ## _name, struct unit_test, ut_ ## _name)
75
Simon Glass78fd76b2025-01-20 14:25:33 -070076/* declare a test suite which can be run directly without a subcommand */
Simon Glass46093b32025-01-20 14:26:05 -070077#define SUITE(_name, _help) { \
Simon Glass78fd76b2025-01-20 14:25:33 -070078 #_name, \
79 suite_start_ ## _name, \
80 suite_end_ ## _name, \
Simon Glass46093b32025-01-20 14:26:05 -070081 _help, \
Simon Glass78fd76b2025-01-20 14:25:33 -070082 }
83
Simon Glass4c990702025-01-20 14:26:03 -070084SUITE_DECL(addrmap);
Simon Glass78fd76b2025-01-20 14:25:33 -070085SUITE_DECL(bdinfo);
Simon Glass4c990702025-01-20 14:26:03 -070086SUITE_DECL(bloblist);
87SUITE_DECL(bootm);
Simon Glass78fd76b2025-01-20 14:25:33 -070088SUITE_DECL(bootstd);
89SUITE_DECL(cmd);
90SUITE_DECL(common);
91SUITE_DECL(dm);
92SUITE_DECL(env);
93SUITE_DECL(exit);
94SUITE_DECL(fdt);
Simon Glass04e76d52025-02-07 11:30:39 -070095SUITE_DECL(fdt_overlay);
Simon Glass78fd76b2025-01-20 14:25:33 -070096SUITE_DECL(font);
Simon Glass4c990702025-01-20 14:26:03 -070097SUITE_DECL(hush);
Simon Glass78fd76b2025-01-20 14:25:33 -070098SUITE_DECL(lib);
Simon Glass4c990702025-01-20 14:26:03 -070099SUITE_DECL(loadm);
Simon Glass78fd76b2025-01-20 14:25:33 -0700100SUITE_DECL(log);
101SUITE_DECL(mbr);
Simon Glass78fd76b2025-01-20 14:25:33 -0700102SUITE_DECL(measurement);
Simon Glass4c990702025-01-20 14:26:03 -0700103SUITE_DECL(mem);
104SUITE_DECL(optee);
Simon Glass78fd76b2025-01-20 14:25:33 -0700105SUITE_DECL(pci_mps);
106SUITE_DECL(seama);
Simon Glass4c990702025-01-20 14:26:03 -0700107SUITE_DECL(setexpr);
Simon Glass78fd76b2025-01-20 14:25:33 -0700108SUITE_DECL(upl);
109
110static struct suite suites[] = {
Simon Glass46093b32025-01-20 14:26:05 -0700111 SUITE(addrmap, "very basic test of addrmap command"),
112 SUITE(bdinfo, "bdinfo (board info) command"),
113 SUITE(bloblist, "bloblist implementation"),
114 SUITE(bootm, "bootm command"),
Simon Glassf8573fc2025-02-07 11:30:49 -0700115 SUITE(bootstd, "standard boot implementation"),
Simon Glass46093b32025-01-20 14:26:05 -0700116 SUITE(cmd, "various commands"),
117 SUITE(common, "tests for common/ directory"),
118 SUITE(dm, "driver model"),
119 SUITE(env, "environment"),
120 SUITE(exit, "shell exit and variables"),
121 SUITE(fdt, "fdt command"),
Simon Glass0f50f902025-02-07 11:30:47 -0700122 SUITE(fdt_overlay, "device tree overlays"),
Simon Glass46093b32025-01-20 14:26:05 -0700123 SUITE(font, "font command"),
124 SUITE(hush, "hush behaviour"),
125 SUITE(lib, "library functions"),
126 SUITE(loadm, "loadm command parameters and loading memory blob"),
127 SUITE(log, "logging functions"),
128 SUITE(mbr, "mbr command"),
129 SUITE(measurement, "TPM-based measured boot"),
130 SUITE(mem, "memory-related commands"),
Simon Glass3947f792025-02-07 11:30:52 -0700131 SUITE(optee, "OP-TEE"),
Simon Glass46093b32025-01-20 14:26:05 -0700132 SUITE(pci_mps, "PCI Express Maximum Payload Size"),
133 SUITE(seama, "seama command parameters loading and decoding"),
134 SUITE(setexpr, "setexpr command"),
135 SUITE(upl, "Universal payload support"),
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500136};
137
Simon Glassa3ce1292025-01-20 14:25:57 -0700138/**
139 * has_tests() - Check if a suite has tests, i.e. is supported in this build
140 *
141 * If the suite is run using a command, we have to assume that tests may be
142 * present, since we have no visibility
143 *
144 * @ste: Suite to check
145 * Return: true if supported, false if not
146 */
147static bool has_tests(struct suite *ste)
148{
149 int n_ents = ste->end - ste->start;
150
Simon Glass0a85dd02025-02-07 11:30:54 -0700151 return n_ents;
Simon Glassa3ce1292025-01-20 14:25:57 -0700152}
153
Simon Glass78fd76b2025-01-20 14:25:33 -0700154/** run_suite() - Run a suite of tests */
Simon Glass6685ece2025-01-20 14:25:58 -0700155static int run_suite(struct unit_test_state *uts, struct suite *ste,
156 struct cmd_tbl *cmdtp, int flag, int argc,
157 char *const argv[])
Simon Glass78fd76b2025-01-20 14:25:33 -0700158{
Simon Glass0a85dd02025-02-07 11:30:54 -0700159 int n_ents = ste->end - ste->start;
160 char prefix[30];
Simon Glass78fd76b2025-01-20 14:25:33 -0700161 int ret;
162
Simon Glass78fd76b2025-01-20 14:25:33 -0700163
Simon Glass0a85dd02025-02-07 11:30:54 -0700164 /* use a standard prefix */
165 snprintf(prefix, sizeof(prefix), "%s_test_", ste->name);
166 ret = cmd_ut_category(uts, ste->name, prefix, ste->start, n_ents,
167 argc, argv);
Simon Glass78fd76b2025-01-20 14:25:33 -0700168
169 return ret;
170}
171
Simon Glassbd9b1512025-02-07 11:30:36 -0700172static void show_stats(struct unit_test_state *uts)
173{
174 if (uts->run_count < 2)
175 return;
176
177 ut_report(&uts->total, uts->run_count);
178 if (CONFIG_IS_ENABLED(UNIT_TEST_DURATION) &&
179 uts->total.test_count && uts->worst) {
180 ulong avg = uts->total.duration_ms / uts->total.test_count;
181
182 printf("Average test time: %ld ms, worst case '%s' took %d ms\n",
183 avg, uts->worst->name, uts->worst_ms);
184 }
185}
186
187static void update_stats(struct unit_test_state *uts, const struct suite *ste)
188{
189 if (CONFIG_IS_ENABLED(UNIT_TEST_DURATION) && uts->cur.test_count) {
190 ulong avg;
191
192 avg = uts->cur.duration_ms ?
193 uts->cur.duration_ms /
194 uts->cur.test_count : 0;
195 if (avg > uts->worst_ms) {
196 uts->worst_ms = avg;
197 uts->worst = ste;
198 }
199 }
200}
201
Simon Glass6685ece2025-01-20 14:25:58 -0700202static int do_ut_all(struct unit_test_state *uts, struct cmd_tbl *cmdtp,
203 int flag, int argc, char *const argv[])
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500204{
205 int i;
206 int retval;
207 int any_fail = 0;
208
Simon Glass78fd76b2025-01-20 14:25:33 -0700209 for (i = 0; i < ARRAY_SIZE(suites); i++) {
210 struct suite *ste = &suites[i];
211 char *const argv[] = {(char *)ste->name, NULL};
212
Simon Glassa3ce1292025-01-20 14:25:57 -0700213 if (has_tests(ste)) {
214 printf("----Running %s tests----\n", ste->name);
Simon Glass6685ece2025-01-20 14:25:58 -0700215 retval = run_suite(uts, ste, cmdtp, flag, 1, argv);
Simon Glassa3ce1292025-01-20 14:25:57 -0700216 if (!any_fail)
217 any_fail = retval;
Simon Glassbd9b1512025-02-07 11:30:36 -0700218 update_stats(uts, ste);
Simon Glassa3ce1292025-01-20 14:25:57 -0700219 }
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500220 }
221
222 return any_fail;
223}
224
Simon Glassfb998c22022-10-29 19:47:12 -0600225static int do_ut_info(struct cmd_tbl *cmdtp, int flag, int argc,
226 char *const argv[])
227{
Simon Glassa3ce1292025-01-20 14:25:57 -0700228 int suite_count, i;
Simon Glasscfb38f82025-01-20 14:25:30 -0700229 const char *flags;
230
Simon Glassa3ce1292025-01-20 14:25:57 -0700231 for (suite_count = 0, i = 0; i < ARRAY_SIZE(suites); i++) {
232 struct suite *ste = &suites[i];
233
234 if (has_tests(ste))
235 suite_count++;
236 }
237
238 printf("Test suites: %d\n", suite_count);
Simon Glassfb998c22022-10-29 19:47:12 -0600239 printf("Total tests: %d\n", (int)UNIT_TEST_ALL_COUNT());
240
Simon Glasscfb38f82025-01-20 14:25:30 -0700241 flags = cmd_arg1(argc, argv);
242 if (flags && !strcmp("-s", flags)) {
Simon Glass3669a972025-02-07 11:30:34 -0700243 int i, total;
Simon Glasscfb38f82025-01-20 14:25:30 -0700244
Simon Glass46093b32025-01-20 14:26:05 -0700245 puts("\nTests Suite Purpose");
246 puts("\n----- ------------ -------------------------\n");
Simon Glass3669a972025-02-07 11:30:34 -0700247 for (i = 0, total = 0; i < ARRAY_SIZE(suites); i++) {
Simon Glass78fd76b2025-01-20 14:25:33 -0700248 struct suite *ste = &suites[i];
249 long n_ent = ste->end - ste->start;
250
Simon Glass0a85dd02025-02-07 11:30:54 -0700251 if (n_ent) {
252 printf("%5ld %-13.13s %s\n", n_ent, ste->name,
253 ste->help);
254 total += n_ent;
255 }
Simon Glass78fd76b2025-01-20 14:25:33 -0700256 }
Simon Glass3669a972025-02-07 11:30:34 -0700257 puts("----- ------------ -------------------------\n");
258 printf("%5d %-13.13s\n", total, "Total");
259
260 if (UNIT_TEST_ALL_COUNT() != total)
261 puts("Error: Suite test-count does not match total\n");
Simon Glasscfb38f82025-01-20 14:25:30 -0700262 }
263
Simon Glassfb998c22022-10-29 19:47:12 -0600264 return 0;
265}
266
Simon Glass78fd76b2025-01-20 14:25:33 -0700267static struct suite *find_suite(const char *name)
268{
269 struct suite *ste;
270 int i;
271
272 for (i = 0, ste = suites; i < ARRAY_SIZE(suites); i++, ste++) {
273 if (!strcmp(ste->name, name))
274 return ste;
275 }
276
277 return NULL;
278}
279
Simon Glassed38aef2020-05-10 11:40:03 -0600280static int do_ut(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500281{
Simon Glass6685ece2025-01-20 14:25:58 -0700282 struct unit_test_state uts;
Simon Glass78fd76b2025-01-20 14:25:33 -0700283 struct suite *ste;
Simon Glass70737152025-02-07 11:30:57 -0700284 char *name;
Simon Glass78fd76b2025-01-20 14:25:33 -0700285 int ret;
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500286
287 if (argc < 2)
288 return CMD_RET_USAGE;
289
290 /* drop initial "ut" arg */
291 argc--;
292 argv++;
293
Simon Glass6685ece2025-01-20 14:25:58 -0700294 ut_init_state(&uts);
Simon Glass78fd76b2025-01-20 14:25:33 -0700295 name = argv[0];
296 if (!strcmp(name, "all")) {
Simon Glass6685ece2025-01-20 14:25:58 -0700297 ret = do_ut_all(&uts, cmdtp, flag, argc, argv);
Simon Glass78fd76b2025-01-20 14:25:33 -0700298 } else if (!strcmp(name, "info")) {
299 ret = do_ut_info(cmdtp, flag, argc, argv);
300 } else {
Simon Glass70737152025-02-07 11:30:57 -0700301 int any_fail = 0;
302 const char *p;
303
304 for (; p = strsep(&name, ","), p; name = NULL) {
305 ste = find_suite(p);
306 if (!ste) {
307 printf("Suite '%s' not found\n", p);
308 return CMD_RET_FAILURE;
309 } else if (!has_tests(ste)) {
310 /* perhaps a Kconfig option needs to be set? */
311 printf("Suite '%s' is not enabled\n", p);
312 return CMD_RET_FAILURE;
313 }
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500314
Simon Glass70737152025-02-07 11:30:57 -0700315 ret = run_suite(&uts, ste, cmdtp, flag, argc, argv);
316 if (!any_fail)
317 any_fail = ret;
318 update_stats(&uts, ste);
319 }
320 ret = any_fail;
Simon Glass78fd76b2025-01-20 14:25:33 -0700321 }
Simon Glassbd9b1512025-02-07 11:30:36 -0700322 show_stats(&uts);
Simon Glass78fd76b2025-01-20 14:25:33 -0700323 if (ret)
324 return ret;
Simon Glass6685ece2025-01-20 14:25:58 -0700325 ut_uninit_state(&uts);
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500326
Simon Glass78fd76b2025-01-20 14:25:33 -0700327 return 0;
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500328}
329
Tom Rini03f146c2023-10-07 15:13:08 -0400330U_BOOT_LONGHELP(ut,
Simon Glass154bb8e2022-10-29 19:47:10 -0600331 "[-r] [-f] [<suite>] - run unit tests\n"
332 " -r<runs> Number of times to run each test\n"
333 " -f Force 'manual' tests to run as well\n"
334 " <suite> Test suite to run, or all\n"
335 "\n"
Simon Glassfb998c22022-10-29 19:47:12 -0600336 "\nOptions for <suite>:"
Simon Glass154bb8e2022-10-29 19:47:10 -0600337 "\nall - execute all enabled tests"
Simon Glasscfb38f82025-01-20 14:25:30 -0700338 "\ninfo [-s] - show info about tests [and suites]"
Tom Rini03f146c2023-10-07 15:13:08 -0400339 );
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500340
341U_BOOT_CMD(
342 ut, CONFIG_SYS_MAXARGS, 1, do_ut,
343 "unit tests", ut_help_text
344);