forked from silentbicycle/greatest
-
Notifications
You must be signed in to change notification settings - Fork 0
/
example.c
384 lines (314 loc) · 10 KB
/
example.c
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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "greatest.h"
/* Define a suite, compiled seperately. */
SUITE_EXTERN(other_suite);
/* Declare a local suite. */
SUITE(suite);
enum foo_t { FOO_1, FOO_2, FOO_3 };
static greatest_enum_str_fun foo_str;
/* Just test against random ints, to show a variety of results. */
TEST example_test_case(void) {
int r = 0;
ASSERT(1 == 1);
r = rand() % 10;
if (r == 1) SKIP();
ASSERT(r >= 1);
PASS();
}
TEST expect_equal(void) {
int i = 9;
ASSERT_EQ(10, i);
PASS();
}
TEST expect_str_equal(void) {
const char *foo1 = "foo1";
ASSERT_STR_EQ("foo2", foo1);
PASS();
}
TEST expect_strn_equal(void) {
const char *foo1 = "foo1";
ASSERT_STRN_EQ("foo2", foo1, 3);
PASS();
}
/* A boxed int type, used to show type-specific equality tests. */
typedef struct {
int i;
} boxed_int;
/* Callback used to check whether two boxed_ints are equal. */
static int boxed_int_equal_cb(const void *exp, const void *got, void *udata) {
const boxed_int *ei = (const boxed_int *)exp;
const boxed_int *gi = (const boxed_int *)got;
/* udata is not used here, but could be used to specify a comparison
* resolution, a string encoding, or any other state that should be
* passed along to the equal and print callbacks. */
(void)udata;
return (ei->i == gi->i);
}
/* Callback to print a boxed_int, used to produce an
* "Exected X, got Y" failure message. */
static int boxed_int_printf_cb(const void *t, void *udata) {
const boxed_int *bi = (const boxed_int *)t;
(void)udata;
return printf("{%d}", bi->i);
}
/* The struct that stores the previous two functions' pointers. */
static greatest_type_info boxed_int_type_info = {
boxed_int_equal_cb,
boxed_int_printf_cb,
};
TEST expect_boxed_int_equal(void) {
boxed_int a = {3};
boxed_int b = {3};
boxed_int c = {4};
ASSERT_EQUAL_T(&a, &b, &boxed_int_type_info, NULL); /* succeeds */
ASSERT_EQUAL_T(&a, &c, &boxed_int_type_info, NULL); /* fails */
PASS();
}
/* The struct that stores the previous two functions' pointers. */
static greatest_type_info boxed_int_type_info_no_print = {
boxed_int_equal_cb,
NULL,
};
TEST expect_boxed_int_equal_no_print(void) {
boxed_int a = {3};
boxed_int b = {3};
boxed_int c = {4};
(void)boxed_int_printf_cb;
/* succeeds */
ASSERT_EQUAL_T(&a, &b, &boxed_int_type_info_no_print, NULL);
/* fails */
ASSERT_EQUAL_T(&a, &c, &boxed_int_type_info_no_print, NULL);
PASS();
}
TEST expect_int_equal_printing_hex(void) {
unsigned int a = 0xba5eba11;
unsigned int b = 0xf005ba11;
ASSERT_EQ_FMT(a, b, "0x%08x");
PASS();
}
TEST expect_floating_point_range(void) {
ASSERT_IN_RANGEm("in range", -0.00001, -0.000110, 0.00010);
ASSERT_IN_RANGEm("in range", 0.00001, 0.000110, 0.00010);
ASSERT_IN_RANGE(0.00001, 0.000110, 0.00010);
ASSERT_IN_RANGEm("out of range", 0.00001, 0.000111, 0.00010);
PASS();
}
/* Flag, used to confirm that teardown hook is being called. */
static int teardown_was_called = 0;
TEST teardown_example_PASS(void) {
teardown_was_called = 0;
PASS();
}
TEST teardown_example_FAIL(void) {
teardown_was_called = 0;
FAILm("Using FAIL to trigger teardown callback");
}
TEST teardown_example_SKIP(void) {
teardown_was_called = 0;
SKIPm("Using SKIP to trigger teardown callback");
}
/* Example of a test case that calls another function which uses ASSERT. */
static greatest_test_res less_than_three(int arg) {
ASSERT(arg <3);
PASS();
}
TEST example_using_subfunctions(void) {
CHECK_CALL(less_than_three(1)); /* <3 */
CHECK_CALL(less_than_three(5)); /* </3 */
PASS();
}
/* Example of an ANSI C compatible way to do test cases with
* arguments: they are passed one argument, a pointer which
* should be cast back to a struct with the other data. */
TEST parametric_example_c89(void *closure) {
int arg = *(int *) closure;
ASSERT(arg > 10);
PASS();
}
/* If using C99, greatest can also do parametric tests without
* needing to manually manage a closure. */
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 19901L
TEST parametric_example_c99(int arg) {
ASSERT(arg > 10);
PASS();
}
#endif
#if GREATEST_USE_LONGJMP
static greatest_test_res subfunction_with_FAIL_WITH_LONGJMP(int arg) {
if (arg == 0) {
FAIL_WITH_LONGJMPm("zero argument (expected failure)");
}
PASS();
}
static greatest_test_res subfunction_with_ASSERT_OR_LONGJMP(int arg) {
ASSERT_OR_LONGJMPm("zero argument (expected failure)", arg != 0);
PASS();
}
TEST fail_via_FAIL_WITH_LONGJMP(void) {
subfunction_with_FAIL_WITH_LONGJMP(0);
PASS();
}
TEST fail_via_FAIL_WITH_LONGJMP_if_0(int arg) {
subfunction_with_FAIL_WITH_LONGJMP(arg);
PASS();
}
TEST fail_via_ASSERT_OR_LONGJMP(void) {
subfunction_with_ASSERT_OR_LONGJMP(0);
PASS();
}
#endif
TEST expect_mem_equal(void) {
char got[56];
char exp[sizeof(got)];
size_t i = 0;
for (i = 0; i < sizeof(got); i++) {
exp[i] = (char)i;
got[i] = (char)i;
}
/* Two bytes differ */
got[23] = 'X';
got[34] = 'X';
ASSERT_MEM_EQm("expected matching memory", got, exp, sizeof(got));
PASS();
}
static const char *foo_str(int v) {
switch ((enum foo_t)v) {
case FOO_1: return "FOO_1";
case FOO_2: return "FOO_2";
case FOO_3: return "FOO_3";
}
return "unknown";
}
static int side_effect = 0;
static enum foo_t foo_2_with_side_effect(void) {
side_effect++;
return FOO_2;
}
TEST expect_enum_equal(void) {
ASSERT_ENUM_EQ(FOO_1, foo_2_with_side_effect(), foo_str);
PASS();
}
TEST expect_enum_equal_only_evaluates_args_once(void) {
/* If the failure case for ASSERT_ENUM_EQ evaluates GOT more
* than once, `side_effect` will be != 1 here. */
ASSERT_EQ_FMTm("ASSERT_ENUM_EQ should only evaluate arguments once",
1, side_effect, "%d");
PASS();
}
static size_t Fibonacci(unsigned char x) {
if (x < 2) {
return 1;
} else {
return Fibonacci(x - 1) + Fibonacci(x - 2);
}
}
TEST extra_slow_test(void) {
unsigned char i;
printf("\nThis test can be skipped with a negative test filter...\n");
for (i = 1; i < 40; i++) {
printf("fib %u -> %lu\n", i, (long unsigned)Fibonacci(i));
}
PASS();
}
static void trace_setup(void *arg) {
printf("-- in setup callback\n");
teardown_was_called = 0;
(void)arg;
}
static void trace_teardown(void *arg) {
printf("-- in teardown callback\n");
teardown_was_called = 1;
(void)arg;
}
/* Primary test suite. */
SUITE(suite) {
volatile int i = 0;
int arg = 0;
printf("\nThis should have some failures:\n");
for (i=0; i<200; i++) {
RUN_TEST(example_test_case);
}
RUN_TEST(expect_equal);
printf("\nThis should fail:\n");
RUN_TEST(expect_str_equal);
printf("\nThis should pass:\n");
RUN_TEST(expect_strn_equal);
printf("\nThis should fail:\n");
RUN_TEST(expect_boxed_int_equal);
printf("\nThis should fail:\n");
RUN_TEST(expect_boxed_int_equal_no_print);
printf("\nThis should fail, printing the mismatched values in hex.\n");
RUN_TEST(expect_int_equal_printing_hex);
printf("\nThis should fail and show floating point values just outside the range.\n");
RUN_TEST(expect_floating_point_range);
/* Set so asserts below won't fail if running in list-only or
* first-fail modes. (setup() won't be called and clear it.) */
teardown_was_called = -1;
/* Add setup/teardown for each test case. */
GREATEST_SET_SETUP_CB(trace_setup, NULL);
GREATEST_SET_TEARDOWN_CB(trace_teardown, NULL);
/* Check that the test-specific teardown hook is called. */
RUN_TEST(teardown_example_PASS);
assert(teardown_was_called);
printf("\nThis should fail:\n");
RUN_TEST(teardown_example_FAIL);
assert(teardown_was_called);
printf("This should be skipped:\n");
RUN_TEST(teardown_example_SKIP);
assert(teardown_was_called);
/* clear setup and teardown */
GREATEST_SET_SETUP_CB(NULL, NULL);
GREATEST_SET_TEARDOWN_CB(NULL, NULL);
printf("This should fail, but note the subfunction that failed.\n");
RUN_TEST(example_using_subfunctions);
/* Run a test with one void* argument (which can point to a
* struct with multiple arguments). */
printf("\nThis should fail:\n");
arg = 10;
RUN_TEST1(parametric_example_c89, &arg);
arg = 11;
RUN_TEST1(parametric_example_c89, &arg);
/* Run a test, with arguments. ('p' for "parametric".) */
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 19901L
printf("\nThis should fail:\n");
RUN_TESTp(parametric_example_c99, 10);
RUN_TESTp(parametric_example_c99, 11);
#endif
#if GREATEST_USE_LONGJMP
RUN_TEST(fail_via_FAIL_WITH_LONGJMP);
RUN_TEST1(fail_via_FAIL_WITH_LONGJMP_if_0, 0);
RUN_TEST(fail_via_ASSERT_OR_LONGJMP);
#endif
#if GREATEST_USE_LONGJMP && \
(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 19901L)
RUN_TESTp(fail_via_FAIL_WITH_LONGJMP_if_0, 0);
#endif
if (GREATEST_IS_VERBOSE()) {
printf("greatest was run with verbosity level: %u\n",
greatest_get_verbosity());
}
printf("\nThis should fail:\n");
RUN_TEST(expect_mem_equal);
printf("\nThis should fail:\n");
RUN_TEST(expect_enum_equal);
printf("\nThis should NOT fail:\n");
RUN_TEST(expect_enum_equal_only_evaluates_args_once);
RUN_TEST(extra_slow_test);
}
TEST standalone_test(void) {
FAILm("(expected failure)");
}
/* Add all the definitions that need to be in the test runner's main file. */
GREATEST_MAIN_DEFS();
int main(int argc, char **argv) {
GREATEST_MAIN_BEGIN(); /* command-line arguments, initialization. */
/* If tests are run outside of a suite, a default suite is used. */
RUN_TEST(standalone_test);
RUN_SUITE(suite);
RUN_SUITE(other_suite);
/* Standalone tests can appear before or after other suites. */
RUN_TEST(standalone_test);
GREATEST_MAIN_END(); /* display results */
}