1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#include "mos/platform/platform.h"
4#include "test_engine_impl.h"
5
6#include <mos/lib/structures/list.h>
7#include <mos/misc/cmdline.h>
8#include <mos/misc/panic.h>
9#include <mos/misc/setup.h>
10#include <mos/syslog/printk.h>
11#include <mos_stdio.h>
12#include <mos_stdlib.h>
13#include <mos_string.h>
14
15s32 test_engine_n_warning_expected = 0;
16
17static void test_engine_warning_handler(const char *func, u32 line, const char *fmt, va_list args)
18{
19 char message[MOS_PRINTK_BUFFER_SIZE];
20 vsnprintf(buf: message, MOS_PRINTK_BUFFER_SIZE, format: fmt, args);
21
22 if (test_engine_n_warning_expected == 0)
23 {
24 lprintk(loglevel: MOS_LOG_WARN, format: "\r\n");
25 lprintk(loglevel: MOS_LOG_WARN, format: "warning: %s", message);
26 lprintk(loglevel: MOS_LOG_WARN, format: " in function: %s (line %u)", func, line);
27 mos_panic("unexpected warning, test failed.");
28 }
29
30 test_engine_n_warning_expected--;
31}
32
33static const char **test_engine_skip_prefix_list = NULL;
34static bool mos_tests_halt_on_success = false;
35
36static bool mos_test_engine_setup_skip_prefix_list(const char *arg)
37{
38 // split the argument into a list of strings
39 int argc = 1;
40 for (int i = 0; arg[i]; i++)
41 if (arg[i] == ',')
42 argc++;
43
44 test_engine_skip_prefix_list = kmalloc(sizeof(char *) * argc);
45
46 int i = 0;
47 char *token = strtok(str: (char *) arg, delim: ",");
48 while (token)
49 {
50 test_engine_skip_prefix_list[i] = token;
51 token = strtok(NULL, delim: ",");
52 i++;
53 }
54
55 return true;
56}
57
58MOS_SETUP("mos_tests_skip_prefix", mos_test_engine_setup_skip_prefix_list);
59
60static bool mos_tests_setup_halt_on_success(const char *arg)
61{
62 mos_tests_halt_on_success = cmdline_string_truthiness(arg, default_value: true);
63 return true;
64}
65
66MOS_SETUP("mos_tests_halt_on_success", mos_tests_setup_halt_on_success);
67
68static bool mos_test_engine_should_skip(const char *test_name)
69{
70 if (!test_engine_skip_prefix_list)
71 return false;
72
73 for (int i = 0; test_engine_skip_prefix_list[i]; i++)
74 {
75 if (strncmp(str1: test_name, str2: test_engine_skip_prefix_list[i], n: strlen(str: test_engine_skip_prefix_list[i])) == 0)
76 return true;
77 }
78
79 return false;
80}
81
82static bool mos_test_engine_run_tests(const char *arg)
83{
84 MOS_UNUSED(arg);
85 kwarn_handler_set(handler: test_engine_warning_handler);
86
87 mos_test_result_t result = { 0 };
88
89 MOS_TEST_FOREACH_TEST_CASE(test_case)
90 {
91 bool should_skip = mos_test_engine_should_skip(test_name: test_case->test_name);
92
93 if (should_skip)
94 continue;
95
96 mos_test_result_t r = { 0 };
97 test_case->test_func(&r);
98
99 result.n_total += r.n_total;
100 result.n_failed += r.n_failed;
101 result.n_skipped += r.n_skipped;
102
103 if (result.n_failed > 0)
104 mos_panic("TEST FAILED.");
105 }
106
107 kwarn_handler_remove();
108
109 u32 passed = result.n_total - result.n_failed - result.n_skipped;
110 pr_emph("ALL %u TESTS PASSED: (%u succeed, %u failed, %u skipped)", result.n_total, passed, result.n_failed, result.n_skipped);
111
112 if (mos_tests_halt_on_success)
113 platform_halt_cpu();
114
115 return true;
116}
117
118MOS_SETUP("mos_tests", mos_test_engine_run_tests);
119