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