blob: 90b5cf0b0ac69702b540370c196ce70d3551bf80 [file] [log] [blame]
Andrew Scullbc7189d2018-08-14 09:35:13 +01001#include "hftest.h"
2
3#include <stdalign.h>
4#include <stdint.h>
5
6#include "hf/fdt.h"
7#include "hf/memiter.h"
8
9alignas(4096) uint8_t kstack[4096];
10
11HFTEST_ENABLE();
12
13extern struct hftest_test hftest_begin[];
14extern struct hftest_test hftest_end[];
15
16static void json(void)
17{
18 struct hftest_test *test;
19 const char *suite = NULL;
20 size_t suites_in_image = 0;
21 size_t tests_in_suite = 0;
22
23 HFTEST_LOG("{");
24 HFTEST_LOG(" \"suites\": [");
25 for (test = hftest_begin; test < hftest_end; ++test) {
26 if (test->suite != suite) {
27 /* Close out previously open suite. */
28 if (tests_in_suite) {
29 HFTEST_LOG(" ]");
30 HFTEST_LOG(" },");
31 }
32 /* Move onto new suite. */
33 ++suites_in_image;
34 suite = test->suite;
35 tests_in_suite = 0;
36 HFTEST_LOG(" {");
37 HFTEST_LOG(" \"name\": \"%s\",", test->suite);
38 }
39 if (test->kind == HFTEST_KIND_SET_UP) {
40 HFTEST_LOG(" \"setup\": true,");
41 }
42 if (test->kind == HFTEST_KIND_TEAR_DOWN) {
43 HFTEST_LOG(" \"teardown\": true,");
44 }
45 if (test->kind == HFTEST_KIND_TEST) {
46 if (!tests_in_suite) {
47 HFTEST_LOG(" \"tests\": [");
48 }
49 /* It's easier to put the comma at the start of the line
50 * than the end even
51 * though the JSON looks a bit funky. */
52 HFTEST_LOG(" %c\"%s\"",
53 tests_in_suite ? ',' : ' ', test->name);
54 ++tests_in_suite;
55 }
56 }
57 if (tests_in_suite) {
58 HFTEST_LOG(" ]");
59 HFTEST_LOG(" }");
60 }
61 HFTEST_LOG(" ]");
62 HFTEST_LOG("}");
63}
64
65static void run_test(hftest_test_fn set_up, hftest_test_fn test,
66 hftest_test_fn tear_down)
67{
68 struct hftest_context ctx = {
69 .failures = 0,
70 };
71
72 if (set_up) {
73 set_up(&ctx);
74 if (ctx.failures) {
75 goto fail;
76 }
77 }
78
79 test(&ctx);
80 if (ctx.failures) {
81 goto fail;
82 }
83
84 if (tear_down) {
85 tear_down(&ctx);
86 if (ctx.failures) {
87 goto fail;
88 }
89 }
90
91 HFTEST_LOG("PASS");
92 return;
93
94fail:
95 HFTEST_LOG("FAIL");
96}
97
98static void run(struct memiter *args)
99{
100 struct memiter suite_name;
101 struct memiter test_name;
102 struct hftest_test *test;
103 bool found_suite = false;
104 const char *suite = NULL;
105 hftest_test_fn suite_set_up = NULL;
106 hftest_test_fn suite_tear_down = NULL;
107
108 if (!memiter_parse_str(args, &suite_name)) {
109 HFTEST_LOG("Unable to parse test suite.");
110 return;
111 }
112
113 if (!memiter_parse_str(args, &test_name)) {
114 HFTEST_LOG("Unable to parse test.");
115 return;
116 }
117
118 for (test = hftest_begin; test < hftest_end; ++test) {
119 /* Find the test suite. */
120 if (found_suite) {
121 if (test->suite != suite) {
122 /* Test wasn't in the suite. */
123 break;
124 }
125 } else {
126 if (test->suite == suite) {
127 /* This isn't the right suite so keep going. */
128 continue;
129 }
130 /* Examine a new suite. */
131 suite = test->suite;
132 if (memiter_iseq(&suite_name, test->suite)) {
133 found_suite = true;
134 }
135 }
136
137 switch (test->kind) {
138 /* The first entries in the suite are the set up and tear down
139 * functions. */
140 case HFTEST_KIND_SET_UP:
141 suite_set_up = test->fn;
142 break;
143 case HFTEST_KIND_TEAR_DOWN:
144 suite_tear_down = test->fn;
145 break;
146 /* Find the test. */
147 case HFTEST_KIND_TEST:
148 if (memiter_iseq(&test_name, test->name)) {
149 run_test(suite_set_up, test->fn,
150 suite_tear_down);
151 return;
152 }
153 break;
154 }
155 }
156
157 HFTEST_LOG("Unable to find requested tests.");
158}
159
160void help(void)
161{
162 HFTEST_LOG("usage:");
163 HFTEST_LOG("");
164 HFTEST_LOG(" help");
165 HFTEST_LOG("");
166 HFTEST_LOG(" Show this help.");
167 HFTEST_LOG("");
168 HFTEST_LOG(" json");
169 HFTEST_LOG("");
170 HFTEST_LOG(
171 " Print a directory of test suites and tests in "
172 "JSON "
173 "format.");
174 HFTEST_LOG("");
175 HFTEST_LOG(" run <suite> <test>");
176 HFTEST_LOG("");
177 HFTEST_LOG(" Run the named test from the named test suite.");
178}
179
180void main(const struct fdt_header *fdt)
181{
182 struct fdt_node n;
183 const char *bootargs;
184 uint32_t bootargs_size;
185 struct memiter bootargs_iter;
186 struct memiter command;
187
188 if (!fdt_root_node(&n, fdt)) {
189 HFTEST_LOG("FDT failed validation.");
190 return;
191 }
192
193 if (!fdt_find_child(&n, "")) {
194 HFTEST_LOG("Unable to find root node in FDT.");
195 return;
196 }
197
198 if (!fdt_find_child(&n, "chosen")) {
199 HFTEST_LOG("Unable to find 'chosen' node in FDT.");
200 return;
201 }
202
203 if (!fdt_read_property(&n, "bootargs", &bootargs, &bootargs_size)) {
204 HFTEST_LOG("Unable to read bootargs.");
205 return;
206 }
207
208 /* Remove null terminator. */
209 memiter_init(&bootargs_iter, bootargs, bootargs_size - 1);
210
211 if (!memiter_parse_str(&bootargs_iter, &command)) {
212 HFTEST_LOG("Unable to parse command.");
213 return;
214 }
215
216 if (memiter_iseq(&command, "json")) {
217 json();
218 return;
219 }
220
221 if (memiter_iseq(&command, "run")) {
222 run(&bootargs_iter);
223 return;
224 }
225
226 help();
227}
228
229void kmain(const struct fdt_header *fdt)
230{
231 main(fdt);
232}