blob: 2959ff5b83e7ab72a6e0e85bfcd5b8553a14095a [file] [log] [blame]
Andrew Scullf35a5c92018-08-07 18:09:46 +01001#ifndef _HF_TEST_H
2#define _HF_TEST_H
3
4#include <stdbool.h>
5#include <stdint.h>
6
7#include "dlog.h"
8
9/*
10 * Prefixed to log lines from tests for easy filtering in the console.
11 */
12#define HF_TEST_LOG_PREFIX "[hf_test] "
13
14/*
15 * Context for tests.
16 */
17struct hf_test_context {
18 uint32_t failures;
19};
20
21/*
22 * This union can store any of the primitive types supported by the assertion
23 * macros.
24 */
25union hf_test_any {
26 bool b;
27 char c;
28 signed char sc;
29 unsigned char uc;
30 signed short ss;
31 unsigned short us;
32 signed int si;
33 unsigned int ui;
34 signed long int sli;
35 unsigned long int uli;
36 signed long long int slli;
37 unsigned long long int ulli;
38 void *p;
39};
40
41/* _Generic formatting doesn't seem to be supported so doing this manually. */
42/* clang-format off */
43
44/* Select the union member to match the type of the expression. */
45#define hf_test_any_get(any, x) \
46 _Generic((x), \
47 bool: (any).b, \
48 char: (any).c, \
49 signed char: (any).sc, \
50 unsigned char: (any).uc, \
51 signed short: (any).ss, \
52 unsigned short: (any).us, \
53 signed int: (any).si, \
54 unsigned int: (any).ui, \
55 signed long int: (any).sli, \
56 unsigned long int: (any).uli, \
57 signed long long int: (any).slli, \
58 unsigned long long int: (any).ulli, \
59 void *: (any).p)
60
61/*
62 * dlog format specifier for types. Note, these aren't the standard specifiers
63 * for the types.
64 */
65#define hf_test_dlog_format(x) \
66 _Generic((x), \
67 bool: "%u", \
68 char: "%c", \
69 signed char: "%d", \
70 unsigned char: "%u", \
71 signed short: "%d", \
72 unsigned short: "%u", \
73 signed int: "%d", \
74 unsigned int: "%u", \
75 signed long int: "%d", \
76 unsigned long int: "%u", \
77 signed long long int: "%d", \
78 unsigned long long int: "%u", \
79 void *: "%p")
80
81/* clang-format on */
82
83#define ASSERT_OP(lhs, rhs, op, fatal) \
84 do { \
85 union hf_test_any lhs_value; \
86 union hf_test_any rhs_value; \
87 hf_test_any_get(lhs_value, lhs) = (lhs); \
88 hf_test_any_get(rhs_value, rhs) = (rhs); \
89 if (!(hf_test_any_get(lhs_value, lhs) \
90 op hf_test_any_get(rhs_value, rhs))) { \
91 ++hf_test_ctx->failures; \
92 dlog(HF_TEST_LOG_PREFIX " %s:%u: Failure\n", \
93 __FILE__, __LINE__); \
94 dlog(HF_TEST_LOG_PREFIX " %s %s %s (%s=", #lhs, \
95 #op, #rhs, #lhs); \
96 dlog(hf_test_dlog_format(lhs), \
97 hf_test_any_get(lhs_value, lhs)); \
98 dlog(", %s=", #rhs); \
99 dlog(hf_test_dlog_format(rhs), \
100 hf_test_any_get(rhs_value, rhs)); \
101 dlog(")\n"); \
102 if (fatal) { \
103 return; \
104 } \
105 } \
106 } while (0)
107
108#define ASSERT_EQ(x, y) ASSERT_OP(x, y, ==, true)
109#define ASSERT_NE(x, y) ASSERT_OP(x, y, !=, true)
110#define ASSERT_LE(x, y) ASSERT_OP(x, y, <=, true)
111#define ASSERT_LT(x, y) ASSERT_OP(x, y, <, true)
112#define ASSERT_GE(x, y) ASSERT_OP(x, y, >=, true)
113#define ASSERT_GT(x, y) ASSERT_OP(x, y, >, true)
114
115#define EXPECT_EQ(x, y) ASSERT_OP(x, y, ==, false)
116#define EXPECT_NE(x, y) ASSERT_OP(x, y, !=, false)
117#define EXPECT_LE(x, y) ASSERT_OP(x, y, <=, false)
118#define EXPECT_LT(x, y) ASSERT_OP(x, y, <, false)
119#define EXPECT_GE(x, y) ASSERT_OP(x, y, >=, false)
120#define EXPECT_GT(x, y) ASSERT_OP(x, y, >, false)
121
122/*
123 * Declare a test case.
124 */
125#define TEST(name) static void name(struct hf_test_context *hf_test_ctx)
126
127/*
128 * Run a test case.
129 */
130#define RUN_TEST(test) \
131 do { \
132 struct hf_test_context ctx = { \
133 .failures = 0, \
134 }; \
135 dlog(HF_TEST_LOG_PREFIX "RUN %s\n", #test); \
136 test(&ctx); \
137 if (ctx.failures) { \
138 dlog(HF_TEST_LOG_PREFIX "FAILED\n"); \
139 } else { \
140 dlog(HF_TEST_LOG_PREFIX "OK\n"); \
141 } \
142 } while (0)
143
144#endif /* _HF_TEST_H */