blob: 1885c78be410c427c7ad061654e662403c383888 [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"),
Heiko Stuebner1c9bb9b2019-10-23 16:46:41 +0200144#ifdef CONFIG_UT_OPTEE
Simon Glass46093b32025-01-20 14:26:05 -0700145 SUITE_CMD(optee, do_ut_optee, "OP-TEE"),
Heiko Stuebner1c9bb9b2019-10-23 16:46:41 +0200146#endif
Simon Glass46093b32025-01-20 14:26:05 -0700147 SUITE(pci_mps, "PCI Express Maximum Payload Size"),
148 SUITE(seama, "seama command parameters loading and decoding"),
149 SUITE(setexpr, "setexpr command"),
150 SUITE(upl, "Universal payload support"),
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500151};
152
Simon Glassa3ce1292025-01-20 14:25:57 -0700153/**
154 * has_tests() - Check if a suite has tests, i.e. is supported in this build
155 *
156 * If the suite is run using a command, we have to assume that tests may be
157 * present, since we have no visibility
158 *
159 * @ste: Suite to check
160 * Return: true if supported, false if not
161 */
162static bool has_tests(struct suite *ste)
163{
164 int n_ents = ste->end - ste->start;
165
166 return n_ents || ste->cmd;
167}
168
Simon Glass78fd76b2025-01-20 14:25:33 -0700169/** run_suite() - Run a suite of tests */
Simon Glass6685ece2025-01-20 14:25:58 -0700170static int run_suite(struct unit_test_state *uts, struct suite *ste,
171 struct cmd_tbl *cmdtp, int flag, int argc,
172 char *const argv[])
Simon Glass78fd76b2025-01-20 14:25:33 -0700173{
174 int ret;
175
176 if (ste->cmd) {
Simon Glass6685ece2025-01-20 14:25:58 -0700177 ret = ste->cmd(uts, cmdtp, flag, argc, argv);
Simon Glass78fd76b2025-01-20 14:25:33 -0700178 } else {
179 int n_ents = ste->end - ste->start;
180 char prefix[30];
181
182 /* use a standard prefix */
Simon Glass598a1a52025-02-07 11:30:37 -0700183 snprintf(prefix, sizeof(prefix), "%s_test_", ste->name);
Simon Glass6685ece2025-01-20 14:25:58 -0700184 ret = cmd_ut_category(uts, ste->name, prefix, ste->start,
185 n_ents, argc, argv);
Simon Glass78fd76b2025-01-20 14:25:33 -0700186 }
187
188 return ret;
189}
190
Simon Glassbd9b1512025-02-07 11:30:36 -0700191static void show_stats(struct unit_test_state *uts)
192{
193 if (uts->run_count < 2)
194 return;
195
196 ut_report(&uts->total, uts->run_count);
197 if (CONFIG_IS_ENABLED(UNIT_TEST_DURATION) &&
198 uts->total.test_count && uts->worst) {
199 ulong avg = uts->total.duration_ms / uts->total.test_count;
200
201 printf("Average test time: %ld ms, worst case '%s' took %d ms\n",
202 avg, uts->worst->name, uts->worst_ms);
203 }
204}
205
206static void update_stats(struct unit_test_state *uts, const struct suite *ste)
207{
208 if (CONFIG_IS_ENABLED(UNIT_TEST_DURATION) && uts->cur.test_count) {
209 ulong avg;
210
211 avg = uts->cur.duration_ms ?
212 uts->cur.duration_ms /
213 uts->cur.test_count : 0;
214 if (avg > uts->worst_ms) {
215 uts->worst_ms = avg;
216 uts->worst = ste;
217 }
218 }
219}
220
Simon Glass6685ece2025-01-20 14:25:58 -0700221static int do_ut_all(struct unit_test_state *uts, struct cmd_tbl *cmdtp,
222 int flag, int argc, char *const argv[])
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500223{
224 int i;
225 int retval;
226 int any_fail = 0;
227
Simon Glass78fd76b2025-01-20 14:25:33 -0700228 for (i = 0; i < ARRAY_SIZE(suites); i++) {
229 struct suite *ste = &suites[i];
230 char *const argv[] = {(char *)ste->name, NULL};
231
Simon Glassa3ce1292025-01-20 14:25:57 -0700232 if (has_tests(ste)) {
233 printf("----Running %s tests----\n", ste->name);
Simon Glass6685ece2025-01-20 14:25:58 -0700234 retval = run_suite(uts, ste, cmdtp, flag, 1, argv);
Simon Glassa3ce1292025-01-20 14:25:57 -0700235 if (!any_fail)
236 any_fail = retval;
Simon Glassbd9b1512025-02-07 11:30:36 -0700237 update_stats(uts, ste);
Simon Glassa3ce1292025-01-20 14:25:57 -0700238 }
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500239 }
Simon Glassfb82a042025-01-20 14:26:02 -0700240 ut_report(&uts->total, uts->run_count);
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500241
242 return any_fail;
243}
244
Simon Glassfb998c22022-10-29 19:47:12 -0600245static int do_ut_info(struct cmd_tbl *cmdtp, int flag, int argc,
246 char *const argv[])
247{
Simon Glassa3ce1292025-01-20 14:25:57 -0700248 int suite_count, i;
Simon Glasscfb38f82025-01-20 14:25:30 -0700249 const char *flags;
250
Simon Glassa3ce1292025-01-20 14:25:57 -0700251 for (suite_count = 0, i = 0; i < ARRAY_SIZE(suites); i++) {
252 struct suite *ste = &suites[i];
253
254 if (has_tests(ste))
255 suite_count++;
256 }
257
258 printf("Test suites: %d\n", suite_count);
Simon Glassfb998c22022-10-29 19:47:12 -0600259 printf("Total tests: %d\n", (int)UNIT_TEST_ALL_COUNT());
260
Simon Glasscfb38f82025-01-20 14:25:30 -0700261 flags = cmd_arg1(argc, argv);
262 if (flags && !strcmp("-s", flags)) {
Simon Glass3669a972025-02-07 11:30:34 -0700263 int i, total;
Simon Glasscfb38f82025-01-20 14:25:30 -0700264
Simon Glass46093b32025-01-20 14:26:05 -0700265 puts("\nTests Suite Purpose");
266 puts("\n----- ------------ -------------------------\n");
Simon Glass3669a972025-02-07 11:30:34 -0700267 for (i = 0, total = 0; i < ARRAY_SIZE(suites); i++) {
Simon Glass78fd76b2025-01-20 14:25:33 -0700268 struct suite *ste = &suites[i];
269 long n_ent = ste->end - ste->start;
270
271 if (n_ent)
Simon Glass46093b32025-01-20 14:26:05 -0700272 printf("%5ld", n_ent);
Simon Glassa3ce1292025-01-20 14:25:57 -0700273 else if (ste->cmd)
Simon Glass46093b32025-01-20 14:26:05 -0700274 printf("%5s", "?");
275 else /* suite is not present */
276 continue;
277 printf(" %-13.13s %s\n", ste->name, ste->help);
Simon Glass3669a972025-02-07 11:30:34 -0700278 total += n_ent;
Simon Glass78fd76b2025-01-20 14:25:33 -0700279 }
Simon Glass3669a972025-02-07 11:30:34 -0700280 puts("----- ------------ -------------------------\n");
281 printf("%5d %-13.13s\n", total, "Total");
282
283 if (UNIT_TEST_ALL_COUNT() != total)
284 puts("Error: Suite test-count does not match total\n");
Simon Glasscfb38f82025-01-20 14:25:30 -0700285 }
286
Simon Glassfb998c22022-10-29 19:47:12 -0600287 return 0;
288}
289
Simon Glass78fd76b2025-01-20 14:25:33 -0700290static struct suite *find_suite(const char *name)
291{
292 struct suite *ste;
293 int i;
294
295 for (i = 0, ste = suites; i < ARRAY_SIZE(suites); i++, ste++) {
296 if (!strcmp(ste->name, name))
297 return ste;
298 }
299
300 return NULL;
301}
302
Simon Glassed38aef2020-05-10 11:40:03 -0600303static int do_ut(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500304{
Simon Glass6685ece2025-01-20 14:25:58 -0700305 struct unit_test_state uts;
Simon Glass78fd76b2025-01-20 14:25:33 -0700306 struct suite *ste;
307 const char *name;
308 int ret;
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500309
310 if (argc < 2)
311 return CMD_RET_USAGE;
312
313 /* drop initial "ut" arg */
314 argc--;
315 argv++;
316
Simon Glass6685ece2025-01-20 14:25:58 -0700317 ut_init_state(&uts);
Simon Glass78fd76b2025-01-20 14:25:33 -0700318 name = argv[0];
319 if (!strcmp(name, "all")) {
Simon Glass6685ece2025-01-20 14:25:58 -0700320 ret = do_ut_all(&uts, cmdtp, flag, argc, argv);
Simon Glass78fd76b2025-01-20 14:25:33 -0700321 } else if (!strcmp(name, "info")) {
322 ret = do_ut_info(cmdtp, flag, argc, argv);
323 } else {
324 ste = find_suite(argv[0]);
325 if (!ste) {
326 printf("Suite '%s' not found\n", argv[0]);
327 return CMD_RET_FAILURE;
Simon Glassa3ce1292025-01-20 14:25:57 -0700328 } else if (!has_tests(ste)) {
329 /* perhaps a Kconfig option needs to be set? */
330 printf("Suite '%s' is not enabled\n", argv[0]);
331 return CMD_RET_FAILURE;
Simon Glass78fd76b2025-01-20 14:25:33 -0700332 }
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500333
Simon Glass6685ece2025-01-20 14:25:58 -0700334 ret = run_suite(&uts, ste, cmdtp, flag, argc, argv);
Simon Glass78fd76b2025-01-20 14:25:33 -0700335 }
Simon Glassbd9b1512025-02-07 11:30:36 -0700336 show_stats(&uts);
Simon Glass78fd76b2025-01-20 14:25:33 -0700337 if (ret)
338 return ret;
Simon Glass6685ece2025-01-20 14:25:58 -0700339 ut_uninit_state(&uts);
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500340
Simon Glass78fd76b2025-01-20 14:25:33 -0700341 return 0;
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500342}
343
Tom Rini03f146c2023-10-07 15:13:08 -0400344U_BOOT_LONGHELP(ut,
Simon Glass154bb8e2022-10-29 19:47:10 -0600345 "[-r] [-f] [<suite>] - run unit tests\n"
346 " -r<runs> Number of times to run each test\n"
347 " -f Force 'manual' tests to run as well\n"
348 " <suite> Test suite to run, or all\n"
349 "\n"
Simon Glassfb998c22022-10-29 19:47:12 -0600350 "\nOptions for <suite>:"
Simon Glass154bb8e2022-10-29 19:47:10 -0600351 "\nall - execute all enabled tests"
Simon Glasscfb38f82025-01-20 14:25:30 -0700352 "\ninfo [-s] - show info about tests [and suites]"
Tom Rini03f146c2023-10-07 15:13:08 -0400353 );
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500354
355U_BOOT_CMD(
356 ut, CONFIG_SYS_MAXARGS, 1, do_ut,
357 "unit tests", ut_help_text
358);