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