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