Coverage Report

Created: 2026-03-11 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/u-boot/test/cmd_ut.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
 * (C) Copyright 2015
4
 * Joe Hershberger, National Instruments, joe.hershberger@ni.com
5
 */
6
7
#include <command.h>
8
#include <console.h>
9
#include <vsprintf.h>
10
#include <test/test.h>
11
#include <test/ut.h>
12
13
/**
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)
22
 * @help: Help-string to show for this suite
23
 */
24
struct suite {
25
  const char *name;
26
  struct unit_test *start;
27
  struct unit_test *end;
28
  const char *help;
29
};
30
31
static int do_ut_all(struct unit_test_state *uts, const char *select_name,
32
         int runs_per_test, bool force_run,
33
         const char *test_insert);
34
35
static int do_ut_info(bool show_suites);
36
37
/* 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
42
/* declare a test suite which can be run directly without a subcommand */
43
#define SUITE(_name, _help) { \
44
  #_name, \
45
  suite_start_ ## _name, \
46
  suite_end_ ## _name, \
47
  _help, \
48
  }
49
50
SUITE_DECL(addrmap);
51
SUITE_DECL(bdinfo);
52
SUITE_DECL(bloblist);
53
SUITE_DECL(bootm);
54
SUITE_DECL(bootstd);
55
SUITE_DECL(cmd);
56
SUITE_DECL(common);
57
SUITE_DECL(dm);
58
SUITE_DECL(env);
59
SUITE_DECL(exit);
60
SUITE_DECL(fdt);
61
SUITE_DECL(fdt_overlay);
62
SUITE_DECL(font);
63
SUITE_DECL(hush);
64
SUITE_DECL(lib);
65
SUITE_DECL(loadm);
66
SUITE_DECL(log);
67
SUITE_DECL(mbr);
68
SUITE_DECL(measurement);
69
SUITE_DECL(mem);
70
SUITE_DECL(optee);
71
SUITE_DECL(pci_mps);
72
SUITE_DECL(seama);
73
SUITE_DECL(setexpr);
74
SUITE_DECL(upl);
75
76
static struct suite suites[] = {
77
  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"),
81
  SUITE(bootstd, "standard boot implementation"),
82
  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"),
88
  SUITE(fdt_overlay, "device tree overlays"),
89
  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"),
97
  SUITE(optee, "OP-TEE"),
98
  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"),
102
};
103
104
/**
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
 */
113
static bool has_tests(struct suite *ste)
114
0
{
115
0
  int n_ents = ste->end - ste->start;
116
117
0
  return n_ents;
118
0
}
119
120
/** run_suite() - Run a suite of tests */
121
static int run_suite(struct unit_test_state *uts, struct suite *ste,
122
         const char *select_name, int runs_per_test, bool force_run,
123
         const char *test_insert)
124
0
{
125
0
  int n_ents = ste->end - ste->start;
126
0
  char prefix[30];
127
0
  int ret;
128
129
  /* use a standard prefix */
130
0
  snprintf(prefix, sizeof(prefix), "%s_test_", ste->name);
131
132
0
  ret = ut_run_list(uts, ste->name, prefix, ste->start, n_ents,
133
0
        select_name, runs_per_test, force_run, test_insert);
134
135
0
  return ret;
136
0
}
137
138
static void show_stats(struct unit_test_state *uts)
139
0
{
140
0
  if (uts->run_count < 2)
141
0
    return;
142
143
0
  ut_report(&uts->total, uts->run_count);
144
0
  if (CONFIG_IS_ENABLED(UNIT_TEST_DURATION) &&
145
0
      uts->total.test_count && uts->worst) {
146
0
    ulong avg = uts->total.duration_ms / uts->total.test_count;
147
148
0
    printf("Average test time: %ld ms, worst case '%s' took %d ms\n",
149
0
           avg, uts->worst->name, uts->worst_ms);
150
0
  }
151
0
}
152
153
static void update_stats(struct unit_test_state *uts, const struct suite *ste)
154
0
{
155
0
  if (CONFIG_IS_ENABLED(UNIT_TEST_DURATION) && uts->cur.test_count) {
156
0
    ulong avg;
157
158
0
    avg = uts->cur.duration_ms ?
159
0
      uts->cur.duration_ms /
160
0
      uts->cur.test_count : 0;
161
0
    if (avg > uts->worst_ms) {
162
0
      uts->worst_ms = avg;
163
0
      uts->worst = ste;
164
0
    }
165
0
  }
166
0
}
167
168
static int do_ut_all(struct unit_test_state *uts, const char *select_name,
169
         int runs_per_test, bool force_run, const char *test_insert)
170
0
{
171
0
  int i;
172
0
  int retval;
173
0
  int any_fail = 0;
174
175
0
  for (i = 0; i < ARRAY_SIZE(suites); i++) {
176
0
    struct suite *ste = &suites[i];
177
178
0
    if (has_tests(ste)) {
179
0
      printf("----Running %s tests----\n", ste->name);
180
0
      retval = run_suite(uts, ste, select_name, runs_per_test,
181
0
             force_run, test_insert);
182
0
      if (!any_fail)
183
0
        any_fail = retval;
184
0
      update_stats(uts, ste);
185
0
    }
186
0
  }
187
188
0
  return any_fail;
189
0
}
190
191
static int do_ut_info(bool show_suites)
192
0
{
193
0
  int suite_count, i;
194
195
0
  for (suite_count = 0, i = 0; i < ARRAY_SIZE(suites); i++) {
196
0
    struct suite *ste = &suites[i];
197
198
0
    if (has_tests(ste))
199
0
      suite_count++;
200
0
  }
201
202
0
  printf("Test suites: %d\n", suite_count);
203
0
  printf("Total tests: %d\n", (int)UNIT_TEST_ALL_COUNT());
204
205
0
  if (show_suites) {
206
0
    int i, total;
207
208
0
    puts("\nTests  Suite         Purpose");
209
0
    puts("\n-----  ------------  -------------------------\n");
210
0
    for (i = 0, total = 0; i < ARRAY_SIZE(suites); i++) {
211
0
      struct suite *ste = &suites[i];
212
0
      long n_ent = ste->end - ste->start;
213
214
0
      if (n_ent) {
215
0
        printf("%5ld  %-13.13s %s\n", n_ent, ste->name,
216
0
               ste->help);
217
0
        total += n_ent;
218
0
      }
219
0
    }
220
0
    puts("-----  ------------  -------------------------\n");
221
0
    printf("%5d  %-13.13s\n", total, "Total");
222
223
0
    if (UNIT_TEST_ALL_COUNT() != total)
224
0
      puts("Error: Suite test-count does not match total\n");
225
0
  }
226
227
0
  return 0;
228
0
}
229
230
static struct suite *find_suite(const char *name)
231
0
{
232
0
  struct suite *ste;
233
0
  int i;
234
235
0
  for (i = 0, ste = suites; i < ARRAY_SIZE(suites); i++, ste++) {
236
0
    if (!strcmp(ste->name, name))
237
0
      return ste;
238
0
  }
239
240
0
  return NULL;
241
0
}
242
243
static int do_ut(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
244
0
{
245
0
  const char *test_insert = NULL, *select_name;
246
0
  struct unit_test_state uts;
247
0
  bool show_suites = false;
248
0
  bool force_run = false;
249
0
  int runs_per_text = 1;
250
0
  struct suite *ste;
251
0
  char *name;
252
0
  int ret;
253
254
  /* drop initial "ut" arg */
255
0
  argc--;
256
0
  argv++;
257
258
0
  while (argc > 0 && *argv[0] == '-') {
259
0
    const char *str = argv[0];
260
261
0
    switch (str[1]) {
262
0
    case 'r':
263
0
      runs_per_text = dectoul(str + 2, NULL);
264
0
      break;
265
0
    case 'f':
266
0
      force_run = true;
267
0
      break;
268
0
    case 'I':
269
0
      test_insert = str + 2;
270
0
      if (!strchr(test_insert, ':'))
271
0
        return CMD_RET_USAGE;
272
0
      break;
273
0
    case 's':
274
0
      show_suites = true;
275
0
      break;
276
0
    }
277
0
    argv++;
278
0
    argc--;
279
0
  }
280
281
0
  if (argc < 1)
282
0
    return CMD_RET_USAGE;
283
284
0
  ut_init_state(&uts);
285
0
  name = argv[0];
286
0
  select_name = cmd_arg1(argc, argv);
287
0
  if (!strcmp(name, "all")) {
288
0
    ret = do_ut_all(&uts, select_name, runs_per_text, force_run,
289
0
        test_insert);
290
0
  } else if (!strcmp(name, "info")) {
291
0
    ret = do_ut_info(show_suites);
292
0
  } else {
293
0
    int any_fail = 0;
294
0
    const char *p;
295
296
0
    for (; p = strsep(&name, ","), p; name = NULL) {
297
0
      ste = find_suite(p);
298
0
      if (!ste) {
299
0
        printf("Suite '%s' not found\n", p);
300
0
        return CMD_RET_FAILURE;
301
0
      } else if (!has_tests(ste)) {
302
        /* perhaps a Kconfig option needs to be set? */
303
0
        printf("Suite '%s' is not enabled\n", p);
304
0
        return CMD_RET_FAILURE;
305
0
      }
306
307
0
      ret = run_suite(&uts, ste, select_name, runs_per_text,
308
0
          force_run, test_insert);
309
0
      if (!any_fail)
310
0
        any_fail = ret;
311
0
      update_stats(&uts, ste);
312
0
    }
313
0
    ret = any_fail;
314
0
  }
315
0
  show_stats(&uts);
316
0
  if (ret)
317
0
    return ret;
318
0
  ut_uninit_state(&uts);
319
320
0
  return 0;
321
0
}
322
323
U_BOOT_LONGHELP(ut,
324
  "[-rs] [-f] [-I<n>:<one_test>][<suites>] - run unit tests\n"
325
  "   -r<runs>   Number of times to run each test\n"
326
  "   -f         Force 'manual' tests to run as well\n"
327
  "   -I         Test to run after <n> other tests have run\n"
328
  "   -s         Show all suites with ut info\n"
329
  "   <suites>   Comma-separated list of suites to run\n"
330
  "\n"
331
  "Options for <suite>:\n"
332
  "all       - execute all enabled tests\n"
333
  "info      - show info about tests [and suites]"
334
  );
335
336
U_BOOT_CMD(
337
  ut, CONFIG_SYS_MAXARGS, 1, do_ut,
338
  "unit tests", ut_help_text
339
);