From: Simon Glass <simon.glass@canonical.com> The ut command shows test output but does not provide a machine-readable indication of whether each individual test passed or failed. External tools must rely on heuristics like scanning for failure patterns in the output. Add a -E flag that emits an explicit result line after each test: Result: PASS: test_name: file.c Result: FAIL: test_name: file.c This allows tools to reliably determine per-test pass/fail status without fragile pattern matching. The flag is optional to maintain backward compatibility with existing scripts. Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- doc/usage/cmd/ut.rst | 7 ++++++- include/test/test.h | 2 ++ test/cmd_ut.c | 8 +++++++- test/test-main.c | 9 +++++++++ 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/doc/usage/cmd/ut.rst b/doc/usage/cmd/ut.rst index 07cd970da6c..c40928dece9 100644 --- a/doc/usage/cmd/ut.rst +++ b/doc/usage/cmd/ut.rst @@ -11,7 +11,7 @@ Synopsis :: - ut [-fmr<runs>] [-R] [-I<n>:<one_test>] [<suite> | all [<test>]] [<args>...] + ut [-Efmr<runs>] [-R] [-I<n>:<one_test>] [<suite> | all [<test>]] [<args>...] ut [-s] info Description @@ -26,6 +26,11 @@ suite test Speciifes a particular test to run, within a suite, or all suites +-E + Emit a result line after each test, in the format + `Result: PASS|FAIL|SKIP: <test_name>: <file>`. This is useful for + automated parsing of test results. + -f, -m Force running of manual tests. Manual tests have the `_norun` suffix and are normally skipped because they require external setup (e.g., creating diff --git a/include/test/test.h b/include/test/test.h index 5ae90e39e00..74225a70e54 100644 --- a/include/test/test.h +++ b/include/test/test.h @@ -97,6 +97,7 @@ struct ut_arg { * @arg_count: Number of parsed arguments * @arg_error: Set if ut_str/int/bool() detects a type mismatch * @keep_record: Preserve console recording when ut_fail() is called + * @emit_result: Emit result line after each test completes * @priv: Private data for tests to use as needed */ struct unit_test_state { @@ -128,6 +129,7 @@ struct unit_test_state { int arg_count; bool arg_error; bool keep_record; + bool emit_result; char priv[UT_PRIV_SIZE]; }; diff --git a/test/cmd_ut.c b/test/cmd_ut.c index 37144242099..d6e591916ce 100644 --- a/test/cmd_ut.c +++ b/test/cmd_ut.c @@ -255,6 +255,7 @@ static int do_ut(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) bool show_suites = false; bool force_run = false; bool keep_record = false; + bool emit_result = false; int runs_per_text = 1; struct suite *ste; char *name; @@ -269,6 +270,9 @@ static int do_ut(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) for (str++; *str; str++) { switch (*str) { + case 'E': + emit_result = true; + break; case 'r': runs_per_text = dectoul(str + 1, NULL); goto next_arg; @@ -299,6 +303,7 @@ next_arg: ut_init_state(&uts); uts.keep_record = keep_record; + uts.emit_result = emit_result; name = argv[0]; select_name = cmd_arg1(argc, argv); @@ -344,7 +349,8 @@ next_arg: } U_BOOT_LONGHELP(ut, - "[-fmrs] [-R] [-I<n>:<one_test>] <suite> [<test> [<args>...]] - run unit tests\n" + "[-Efmrs] [-R] [-I<n>:<one_test>] <suite> [<test> [<args>...]] - run unit tests\n" + " -E Emit result line after each test\n" " -r<runs> Number of times to run each test\n" " -f/-m Force 'manual' tests to run as well\n" " -I Test to run after <n> other tests have run\n" diff --git a/test/test-main.c b/test/test-main.c index c9e164da678..2524a154186 100644 --- a/test/test-main.c +++ b/test/test-main.c @@ -624,6 +624,7 @@ static int ut_run_test(struct unit_test_state *uts, struct unit_test *test, { const char *fname = strrchr(test->file, '/') + 1; const char *note = ""; + int old_fail_count; int ret; if ((test->flags & UTF_DM) && !uts->of_live) @@ -639,6 +640,7 @@ static int ut_run_test(struct unit_test_state *uts, struct unit_test *test, if (ret) return ret; + old_fail_count = uts->cur.fail_count; uts->arg_error = false; ret = test->func(uts); if (ret == -EAGAIN) @@ -650,6 +652,13 @@ static int ut_run_test(struct unit_test_state *uts, struct unit_test *test, ut_set_state(NULL); + if (uts->emit_result) { + bool passed = uts->cur.fail_count == old_fail_count; + + printf("Result: %s: %s: %s%s\n", passed ? "PASS" : "FAIL", + test_name, fname, note); + } + return 0; } -- 2.43.0