blob: bc2da617e5113eb98d464b3c48a68ea7105854ba [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 Glass78fd76b2025-01-20 14:25:33 -070037/* declare linker-list symbols for the start and end of a suite */
38#define SUITE_DECL(_name) \
39 ll_start_decl(suite_start_ ## _name, struct unit_test, ut_ ## _name); \
40 ll_end_decl(suite_end_ ## _name, struct unit_test, ut_ ## _name)
41
Simon Glass78fd76b2025-01-20 14:25:33 -070042/* declare a test suite which can be run directly without a subcommand */
Simon Glass46093b32025-01-20 14:26:05 -070043#define SUITE(_name, _help) { \
Simon Glass78fd76b2025-01-20 14:25:33 -070044 #_name, \
45 suite_start_ ## _name, \
46 suite_end_ ## _name, \
Simon Glass46093b32025-01-20 14:26:05 -070047 _help, \
Simon Glass78fd76b2025-01-20 14:25:33 -070048 }
49
Simon Glass4c990702025-01-20 14:26:03 -070050SUITE_DECL(addrmap);
Simon Glass78fd76b2025-01-20 14:25:33 -070051SUITE_DECL(bdinfo);
Simon Glass4c990702025-01-20 14:26:03 -070052SUITE_DECL(bloblist);
53SUITE_DECL(bootm);
Simon Glass78fd76b2025-01-20 14:25:33 -070054SUITE_DECL(bootstd);
55SUITE_DECL(cmd);
56SUITE_DECL(common);
57SUITE_DECL(dm);
58SUITE_DECL(env);
59SUITE_DECL(exit);
60SUITE_DECL(fdt);
Simon Glass04e76d52025-02-07 11:30:39 -070061SUITE_DECL(fdt_overlay);
Simon Glass78fd76b2025-01-20 14:25:33 -070062SUITE_DECL(font);
Simon Glass4c990702025-01-20 14:26:03 -070063SUITE_DECL(hush);
Simon Glass78fd76b2025-01-20 14:25:33 -070064SUITE_DECL(lib);
Simon Glass4c990702025-01-20 14:26:03 -070065SUITE_DECL(loadm);
Simon Glass78fd76b2025-01-20 14:25:33 -070066SUITE_DECL(log);
67SUITE_DECL(mbr);
Simon Glass78fd76b2025-01-20 14:25:33 -070068SUITE_DECL(measurement);
Simon Glass4c990702025-01-20 14:26:03 -070069SUITE_DECL(mem);
70SUITE_DECL(optee);
Simon Glass78fd76b2025-01-20 14:25:33 -070071SUITE_DECL(pci_mps);
72SUITE_DECL(seama);
Simon Glass4c990702025-01-20 14:26:03 -070073SUITE_DECL(setexpr);
Simon Glass78fd76b2025-01-20 14:25:33 -070074SUITE_DECL(upl);
75
76static struct suite suites[] = {
Simon Glass46093b32025-01-20 14:26:05 -070077 SUITE(addrmap, "very basic test of addrmap command"),
78 SUITE(bdinfo, "bdinfo (board info) command"),
79 SUITE(bloblist, "bloblist implementation"),
80 SUITE(bootm, "bootm command"),
Simon Glassf8573fc2025-02-07 11:30:49 -070081 SUITE(bootstd, "standard boot implementation"),
Simon Glass46093b32025-01-20 14:26:05 -070082 SUITE(cmd, "various commands"),
83 SUITE(common, "tests for common/ directory"),
84 SUITE(dm, "driver model"),
85 SUITE(env, "environment"),
86 SUITE(exit, "shell exit and variables"),
87 SUITE(fdt, "fdt command"),
Simon Glass0f50f902025-02-07 11:30:47 -070088 SUITE(fdt_overlay, "device tree overlays"),
Simon Glass46093b32025-01-20 14:26:05 -070089 SUITE(font, "font command"),
90 SUITE(hush, "hush behaviour"),
91 SUITE(lib, "library functions"),
92 SUITE(loadm, "loadm command parameters and loading memory blob"),
93 SUITE(log, "logging functions"),
94 SUITE(mbr, "mbr command"),
95 SUITE(measurement, "TPM-based measured boot"),
96 SUITE(mem, "memory-related commands"),
Simon Glass3947f792025-02-07 11:30:52 -070097 SUITE(optee, "OP-TEE"),
Simon Glass46093b32025-01-20 14:26:05 -070098 SUITE(pci_mps, "PCI Express Maximum Payload Size"),
99 SUITE(seama, "seama command parameters loading and decoding"),
100 SUITE(setexpr, "setexpr command"),
101 SUITE(upl, "Universal payload support"),
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500102};
103
Simon Glassa3ce1292025-01-20 14:25:57 -0700104/**
105 * has_tests() - Check if a suite has tests, i.e. is supported in this build
106 *
107 * If the suite is run using a command, we have to assume that tests may be
108 * present, since we have no visibility
109 *
110 * @ste: Suite to check
111 * Return: true if supported, false if not
112 */
113static bool has_tests(struct suite *ste)
114{
115 int n_ents = ste->end - ste->start;
116
Simon Glass0a85dd02025-02-07 11:30:54 -0700117 return n_ents;
Simon Glassa3ce1292025-01-20 14:25:57 -0700118}
119
Simon Glass78fd76b2025-01-20 14:25:33 -0700120/** run_suite() - Run a suite of tests */
Simon Glass6685ece2025-01-20 14:25:58 -0700121static int run_suite(struct unit_test_state *uts, struct suite *ste,
122 struct cmd_tbl *cmdtp, int flag, int argc,
123 char *const argv[])
Simon Glass78fd76b2025-01-20 14:25:33 -0700124{
Simon Glass0a85dd02025-02-07 11:30:54 -0700125 int n_ents = ste->end - ste->start;
Simon Glassb6f23882025-02-07 11:30:58 -0700126 const char *test_insert = NULL;
127 int runs_per_text = 1;
128 bool force_run = false;
Simon Glass0a85dd02025-02-07 11:30:54 -0700129 char prefix[30];
Simon Glass78fd76b2025-01-20 14:25:33 -0700130 int ret;
131
Simon Glass0a85dd02025-02-07 11:30:54 -0700132 /* use a standard prefix */
133 snprintf(prefix, sizeof(prefix), "%s_test_", ste->name);
Simon Glassb6f23882025-02-07 11:30:58 -0700134
135 while (argc > 1 && *argv[1] == '-') {
136 const char *str = argv[1];
137
138 switch (str[1]) {
139 case 'r':
140 runs_per_text = dectoul(str + 2, NULL);
141 break;
142 case 'f':
143 force_run = true;
144 break;
145 case 'I':
146 test_insert = str + 2;
147 break;
148 }
149 argv++;
150 argc--;
151 }
152
153 ret = ut_run_list(uts, ste->name, prefix, ste->start, n_ents,
154 cmd_arg1(argc, argv), runs_per_text, force_run,
155 test_insert);
Simon Glass78fd76b2025-01-20 14:25:33 -0700156
157 return ret;
158}
159
Simon Glassbd9b1512025-02-07 11:30:36 -0700160static void show_stats(struct unit_test_state *uts)
161{
162 if (uts->run_count < 2)
163 return;
164
165 ut_report(&uts->total, uts->run_count);
166 if (CONFIG_IS_ENABLED(UNIT_TEST_DURATION) &&
167 uts->total.test_count && uts->worst) {
168 ulong avg = uts->total.duration_ms / uts->total.test_count;
169
170 printf("Average test time: %ld ms, worst case '%s' took %d ms\n",
171 avg, uts->worst->name, uts->worst_ms);
172 }
173}
174
175static void update_stats(struct unit_test_state *uts, const struct suite *ste)
176{
177 if (CONFIG_IS_ENABLED(UNIT_TEST_DURATION) && uts->cur.test_count) {
178 ulong avg;
179
180 avg = uts->cur.duration_ms ?
181 uts->cur.duration_ms /
182 uts->cur.test_count : 0;
183 if (avg > uts->worst_ms) {
184 uts->worst_ms = avg;
185 uts->worst = ste;
186 }
187 }
188}
189
Simon Glass6685ece2025-01-20 14:25:58 -0700190static int do_ut_all(struct unit_test_state *uts, struct cmd_tbl *cmdtp,
191 int flag, int argc, char *const argv[])
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500192{
193 int i;
194 int retval;
195 int any_fail = 0;
196
Simon Glass78fd76b2025-01-20 14:25:33 -0700197 for (i = 0; i < ARRAY_SIZE(suites); i++) {
198 struct suite *ste = &suites[i];
199 char *const argv[] = {(char *)ste->name, NULL};
200
Simon Glassa3ce1292025-01-20 14:25:57 -0700201 if (has_tests(ste)) {
202 printf("----Running %s tests----\n", ste->name);
Simon Glass6685ece2025-01-20 14:25:58 -0700203 retval = run_suite(uts, ste, cmdtp, flag, 1, argv);
Simon Glassa3ce1292025-01-20 14:25:57 -0700204 if (!any_fail)
205 any_fail = retval;
Simon Glassbd9b1512025-02-07 11:30:36 -0700206 update_stats(uts, ste);
Simon Glassa3ce1292025-01-20 14:25:57 -0700207 }
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500208 }
209
210 return any_fail;
211}
212
Simon Glassfb998c22022-10-29 19:47:12 -0600213static int do_ut_info(struct cmd_tbl *cmdtp, int flag, int argc,
214 char *const argv[])
215{
Simon Glassa3ce1292025-01-20 14:25:57 -0700216 int suite_count, i;
Simon Glasscfb38f82025-01-20 14:25:30 -0700217 const char *flags;
218
Simon Glassa3ce1292025-01-20 14:25:57 -0700219 for (suite_count = 0, i = 0; i < ARRAY_SIZE(suites); i++) {
220 struct suite *ste = &suites[i];
221
222 if (has_tests(ste))
223 suite_count++;
224 }
225
226 printf("Test suites: %d\n", suite_count);
Simon Glassfb998c22022-10-29 19:47:12 -0600227 printf("Total tests: %d\n", (int)UNIT_TEST_ALL_COUNT());
228
Simon Glasscfb38f82025-01-20 14:25:30 -0700229 flags = cmd_arg1(argc, argv);
230 if (flags && !strcmp("-s", flags)) {
Simon Glass3669a972025-02-07 11:30:34 -0700231 int i, total;
Simon Glasscfb38f82025-01-20 14:25:30 -0700232
Simon Glass46093b32025-01-20 14:26:05 -0700233 puts("\nTests Suite Purpose");
234 puts("\n----- ------------ -------------------------\n");
Simon Glass3669a972025-02-07 11:30:34 -0700235 for (i = 0, total = 0; i < ARRAY_SIZE(suites); i++) {
Simon Glass78fd76b2025-01-20 14:25:33 -0700236 struct suite *ste = &suites[i];
237 long n_ent = ste->end - ste->start;
238
Simon Glass0a85dd02025-02-07 11:30:54 -0700239 if (n_ent) {
240 printf("%5ld %-13.13s %s\n", n_ent, ste->name,
241 ste->help);
242 total += n_ent;
243 }
Simon Glass78fd76b2025-01-20 14:25:33 -0700244 }
Simon Glass3669a972025-02-07 11:30:34 -0700245 puts("----- ------------ -------------------------\n");
246 printf("%5d %-13.13s\n", total, "Total");
247
248 if (UNIT_TEST_ALL_COUNT() != total)
249 puts("Error: Suite test-count does not match total\n");
Simon Glasscfb38f82025-01-20 14:25:30 -0700250 }
251
Simon Glassfb998c22022-10-29 19:47:12 -0600252 return 0;
253}
254
Simon Glass78fd76b2025-01-20 14:25:33 -0700255static struct suite *find_suite(const char *name)
256{
257 struct suite *ste;
258 int i;
259
260 for (i = 0, ste = suites; i < ARRAY_SIZE(suites); i++, ste++) {
261 if (!strcmp(ste->name, name))
262 return ste;
263 }
264
265 return NULL;
266}
267
Simon Glassed38aef2020-05-10 11:40:03 -0600268static int do_ut(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500269{
Simon Glass6685ece2025-01-20 14:25:58 -0700270 struct unit_test_state uts;
Simon Glass78fd76b2025-01-20 14:25:33 -0700271 struct suite *ste;
Simon Glass70737152025-02-07 11:30:57 -0700272 char *name;
Simon Glass78fd76b2025-01-20 14:25:33 -0700273 int ret;
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500274
275 if (argc < 2)
276 return CMD_RET_USAGE;
277
278 /* drop initial "ut" arg */
279 argc--;
280 argv++;
281
Simon Glass6685ece2025-01-20 14:25:58 -0700282 ut_init_state(&uts);
Simon Glass78fd76b2025-01-20 14:25:33 -0700283 name = argv[0];
284 if (!strcmp(name, "all")) {
Simon Glass6685ece2025-01-20 14:25:58 -0700285 ret = do_ut_all(&uts, cmdtp, flag, argc, argv);
Simon Glass78fd76b2025-01-20 14:25:33 -0700286 } else if (!strcmp(name, "info")) {
287 ret = do_ut_info(cmdtp, flag, argc, argv);
288 } else {
Simon Glass70737152025-02-07 11:30:57 -0700289 int any_fail = 0;
290 const char *p;
291
292 for (; p = strsep(&name, ","), p; name = NULL) {
293 ste = find_suite(p);
294 if (!ste) {
295 printf("Suite '%s' not found\n", p);
296 return CMD_RET_FAILURE;
297 } else if (!has_tests(ste)) {
298 /* perhaps a Kconfig option needs to be set? */
299 printf("Suite '%s' is not enabled\n", p);
300 return CMD_RET_FAILURE;
301 }
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500302
Simon Glass70737152025-02-07 11:30:57 -0700303 ret = run_suite(&uts, ste, cmdtp, flag, argc, argv);
304 if (!any_fail)
305 any_fail = ret;
306 update_stats(&uts, ste);
307 }
308 ret = any_fail;
Simon Glass78fd76b2025-01-20 14:25:33 -0700309 }
Simon Glassbd9b1512025-02-07 11:30:36 -0700310 show_stats(&uts);
Simon Glass78fd76b2025-01-20 14:25:33 -0700311 if (ret)
312 return ret;
Simon Glass6685ece2025-01-20 14:25:58 -0700313 ut_uninit_state(&uts);
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500314
Simon Glass78fd76b2025-01-20 14:25:33 -0700315 return 0;
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500316}
317
Tom Rini03f146c2023-10-07 15:13:08 -0400318U_BOOT_LONGHELP(ut,
Simon Glass154bb8e2022-10-29 19:47:10 -0600319 "[-r] [-f] [<suite>] - run unit tests\n"
320 " -r<runs> Number of times to run each test\n"
321 " -f Force 'manual' tests to run as well\n"
322 " <suite> Test suite to run, or all\n"
323 "\n"
Simon Glassfb998c22022-10-29 19:47:12 -0600324 "\nOptions for <suite>:"
Simon Glass154bb8e2022-10-29 19:47:10 -0600325 "\nall - execute all enabled tests"
Simon Glasscfb38f82025-01-20 14:25:30 -0700326 "\ninfo [-s] - show info about tests [and suites]"
Tom Rini03f146c2023-10-07 15:13:08 -0400327 );
Joe Hershberger11dd7cc2015-05-20 14:27:28 -0500328
329U_BOOT_CMD(
330 ut, CONFIG_SYS_MAXARGS, 1, do_ut,
331 "unit tests", ut_help_text
332);