1 /*
2 The latest version of this library is available on GitHub;
3 https://github.com/sheredom/utest.h
4 */
5
6 /*
7 This is free and unencumbered software released into the public domain.
8
9 Anyone is free to copy, modify, publish, use, compile, sell, or
10 distribute this software, either in source code form or as a compiled
11 binary, for any purpose, commercial or non-commercial, and by any
12 means.
13
14 In jurisdictions that recognize copyright laws, the author or authors
15 of this software dedicate any and all copyright interest in the
16 software to the public domain. We make this dedication for the benefit
17 of the public at large and to the detriment of our heirs and
18 successors. We intend this dedication to be an overt act of
19 relinquishment in perpetuity of all present and future rights to this
20 software under copyright law.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25 IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
26 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
27 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 OTHER DEALINGS IN THE SOFTWARE.
29
30 For more information, please refer to <http://unlicense.org/>
31 */
32
33 #ifndef SHEREDOM_UTEST_H_INCLUDED
34 #define SHEREDOM_UTEST_H_INCLUDED
35
36 #ifdef _MSC_VER
37 /*
38 Disable warning about not inlining 'inline' functions.
39 TODO: We'll fix this later by not using fprintf within our macros, and
40 instead use snprintf to a realloc'ed buffer.
41 */
42 #pragma warning(disable : 4710)
43
44 /*
45 Disable warning about inlining functions that are not marked 'inline'.
46 TODO: add a UTEST_NOINLINE onto the macro generated functions to fix this.
47 */
48 #pragma warning(disable : 4711)
49 #pragma warning(push, 1)
50 #endif
51
52 #if defined(_MSC_VER)
53 #define int64_t __int64
54 #define uint64_t unsigned __int64
55 #else
56 #include <stdint.h>
57 #endif
58
59 #include <stddef.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63
64 #if defined(_MSC_VER)
65 #pragma warning(pop)
66 #endif
67
68 #if defined(_MSC_VER)
69 #if defined(_M_IX86)
70 #define _X86_
71 #endif
72
73 #if defined(_M_AMD64)
74 #define _AMD64_
75 #endif
76
77 #pragma warning(push, 1)
78 #include <windef.h>
79 #include <winbase.h>
80 #pragma warning(pop)
81
82 #elif defined(__linux__)
83
84 /*
85 slightly obscure include here - we need to include glibc's features.h, but
86 we don't want to just include a header that might not be defined for other
87 c libraries like musl. Instead we include limits.h, which we know on all
88 glibc distributions includes features.h
89 */
90 #include <limits.h>
91
92 #if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
93 #include <time.h>
94
95 #if ((2 < __GLIBC__) || ((2 == __GLIBC__) && (17 <= __GLIBC_MINOR__)))
96 /* glibc is version 2.17 or above, so we can just use clock_gettime */
97 #define UTEST_USE_CLOCKGETTIME
98 #else
99 #include <sys/syscall.h>
100 #include <unistd.h>
101 #endif
102 #endif
103
104 #elif defined(__APPLE__)
105 #include <mach/mach_time.h>
106 #endif
107
108 #if defined(_MSC_VER)
109 #define UTEST_PRId64 "I64d"
110 #define UTEST_PRIu64 "I64u"
111 #define UTEST_INLINE __forceinline
112
113 #pragma section(".CRT$XCU", read)
114 #define UTEST_INITIALIZER(f) \
115 static void __cdecl f(void); \
116 __declspec(allocate(".CRT$XCU")) void(__cdecl * f##_)(void) = f; \
117 static void __cdecl f(void)
118 #else
119 #if defined(__linux__)
120 #if defined(__clang__)
121 #if __has_warning("-Wreserved-id-macro")
122 #pragma clang diagnostic push
123 #pragma clang diagnostic ignored "-Wreserved-id-macro"
124 #endif
125 #endif
126
127 #define __STDC_FORMAT_MACROS 1
128
129 #if defined(__clang__)
130 #if __has_warning("-Wreserved-id-macro")
131 #pragma clang diagnostic pop
132 #endif
133 #endif
134 #endif
135
136 #include <inttypes.h>
137
138 #define UTEST_PRId64 PRId64
139 #define UTEST_PRIu64 PRIu64
140 #define UTEST_INLINE inline
141
142 #define UTEST_INITIALIZER(f) \
143 static void f(void) __attribute__((constructor)); \
144 static void f(void)
145 #endif
146
147 #if defined(__cplusplus)
148 #define UTEST_CAST(type, x) static_cast<type>(x)
149 #define UTEST_PTR_CAST(type, x) reinterpret_cast<type>(x)
150 #define UTEST_EXTERN extern "C"
151 #else
152 #define UTEST_CAST(type, x) ((type)x)
153 #define UTEST_PTR_CAST(type, x) ((type)x)
154 #define UTEST_EXTERN extern
155 #endif
156
utest_ns(void)157 static UTEST_INLINE int64_t utest_ns(void) {
158 #ifdef _MSC_VER
159 LARGE_INTEGER counter;
160 LARGE_INTEGER frequency;
161 QueryPerformanceCounter(&counter);
162 QueryPerformanceFrequency(&frequency);
163 return UTEST_CAST(int64_t,
164 (counter.QuadPart * 1000000000) / frequency.QuadPart);
165 #elif defined(__linux)
166 struct timespec ts;
167 const clockid_t cid = CLOCK_REALTIME;
168 #if defined(UTEST_USE_CLOCKGETTIME)
169 clock_gettime(cid, &ts);
170 #else
171 syscall(SYS_clock_gettime, cid, &ts);
172 #endif
173 return UTEST_CAST(int64_t, ts.tv_sec) * 1000 * 1000 * 1000 + ts.tv_nsec;
174 #elif __APPLE__
175 return UTEST_CAST(int64_t, mach_absolute_time());
176 #endif
177 }
178
179 typedef void (*utest_testcase_t)(int *, size_t);
180
181 struct utest_test_state_s {
182 utest_testcase_t func;
183 size_t index;
184 char *name;
185 };
186
187 struct utest_state_s {
188 struct utest_test_state_s *tests;
189 size_t tests_length;
190 FILE *output;
191 };
192
193 /* extern to the global state utest needs to execute */
194 UTEST_EXTERN struct utest_state_s utest_state;
195
196 #if defined(_MSC_VER)
197 #define UTEST_WEAK __forceinline
198 #else
199 #define UTEST_WEAK __attribute__((weak))
200 #endif
201
202 #if defined(_MSC_VER)
203 #define UTEST_UNUSED
204 #else
205 #define UTEST_UNUSED __attribute__((unused))
206 #endif
207
208 #ifdef __clang__
209 #pragma clang diagnostic push
210 #pragma clang diagnostic ignored "-Wvariadic-macros"
211 #endif
212 #define UTEST_PRINTF(...) \
213 if (utest_state.output) { \
214 fprintf(utest_state.output, __VA_ARGS__); \
215 } \
216 printf(__VA_ARGS__)
217 #ifdef __clang__
218 #pragma clang diagnostic pop
219 #endif
220
221 #ifdef _MSC_VER
222 #define UTEST_SNPRINTF(BUFFER, N, ...) _snprintf_s(BUFFER, N, N, __VA_ARGS__)
223 #else
224 #ifdef __clang__
225 #pragma clang diagnostic push
226 #pragma clang diagnostic ignored "-Wvariadic-macros"
227 #endif
228 #define UTEST_SNPRINTF(...) snprintf(__VA_ARGS__)
229 #ifdef __clang__
230 #pragma clang diagnostic pop
231 #endif
232 #endif
233
234 #if defined(__cplusplus)
235 /* if we are using c++ we can use overloaded methods (its in the language) */
236 #define UTEST_OVERLOADABLE
237 #elif defined(__clang__)
238 /* otherwise, if we are using clang with c - use the overloadable attribute */
239 #define UTEST_OVERLOADABLE __attribute__((overloadable))
240 #endif
241
242 #if defined(UTEST_OVERLOADABLE)
243 UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(const void* p);
utest_type_printer(const void * p)244 UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(const void* p) {
245 UTEST_PRINTF("%p", p);
246 }
247 UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(float f);
utest_type_printer(float f)248 UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(float f) {
249 UTEST_PRINTF("%f", UTEST_CAST(double, f));
250 }
251
252 UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(double d);
utest_type_printer(double d)253 UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(double d) {
254 UTEST_PRINTF("%f", d);
255 }
256
257 UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long double d);
utest_type_printer(long double d)258 UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long double d) {
259 UTEST_PRINTF("%Lf", d);
260 }
261
262 UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(int i);
utest_type_printer(int i)263 UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(int i) {
264 UTEST_PRINTF("%d", i);
265 }
266
267 UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(unsigned int i);
utest_type_printer(unsigned int i)268 UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(unsigned int i) {
269 UTEST_PRINTF("%u", i);
270 }
271
272 UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long int i);
utest_type_printer(long int i)273 UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long int i) {
274 UTEST_PRINTF("%ld", i);
275 }
276
277 UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long unsigned int i);
utest_type_printer(long unsigned int i)278 UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long unsigned int i) {
279 UTEST_PRINTF("%lu", i);
280 }
281
282 /*
283 long long is a c++11 extension
284 TODO: grok for c++11 version here
285 */
286 #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
287 UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long long int i);
utest_type_printer(long long int i)288 UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long long int i) {
289 UTEST_PRINTF("%lld", i);
290 }
291
292 UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long long unsigned int i);
293 UTEST_WEAK UTEST_OVERLOADABLE void
utest_type_printer(long long unsigned int i)294 utest_type_printer(long long unsigned int i) {
295 UTEST_PRINTF("%llu", i);
296 }
297 #endif
298 #else
299 /*
300 we don't have the ability to print the values we got, so we create a macro
301 to tell our users we can't do anything fancy
302 */
303 #define utest_type_printer(...) UTEST_PRINTF("undef")
304 #endif
305
306 #if defined(__clang__)
307 #define UTEST_EXPECT(x, y, cond) \
308 { \
309 _Pragma("clang diagnostic push") _Pragma( \
310 "clang diagnostic ignored \"-Wlanguage-extension-token\"") typeof(y) \
311 xEval = (x); \
312 typeof(y) yEval = (y); \
313 _Pragma("clang diagnostic pop") if (!((xEval)cond(yEval))) { \
314 UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \
315 UTEST_PRINTF(" Expected : "); \
316 utest_type_printer(xEval); \
317 UTEST_PRINTF("\n"); \
318 UTEST_PRINTF(" Actual : "); \
319 utest_type_printer(yEval); \
320 UTEST_PRINTF("\n"); \
321 *utest_result = 1; \
322 } \
323 }
324 #elif defined(__GNUC__)
325 #define UTEST_EXPECT(x, y, cond) \
326 { \
327 typeof(y) xEval = (x); \
328 typeof(y) yEval = (y); \
329 if (!((xEval)cond(yEval))) { \
330 UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \
331 UTEST_PRINTF(" Expected : "); \
332 utest_type_printer(xEval); \
333 UTEST_PRINTF("\n"); \
334 UTEST_PRINTF(" Actual : "); \
335 utest_type_printer(yEval); \
336 UTEST_PRINTF("\n"); \
337 *utest_result = 1; \
338 } \
339 }
340 #else
341 #define UTEST_EXPECT(x, y, cond) \
342 { \
343 if (!((x)cond(y))) { \
344 UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \
345 *utest_result = 1; \
346 } \
347 }
348 #endif
349
350 #define EXPECT_TRUE(x) \
351 if (!(x)) { \
352 UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \
353 UTEST_PRINTF(" Expected : true\n"); \
354 UTEST_PRINTF(" Actual : %s\n", (x) ? "true" : "false"); \
355 *utest_result = 1; \
356 }
357
358 #define EXPECT_FALSE(x) \
359 if (x) { \
360 UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \
361 UTEST_PRINTF(" Expected : false\n"); \
362 UTEST_PRINTF(" Actual : %s\n", (x) ? "true" : "false"); \
363 *utest_result = 1; \
364 }
365
366 #define EXPECT_EQ(x, y) UTEST_EXPECT(x, y, ==)
367 #define EXPECT_NE(x, y) UTEST_EXPECT(x, y, !=)
368 #define EXPECT_LT(x, y) UTEST_EXPECT(x, y, <)
369 #define EXPECT_LE(x, y) UTEST_EXPECT(x, y, <=)
370 #define EXPECT_GT(x, y) UTEST_EXPECT(x, y, >)
371 #define EXPECT_GE(x, y) UTEST_EXPECT(x, y, >=)
372
373 #define EXPECT_STREQ(x, y) \
374 if (0 != strcmp(x, y)) { \
375 UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \
376 UTEST_PRINTF(" Expected : \"%s\"\n", x); \
377 UTEST_PRINTF(" Actual : \"%s\"\n", y); \
378 *utest_result = 1; \
379 }
380
381 #define EXPECT_STRNE(x, y) \
382 if (0 == strcmp(x, y)) { \
383 UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \
384 UTEST_PRINTF(" Expected : \"%s\"\n", x); \
385 UTEST_PRINTF(" Actual : \"%s\"\n", y); \
386 *utest_result = 1; \
387 }
388
389 #if defined(__clang__)
390 #define UTEST_ASSERT(x, y, cond) \
391 { \
392 _Pragma("clang diagnostic push") _Pragma( \
393 "clang diagnostic ignored \"-Wlanguage-extension-token\"") typeof(y) \
394 xEval = (x); \
395 typeof(y) yEval = (y); \
396 _Pragma("clang diagnostic pop") if (!((xEval)cond(yEval))) { \
397 UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \
398 UTEST_PRINTF(" Expected : "); \
399 utest_type_printer(xEval); \
400 UTEST_PRINTF("\n"); \
401 UTEST_PRINTF(" Actual : "); \
402 utest_type_printer(yEval); \
403 UTEST_PRINTF("\n"); \
404 *utest_result = 1; \
405 return; \
406 } \
407 }
408 #elif defined(__GNUC__)
409 #define UTEST_ASSERT(x, y, cond) \
410 { \
411 typeof(y) xEval = (x); \
412 typeof(y) yEval = (y); \
413 if (!((xEval)cond(yEval))) { \
414 UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \
415 UTEST_PRINTF(" Expected : "); \
416 utest_type_printer(xEval); \
417 UTEST_PRINTF("\n"); \
418 UTEST_PRINTF(" Actual : "); \
419 utest_type_printer(yEval); \
420 UTEST_PRINTF("\n"); \
421 *utest_result = 1; \
422 return; \
423 } \
424 }
425 #else
426 #define UTEST_ASSERT(x, y, cond) \
427 { \
428 if (!((x)cond(y))) { \
429 UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \
430 *utest_result = 1; \
431 return; \
432 } \
433 }
434 #endif
435
436 #define ASSERT_TRUE(x) \
437 if (!(x)) { \
438 UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \
439 UTEST_PRINTF(" Expected : true\n"); \
440 UTEST_PRINTF(" Actual : %s\n", (x) ? "true" : "false"); \
441 *utest_result = 1; \
442 return; \
443 }
444
445 #define ASSERT_FALSE(x) \
446 if (x) { \
447 UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \
448 UTEST_PRINTF(" Expected : false\n"); \
449 UTEST_PRINTF(" Actual : %s\n", (x) ? "true" : "false"); \
450 *utest_result = 1; \
451 return; \
452 }
453
454 #define ASSERT_EQ(x, y) UTEST_ASSERT(x, y, ==)
455 #define ASSERT_NE(x, y) UTEST_ASSERT(x, y, !=)
456 #define ASSERT_LT(x, y) UTEST_ASSERT(x, y, <)
457 #define ASSERT_LE(x, y) UTEST_ASSERT(x, y, <=)
458 #define ASSERT_GT(x, y) UTEST_ASSERT(x, y, >)
459 #define ASSERT_GE(x, y) UTEST_ASSERT(x, y, >=)
460
461 #define ASSERT_STREQ(x, y) \
462 EXPECT_STREQ(x, y); \
463 if (0 != strcmp(x, y)) { \
464 UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \
465 UTEST_PRINTF(" Expected : \"%s\"\n", x); \
466 UTEST_PRINTF(" Actual : \"%s\"\n", y); \
467 *utest_result = 1; \
468 return; \
469 }
470
471 #define ASSERT_STRNE(x, y) \
472 EXPECT_STRNE(x, y); \
473 if (0 == strcmp(x, y)) { \
474 UTEST_PRINTF("%s:%u: Failure\n", __FILE__, __LINE__); \
475 UTEST_PRINTF(" Expected : \"%s\"\n", x); \
476 UTEST_PRINTF(" Actual : \"%s\"\n", y); \
477 *utest_result = 1; \
478 return; \
479 }
480
481 #define UTEST(SET, NAME) \
482 UTEST_EXTERN struct utest_state_s utest_state; \
483 static void utest_run_##SET##_##NAME(int *utest_result); \
484 static void utest_##SET##_##NAME(int *utest_result, size_t utest_index) { \
485 (void)utest_index; \
486 utest_run_##SET##_##NAME(utest_result); \
487 } \
488 UTEST_INITIALIZER(utest_register_##SET##_##NAME) { \
489 const size_t index = utest_state.tests_length++; \
490 const char *name_part = #SET "." #NAME; \
491 const size_t name_size = strlen(name_part) + 1; \
492 char *name = UTEST_PTR_CAST(char *, malloc(name_size)); \
493 utest_state.tests = \
494 UTEST_PTR_CAST(struct utest_test_state_s *, \
495 realloc(UTEST_PTR_CAST(void *, utest_state.tests), \
496 sizeof(struct utest_test_state_s) * \
497 utest_state.tests_length)); \
498 utest_state.tests[index].func = &utest_##SET##_##NAME; \
499 utest_state.tests[index].name = name; \
500 UTEST_SNPRINTF(name, name_size, "%s", name_part); \
501 } \
502 void utest_run_##SET##_##NAME(int *utest_result)
503
504 #define UTEST_F_SETUP(FIXTURE) \
505 static void utest_f_setup_##FIXTURE(int *utest_result, \
506 struct FIXTURE *utest_fixture)
507
508 #define UTEST_F_TEARDOWN(FIXTURE) \
509 static void utest_f_teardown_##FIXTURE(int *utest_result, \
510 struct FIXTURE *utest_fixture)
511
512 #define UTEST_F(FIXTURE, NAME) \
513 UTEST_EXTERN struct utest_state_s utest_state; \
514 static void utest_f_setup_##FIXTURE(int *, struct FIXTURE *); \
515 static void utest_f_teardown_##FIXTURE(int *, struct FIXTURE *); \
516 static void utest_run_##FIXTURE##_##NAME(int *, struct FIXTURE *); \
517 static void utest_f_##FIXTURE##_##NAME(int *utest_result, \
518 size_t utest_index) { \
519 struct FIXTURE fixture; \
520 (void)utest_index; \
521 memset(&fixture, 0, sizeof(fixture)); \
522 utest_f_setup_##FIXTURE(utest_result, &fixture); \
523 if (0 != *utest_result) { \
524 return; \
525 } \
526 utest_run_##FIXTURE##_##NAME(utest_result, &fixture); \
527 utest_f_teardown_##FIXTURE(utest_result, &fixture); \
528 } \
529 UTEST_INITIALIZER(utest_register_##FIXTURE##_##NAME) { \
530 const size_t index = utest_state.tests_length++; \
531 const char *name_part = #FIXTURE "." #NAME; \
532 const size_t name_size = strlen(name_part) + 1; \
533 char *name = UTEST_PTR_CAST(char *, malloc(name_size)); \
534 utest_state.tests = \
535 UTEST_PTR_CAST(struct utest_test_state_s *, \
536 realloc(UTEST_PTR_CAST(void *, utest_state.tests), \
537 sizeof(struct utest_test_state_s) * \
538 utest_state.tests_length)); \
539 utest_state.tests[index].func = &utest_f_##FIXTURE##_##NAME; \
540 utest_state.tests[index].name = name; \
541 UTEST_SNPRINTF(name, name_size, "%s", name_part); \
542 } \
543 void utest_run_##FIXTURE##_##NAME(int *utest_result, \
544 struct FIXTURE *utest_fixture)
545
546 #define UTEST_I_SETUP(FIXTURE) \
547 static void utest_i_setup_##FIXTURE( \
548 int *utest_result, struct FIXTURE *utest_fixture, size_t utest_index)
549
550 #define UTEST_I_TEARDOWN(FIXTURE) \
551 static void utest_i_teardown_##FIXTURE( \
552 int *utest_result, struct FIXTURE *utest_fixture, size_t utest_index)
553
554 #define UTEST_I(FIXTURE, NAME, INDEX) \
555 UTEST_EXTERN struct utest_state_s utest_state; \
556 static void utest_run_##FIXTURE##_##NAME##_##INDEX(int *, struct FIXTURE *); \
557 static void utest_i_##FIXTURE##_##NAME##_##INDEX(int *utest_result, \
558 size_t index) { \
559 struct FIXTURE fixture; \
560 memset(&fixture, 0, sizeof(fixture)); \
561 utest_i_setup_##FIXTURE(utest_result, &fixture, index); \
562 if (0 != *utest_result) { \
563 return; \
564 } \
565 utest_run_##FIXTURE##_##NAME##_##INDEX(utest_result, &fixture); \
566 utest_i_teardown_##FIXTURE(utest_result, &fixture, index); \
567 } \
568 UTEST_INITIALIZER(utest_register_##FIXTURE##_##NAME##_##INDEX) { \
569 size_t i; \
570 uint64_t iUp; \
571 for (i = 0; i < (INDEX); i++) { \
572 const size_t index = utest_state.tests_length++; \
573 const char *name_part = #FIXTURE "." #NAME; \
574 const size_t name_size = strlen(name_part) + 32; \
575 char *name = UTEST_PTR_CAST(char *, malloc(name_size)); \
576 utest_state.tests = \
577 UTEST_PTR_CAST(struct utest_test_state_s *, \
578 realloc(UTEST_PTR_CAST(void *, utest_state.tests), \
579 sizeof(struct utest_test_state_s) * \
580 utest_state.tests_length)); \
581 utest_state.tests[index].func = &utest_i_##FIXTURE##_##NAME##_##INDEX; \
582 utest_state.tests[index].index = i; \
583 utest_state.tests[index].name = name; \
584 iUp = UTEST_CAST(uint64_t, i); \
585 UTEST_SNPRINTF(name, name_size, "%s/%" UTEST_PRIu64, name_part, iUp); \
586 } \
587 } \
588 void utest_run_##FIXTURE##_##NAME##_##INDEX(int *utest_result, \
589 struct FIXTURE *utest_fixture)
590
591 UTEST_WEAK
592 int utest_should_filter_test(const char *filter, const char *testcase);
utest_should_filter_test(const char * filter,const char * testcase)593 UTEST_WEAK int utest_should_filter_test(const char *filter,
594 const char *testcase) {
595 if (filter) {
596 const char *filter_cur = filter;
597 const char *testcase_cur = testcase;
598 const char *filter_wildcard = 0;
599
600 while (('\0' != *filter_cur) && ('\0' != *testcase_cur)) {
601 if ('*' == *filter_cur) {
602 /* store the position of the wildcard */
603 filter_wildcard = filter_cur;
604
605 /* skip the wildcard character */
606 filter_cur++;
607
608 while (('\0' != *filter_cur) && ('\0' != *testcase_cur)) {
609 if ('*' == *filter_cur) {
610 /*
611 we found another wildcard (filter is something like *foo*) so we
612 exit the current loop, and return to the parent loop to handle
613 the wildcard case
614 */
615 break;
616 } else if (*filter_cur != *testcase_cur) {
617 /* otherwise our filter didn't match, so reset it */
618 filter_cur = filter_wildcard;
619 }
620
621 /* move testcase along */
622 testcase_cur++;
623
624 /* move filter along */
625 filter_cur++;
626 }
627
628 if (('\0' == *filter_cur) && ('\0' == *testcase_cur)) {
629 return 0;
630 }
631
632 /* if the testcase has been exhausted, we don't have a match! */
633 if ('\0' == *testcase_cur) {
634 return 1;
635 }
636 } else {
637 if (*testcase_cur != *filter_cur) {
638 /* test case doesn't match filter */
639 return 1;
640 } else {
641 /* move our filter and testcase forward */
642 testcase_cur++;
643 filter_cur++;
644 }
645 }
646 }
647
648 if (('\0' != *filter_cur) ||
649 (('\0' != *testcase_cur) &&
650 ((filter == filter_cur) || ('*' != filter_cur[-1])))) {
651 /* we have a mismatch! */
652 return 1;
653 }
654 }
655
656 return 0;
657 }
658
utest_strncmp(const char * a,const char * b,size_t n)659 static UTEST_INLINE int utest_strncmp(const char *a, const char *b, size_t n) {
660 /* strncmp breaks on Wall / Werror on gcc/clang, so we avoid using it */
661 unsigned i;
662
663 for (i = 0; i < n; i++) {
664 if (a[i] < b[i]) {
665 return -1;
666 } else if (a[i] > b[i]) {
667 return 1;
668 }
669 }
670
671 return 0;
672 }
673
utest_fopen(const char * filename,const char * mode)674 static UTEST_INLINE FILE *utest_fopen(const char *filename, const char *mode) {
675 #ifdef _MSC_VER
676 FILE *file;
677 if (0 == fopen_s(&file, filename, mode)) {
678 return file;
679 } else {
680 return 0;
681 }
682 #else
683 return fopen(filename, mode);
684 #endif
685 }
686
687 UTEST_WEAK int utest_main(int argc, const char *const argv[]);
utest_main(int argc,const char * const argv[])688 UTEST_WEAK int utest_main(int argc, const char *const argv[]) {
689 uint64_t failed = 0;
690 size_t index = 0;
691 size_t *failed_testcases = 0;
692 size_t failed_testcases_length = 0;
693 const char *filter = 0;
694 uint64_t ran_tests = 0;
695
696 /* loop through all arguments looking for our options */
697 for (index = 1; index < UTEST_CAST(size_t, argc); index++) {
698 const char help_str[] = "--help";
699 const char filter_str[] = "--filter=";
700 const char output_str[] = "--output=";
701
702 if (0 == utest_strncmp(argv[index], help_str, strlen(help_str))) {
703 printf("utest.h - the single file unit testing solution for C/C++!\n"
704 "Command line Options:\n"
705 " --help Show this message and exit.\n"
706 " --filter=<filter> Filter the test cases to run (EG. MyTest*.a "
707 "would run MyTestCase.a but not MyTestCase.b).\n"
708 " --output=<output> Output an xunit XML file to the file "
709 "specified in <output>.\n");
710 goto cleanup;
711 } else if (0 ==
712 utest_strncmp(argv[index], filter_str, strlen(filter_str))) {
713 /* user wants to filter what test cases run! */
714 filter = argv[index] + strlen(filter_str);
715 } else if (0 ==
716 utest_strncmp(argv[index], output_str, strlen(output_str))) {
717 utest_state.output = utest_fopen(argv[index] + strlen(output_str), "w+");
718 }
719 }
720
721 for (index = 0; index < utest_state.tests_length; index++) {
722 if (utest_should_filter_test(filter, utest_state.tests[index].name)) {
723 continue;
724 }
725
726 ran_tests++;
727 }
728
729 printf("\033[32m[==========]\033[0m Running %" UTEST_PRIu64 " test cases.\n",
730 UTEST_CAST(uint64_t, ran_tests));
731
732 if (utest_state.output) {
733 fprintf(utest_state.output, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
734 fprintf(utest_state.output,
735 "<testsuites tests=\"%" UTEST_PRIu64 "\" name=\"All\">\n",
736 UTEST_CAST(uint64_t, ran_tests));
737 fprintf(utest_state.output,
738 "<testsuite name=\"Tests\" tests=\"%" UTEST_PRIu64 "\">\n",
739 UTEST_CAST(uint64_t, ran_tests));
740 }
741
742 for (index = 0; index < utest_state.tests_length; index++) {
743 int result = 0;
744 int64_t ns = 0;
745
746 if (utest_should_filter_test(filter, utest_state.tests[index].name)) {
747 continue;
748 }
749
750 printf("\033[32m[ RUN ]\033[0m %s\n", utest_state.tests[index].name);
751
752 if (utest_state.output) {
753 fprintf(utest_state.output, "<testcase name=\"%s\">",
754 utest_state.tests[index].name);
755 }
756
757 ns = utest_ns();
758 utest_state.tests[index].func(&result, utest_state.tests[index].index);
759 ns = utest_ns() - ns;
760
761 if (utest_state.output) {
762 fprintf(utest_state.output, "</testcase>\n");
763 }
764
765 if (0 != result) {
766 const size_t failed_testcase_index = failed_testcases_length++;
767 failed_testcases = UTEST_PTR_CAST(
768 size_t *, realloc(UTEST_PTR_CAST(void *, failed_testcases),
769 sizeof(size_t) * failed_testcases_length));
770 failed_testcases[failed_testcase_index] = index;
771 failed++;
772 printf("\033[31m[ FAILED ]\033[0m %s (%" UTEST_PRId64 "ns)\n",
773 utest_state.tests[index].name, ns);
774 } else {
775 printf("\033[32m[ OK ]\033[0m %s (%" UTEST_PRId64 "ns)\n",
776 utest_state.tests[index].name, ns);
777 }
778 }
779
780 printf("\033[32m[==========]\033[0m %" UTEST_PRIu64 " test cases ran.\n",
781 ran_tests);
782 printf("\033[32m[ PASSED ]\033[0m %" UTEST_PRIu64 " tests.\n",
783 ran_tests - failed);
784
785 if (0 != failed) {
786 printf("\033[31m[ FAILED ]\033[0m %" UTEST_PRIu64
787 " tests, listed below:\n",
788 failed);
789 for (index = 0; index < failed_testcases_length; index++) {
790 printf("\033[31m[ FAILED ]\033[0m %s\n",
791 utest_state.tests[failed_testcases[index]].name);
792 }
793 }
794
795 if (utest_state.output) {
796 fprintf(utest_state.output, "</testsuite>\n</testsuites>\n");
797 }
798
799 cleanup:
800 for (index = 0; index < utest_state.tests_length; index++) {
801 free(UTEST_PTR_CAST(void *, utest_state.tests[index].name));
802 }
803
804 free(UTEST_PTR_CAST(void *, failed_testcases));
805 free(UTEST_PTR_CAST(void *, utest_state.tests));
806
807 if (utest_state.output) {
808 fclose(utest_state.output);
809 }
810
811 return UTEST_CAST(int, failed);
812 }
813
814 /*
815 we need, in exactly one source file, define the global struct that will hold
816 the data we need to run utest. This macro allows the user to declare the
817 data without having to use the UTEST_MAIN macro, thus allowing them to write
818 their own main() function.
819 */
820 #define UTEST_STATE() struct utest_state_s utest_state = {0, 0, 0}
821
822 /*
823 define a main() function to call into utest.h and start executing tests! A
824 user can optionally not use this macro, and instead define their own main()
825 function and manually call utest_main. The user must, in exactly one source
826 file, use the UTEST_STATE macro to declare a global struct variable that
827 utest requires.
828 */
829 #define UTEST_MAIN() \
830 UTEST_STATE(); \
831 int main(int argc, const char *const argv[]) { \
832 return utest_main(argc, argv); \
833 }
834
835 #endif /* SHEREDOM_UTEST_H_INCLUDED */
836