blob: c4a42ee2e20f4b739a58a6205a1f1c14d4f85820 [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>
Joe Hershberger11dd7cc2015-05-20 14:27:28 -050010#include <test/suites.h>
Simon Glass81cbe1c2017-11-25 11:57:29 -070011#include <test/test.h>
Simon Glass5722fb22021-03-07 17:34:47 -070012#include <test/ut.h>
Joe Hershberger11dd7cc2015-05-20 14:27:28 -050013
Simon Glass78fd76b2025-01-20 14:25:33 -070014/**
15 * struct suite - A set of tests for a certain topic
16 *
17 * All tests end up in a single 'struct unit_test' linker-list array, in order
18 * of the suite they are in
19 *
20 * @name: Name of suite
21 * @start: First test in suite
22 * @end: End test in suite (points to the first test in the next suite)
23 * @cmd: Command to use to run the suite
Simon Glass46093b32025-01-20 14:26:05 -070024 * @help: Help-string to show for this suite
Simon Glass78fd76b2025-01-20 14:25:33 -070025 */
26struct suite {
27 const char *name;
28 struct unit_test *start;
29 struct unit_test *end;
30 ut_cmd_func cmd;
Simon Glass46093b32025-01-20 14:26:05 -070031 const char *help;
Simon Glass78fd76b2025-01-20 14:25:33 -070032};
33
Simon Glass6685ece2025-01-20 14:25:58 -070034static int do_ut_all(struct unit_test_state *uts, struct cmd_tbl *cmdtp,
35 int flag, int argc, char *const argv[]);
Joe Hershberger11dd7cc2015-05-20 14:27:28 -050036
Simon Glassfb998c22022-10-29 19:47:12 -060037static int do_ut_info(struct cmd_tbl *cmdtp, int flag, int argc,
38 char *const argv[]);
39
Simon Glass6685ece2025-01-20 14:25:58 -070040int cmd_ut_category(struct unit_test_state *uts, const char *name,
41 const char *prefix, struct unit_test *tests, int n_ents,
Simon Glassed38aef2020-05-10 11:40:03 -060042 int argc, char *const argv[])
Simon Glass81cbe1c2017-11-25 11:57:29 -070043{
Simon Glass85ba7c32022-10-29 19:47:13 -060044 const char *test_insert = NULL;
Simon Glass91a187b2022-08-01 07:58:45 -060045 int runs_per_text = 1;
Simon Glass1f1614b2022-10-20 18:22:50 -060046 bool force_run = false;
Simon Glass5722fb22021-03-07 17:34:47 -070047 int ret;
Simon Glass81cbe1c2017-11-25 11:57:29 -070048
Simon Glass1f1614b2022-10-20 18:22:50 -060049 while (argc > 1 && *argv[1] == '-') {
50 const char *str = argv[1];
51
52 switch (str[1]) {
53 case 'r':
54 runs_per_text = dectoul(str + 2, NULL);
55 break;
56 case 'f':
57 force_run = true;
58 break;
Simon Glass85ba7c32022-10-29 19:47:13 -060059 case 'I':
60 test_insert = str + 2;
61 break;
Simon Glass1f1614b2022-10-20 18:22:50 -060062 }
Simon Glass91a187b2022-08-01 07:58:45 -060063 argv++;
Simon Glass85ba7c32022-10-29 19:47:13 -060064 argc--;
Simon Glass91a187b2022-08-01 07:58:45 -060065 }
66
Simon Glass6685ece2025-01-20 14:25:58 -070067 ret = ut_run_list(uts, name, prefix, tests, n_ents,
Simon Glass793a98e2023-11-18 14:05:20 -070068 cmd_arg1(argc, argv), runs_per_text, force_run,
Simon Glass85ba7c32022-10-29 19:47:13 -060069 test_insert);
Simon Glass81cbe1c2017-11-25 11:57:29 -070070
Simon Glass5722fb22021-03-07 17:34:47 -070071 return ret ? CMD_RET_FAILURE : 0;
Simon Glass81cbe1c2017-11-25 11:57:29 -070072}
73
Simon Glass78fd76b2025-01-20 14:25:33 -070074/* declare linker-list symbols for the start and end of a suite */
75#define SUITE_DECL(_name) \
76 ll_start_decl(suite_start_ ## _name, struct unit_test, ut_ ## _name); \
77 ll_end_decl(suite_end_ ## _name, struct unit_test, ut_ ## _name)
78
79/* declare a test suite which uses a subcommand to run */
Simon Glass46093b32025-01-20 14:26:05 -070080#define SUITE_CMD(_name, _cmd_func, _help) { \
Simon Glass78fd76b2025-01-20 14:25:33 -070081 #_name, \
82 suite_start_ ## _name, \
83 suite_end_ ## _name, \
84 _cmd_func, \
Simon Glass46093b32025-01-20 14:26:05 -070085 _help, \
Simon Glass78fd76b2025-01-20 14:25:33 -070086 }
87
88/* declare a test suite which can be run directly without a subcommand */
Simon Glass46093b32025-01-20 14:26:05 -070089#define SUITE(_name, _help) { \
Simon Glass78fd76b2025-01-20 14:25:33 -070090 #_name, \
91 suite_start_ ## _name, \
92 suite_end_ ## _name, \
93 NULL, \
Simon Glass46093b32025-01-20 14:26:05 -070094 _help, \
Simon Glass78fd76b2025-01-20 14:25:33 -070095 }
96
Simon Glass4c990702025-01-20 14:26:03 -070097SUITE_DECL(addrmap);
Simon Glass78fd76b2025-01-20 14:25:33 -070098SUITE_DECL(bdinfo);
Simon Glass4c990702025-01-20 14:26:03 -070099SUITE_DECL(bloblist);
100SUITE_DECL(bootm);
Simon Glass78fd76b2025-01-20 14:25:33 -0700101SUITE_DECL(bootstd);
102SUITE_DECL(cmd);
103SUITE_DECL(common);
104SUITE_DECL(dm);
105SUITE_DECL(env);
106SUITE_DECL(exit);
107SUITE_DECL(fdt);
Simon Glass04e76d52025-02-07 11:30:39 -0700108SUITE_DECL(fdt_overlay);
Simon Glass78fd76b2025-01-20 14:25:33 -0700109SUITE_DECL(font);
Simon Glass4c990702025-01-20 14:26:03 -0700110SUITE_DECL(hush);
Simon Glass78fd76b2025-01-20 14:25:33 -0700111SUITE_DECL(lib);
Simon Glass4c990702025-01-20 14:26:03 -0700112SUITE_DECL(loadm);
Simon Glass78fd76b2025-01-20 14:25:33 -0700113SUITE_DECL(log);
114SUITE_DECL(mbr);
Simon Glass78fd76b2025-01-20 14:25:33 -0700115SUITE_DECL(measurement);
Simon Glass4c990702025-01-20 14:26:03 -0700116SUITE_DECL(mem);
117SUITE_DECL(optee);
Simon Glass78fd76b2025-01-20 14:25:33 -0700118SUITE_DECL(pci_mps);
119SUITE_DECL(seama);
Simon Glass4c990702025-01-20 14:26:03 -0700120SUITE_DECL(setexpr);
Simon Glass78fd76b2025-01-20 14:25:33 -0700121SUITE_DECL(upl);
122
123static struct suite suites[] = {
Simon Glass46093b32025-01-20 14:26:05 -0700124 SUITE(addrmap, "very basic test of addrmap command"),
125 SUITE(bdinfo, "bdinfo (board info) command"),
126 SUITE(bloblist, "bloblist implementation"),
127 SUITE(bootm, "bootm command"),
Simon Glass804aa372023-10-01 19:15:15 -0600128#ifdef CONFIG_UT_BOOTSTD
Simon Glass46093b32025-01-20 14:26:05 -0700129 SUITE_CMD(bootstd, do_ut_bootstd, "standard boot implementation"),
Simon Glassb255efc2022-04-24 23:31:24 -0600130#endif
Simon Glass46093b32025-01-20 14:26:05 -0700131 SUITE(cmd, "various commands"),
132 SUITE(common, "tests for common/ directory"),
133 SUITE(dm, "driver model"),
134 SUITE(env, "environment"),
135 SUITE(exit, "shell exit and variables"),
136 SUITE(fdt, "fdt command"),
Simon Glass0f50f902025-02-07 11:30:47 -0700137 SUITE(fdt_overlay, "device tree overlays"),
Simon Glass46093b32025-01-20 14:26:05 -0700138 SUITE(font, "font command"),
139 SUITE(hush, "hush behaviour"),
140 SUITE(lib, "library functions"),
141 SUITE(loadm, "loadm command parameters and loading memory blob"),
142 SUITE(log, "logging functions"),
143 SUITE(mbr, "mbr command"),
144 SUITE(measurement, "TPM-based measured boot"),
145 SUITE(mem, "memory-related commands"),
Heiko Stuebner1c9bb9b2019-10-23 16:46:41 +0200146#ifdef CONFIG_UT_OPTEE
Simon Glass46093b32025-01-20 14:26:05 -0700147 SUITE_CMD(optee, do_ut_optee, "OP-TEE"),
Heiko Stuebner1c9bb9b2019-10-23 16:46:41 +0200148#endif
Simon Glass46093b32025-01-20 14:26:05 -0700149 SUITE(pci_mps, "PCI Express Maximum Payload Size"),
150 SUITE(seama, "seama command parameters loading and decoding"),
151 SUITE(setexpr, "setexpr command"),
152 SUITE(upl, "Universal payload support"),
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500153};
154
Simon Glassa3ce1292025-01-20 14:25:57 -0700155/**
156 * has_tests() - Check if a suite has tests, i.e. is supported in this build
157 *
158 * If the suite is run using a command, we have to assume that tests may be
159 * present, since we have no visibility
160 *
161 * @ste: Suite to check
162 * Return: true if supported, false if not
163 */
164static bool has_tests(struct suite *ste)
165{
166 int n_ents = ste->end - ste->start;
167
168 return n_ents || ste->cmd;
169}
170
Simon Glass78fd76b2025-01-20 14:25:33 -0700171/** run_suite() - Run a suite of tests */
Simon Glass6685ece2025-01-20 14:25:58 -0700172static int run_suite(struct unit_test_state *uts, struct suite *ste,
173 struct cmd_tbl *cmdtp, int flag, int argc,
174 char *const argv[])
Simon Glass78fd76b2025-01-20 14:25:33 -0700175{
176 int ret;
177
178 if (ste->cmd) {
Simon Glass6685ece2025-01-20 14:25:58 -0700179 ret = ste->cmd(uts, cmdtp, flag, argc, argv);
Simon Glass78fd76b2025-01-20 14:25:33 -0700180 } else {
181 int n_ents = ste->end - ste->start;
182 char prefix[30];
183
184 /* use a standard prefix */
Simon Glass598a1a52025-02-07 11:30:37 -0700185 snprintf(prefix, sizeof(prefix), "%s_test_", ste->name);
Simon Glass6685ece2025-01-20 14:25:58 -0700186 ret = cmd_ut_category(uts, ste->name, prefix, ste->start,
187 n_ents, argc, argv);
Simon Glass78fd76b2025-01-20 14:25:33 -0700188 }
189
190 return ret;
191}
192
Simon Glassbd9b1512025-02-07 11:30:36 -0700193static void show_stats(struct unit_test_state *uts)
194{
195 if (uts->run_count < 2)
196 return;
197
198 ut_report(&uts->total, uts->run_count);
199 if (CONFIG_IS_ENABLED(UNIT_TEST_DURATION) &&
200 uts->total.test_count && uts->worst) {
201 ulong avg = uts->total.duration_ms / uts->total.test_count;
202
203 printf("Average test time: %ld ms, worst case '%s' took %d ms\n",
204 avg, uts->worst->name, uts->worst_ms);
205 }
206}
207
208static void update_stats(struct unit_test_state *uts, const struct suite *ste)
209{
210 if (CONFIG_IS_ENABLED(UNIT_TEST_DURATION) && uts->cur.test_count) {
211 ulong avg;
212
213 avg = uts->cur.duration_ms ?
214 uts->cur.duration_ms /
215 uts->cur.test_count : 0;
216 if (avg > uts->worst_ms) {
217 uts->worst_ms = avg;
218 uts->worst = ste;
219 }
220 }
221}
222
Simon Glass6685ece2025-01-20 14:25:58 -0700223static int do_ut_all(struct unit_test_state *uts, struct cmd_tbl *cmdtp,
224 int flag, int argc, char *const argv[])
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500225{
226 int i;
227 int retval;
228 int any_fail = 0;
229
Simon Glass78fd76b2025-01-20 14:25:33 -0700230 for (i = 0; i < ARRAY_SIZE(suites); i++) {
231 struct suite *ste = &suites[i];
232 char *const argv[] = {(char *)ste->name, NULL};
233
Simon Glassa3ce1292025-01-20 14:25:57 -0700234 if (has_tests(ste)) {
235 printf("----Running %s tests----\n", ste->name);
Simon Glass6685ece2025-01-20 14:25:58 -0700236 retval = run_suite(uts, ste, cmdtp, flag, 1, argv);
Simon Glassa3ce1292025-01-20 14:25:57 -0700237 if (!any_fail)
238 any_fail = retval;
Simon Glassbd9b1512025-02-07 11:30:36 -0700239 update_stats(uts, ste);
Simon Glassa3ce1292025-01-20 14:25:57 -0700240 }
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500241 }
Simon Glassfb82a042025-01-20 14:26:02 -0700242 ut_report(&uts->total, uts->run_count);
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500243
244 return any_fail;
245}
246
Simon Glassfb998c22022-10-29 19:47:12 -0600247static int do_ut_info(struct cmd_tbl *cmdtp, int flag, int argc,
248 char *const argv[])
249{
Simon Glassa3ce1292025-01-20 14:25:57 -0700250 int suite_count, i;
Simon Glasscfb38f82025-01-20 14:25:30 -0700251 const char *flags;
252
Simon Glassa3ce1292025-01-20 14:25:57 -0700253 for (suite_count = 0, i = 0; i < ARRAY_SIZE(suites); i++) {
254 struct suite *ste = &suites[i];
255
256 if (has_tests(ste))
257 suite_count++;
258 }
259
260 printf("Test suites: %d\n", suite_count);
Simon Glassfb998c22022-10-29 19:47:12 -0600261 printf("Total tests: %d\n", (int)UNIT_TEST_ALL_COUNT());
262
Simon Glasscfb38f82025-01-20 14:25:30 -0700263 flags = cmd_arg1(argc, argv);
264 if (flags && !strcmp("-s", flags)) {
Simon Glass3669a972025-02-07 11:30:34 -0700265 int i, total;
Simon Glasscfb38f82025-01-20 14:25:30 -0700266
Simon Glass46093b32025-01-20 14:26:05 -0700267 puts("\nTests Suite Purpose");
268 puts("\n----- ------------ -------------------------\n");
Simon Glass3669a972025-02-07 11:30:34 -0700269 for (i = 0, total = 0; i < ARRAY_SIZE(suites); i++) {
Simon Glass78fd76b2025-01-20 14:25:33 -0700270 struct suite *ste = &suites[i];
271 long n_ent = ste->end - ste->start;
272
273 if (n_ent)
Simon Glass46093b32025-01-20 14:26:05 -0700274 printf("%5ld", n_ent);
Simon Glassa3ce1292025-01-20 14:25:57 -0700275 else if (ste->cmd)
Simon Glass46093b32025-01-20 14:26:05 -0700276 printf("%5s", "?");
277 else /* suite is not present */
278 continue;
279 printf(" %-13.13s %s\n", ste->name, ste->help);
Simon Glass3669a972025-02-07 11:30:34 -0700280 total += n_ent;
Simon Glass78fd76b2025-01-20 14:25:33 -0700281 }
Simon Glass3669a972025-02-07 11:30:34 -0700282 puts("----- ------------ -------------------------\n");
283 printf("%5d %-13.13s\n", total, "Total");
284
285 if (UNIT_TEST_ALL_COUNT() != total)
286 puts("Error: Suite test-count does not match total\n");
Simon Glasscfb38f82025-01-20 14:25:30 -0700287 }
288
Simon Glassfb998c22022-10-29 19:47:12 -0600289 return 0;
290}
291
Simon Glass78fd76b2025-01-20 14:25:33 -0700292static struct suite *find_suite(const char *name)
293{
294 struct suite *ste;
295 int i;
296
297 for (i = 0, ste = suites; i < ARRAY_SIZE(suites); i++, ste++) {
298 if (!strcmp(ste->name, name))
299 return ste;
300 }
301
302 return NULL;
303}
304
Simon Glassed38aef2020-05-10 11:40:03 -0600305static int do_ut(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500306{
Simon Glass6685ece2025-01-20 14:25:58 -0700307 struct unit_test_state uts;
Simon Glass78fd76b2025-01-20 14:25:33 -0700308 struct suite *ste;
309 const char *name;
310 int ret;
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500311
312 if (argc < 2)
313 return CMD_RET_USAGE;
314
315 /* drop initial "ut" arg */
316 argc--;
317 argv++;
318
Simon Glass6685ece2025-01-20 14:25:58 -0700319 ut_init_state(&uts);
Simon Glass78fd76b2025-01-20 14:25:33 -0700320 name = argv[0];
321 if (!strcmp(name, "all")) {
Simon Glass6685ece2025-01-20 14:25:58 -0700322 ret = do_ut_all(&uts, cmdtp, flag, argc, argv);
Simon Glass78fd76b2025-01-20 14:25:33 -0700323 } else if (!strcmp(name, "info")) {
324 ret = do_ut_info(cmdtp, flag, argc, argv);
325 } else {
326 ste = find_suite(argv[0]);
327 if (!ste) {
328 printf("Suite '%s' not found\n", argv[0]);
329 return CMD_RET_FAILURE;
Simon Glassa3ce1292025-01-20 14:25:57 -0700330 } else if (!has_tests(ste)) {
331 /* perhaps a Kconfig option needs to be set? */
332 printf("Suite '%s' is not enabled\n", argv[0]);
333 return CMD_RET_FAILURE;
Simon Glass78fd76b2025-01-20 14:25:33 -0700334 }
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500335
Simon Glass6685ece2025-01-20 14:25:58 -0700336 ret = run_suite(&uts, ste, cmdtp, flag, argc, argv);
Simon Glass78fd76b2025-01-20 14:25:33 -0700337 }
Simon Glassbd9b1512025-02-07 11:30:36 -0700338 show_stats(&uts);
Simon Glass78fd76b2025-01-20 14:25:33 -0700339 if (ret)
340 return ret;
Simon Glass6685ece2025-01-20 14:25:58 -0700341 ut_uninit_state(&uts);
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500342
Simon Glass78fd76b2025-01-20 14:25:33 -0700343 return 0;
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500344}
345
Tom Rini03f146c2023-10-07 15:13:08 -0400346U_BOOT_LONGHELP(ut,
Simon Glass154bb8e2022-10-29 19:47:10 -0600347 "[-r] [-f] [<suite>] - run unit tests\n"
348 " -r<runs> Number of times to run each test\n"
349 " -f Force 'manual' tests to run as well\n"
350 " <suite> Test suite to run, or all\n"
351 "\n"
Simon Glassfb998c22022-10-29 19:47:12 -0600352 "\nOptions for <suite>:"
Simon Glass154bb8e2022-10-29 19:47:10 -0600353 "\nall - execute all enabled tests"
Simon Glasscfb38f82025-01-20 14:25:30 -0700354 "\ninfo [-s] - show info about tests [and suites]"
Tom Rini03f146c2023-10-07 15:13:08 -0400355 );
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500356
357U_BOOT_CMD(
358 ut, CONFIG_SYS_MAXARGS, 1, do_ut,
359 "unit tests", ut_help_text
360);