1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
lily
====
**lily** is a testing library for C. It provides assertions and
clean test registration.
To incorporate lily into a project, just copy `lily-test.h` into
your source code.
usage
-----
A basic unit test file looks like this:
```
#include "lily-test.h"
LILY_FILE_BEGIN(example_file)
LILY_TEST("example test 1")
{
CHECK_EQ(1+1, 2, "%d");
}
#include LILY_PUSH_TEST()
LILY_TEST("example test 2")
{
CHECK_LT(3.0, 4.0, "%0.2f");
}
#include LILY_PUSH_TEST()
#define LILY_FILE_END
#include LILY_REGISTER_TESTS()
```
This will define a function pointer `example_file` with signature `void ()`
that, when called, will execute the two tests and display to stderr any errors
that they generate. While there is more boilerplate than in comparable C++
libraries, this means that lily-test supports test auto-registration. To add a
new test, just use the LILY_TEST macro as shown, and then follow the function
body with `#include LILY_PUSH_TEST()` to register it. These macros will only
work correctly when used between a LILY_FILE_BEGIN and LILY_FILE_END block,
and only when used together; using LILY_TEST without a LILY_PUSH_TEST is
probably going to throw up a ton of compile errors.
### Using a single file
For very small projects, you may be able to get away with using only a single
unit test file. In this case, you should set it up along the following lines:
```
#define LILY_IMPLEMENTATION
#include "lily-test.h"
/* any includes or code to get your tests working */
LILY_FILE_BEGIN(tests)
/* test definitions... */
#define LILY_FILE_END
#include LILY_REGISTER_TESTS()
int main()
{
lily_begin();
tests();
lily_finish();
return 0;
}
```
However, in most cases you will want to have multiple test files.
### Multiple test files
You will need, in addition to your unit test files, a header file that
contains extern declarations of the function pointers defined by your files
and a main C source file that contains a main function to run all of the
function pointers. A nice way to set this up is to use X-macros, like this:
```
/* tests.h */
#define TESTS \
X(suite_1) \
X(suite_2) \
X(suite_3) \
#define X(suite) extern void (*suite)();
TESTS
#undef X
/* tests_main.c */
#define LILY_IMPLEMENTATION
#include "lily-test.h"
int main()
{
lily_begin();
#define X(suite) suite();
TESTS
#undef X
lily_finish();
return 0;
}
```
This is convenient, because it means that when you add a new test file you
need only add a single line to the definition of the TESTS macro in tests.h
and all of the other relevant code is added for you automatically.
Note that exactly ONE file should define LILY_IMPLEMENTATION. I find it
reasonable to make this the same file with the implementation of main but YMMV.
assertions
----------
There are two different basic types of assertions: checks and requirements.
Both checks and requires will mark the overall test as failed if they are false,
but a require will also immediately stop executing the test in addition.
### check macros
**CHECK(x)**
Marks the test as failed if x is false and prints stringified x.
**CHECK_EQ(x, y, fmt)**
Marks the test as failed if x == y is false. Prints both the stringified names
of x and y as well as their values, using the printf format code provided in fmt.
**CHECK_NEQ(x, y, fmt)**
Marks the test as failed if x != y is false. Prints both the stringified names
of x and y as well as their values, using the printf format code provided in fmt.
**CHECK_LT(x, y, fmt)**
Marks the test as failed if x < y is false. Prints both the stringified names
of x and y as well as their values, using the printf format code provided in fmt.
**CHECK_LE(x, y, fmt)**
Marks the test as failed if x <= y is false. Prints both the stringified names
of x and y as well as their values, using the printf format code provided in fmt.
**CHECK_GT(x, y, fmt)**
Marks the test as failed if x > y is false. Prints both the stringified names
of x and y as well as their values, using the printf format code provided in fmt.
**CHECK_GE(x, y, fmt)**
Marks the test as failed if x >= y is false. Prints both the stringified names
of x and y as well as their values, using the printf format code provided in fmt.
### require macros
**REQUIRE(x)**
Marks the test as failed and immediately ends test execution if x is false and
prints stringified x.
**REQUIRE_EQ(x, y, fmt)**
Marks the test as failed and immediately ends test execution if x == y is false.
Prints both the stringified names of x and y as well as their values, using the
printf format code provided in fmt.
**REQUIRE_NEQ(x, y, fmt)**
Marks the test as failed and immediately ends test execution if x != y is false.
Prints both the stringified names of x and y as well as their values, using the
printf format code provided in fmt.
**REQUIRE_LT(x, y, fmt)**
Marks the test as failed and immediately ends test execution if x < y is false.
Prints both the stringified names of x and y as well as their values, using the
printf format code provided in fmt.
**REQUIRE_LE(x, y, fmt)**
Marks the test as failed and immediately ends test execution if x <= y is false.
Prints both the stringified names of x and y as well as their values, using the
printf format code provided in fmt.
**REQUIRE_GT(x, y, fmt)**
Marks the test as failed and immediately ends test execution if x > y is false.
Prints both the stringified names of x and y as well as their values, using the
printf format code provided in fmt.
**REQUIRE_GE(x, y, fmt)**
Marks the test as failed and immediately ends test execution if x >= y is false.
Prints both the stringified names of x and y as well as their values, using the
printf format code provided in fmt.
|