blob: 290b4675856a2f57aa71c92e6bf47afc8a93a763 [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#pragma once
18
19#include <stdbool.h>
20#include <stddef.h>
21#include <stdint.h>
22
23#include "hf/dlog.h"
24
25/*
26 * Define a set up function to be run before every test in a test suite.
27 */
28#define SET_UP(suite) HFTEST_SET_UP(suite)
29
30/*
31 * Define a tear down function to be run after every test in a test suite.
32 */
33#define TEAR_DOWN(suite) HFTEST_TEAR_DOWN(suite)
34
35/*
36 * Define a test as part of a test suite.
37 */
38#define TEST(suite, test) HFTEST_TEST(suite, test)
39
40/* Assertions. */
41#define ASSERT_EQ(x, y) ASSERT_OP(x, y, ==, true)
42#define ASSERT_NE(x, y) ASSERT_OP(x, y, !=, true)
43#define ASSERT_LE(x, y) ASSERT_OP(x, y, <=, true)
44#define ASSERT_LT(x, y) ASSERT_OP(x, y, <, true)
45#define ASSERT_GE(x, y) ASSERT_OP(x, y, >=, true)
46#define ASSERT_GT(x, y) ASSERT_OP(x, y, >, true)
47
Andrew Scull7fd4bb72018-12-08 23:40:12 +000048#define ASSERT_TRUE(x) ASSERT_EQ(x, true);
49#define ASSERT_FALSE(x) ASSERT_EQ(x, false);
50
Andrew Scullbc7189d2018-08-14 09:35:13 +010051#define EXPECT_EQ(x, y) ASSERT_OP(x, y, ==, false)
52#define EXPECT_NE(x, y) ASSERT_OP(x, y, !=, false)
53#define EXPECT_LE(x, y) ASSERT_OP(x, y, <=, false)
54#define EXPECT_LT(x, y) ASSERT_OP(x, y, <, false)
55#define EXPECT_GE(x, y) ASSERT_OP(x, y, >=, false)
56#define EXPECT_GT(x, y) ASSERT_OP(x, y, >, false)
57
Andrew Scull7fd4bb72018-12-08 23:40:12 +000058#define EXPECT_TRUE(x) EXPECT_EQ(x, true);
59#define EXPECT_FALSE(x) EXPECT_EQ(x, false);
60
Andrew Scullbc7189d2018-08-14 09:35:13 +010061/*
62 * This must be used exactly once in a test image to signal to the linker that
63 * the .hftest section is allowed to be included in the generated image.
64 */
65#define HFTEST_ENABLE() int hftest_enable
66
67/*
68 * Prefixed to log lines from tests for easy filtering in the console.
69 */
70#define HFTEST_LOG_PREFIX "[hftest] "
71
72/* Above this point is the public API. Below are the implementation details. */
73
74/* Log with the HFTEST_LOG_PREFIX and a new line. The zero is added so there is
75 * always at least one variadic argument. */
76#define HFTEST_LOG(...) HFTEST_LOG_IMPL(__VA_ARGS__, 0)
77#define HFTEST_LOG_IMPL(format, ...) \
78 dlog("%s" format "\n", HFTEST_LOG_PREFIX, __VA_ARGS__)
79
80/* Helper to wrap the argument in quotes. */
81#define HFTEST_STR(str) #str
82
83/* Sections are names such that when the linker sorts them, all entries for the
84 * same test suite are contiguous and the set up and tear down entries come
85 * before the tests. This order simplifies test discovery in the running image.
86 */
87#define HFTEST_SET_UP_SECTION(suite_name) \
88 HFTEST_STR(.hftest.suite_name .1set_up)
89#define HFTEST_TEAR_DOWN_SECTION(suite_name) \
90 HFTEST_STR(.hftest.suite_name .1tear_down)
91#define HFTEST_TEST_SECTION(suite_name, test_name) \
92 HFTEST_STR(.hftest.suite_name .2test.test_name)
93
94/* Helpers to construct unique identifiers. */
95#define HFTEST_SET_UP_STRUCT(suite_name) hftest_set_up_##suite_name
96#define HFTEST_TEAR_DOWN_STRUCT(suite_name) hftest_tear_down_##suite_name
97#define HFTEST_TEST_STRUCT(suite_name, test_name) \
98 hftest_test_##suite_name##_##test_name
99
100#define HFTEST_SET_UP_FN(suite_name) hftest_set_up_fn_##suite_name
101#define HFTEST_TEAR_DOWN_FN(suite_name) hftest_tear_down_fn_##suite_name
102#define HFTEST_TEST_FN(suite_name, test_name) \
103 hftest_test_fn_##suite_name##_##test_name
104
105/* Register test functions. */
106#define HFTEST_SET_UP(suite_name) \
107 static void HFTEST_SET_UP_FN(suite_name)(struct hftest_context * \
108 hftest_ctx); \
109 const struct hftest_test __attribute__((used)) \
110 __attribute__((section(HFTEST_SET_UP_SECTION(suite_name)))) \
111 HFTEST_SET_UP_STRUCT(suite_name) = { \
112 .suite = #suite_name, \
113 .kind = HFTEST_KIND_SET_UP, \
114 .fn = HFTEST_SET_UP_FN(suite_name), \
115 }; \
116 static void HFTEST_SET_UP_FN(suite_name)( \
117 __attribute__((unused)) struct hftest_context * hftest_ctx)
118
119#define HFTEST_TEAR_DOWN(suite_name) \
120 static void HFTEST_TEAR_DOWN_FN(suite_name)(struct hftest_context * \
121 hftest_ctx); \
122 const struct hftest_test __attribute__((used)) \
123 __attribute__((section(HFTEST_TEAR_DOWN_SECTION(suite_name)))) \
124 HFTEST_TEAR_DOWN_STRUCT(suite_name) = { \
125 .suite = #suite_name, \
126 .kind = HFTEST_KIND_TEAR_DOWN, \
127 .fn = HFTEST_TEAR_DOWN_FN(suite_name), \
128 }; \
129 static void HFTEST_TEAR_DOWN_FN(suite_name)( \
130 __attribute__((unused)) struct hftest_context * hftest_ctx)
131
132#define HFTEST_TEST(suite_name, test_name) \
133 static void HFTEST_TEST_FN( \
134 suite_name, test_name)(struct hftest_context * hftest_ctx); \
135 const struct hftest_test __attribute__((used)) __attribute__( \
136 (section(HFTEST_TEST_SECTION(suite_name, test_name)))) \
137 HFTEST_TEST_STRUCT(suite_name, test_name) = { \
138 .suite = #suite_name, \
139 .kind = HFTEST_KIND_TEST, \
140 .name = #test_name, \
141 .fn = HFTEST_TEST_FN(suite_name, test_name), \
142 }; \
143 static void HFTEST_TEST_FN(suite_name, test_name)( \
144 __attribute__((unused)) struct hftest_context * hftest_ctx)
145
146/* Context for tests. */
147struct hftest_context {
148 uint32_t failures;
149};
150
151/* A test case. */
152typedef void (*hftest_test_fn)(struct hftest_context *);
153
154enum hftest_kind {
155 HFTEST_KIND_SET_UP = 0,
156 HFTEST_KIND_TEST = 1,
157 HFTEST_KIND_TEAR_DOWN = 2,
158};
159
160struct hftest_test {
161 const char *suite;
162 enum hftest_kind kind;
163 const char *name;
164 hftest_test_fn fn;
165};
166
167/*
168 * This union can store any of the primitive types supported by the assertion
169 * macros.
170 *
171 * It does not include pointers as comparison of pointers is not often needed
172 * and could be a mistake for string comparison. If pointer comparison is needed
173 * and explicit assertion such as ASSERT_PTR_EQ() would be more appropriate.
174 */
175union hftest_any {
176 bool b;
177 char c;
178 signed char sc;
179 unsigned char uc;
180 signed short ss;
181 unsigned short us;
182 signed int si;
183 unsigned int ui;
184 signed long int sli;
185 unsigned long int uli;
186 signed long long int slli;
187 unsigned long long int ulli;
188};
189
190/* _Generic formatting doesn't seem to be supported so doing this manually. */
191/* clang-format off */
192
193/* Select the union member to match the type of the expression. */
194#define hftest_any_get(any, x) \
195 _Generic((x), \
196 bool: (any).b, \
197 char: (any).c, \
198 signed char: (any).sc, \
199 unsigned char: (any).uc, \
200 signed short: (any).ss, \
201 unsigned short: (any).us, \
202 signed int: (any).si, \
203 unsigned int: (any).ui, \
204 signed long int: (any).sli, \
205 unsigned long int: (any).uli, \
206 signed long long int: (any).slli, \
207 unsigned long long int: (any).ulli)
208
209/*
210 * dlog format specifier for types. Note, these aren't the standard specifiers
211 * for the types.
212 */
213#define hftest_dlog_format(x) \
214 _Generic((x), \
215 bool: "%u", \
216 char: "%c", \
217 signed char: "%d", \
218 unsigned char: "%u", \
219 signed short: "%d", \
220 unsigned short: "%u", \
221 signed int: "%d", \
222 unsigned int: "%u", \
223 signed long int: "%d", \
224 unsigned long int: "%u", \
225 signed long long int: "%d", \
226 unsigned long long int: "%u")
227
228/* clang-format on */
229
230#define ASSERT_OP(lhs, rhs, op, fatal) \
231 do { \
232 union hftest_any lhs_value; \
233 union hftest_any rhs_value; \
234 hftest_any_get(lhs_value, lhs) = (lhs); \
235 hftest_any_get(rhs_value, rhs) = (rhs); \
236 if (!(hftest_any_get(lhs_value, lhs) \
237 op hftest_any_get(rhs_value, rhs))) { \
238 ++hftest_ctx->failures; \
239 dlog(HFTEST_LOG_PREFIX " %s:%u: Failure\n", __FILE__, \
240 __LINE__); \
241 dlog(HFTEST_LOG_PREFIX " %s %s %s (%s=", #lhs, #op, \
242 #rhs, #lhs); \
243 dlog(hftest_dlog_format(lhs), \
244 hftest_any_get(lhs_value, lhs)); \
245 dlog(", %s=", #rhs); \
246 dlog(hftest_dlog_format(rhs), \
247 hftest_any_get(rhs_value, rhs)); \
248 dlog(")\n"); \
249 if (fatal) { \
250 return; \
251 } \
252 } \
253 } while (0)