blob: 6d1e20ef02ea1b9567381ff4b32377fff963a447 [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 Glassf8573fc2025-02-07 11:30:49 -0700128 SUITE(bootstd, "standard boot implementation"),
Simon Glass46093b32025-01-20 14:26:05 -0700129 SUITE(cmd, "various commands"),
130 SUITE(common, "tests for common/ directory"),
131 SUITE(dm, "driver model"),
132 SUITE(env, "environment"),
133 SUITE(exit, "shell exit and variables"),
134 SUITE(fdt, "fdt command"),
Simon Glass0f50f902025-02-07 11:30:47 -0700135 SUITE(fdt_overlay, "device tree overlays"),
Simon Glass46093b32025-01-20 14:26:05 -0700136 SUITE(font, "font command"),
137 SUITE(hush, "hush behaviour"),
138 SUITE(lib, "library functions"),
139 SUITE(loadm, "loadm command parameters and loading memory blob"),
140 SUITE(log, "logging functions"),
141 SUITE(mbr, "mbr command"),
142 SUITE(measurement, "TPM-based measured boot"),
143 SUITE(mem, "memory-related commands"),
Simon Glass3947f792025-02-07 11:30:52 -0700144 SUITE(optee, "OP-TEE"),
Simon Glass46093b32025-01-20 14:26:05 -0700145 SUITE(pci_mps, "PCI Express Maximum Payload Size"),
146 SUITE(seama, "seama command parameters loading and decoding"),
147 SUITE(setexpr, "setexpr command"),
148 SUITE(upl, "Universal payload support"),
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500149};
150
Simon Glassa3ce1292025-01-20 14:25:57 -0700151/**
152 * has_tests() - Check if a suite has tests, i.e. is supported in this build
153 *
154 * If the suite is run using a command, we have to assume that tests may be
155 * present, since we have no visibility
156 *
157 * @ste: Suite to check
158 * Return: true if supported, false if not
159 */
160static bool has_tests(struct suite *ste)
161{
162 int n_ents = ste->end - ste->start;
163
164 return n_ents || ste->cmd;
165}
166
Simon Glass78fd76b2025-01-20 14:25:33 -0700167/** run_suite() - Run a suite of tests */
Simon Glass6685ece2025-01-20 14:25:58 -0700168static int run_suite(struct unit_test_state *uts, struct suite *ste,
169 struct cmd_tbl *cmdtp, int flag, int argc,
170 char *const argv[])
Simon Glass78fd76b2025-01-20 14:25:33 -0700171{
172 int ret;
173
174 if (ste->cmd) {
Simon Glass6685ece2025-01-20 14:25:58 -0700175 ret = ste->cmd(uts, cmdtp, flag, argc, argv);
Simon Glass78fd76b2025-01-20 14:25:33 -0700176 } else {
177 int n_ents = ste->end - ste->start;
178 char prefix[30];
179
180 /* use a standard prefix */
Simon Glass598a1a52025-02-07 11:30:37 -0700181 snprintf(prefix, sizeof(prefix), "%s_test_", ste->name);
Simon Glass6685ece2025-01-20 14:25:58 -0700182 ret = cmd_ut_category(uts, ste->name, prefix, ste->start,
183 n_ents, argc, argv);
Simon Glass78fd76b2025-01-20 14:25:33 -0700184 }
185
186 return ret;
187}
188
Simon Glassbd9b1512025-02-07 11:30:36 -0700189static void show_stats(struct unit_test_state *uts)
190{
191 if (uts->run_count < 2)
192 return;
193
194 ut_report(&uts->total, uts->run_count);
195 if (CONFIG_IS_ENABLED(UNIT_TEST_DURATION) &&
196 uts->total.test_count && uts->worst) {
197 ulong avg = uts->total.duration_ms / uts->total.test_count;
198
199 printf("Average test time: %ld ms, worst case '%s' took %d ms\n",
200 avg, uts->worst->name, uts->worst_ms);
201 }
202}
203
204static void update_stats(struct unit_test_state *uts, const struct suite *ste)
205{
206 if (CONFIG_IS_ENABLED(UNIT_TEST_DURATION) && uts->cur.test_count) {
207 ulong avg;
208
209 avg = uts->cur.duration_ms ?
210 uts->cur.duration_ms /
211 uts->cur.test_count : 0;
212 if (avg > uts->worst_ms) {
213 uts->worst_ms = avg;
214 uts->worst = ste;
215 }
216 }
217}
218
Simon Glass6685ece2025-01-20 14:25:58 -0700219static int do_ut_all(struct unit_test_state *uts, struct cmd_tbl *cmdtp,
220 int flag, int argc, char *const argv[])
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500221{
222 int i;
223 int retval;
224 int any_fail = 0;
225
Simon Glass78fd76b2025-01-20 14:25:33 -0700226 for (i = 0; i < ARRAY_SIZE(suites); i++) {
227 struct suite *ste = &suites[i];
228 char *const argv[] = {(char *)ste->name, NULL};
229
Simon Glassa3ce1292025-01-20 14:25:57 -0700230 if (has_tests(ste)) {
231 printf("----Running %s tests----\n", ste->name);
Simon Glass6685ece2025-01-20 14:25:58 -0700232 retval = run_suite(uts, ste, cmdtp, flag, 1, argv);
Simon Glassa3ce1292025-01-20 14:25:57 -0700233 if (!any_fail)
234 any_fail = retval;
Simon Glassbd9b1512025-02-07 11:30:36 -0700235 update_stats(uts, ste);
Simon Glassa3ce1292025-01-20 14:25:57 -0700236 }
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500237 }
Simon Glassfb82a042025-01-20 14:26:02 -0700238 ut_report(&uts->total, uts->run_count);
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500239
240 return any_fail;
241}
242
Simon Glassfb998c22022-10-29 19:47:12 -0600243static int do_ut_info(struct cmd_tbl *cmdtp, int flag, int argc,
244 char *const argv[])
245{
Simon Glassa3ce1292025-01-20 14:25:57 -0700246 int suite_count, i;
Simon Glasscfb38f82025-01-20 14:25:30 -0700247 const char *flags;
248
Simon Glassa3ce1292025-01-20 14:25:57 -0700249 for (suite_count = 0, i = 0; i < ARRAY_SIZE(suites); i++) {
250 struct suite *ste = &suites[i];
251
252 if (has_tests(ste))
253 suite_count++;
254 }
255
256 printf("Test suites: %d\n", suite_count);
Simon Glassfb998c22022-10-29 19:47:12 -0600257 printf("Total tests: %d\n", (int)UNIT_TEST_ALL_COUNT());
258
Simon Glasscfb38f82025-01-20 14:25:30 -0700259 flags = cmd_arg1(argc, argv);
260 if (flags && !strcmp("-s", flags)) {
Simon Glass3669a972025-02-07 11:30:34 -0700261 int i, total;
Simon Glasscfb38f82025-01-20 14:25:30 -0700262
Simon Glass46093b32025-01-20 14:26:05 -0700263 puts("\nTests Suite Purpose");
264 puts("\n----- ------------ -------------------------\n");
Simon Glass3669a972025-02-07 11:30:34 -0700265 for (i = 0, total = 0; i < ARRAY_SIZE(suites); i++) {
Simon Glass78fd76b2025-01-20 14:25:33 -0700266 struct suite *ste = &suites[i];
267 long n_ent = ste->end - ste->start;
268
269 if (n_ent)
Simon Glass46093b32025-01-20 14:26:05 -0700270 printf("%5ld", n_ent);
Simon Glassa3ce1292025-01-20 14:25:57 -0700271 else if (ste->cmd)
Simon Glass46093b32025-01-20 14:26:05 -0700272 printf("%5s", "?");
273 else /* suite is not present */
274 continue;
275 printf(" %-13.13s %s\n", ste->name, ste->help);
Simon Glass3669a972025-02-07 11:30:34 -0700276 total += n_ent;
Simon Glass78fd76b2025-01-20 14:25:33 -0700277 }
Simon Glass3669a972025-02-07 11:30:34 -0700278 puts("----- ------------ -------------------------\n");
279 printf("%5d %-13.13s\n", total, "Total");
280
281 if (UNIT_TEST_ALL_COUNT() != total)
282 puts("Error: Suite test-count does not match total\n");
Simon Glasscfb38f82025-01-20 14:25:30 -0700283 }
284
Simon Glassfb998c22022-10-29 19:47:12 -0600285 return 0;
286}
287
Simon Glass78fd76b2025-01-20 14:25:33 -0700288static struct suite *find_suite(const char *name)
289{
290 struct suite *ste;
291 int i;
292
293 for (i = 0, ste = suites; i < ARRAY_SIZE(suites); i++, ste++) {
294 if (!strcmp(ste->name, name))
295 return ste;
296 }
297
298 return NULL;
299}
300
Simon Glassed38aef2020-05-10 11:40:03 -0600301static int do_ut(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500302{
Simon Glass6685ece2025-01-20 14:25:58 -0700303 struct unit_test_state uts;
Simon Glass78fd76b2025-01-20 14:25:33 -0700304 struct suite *ste;
305 const char *name;
306 int ret;
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500307
308 if (argc < 2)
309 return CMD_RET_USAGE;
310
311 /* drop initial "ut" arg */
312 argc--;
313 argv++;
314
Simon Glass6685ece2025-01-20 14:25:58 -0700315 ut_init_state(&uts);
Simon Glass78fd76b2025-01-20 14:25:33 -0700316 name = argv[0];
317 if (!strcmp(name, "all")) {
Simon Glass6685ece2025-01-20 14:25:58 -0700318 ret = do_ut_all(&uts, cmdtp, flag, argc, argv);
Simon Glass78fd76b2025-01-20 14:25:33 -0700319 } else if (!strcmp(name, "info")) {
320 ret = do_ut_info(cmdtp, flag, argc, argv);
321 } else {
322 ste = find_suite(argv[0]);
323 if (!ste) {
324 printf("Suite '%s' not found\n", argv[0]);
325 return CMD_RET_FAILURE;
Simon Glassa3ce1292025-01-20 14:25:57 -0700326 } else if (!has_tests(ste)) {
327 /* perhaps a Kconfig option needs to be set? */
328 printf("Suite '%s' is not enabled\n", argv[0]);
329 return CMD_RET_FAILURE;
Simon Glass78fd76b2025-01-20 14:25:33 -0700330 }
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500331
Simon Glass6685ece2025-01-20 14:25:58 -0700332 ret = run_suite(&uts, ste, cmdtp, flag, argc, argv);
Simon Glass78fd76b2025-01-20 14:25:33 -0700333 }
Simon Glassbd9b1512025-02-07 11:30:36 -0700334 show_stats(&uts);
Simon Glass78fd76b2025-01-20 14:25:33 -0700335 if (ret)
336 return ret;
Simon Glass6685ece2025-01-20 14:25:58 -0700337 ut_uninit_state(&uts);
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500338
Simon Glass78fd76b2025-01-20 14:25:33 -0700339 return 0;
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500340}
341
Tom Rini03f146c2023-10-07 15:13:08 -0400342U_BOOT_LONGHELP(ut,
Simon Glass154bb8e2022-10-29 19:47:10 -0600343 "[-r] [-f] [<suite>] - run unit tests\n"
344 " -r<runs> Number of times to run each test\n"
345 " -f Force 'manual' tests to run as well\n"
346 " <suite> Test suite to run, or all\n"
347 "\n"
Simon Glassfb998c22022-10-29 19:47:12 -0600348 "\nOptions for <suite>:"
Simon Glass154bb8e2022-10-29 19:47:10 -0600349 "\nall - execute all enabled tests"
Simon Glasscfb38f82025-01-20 14:25:30 -0700350 "\ninfo [-s] - show info about tests [and suites]"
Tom Rini03f146c2023-10-07 15:13:08 -0400351 );
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500352
353U_BOOT_CMD(
354 ut, CONFIG_SYS_MAXARGS, 1, do_ut,
355 "unit tests", ut_help_text
356);