xref: /freebsd/sys/contrib/openzfs/tests/unit/munit.c (revision d9497217456002b0ddad3cd319570d0b098daa29)
1 // SPDX-License-Identifier: MIT
2 /* µnit Testing Framework
3  * Copyright (c) 2013-2018 Evan Nemerson <evan@nemerson.com>
4  *
5  * Permission is hereby granted, free of charge, to any person
6  * obtaining a copy of this software and associated documentation
7  * files (the "Software"), to deal in the Software without
8  * restriction, including without limitation the rights to use, copy,
9  * modify, merge, publish, distribute, sublicense, and/or sell copies
10  * of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25 
26 /*** Configuration ***/
27 
28 /* This is just where the output from the test goes.  It's really just
29  * meant to let you choose stdout or stderr, but if anyone really want
30  * to direct it to a file let me know, it would be fairly easy to
31  * support. */
32 #if !defined(MUNIT_OUTPUT_FILE)
33 #  define MUNIT_OUTPUT_FILE stdout
34 #endif
35 
36 /* This is a bit more useful; it tells µnit how to format the seconds in
37  * timed tests.  If your tests run for longer you might want to reduce
38  * it, and if your computer is really fast and your tests are tiny you
39  * can increase it. */
40 #if !defined(MUNIT_TEST_TIME_FORMAT)
41 #  define MUNIT_TEST_TIME_FORMAT "0.8f"
42 #endif
43 
44 /* If you have long test names you might want to consider bumping
45  * this.  The result information takes 43 characters. */
46 #if !defined(MUNIT_TEST_NAME_LEN)
47 #  define MUNIT_TEST_NAME_LEN 37
48 #endif
49 
50 /* If you don't like the timing information, you can disable it by
51  * defining MUNIT_DISABLE_TIMING. */
52 #if !defined(MUNIT_DISABLE_TIMING)
53 #  define MUNIT_ENABLE_TIMING
54 #endif
55 
56 /* OpenZFS: claim no strerror_r, causing munit to use its own internal
57  * fallback. There are two version of strerror_r (XSI and GNU), subtly
58  * different, and some glibc versions have warn_unused_result set on the
59  * prototype. munit is not prepared for this variance, so better just to
60  * let it do its own thing. -- robn, 2026-05-21 */
61 #if !defined(MUNIT_NO_STRERROR_R)
62 #  define MUNIT_NO_STRERROR_R
63 #endif
64 
65 /*** End configuration ***/
66 
67 #if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE < 200809L)
68 #  undef _POSIX_C_SOURCE
69 #endif
70 #if !defined(_POSIX_C_SOURCE)
71 #  define _POSIX_C_SOURCE 200809L
72 #endif
73 
74 /* Solaris freaks out if you try to use a POSIX or SUS standard without
75  * the "right" C standard. */
76 #if defined(_XOPEN_SOURCE)
77 #  undef _XOPEN_SOURCE
78 #endif
79 
80 #if defined(__STDC_VERSION__)
81 #  if __STDC_VERSION__ >= 201112L
82 #    define _XOPEN_SOURCE 700
83 #  elif __STDC_VERSION__ >= 199901L
84 #    define _XOPEN_SOURCE 600
85 #  endif
86 #endif
87 
88 /* Because, according to Microsoft, POSIX is deprecated.  You've got
89  * to appreciate the chutzpah. */
90 #if defined(_MSC_VER) && !defined(_CRT_NONSTDC_NO_DEPRECATE)
91 #  define _CRT_NONSTDC_NO_DEPRECATE
92 #endif
93 
94 #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
95 #  include <stdbool.h>
96 #elif defined(_WIN32)
97 /* https://msdn.microsoft.com/en-us/library/tf4dy80a.aspx */
98 #endif
99 
100 #include <limits.h>
101 #include <time.h>
102 #include <errno.h>
103 #include <string.h>
104 #include <stdlib.h>
105 #include <stdio.h>
106 #include <stdarg.h>
107 #include <setjmp.h>
108 
109 #if !defined(MUNIT_NO_NL_LANGINFO) && !defined(_WIN32)
110 #  define MUNIT_NL_LANGINFO
111 #  include <locale.h>
112 #  include <langinfo.h>
113 #  include <strings.h>
114 #endif
115 
116 #if !defined(_WIN32)
117 #  include <unistd.h>
118 #  include <sys/types.h>
119 #  include <sys/wait.h>
120 #else
121 #  include <windows.h>
122 #  include <io.h>
123 #  include <fcntl.h>
124 #  if !defined(STDERR_FILENO)
125 #    define STDERR_FILENO _fileno(stderr)
126 #  endif
127 #endif
128 
129 #include "munit.h"
130 
131 #define MUNIT_STRINGIFY(x) #x
132 #define MUNIT_XSTRINGIFY(x) MUNIT_STRINGIFY(x)
133 
134 #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) ||  \
135   defined(__IBMCPP__)
136 #  define MUNIT_THREAD_LOCAL __thread
137 #elif (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201102L)) ||          \
138   defined(_Thread_local)
139 #  define MUNIT_THREAD_LOCAL _Thread_local
140 #elif defined(_WIN32)
141 #  define MUNIT_THREAD_LOCAL __declspec(thread)
142 #endif
143 
144 /* MSVC 12.0 will emit a warning at /W4 for code like 'do { ... }
145  * while (0)', or 'do { ... } while (1)'.  I'm pretty sure nobody
146  * at Microsoft compiles with /W4. */
147 #if defined(_MSC_VER) && (_MSC_VER <= 1800)
148 #  pragma warning(disable : 4127)
149 #endif
150 
151 #if defined(_WIN32) || defined(__EMSCRIPTEN__)
152 #  define MUNIT_NO_FORK
153 #endif
154 
155 #if defined(__EMSCRIPTEN__)
156 #  define MUNIT_NO_BUFFER
157 #endif
158 
159 /*** Logging ***/
160 
161 static MunitLogLevel munit_log_level_visible = MUNIT_LOG_INFO;
162 static MunitLogLevel munit_log_level_fatal = MUNIT_LOG_ERROR;
163 
164 #if defined(MUNIT_THREAD_LOCAL)
165 static MUNIT_THREAD_LOCAL munit_bool munit_error_jmp_buf_valid = 0;
166 static MUNIT_THREAD_LOCAL jmp_buf munit_error_jmp_buf;
167 #endif
168 
169 /* At certain warning levels, mingw will trigger warnings about
170  * suggesting the format attribute, which we've explicity *not* set
171  * because it will then choke on our attempts to use the MS-specific
172  * I64 modifier for size_t (which we have to use since MSVC doesn't
173  * support the C99 z modifier). */
174 
175 #if defined(__MINGW32__) || defined(__MINGW64__)
176 #  pragma GCC diagnostic push
177 #  pragma GCC diagnostic ignored "-Wsuggest-attribute=format"
178 #endif
179 
180 MUNIT_PRINTF(5, 0)
munit_logf_exv(MunitLogLevel level,FILE * fp,const char * filename,int line,const char * format,va_list ap)181 static void munit_logf_exv(MunitLogLevel level, FILE *fp, const char *filename,
182                            int line, const char *format, va_list ap) {
183   if (level < munit_log_level_visible)
184     return;
185 
186   switch (level) {
187   case MUNIT_LOG_DEBUG:
188     fputs("Debug", fp);
189     break;
190   case MUNIT_LOG_INFO:
191     fputs("Info", fp);
192     break;
193   case MUNIT_LOG_WARNING:
194     fputs("Warning", fp);
195     break;
196   case MUNIT_LOG_ERROR:
197     fputs("Error", fp);
198     break;
199   default:
200     munit_logf_ex(MUNIT_LOG_ERROR, filename, line, "Invalid log level (%d)",
201                   level);
202     return;
203   }
204 
205   fputs(": ", fp);
206   if (filename != NULL)
207     fprintf(fp, "%s:%d: ", filename, line);
208   vfprintf(fp, format, ap);
209   fputc('\n', fp);
210 }
211 
212 MUNIT_PRINTF(3, 4)
munit_logf_internal(MunitLogLevel level,FILE * fp,const char * format,...)213 static void munit_logf_internal(MunitLogLevel level, FILE *fp,
214                                 const char *format, ...) {
215   va_list ap;
216 
217   va_start(ap, format);
218   munit_logf_exv(level, fp, NULL, 0, format, ap);
219   va_end(ap);
220 }
221 
munit_log_internal(MunitLogLevel level,FILE * fp,const char * message)222 static void munit_log_internal(MunitLogLevel level, FILE *fp,
223                                const char *message) {
224   munit_logf_internal(level, fp, "%s", message);
225 }
226 
munit_logf_ex(MunitLogLevel level,const char * filename,int line,const char * format,...)227 void munit_logf_ex(MunitLogLevel level, const char *filename, int line,
228                    const char *format, ...) {
229   va_list ap;
230 
231   va_start(ap, format);
232   munit_logf_exv(level, stderr, filename, line, format, ap);
233   va_end(ap);
234 
235   if (level >= munit_log_level_fatal) {
236 #if defined(MUNIT_THREAD_LOCAL)
237     if (munit_error_jmp_buf_valid)
238       longjmp(munit_error_jmp_buf, 1);
239 #endif
240     abort();
241   }
242 }
243 
munit_errorf_ex(const char * filename,int line,const char * format,...)244 void munit_errorf_ex(const char *filename, int line, const char *format, ...) {
245   va_list ap;
246 
247   va_start(ap, format);
248   munit_logf_exv(MUNIT_LOG_ERROR, stderr, filename, line, format, ap);
249   va_end(ap);
250 
251 #if defined(MUNIT_THREAD_LOCAL)
252   if (munit_error_jmp_buf_valid)
253     longjmp(munit_error_jmp_buf, 1);
254 #endif
255   abort();
256 }
257 
258 #if defined(__MINGW32__) || defined(__MINGW64__)
259 #  pragma GCC diagnostic pop
260 #endif
261 
262 #if !defined(MUNIT_STRERROR_LEN)
263 #  define MUNIT_STRERROR_LEN 80
264 #endif
265 
munit_log_errno(MunitLogLevel level,FILE * fp,const char * msg)266 static void munit_log_errno(MunitLogLevel level, FILE *fp, const char *msg) {
267 #if defined(MUNIT_NO_STRERROR_R) ||                                            \
268   (defined(__MINGW32__) && !defined(MINGW_HAS_SECURE_API))
269   munit_logf_internal(level, fp, "%s: %s (%d)", msg, strerror(errno), errno);
270 #else
271   char munit_error_str[MUNIT_STRERROR_LEN];
272   munit_error_str[0] = '\0';
273 
274 #  if !defined(_WIN32)
275   strerror_r(errno, munit_error_str, MUNIT_STRERROR_LEN);
276 #  else
277   strerror_s(munit_error_str, MUNIT_STRERROR_LEN, errno);
278 #  endif
279 
280   munit_logf_internal(level, fp, "%s: %s (%d)", msg, munit_error_str, errno);
281 #endif
282 }
283 
284 /*** Memory allocation ***/
285 
munit_malloc_ex(const char * filename,int line,size_t size)286 void *munit_malloc_ex(const char *filename, int line, size_t size) {
287   void *ptr;
288 
289   if (size == 0)
290     return NULL;
291 
292   ptr = calloc(1, size);
293   if (MUNIT_UNLIKELY(ptr == NULL)) {
294     munit_logf_ex(MUNIT_LOG_ERROR, filename, line,
295                   "Failed to allocate %" MUNIT_SIZE_MODIFIER "u bytes.", size);
296   }
297 
298   return ptr;
299 }
300 
301 /*** Timer code ***/
302 
303 #if defined(MUNIT_ENABLE_TIMING)
304 
305 #  define psnip_uint64_t munit_uint64_t
306 #  define psnip_uint32_t munit_uint32_t
307 
308 /* Code copied from portable-snippets
309  * <https://github.com/nemequ/portable-snippets/>.  If you need to
310  * change something, please do it there so we can keep the code in
311  * sync. */
312 
313 /* Clocks (v1)
314  * Portable Snippets - https://gitub.com/nemequ/portable-snippets
315  * Created by Evan Nemerson <evan@nemerson.com>
316  *
317  *   To the extent possible under law, the authors have waived all
318  *   copyright and related or neighboring rights to this code.  For
319  *   details, see the Creative Commons Zero 1.0 Universal license at
320  *   https://creativecommons.org/publicdomain/zero/1.0/
321  */
322 
323 #  if !defined(PSNIP_CLOCK_H)
324 #    define PSNIP_CLOCK_H
325 
326 #    if !defined(psnip_uint64_t)
327 #      include "../exact-int/exact-int.h"
328 #    endif
329 
330 #    if !defined(PSNIP_CLOCK_STATIC_INLINE)
331 #      if defined(__GNUC__)
332 #        define PSNIP_CLOCK__COMPILER_ATTRIBUTES __attribute__((__unused__))
333 #      else
334 #        define PSNIP_CLOCK__COMPILER_ATTRIBUTES
335 #      endif
336 
337 #      define PSNIP_CLOCK__FUNCTION PSNIP_CLOCK__COMPILER_ATTRIBUTES static
338 #    endif
339 
340 enum PsnipClockType {
341   /* This clock provides the current time, in units since 1970-01-01
342    * 00:00:00 UTC not including leap seconds.  In other words, UNIX
343    * time.  Keep in mind that this clock doesn't account for leap
344    * seconds, and can go backwards (think NTP adjustments). */
345   PSNIP_CLOCK_TYPE_WALL = 1,
346   /* The CPU time is a clock which increases only when the current
347    * process is active (i.e., it doesn't increment while blocking on
348    * I/O). */
349   PSNIP_CLOCK_TYPE_CPU = 2,
350   /* Monotonic time is always running (unlike CPU time), but it only
351      ever moves forward unless you reboot the system.  Things like NTP
352      adjustments have no effect on this clock. */
353   PSNIP_CLOCK_TYPE_MONOTONIC = 3
354 };
355 
356 struct PsnipClockTimespec {
357   psnip_uint64_t seconds;
358   psnip_uint64_t nanoseconds;
359 };
360 
361 /* Methods we support: */
362 
363 #    define PSNIP_CLOCK_METHOD_CLOCK_GETTIME 1
364 #    define PSNIP_CLOCK_METHOD_TIME 2
365 #    define PSNIP_CLOCK_METHOD_GETTIMEOFDAY 3
366 #    define PSNIP_CLOCK_METHOD_QUERYPERFORMANCECOUNTER 4
367 #    define PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME 5
368 #    define PSNIP_CLOCK_METHOD_CLOCK 6
369 #    define PSNIP_CLOCK_METHOD_GETPROCESSTIMES 7
370 #    define PSNIP_CLOCK_METHOD_GETRUSAGE 8
371 #    define PSNIP_CLOCK_METHOD_GETSYSTEMTIMEPRECISEASFILETIME 9
372 #    define PSNIP_CLOCK_METHOD_GETTICKCOUNT64 10
373 
374 #    include <assert.h>
375 
376 #    if defined(HEDLEY_UNREACHABLE)
377 #      define PSNIP_CLOCK_UNREACHABLE() HEDLEY_UNREACHABLE()
378 #    else
379 #      define PSNIP_CLOCK_UNREACHABLE() assert(0)
380 #    endif
381 
382 /* Choose an implementation */
383 
384 /* #undef PSNIP_CLOCK_WALL_METHOD */
385 /* #undef PSNIP_CLOCK_CPU_METHOD */
386 /* #undef PSNIP_CLOCK_MONOTONIC_METHOD */
387 
388 /* We want to be able to detect the libc implementation, so we include
389    <limits.h> (<features.h> isn't available everywhere). */
390 
391 #    if defined(__unix__) || defined(__unix) || defined(__linux__)
392 #      include <limits.h>
393 #      include <unistd.h>
394 #    endif
395 
396 #    if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)
397 /* These are known to work without librt.  If you know of others
398  * please let us know so we can add them. */
399 #      if (defined(__GLIBC__) &&                                               \
400            (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 17))) ||    \
401         (defined(__FreeBSD__))
402 #        define PSNIP_CLOCK_HAVE_CLOCK_GETTIME
403 #      elif !defined(PSNIP_CLOCK_NO_LIBRT)
404 #        define PSNIP_CLOCK_HAVE_CLOCK_GETTIME
405 #      endif
406 #    endif
407 
408 #    if defined(_WIN32)
409 #      if !defined(PSNIP_CLOCK_CPU_METHOD)
410 #        define PSNIP_CLOCK_CPU_METHOD PSNIP_CLOCK_METHOD_GETPROCESSTIMES
411 #      endif
412 #      if !defined(PSNIP_CLOCK_MONOTONIC_METHOD)
413 #        define PSNIP_CLOCK_MONOTONIC_METHOD                                   \
414           PSNIP_CLOCK_METHOD_QUERYPERFORMANCECOUNTER
415 #      endif
416 #    endif
417 
418 #    if defined(__MACH__) && !defined(__gnu_hurd__)
419 #      if !defined(PSNIP_CLOCK_MONOTONIC_METHOD)
420 #        define PSNIP_CLOCK_MONOTONIC_METHOD                                   \
421           PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME
422 #      endif
423 #    endif
424 
425 #    if defined(PSNIP_CLOCK_HAVE_CLOCK_GETTIME)
426 #      include <time.h>
427 #      if !defined(PSNIP_CLOCK_WALL_METHOD)
428 #        if defined(CLOCK_REALTIME_PRECISE)
429 #          define PSNIP_CLOCK_WALL_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
430 #          define PSNIP_CLOCK_CLOCK_GETTIME_WALL CLOCK_REALTIME_PRECISE
431 #        elif !defined(__sun)
432 #          define PSNIP_CLOCK_WALL_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
433 #          define PSNIP_CLOCK_CLOCK_GETTIME_WALL CLOCK_REALTIME
434 #        endif
435 #      endif
436 #      if !defined(PSNIP_CLOCK_CPU_METHOD)
437 #        if defined(_POSIX_CPUTIME) || defined(CLOCK_PROCESS_CPUTIME_ID)
438 #          define PSNIP_CLOCK_CPU_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
439 #          define PSNIP_CLOCK_CLOCK_GETTIME_CPU CLOCK_PROCESS_CPUTIME_ID
440 #        elif defined(CLOCK_VIRTUAL)
441 #          define PSNIP_CLOCK_CPU_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
442 #          define PSNIP_CLOCK_CLOCK_GETTIME_CPU CLOCK_VIRTUAL
443 #        endif
444 #      endif
445 #      if !defined(PSNIP_CLOCK_MONOTONIC_METHOD)
446 #        if defined(CLOCK_MONOTONIC_RAW)
447 #          define PSNIP_CLOCK_MONOTONIC_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
448 #          define PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC CLOCK_MONOTONIC
449 #        elif defined(CLOCK_MONOTONIC_PRECISE)
450 #          define PSNIP_CLOCK_MONOTONIC_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
451 #          define PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC CLOCK_MONOTONIC_PRECISE
452 #        elif defined(_POSIX_MONOTONIC_CLOCK) || defined(CLOCK_MONOTONIC)
453 #          define PSNIP_CLOCK_MONOTONIC_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
454 #          define PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC CLOCK_MONOTONIC
455 #        endif
456 #      endif
457 #    endif
458 
459 #    if defined(_POSIX_VERSION) && (_POSIX_VERSION >= 200112L)
460 #      if !defined(PSNIP_CLOCK_WALL_METHOD)
461 #        define PSNIP_CLOCK_WALL_METHOD PSNIP_CLOCK_METHOD_GETTIMEOFDAY
462 #      endif
463 #    endif
464 
465 #    if !defined(PSNIP_CLOCK_WALL_METHOD)
466 #      define PSNIP_CLOCK_WALL_METHOD PSNIP_CLOCK_METHOD_TIME
467 #    endif
468 
469 #    if !defined(PSNIP_CLOCK_CPU_METHOD)
470 #      define PSNIP_CLOCK_CPU_METHOD PSNIP_CLOCK_METHOD_CLOCK
471 #    endif
472 
473 /* Primarily here for testing. */
474 #    if !defined(PSNIP_CLOCK_MONOTONIC_METHOD) &&                              \
475       defined(PSNIP_CLOCK_REQUIRE_MONOTONIC)
476 #      error No monotonic clock found.
477 #    endif
478 
479 /* Implementations */
480 
481 #    if (defined(PSNIP_CLOCK_CPU_METHOD) &&                                    \
482          (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) ||      \
483       (defined(PSNIP_CLOCK_WALL_METHOD) &&                                     \
484        (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) ||       \
485       (defined(PSNIP_CLOCK_MONOTONIC_METHOD) &&                                \
486        (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) ||  \
487       (defined(PSNIP_CLOCK_CPU_METHOD) &&                                      \
488        (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK)) ||                \
489       (defined(PSNIP_CLOCK_WALL_METHOD) &&                                     \
490        (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK)) ||               \
491       (defined(PSNIP_CLOCK_MONOTONIC_METHOD) &&                                \
492        (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK)) ||          \
493       (defined(PSNIP_CLOCK_CPU_METHOD) &&                                      \
494        (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_TIME)) ||                 \
495       (defined(PSNIP_CLOCK_WALL_METHOD) &&                                     \
496        (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_TIME)) ||                \
497       (defined(PSNIP_CLOCK_MONOTONIC_METHOD) &&                                \
498        (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_TIME))
499 #      include <time.h>
500 #    endif
501 
502 #    if (defined(PSNIP_CLOCK_CPU_METHOD) &&                                    \
503          (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY)) ||       \
504       (defined(PSNIP_CLOCK_WALL_METHOD) &&                                     \
505        (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY)) ||        \
506       (defined(PSNIP_CLOCK_MONOTONIC_METHOD) &&                                \
507        (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY))
508 #      include <sys/time.h>
509 #    endif
510 
511 #    if (defined(PSNIP_CLOCK_CPU_METHOD) &&                                    \
512          (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES)) ||    \
513       (defined(PSNIP_CLOCK_WALL_METHOD) &&                                     \
514        (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES)) ||     \
515       (defined(PSNIP_CLOCK_MONOTONIC_METHOD) &&                                \
516        (PSNIP_CLOCK_MONOTONIC_METHOD ==                                        \
517         PSNIP_CLOCK_METHOD_GETPROCESSTIMES)) ||                                \
518       (defined(PSNIP_CLOCK_CPU_METHOD) &&                                      \
519        (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64)) ||       \
520       (defined(PSNIP_CLOCK_WALL_METHOD) &&                                     \
521        (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64)) ||      \
522       (defined(PSNIP_CLOCK_MONOTONIC_METHOD) &&                                \
523        (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64))
524 #      include <windows.h>
525 #    endif
526 
527 #    if (defined(PSNIP_CLOCK_CPU_METHOD) &&                                    \
528          (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETRUSAGE)) ||          \
529       (defined(PSNIP_CLOCK_WALL_METHOD) &&                                     \
530        (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETRUSAGE)) ||           \
531       (defined(PSNIP_CLOCK_MONOTONIC_METHOD) &&                                \
532        (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETRUSAGE))
533 #      include <sys/time.h>
534 #      include <sys/resource.h>
535 #    endif
536 
537 #    if (defined(PSNIP_CLOCK_CPU_METHOD) &&                                    \
538          (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME)) || \
539       (defined(PSNIP_CLOCK_WALL_METHOD) &&                                     \
540        (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME)) ||  \
541       (defined(PSNIP_CLOCK_MONOTONIC_METHOD) &&                                \
542        (PSNIP_CLOCK_MONOTONIC_METHOD ==                                        \
543         PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME))
544 #      include <CoreServices/CoreServices.h>
545 #      include <mach/mach.h>
546 #      include <mach/mach_time.h>
547 #    endif
548 
549 /*** Implementations ***/
550 
551 #    define PSNIP_CLOCK_NSEC_PER_SEC ((psnip_uint32_t)(1000000000ULL))
552 
553 #    if (defined(PSNIP_CLOCK_CPU_METHOD) &&                                    \
554          (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) ||      \
555       (defined(PSNIP_CLOCK_WALL_METHOD) &&                                     \
556        (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) ||       \
557       (defined(PSNIP_CLOCK_MONOTONIC_METHOD) &&                                \
558        (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME))
559 PSNIP_CLOCK__FUNCTION psnip_uint32_t
psnip_clock__clock_getres(clockid_t clk_id)560 psnip_clock__clock_getres(clockid_t clk_id) {
561   struct timespec res;
562   int r;
563 
564   r = clock_getres(clk_id, &res);
565   if (r != 0)
566     return 0;
567 
568   return (psnip_uint32_t)(PSNIP_CLOCK_NSEC_PER_SEC /
569                           (psnip_uint64_t)res.tv_nsec);
570 }
571 
572 PSNIP_CLOCK__FUNCTION int
psnip_clock__clock_gettime(clockid_t clk_id,struct PsnipClockTimespec * res)573 psnip_clock__clock_gettime(clockid_t clk_id, struct PsnipClockTimespec *res) {
574   struct timespec ts;
575 
576   if (clock_gettime(clk_id, &ts) != 0)
577     return -10;
578 
579   res->seconds = (psnip_uint64_t)(ts.tv_sec);
580   res->nanoseconds = (psnip_uint64_t)(ts.tv_nsec);
581 
582   return 0;
583 }
584 #    endif
585 
psnip_clock_wall_get_precision(void)586 PSNIP_CLOCK__FUNCTION psnip_uint32_t psnip_clock_wall_get_precision(void) {
587 #    if !defined(PSNIP_CLOCK_WALL_METHOD)
588   return 0;
589 #    elif defined(PSNIP_CLOCK_WALL_METHOD) &&                                  \
590       PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME
591   return psnip_clock__clock_getres(PSNIP_CLOCK_CLOCK_GETTIME_WALL);
592 #    elif defined(PSNIP_CLOCK_WALL_METHOD) &&                                  \
593       PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY
594   return 1000000;
595 #    elif defined(PSNIP_CLOCK_WALL_METHOD) &&                                  \
596       PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_TIME
597   return 1;
598 #    else
599   return 0;
600 #    endif
601 }
602 
603 PSNIP_CLOCK__FUNCTION int
psnip_clock_wall_get_time(struct PsnipClockTimespec * res)604 psnip_clock_wall_get_time(struct PsnipClockTimespec *res) {
605 #    if !defined(PSNIP_CLOCK_WALL_METHOD)
606   (void)res;
607 
608   return -2;
609 #    elif defined(PSNIP_CLOCK_WALL_METHOD) &&                                  \
610       PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME
611   return psnip_clock__clock_gettime(PSNIP_CLOCK_CLOCK_GETTIME_WALL, res);
612 #    elif defined(PSNIP_CLOCK_WALL_METHOD) &&                                  \
613       PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_TIME
614   res->seconds = time(NULL);
615   res->nanoseconds = 0;
616 #    elif defined(PSNIP_CLOCK_WALL_METHOD) &&                                  \
617       PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY
618   struct timeval tv;
619 
620   if (gettimeofday(&tv, NULL) != 0)
621     return -6;
622 
623   res->seconds = (psnip_uint64_t)tv.tv_sec;
624   res->nanoseconds = (psnip_uint64_t)tv.tv_usec * 1000;
625 #    else
626   (void)res;
627 
628   return -2;
629 #    endif
630 
631   return 0;
632 }
633 
psnip_clock_cpu_get_precision(void)634 PSNIP_CLOCK__FUNCTION psnip_uint32_t psnip_clock_cpu_get_precision(void) {
635 #    if !defined(PSNIP_CLOCK_CPU_METHOD)
636   return 0;
637 #    elif defined(PSNIP_CLOCK_CPU_METHOD) &&                                   \
638       PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME
639   return psnip_clock__clock_getres(PSNIP_CLOCK_CLOCK_GETTIME_CPU);
640 #    elif defined(PSNIP_CLOCK_CPU_METHOD) &&                                   \
641       PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK
642   return CLOCKS_PER_SEC;
643 #    elif defined(PSNIP_CLOCK_CPU_METHOD) &&                                   \
644       PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES
645   return PSNIP_CLOCK_NSEC_PER_SEC / 100;
646 #    else
647   return 0;
648 #    endif
649 }
650 
651 PSNIP_CLOCK__FUNCTION int
psnip_clock_cpu_get_time(struct PsnipClockTimespec * res)652 psnip_clock_cpu_get_time(struct PsnipClockTimespec *res) {
653 #    if !defined(PSNIP_CLOCK_CPU_METHOD)
654   (void)res;
655   return -2;
656 #    elif defined(PSNIP_CLOCK_CPU_METHOD) &&                                   \
657       PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME
658   return psnip_clock__clock_gettime(PSNIP_CLOCK_CLOCK_GETTIME_CPU, res);
659 #    elif defined(PSNIP_CLOCK_CPU_METHOD) &&                                   \
660       PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK
661   clock_t t = clock();
662   if (t == ((clock_t)-1))
663     return -5;
664   res->seconds = t / CLOCKS_PER_SEC;
665   res->nanoseconds =
666     (t % CLOCKS_PER_SEC) * (PSNIP_CLOCK_NSEC_PER_SEC / CLOCKS_PER_SEC);
667 #    elif defined(PSNIP_CLOCK_CPU_METHOD) &&                                   \
668       PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES
669   FILETIME CreationTime, ExitTime, KernelTime, UserTime;
670   LARGE_INTEGER date, adjust;
671 
672   if (!GetProcessTimes(GetCurrentProcess(), &CreationTime, &ExitTime,
673                        &KernelTime, &UserTime))
674     return -7;
675 
676   /* http://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/ */
677   date.HighPart = (LONG)UserTime.dwHighDateTime;
678   date.LowPart = UserTime.dwLowDateTime;
679   adjust.QuadPart = 11644473600000 * 10000;
680   date.QuadPart -= adjust.QuadPart;
681 
682   res->seconds = (psnip_uint64_t)(date.QuadPart / 10000000);
683   res->nanoseconds = (psnip_uint64_t)(date.QuadPart % 10000000) *
684                      (PSNIP_CLOCK_NSEC_PER_SEC / 100);
685 #    elif PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETRUSAGE
686   struct rusage usage;
687   if (getrusage(RUSAGE_SELF, &usage) != 0)
688     return -8;
689 
690   res->seconds = usage.ru_utime.tv_sec;
691   res->nanoseconds = tv.tv_usec * 1000;
692 #    else
693   (void)res;
694   return -2;
695 #    endif
696 
697   return 0;
698 }
699 
psnip_clock_monotonic_get_precision(void)700 PSNIP_CLOCK__FUNCTION psnip_uint32_t psnip_clock_monotonic_get_precision(void) {
701 #    if !defined(PSNIP_CLOCK_MONOTONIC_METHOD)
702   return 0;
703 #    elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) &&                             \
704       PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME
705   return psnip_clock__clock_getres(PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC);
706 #    elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) &&                             \
707       PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME
708   static mach_timebase_info_data_t tbi = {
709     0,
710   };
711   if (tbi.denom == 0)
712     mach_timebase_info(&tbi);
713   return (psnip_uint32_t)(tbi.numer / tbi.denom);
714 #    elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) &&                             \
715       PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64
716   return 1000;
717 #    elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) &&                             \
718       PSNIP_CLOCK_MONOTONIC_METHOD ==                                          \
719         PSNIP_CLOCK_METHOD_QUERYPERFORMANCECOUNTER
720   LARGE_INTEGER Frequency;
721   QueryPerformanceFrequency(&Frequency);
722   return (psnip_uint32_t)((Frequency.QuadPart > PSNIP_CLOCK_NSEC_PER_SEC)
723                             ? PSNIP_CLOCK_NSEC_PER_SEC
724                             : Frequency.QuadPart);
725 #    else
726   return 0;
727 #    endif
728 }
729 
730 PSNIP_CLOCK__FUNCTION int
psnip_clock_monotonic_get_time(struct PsnipClockTimespec * res)731 psnip_clock_monotonic_get_time(struct PsnipClockTimespec *res) {
732 #    if !defined(PSNIP_CLOCK_MONOTONIC_METHOD)
733   (void)res;
734   return -2;
735 #    elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) &&                             \
736       PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME
737   return psnip_clock__clock_gettime(PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC, res);
738 #    elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) &&                             \
739       PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME
740   psnip_uint64_t nsec = mach_absolute_time();
741   static mach_timebase_info_data_t tbi = {
742     0,
743   };
744   if (tbi.denom == 0)
745     mach_timebase_info(&tbi);
746   nsec *= ((psnip_uint64_t)tbi.numer) / ((psnip_uint64_t)tbi.denom);
747   res->seconds = nsec / PSNIP_CLOCK_NSEC_PER_SEC;
748   res->nanoseconds = nsec % PSNIP_CLOCK_NSEC_PER_SEC;
749 #    elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) &&                             \
750       PSNIP_CLOCK_MONOTONIC_METHOD ==                                          \
751         PSNIP_CLOCK_METHOD_QUERYPERFORMANCECOUNTER
752   LARGE_INTEGER t, f;
753   if (QueryPerformanceCounter(&t) == 0)
754     return -12;
755 
756   QueryPerformanceFrequency(&f);
757   res->seconds = (psnip_uint64_t)(t.QuadPart / f.QuadPart);
758   res->nanoseconds = (psnip_uint64_t)(t.QuadPart % f.QuadPart);
759   if (f.QuadPart > PSNIP_CLOCK_NSEC_PER_SEC)
760     res->nanoseconds /= (psnip_uint64_t)f.QuadPart / PSNIP_CLOCK_NSEC_PER_SEC;
761   else
762     res->nanoseconds *= PSNIP_CLOCK_NSEC_PER_SEC / (psnip_uint64_t)f.QuadPart;
763 #    elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) &&                             \
764       PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64
765   const ULONGLONG msec = GetTickCount64();
766   res->seconds = msec / 1000;
767   res->nanoseconds = sec % 1000;
768 #    else
769   return -2;
770 #    endif
771 
772   return 0;
773 }
774 
775 /* Returns the number of ticks per second for the specified clock.
776  * For example, a clock with millisecond precision would return 1000,
777  * and a clock with 1 second (such as the time() function) would
778  * return 1.
779  *
780  * If the requested clock isn't available, it will return 0.
781  * Hopefully this will be rare, but if it happens to you please let us
782  * know so we can work on finding a way to support your system.
783  *
784  * Note that different clocks on the same system often have a
785  * different precisions.
786  */
787 PSNIP_CLOCK__FUNCTION psnip_uint32_t
psnip_clock_get_precision(enum PsnipClockType clock_type)788 psnip_clock_get_precision(enum PsnipClockType clock_type) {
789   switch (clock_type) {
790   case PSNIP_CLOCK_TYPE_MONOTONIC:
791     return psnip_clock_monotonic_get_precision();
792   case PSNIP_CLOCK_TYPE_CPU:
793     return psnip_clock_cpu_get_precision();
794   case PSNIP_CLOCK_TYPE_WALL:
795     return psnip_clock_wall_get_precision();
796   }
797 
798   PSNIP_CLOCK_UNREACHABLE();
799   return 0;
800 }
801 
802 /* Set the provided timespec to the requested time.  Returns 0 on
803  * success, or a negative value on failure. */
psnip_clock_get_time(enum PsnipClockType clock_type,struct PsnipClockTimespec * res)804 PSNIP_CLOCK__FUNCTION int psnip_clock_get_time(enum PsnipClockType clock_type,
805                                                struct PsnipClockTimespec *res) {
806   assert(res != NULL);
807 
808   switch (clock_type) {
809   case PSNIP_CLOCK_TYPE_MONOTONIC:
810     return psnip_clock_monotonic_get_time(res);
811   case PSNIP_CLOCK_TYPE_CPU:
812     return psnip_clock_cpu_get_time(res);
813   case PSNIP_CLOCK_TYPE_WALL:
814     return psnip_clock_wall_get_time(res);
815   }
816 
817   return -1;
818 }
819 
820 #  endif /* !defined(PSNIP_CLOCK_H) */
821 
munit_clock_get_elapsed(struct PsnipClockTimespec * start,struct PsnipClockTimespec * end)822 static psnip_uint64_t munit_clock_get_elapsed(struct PsnipClockTimespec *start,
823                                               struct PsnipClockTimespec *end) {
824   psnip_uint64_t r = (end->seconds - start->seconds) * PSNIP_CLOCK_NSEC_PER_SEC;
825   if (end->nanoseconds < start->nanoseconds) {
826     return r - (start->nanoseconds - end->nanoseconds);
827   }
828 
829   return r + (end->nanoseconds - start->nanoseconds);
830 }
831 
832 #else
833 #  include <time.h>
834 #endif /* defined(MUNIT_ENABLE_TIMING) */
835 
836 /*** PRNG stuff ***/
837 
838 /* This is (unless I screwed up, which is entirely possible) the
839  * version of PCG with 32-bit state.  It was chosen because it has a
840  * small enough state that we should reliably be able to use CAS
841  * instead of requiring a lock for thread-safety.
842  *
843  * If I did screw up, I probably will not bother changing it unless
844  * there is a significant bias.  It's really not important this be
845  * particularly strong, as long as it is fairly random it's much more
846  * important that it be reproducible, so bug reports have a better
847  * chance of being reproducible. */
848 
849 #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) &&              \
850   !defined(__STDC_NO_ATOMICS__) && !defined(__EMSCRIPTEN__) &&                 \
851   (!defined(__GNUC_MINOR__) || (__GNUC__ > 4) ||                               \
852    (__GNUC__ == 4 && __GNUC_MINOR__ > 8))
853 #  define HAVE_STDATOMIC
854 #elif defined(__clang__)
855 #  if __has_extension(c_atomic)
856 #    define HAVE_CLANG_ATOMICS
857 #  endif
858 #endif
859 
860 /* Workaround for http://llvm.org/bugs/show_bug.cgi?id=26911 */
861 #if defined(__clang__) && defined(_WIN32)
862 #  undef HAVE_STDATOMIC
863 #  if defined(__c2__)
864 #    undef HAVE_CLANG_ATOMICS
865 #  endif
866 #endif
867 
868 #if defined(_OPENMP)
869 #  define ATOMIC_UINT32_T uint32_t
870 #elif defined(HAVE_STDATOMIC)
871 #  include <stdatomic.h>
872 #  define ATOMIC_UINT32_T _Atomic uint32_t
873 #elif defined(HAVE_CLANG_ATOMICS)
874 #  define ATOMIC_UINT32_T _Atomic uint32_t
875 #elif defined(_WIN32)
876 #  define ATOMIC_UINT32_T volatile LONG
877 #else
878 #  define ATOMIC_UINT32_T volatile uint32_t
879 #endif
880 
881 static ATOMIC_UINT32_T munit_rand_state = 42;
882 
883 #if defined(_OPENMP)
munit_atomic_store(ATOMIC_UINT32_T * dest,ATOMIC_UINT32_T value)884 static inline void munit_atomic_store(ATOMIC_UINT32_T *dest,
885                                       ATOMIC_UINT32_T value) {
886 #  pragma omp critical(munit_atomics)
887   *dest = value;
888 }
889 
munit_atomic_load(ATOMIC_UINT32_T * src)890 static inline uint32_t munit_atomic_load(ATOMIC_UINT32_T *src) {
891   int ret;
892 #  pragma omp critical(munit_atomics)
893   ret = *src;
894   return ret;
895 }
896 
munit_atomic_cas(ATOMIC_UINT32_T * dest,ATOMIC_UINT32_T * expected,ATOMIC_UINT32_T desired)897 static inline uint32_t munit_atomic_cas(ATOMIC_UINT32_T *dest,
898                                         ATOMIC_UINT32_T *expected,
899                                         ATOMIC_UINT32_T desired) {
900   munit_bool ret;
901 
902 #  pragma omp critical(munit_atomics)
903   {
904     if (*dest == *expected) {
905       *dest = desired;
906       ret = 1;
907     } else {
908       ret = 0;
909     }
910   }
911 
912   return ret;
913 }
914 #elif defined(HAVE_STDATOMIC)
915 #  define munit_atomic_store(dest, value) atomic_store(dest, value)
916 #  define munit_atomic_load(src) atomic_load(src)
917 #  define munit_atomic_cas(dest, expected, value)                              \
918     atomic_compare_exchange_weak(dest, expected, value)
919 #elif defined(HAVE_CLANG_ATOMICS)
920 #  define munit_atomic_store(dest, value)                                      \
921     __c11_atomic_store(dest, value, __ATOMIC_SEQ_CST)
922 #  define munit_atomic_load(src) __c11_atomic_load(src, __ATOMIC_SEQ_CST)
923 #  define munit_atomic_cas(dest, expected, value)                              \
924     __c11_atomic_compare_exchange_weak(dest, expected, value,                  \
925                                        __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
926 #elif defined(__GNUC__) && (__GNUC__ > 4) ||                                   \
927   (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
928 #  define munit_atomic_store(dest, value)                                      \
929     __atomic_store_n(dest, value, __ATOMIC_SEQ_CST)
930 #  define munit_atomic_load(src) __atomic_load_n(src, __ATOMIC_SEQ_CST)
931 #  define munit_atomic_cas(dest, expected, value)                              \
932     __atomic_compare_exchange_n(dest, expected, value, 1, __ATOMIC_SEQ_CST,    \
933                                 __ATOMIC_SEQ_CST)
934 #elif defined(__GNUC__) && (__GNUC__ >= 4)
935 #  define munit_atomic_store(dest, value)                                      \
936     do {                                                                       \
937       *(dest) = (value);                                                       \
938     } while (0)
939 #  define munit_atomic_load(src) (*(src))
940 #  define munit_atomic_cas(dest, expected, value)                              \
941     __sync_bool_compare_and_swap(dest, *expected, value)
942 #elif defined(_WIN32) /* Untested */
943 #  define munit_atomic_store(dest, value)                                      \
944     do {                                                                       \
945       *(dest) = (value);                                                       \
946     } while (0)
947 #  define munit_atomic_load(src) (*(src))
948 #  define munit_atomic_cas(dest, expected, value)                              \
949     InterlockedCompareExchange((dest), (value), *(expected))
950 #else
951 #  warning No atomic implementation, PRNG will not be thread-safe
952 #  define munit_atomic_store(dest, value)                                      \
953     do {                                                                       \
954       *(dest) = (value);                                                       \
955     } while (0)
956 #  define munit_atomic_load(src) (*(src))
munit_atomic_cas(ATOMIC_UINT32_T * dest,ATOMIC_UINT32_T * expected,ATOMIC_UINT32_T desired)957 static inline munit_bool munit_atomic_cas(ATOMIC_UINT32_T *dest,
958                                           ATOMIC_UINT32_T *expected,
959                                           ATOMIC_UINT32_T desired) {
960   if (*dest == *expected) {
961     *dest = desired;
962     return 1;
963   } else {
964     return 0;
965   }
966 }
967 #endif
968 
969 #define MUNIT_PRNG_MULTIPLIER (747796405U)
970 #define MUNIT_PRNG_INCREMENT (1729U)
971 
munit_rand_next_state(munit_uint32_t state)972 static munit_uint32_t munit_rand_next_state(munit_uint32_t state) {
973   return state * MUNIT_PRNG_MULTIPLIER + MUNIT_PRNG_INCREMENT;
974 }
975 
munit_rand_from_state(munit_uint32_t state)976 static munit_uint32_t munit_rand_from_state(munit_uint32_t state) {
977   munit_uint32_t res = ((state >> ((state >> 28) + 4)) ^ state) * (277803737U);
978   res ^= res >> 22;
979   return res;
980 }
981 
munit_rand_seed(munit_uint32_t seed)982 void munit_rand_seed(munit_uint32_t seed) {
983   munit_uint32_t state = munit_rand_next_state(seed + MUNIT_PRNG_INCREMENT);
984   munit_atomic_store(&munit_rand_state, state);
985 }
986 
munit_rand_generate_seed(void)987 static munit_uint32_t munit_rand_generate_seed(void) {
988   munit_uint32_t seed, state;
989 #if defined(MUNIT_ENABLE_TIMING)
990   struct PsnipClockTimespec wc = {
991     0,
992   };
993 
994   psnip_clock_get_time(PSNIP_CLOCK_TYPE_WALL, &wc);
995   seed = (munit_uint32_t)wc.nanoseconds;
996 #else
997   seed = (munit_uint32_t)time(NULL);
998 #endif
999 
1000   state = munit_rand_next_state(seed + MUNIT_PRNG_INCREMENT);
1001   return munit_rand_from_state(state);
1002 }
1003 
munit_rand_state_uint32(munit_uint32_t * state)1004 static munit_uint32_t munit_rand_state_uint32(munit_uint32_t *state) {
1005   const munit_uint32_t old = *state;
1006   *state = munit_rand_next_state(old);
1007   return munit_rand_from_state(old);
1008 }
1009 
munit_rand_uint32(void)1010 munit_uint32_t munit_rand_uint32(void) {
1011   munit_uint32_t old, state;
1012 
1013   do {
1014     old = munit_atomic_load(&munit_rand_state);
1015     state = munit_rand_next_state(old);
1016   } while (!munit_atomic_cas(&munit_rand_state, &old, state));
1017 
1018   return munit_rand_from_state(old);
1019 }
1020 
munit_rand_state_memory(munit_uint32_t * state,size_t size,munit_uint8_t * data)1021 static void munit_rand_state_memory(munit_uint32_t *state, size_t size,
1022                                     munit_uint8_t *data) {
1023   size_t members_remaining = size / sizeof(munit_uint32_t);
1024   size_t bytes_remaining = size % sizeof(munit_uint32_t);
1025   munit_uint8_t *b = data;
1026   munit_uint32_t rv;
1027   while (members_remaining-- > 0) {
1028     rv = munit_rand_state_uint32(state);
1029     memcpy(b, &rv, sizeof(munit_uint32_t));
1030     b += sizeof(munit_uint32_t);
1031   }
1032   if (bytes_remaining != 0) {
1033     rv = munit_rand_state_uint32(state);
1034     memcpy(b, &rv, bytes_remaining);
1035   }
1036 }
1037 
munit_rand_memory(size_t size,munit_uint8_t * data)1038 void munit_rand_memory(size_t size, munit_uint8_t *data) {
1039   munit_uint32_t old, state;
1040 
1041   do {
1042     state = old = munit_atomic_load(&munit_rand_state);
1043     munit_rand_state_memory(&state, size, data);
1044   } while (!munit_atomic_cas(&munit_rand_state, &old, state));
1045 }
1046 
munit_rand_state_at_most(munit_uint32_t * state,munit_uint32_t salt,munit_uint32_t max)1047 static munit_uint32_t munit_rand_state_at_most(munit_uint32_t *state,
1048                                                munit_uint32_t salt,
1049                                                munit_uint32_t max) {
1050   /* We want (UINT32_MAX + 1) % max, which in unsigned arithmetic is the same
1051    * as (UINT32_MAX + 1 - max) % max = -max % max. We compute -max using not
1052    * to avoid compiler warnings.
1053    */
1054   const munit_uint32_t min = (~max + 1U) % max;
1055   munit_uint32_t x;
1056 
1057   if (max == (~((munit_uint32_t)0U)))
1058     return munit_rand_state_uint32(state) ^ salt;
1059 
1060   max++;
1061 
1062   do {
1063     x = munit_rand_state_uint32(state) ^ salt;
1064   } while (x < min);
1065 
1066   return x % max;
1067 }
1068 
munit_rand_at_most(munit_uint32_t salt,munit_uint32_t max)1069 static munit_uint32_t munit_rand_at_most(munit_uint32_t salt,
1070                                          munit_uint32_t max) {
1071   munit_uint32_t old, state;
1072   munit_uint32_t retval;
1073 
1074   do {
1075     state = old = munit_atomic_load(&munit_rand_state);
1076     retval = munit_rand_state_at_most(&state, salt, max);
1077   } while (!munit_atomic_cas(&munit_rand_state, &old, state));
1078 
1079   return retval;
1080 }
1081 
munit_rand_int_range(int min,int max)1082 int munit_rand_int_range(int min, int max) {
1083   munit_uint64_t range = (munit_uint64_t)max - (munit_uint64_t)min;
1084 
1085   if (min > max)
1086     return munit_rand_int_range(max, min);
1087 
1088   if (range > (~((munit_uint32_t)0U)))
1089     range = (~((munit_uint32_t)0U));
1090 
1091   return min + (int)munit_rand_at_most(0, (munit_uint32_t)range);
1092 }
1093 
munit_rand_double(void)1094 double munit_rand_double(void) {
1095   munit_uint32_t old, state;
1096   double retval = 0.0;
1097 
1098   do {
1099     state = old = munit_atomic_load(&munit_rand_state);
1100 
1101     /* See http://mumble.net/~campbell/tmp/random_real.c for how to do
1102      * this right.  Patches welcome if you feel that this is too
1103      * biased. */
1104     retval = munit_rand_state_uint32(&state) / ((~((munit_uint32_t)0U)) + 1.0);
1105   } while (!munit_atomic_cas(&munit_rand_state, &old, state));
1106 
1107   return retval;
1108 }
1109 
1110 /*** Test suite handling ***/
1111 
1112 typedef struct {
1113   unsigned int successful;
1114   unsigned int skipped;
1115   unsigned int failed;
1116   unsigned int errored;
1117 #if defined(MUNIT_ENABLE_TIMING)
1118   munit_uint64_t cpu_clock;
1119   munit_uint64_t wall_clock;
1120 #endif
1121 } MunitReport;
1122 
1123 typedef struct {
1124   const char *prefix;
1125   const MunitSuite *suite;
1126   const char **tests;
1127   munit_uint32_t seed;
1128   unsigned int iterations;
1129   MunitParameter *parameters;
1130   munit_bool single_parameter_mode;
1131   void *user_data;
1132   MunitReport report;
1133   munit_bool colorize;
1134   munit_bool fork;
1135   munit_bool show_stderr;
1136   munit_bool fatal_failures;
1137 } MunitTestRunner;
1138 
munit_parameters_get(const MunitParameter params[],const char * key)1139 const char *munit_parameters_get(const MunitParameter params[],
1140                                  const char *key) {
1141   const MunitParameter *param;
1142 
1143   for (param = params; param != NULL && param->name != NULL; param++)
1144     if (strcmp(param->name, key) == 0)
1145       return param->value;
1146   return NULL;
1147 }
1148 
1149 #if defined(MUNIT_ENABLE_TIMING)
munit_print_time(FILE * fp,munit_uint64_t nanoseconds)1150 static void munit_print_time(FILE *fp, munit_uint64_t nanoseconds) {
1151   fprintf(fp, "%" MUNIT_TEST_TIME_FORMAT,
1152           ((double)nanoseconds) / ((double)PSNIP_CLOCK_NSEC_PER_SEC));
1153 }
1154 #endif
1155 
1156 /* Add a paramter to an array of parameters. */
munit_parameters_add(size_t * params_size,MunitParameter ** params,char * name,char * value)1157 static MunitResult munit_parameters_add(size_t *params_size,
1158                                         MunitParameter **params, char *name,
1159                                         char *value) {
1160   *params = realloc(*params, sizeof(MunitParameter) * (*params_size + 2));
1161   if (*params == NULL)
1162     return MUNIT_ERROR;
1163 
1164   (*params)[*params_size].name = name;
1165   (*params)[*params_size].value = value;
1166   (*params_size)++;
1167   (*params)[*params_size].name = NULL;
1168   (*params)[*params_size].value = NULL;
1169 
1170   return MUNIT_OK;
1171 }
1172 
1173 /* Concatenate two strings, but just return one of the components
1174  * unaltered if the other is NULL or "". */
munit_maybe_concat(size_t * len,char * prefix,char * suffix)1175 static char *munit_maybe_concat(size_t *len, char *prefix, char *suffix) {
1176   char *res;
1177   size_t res_l;
1178   const size_t prefix_l = prefix != NULL ? strlen(prefix) : 0;
1179   const size_t suffix_l = suffix != NULL ? strlen(suffix) : 0;
1180   if (prefix_l == 0 && suffix_l == 0) {
1181     res = NULL;
1182     res_l = 0;
1183   } else if (prefix_l == 0 && suffix_l != 0) {
1184     res = suffix;
1185     res_l = suffix_l;
1186   } else if (prefix_l != 0 && suffix_l == 0) {
1187     res = prefix;
1188     res_l = prefix_l;
1189   } else {
1190     res_l = prefix_l + suffix_l;
1191     res = malloc(res_l + 1);
1192     memcpy(res, prefix, prefix_l);
1193     memcpy(res + prefix_l, suffix, suffix_l);
1194     res[res_l] = 0;
1195   }
1196 
1197   if (len != NULL)
1198     *len = res_l;
1199 
1200   return res;
1201 }
1202 
1203 /* Possbily free a string returned by munit_maybe_concat. */
munit_maybe_free_concat(char * s,const char * prefix,const char * suffix)1204 static void munit_maybe_free_concat(char *s, const char *prefix,
1205                                     const char *suffix) {
1206   if (prefix != s && suffix != s)
1207     free(s);
1208 }
1209 
1210 /* Cheap string hash function, just used to salt the PRNG. */
munit_str_hash(const char * name)1211 static munit_uint32_t munit_str_hash(const char *name) {
1212   const char *p;
1213   munit_uint32_t h = 5381U;
1214 
1215   for (p = name; *p != '\0'; p++)
1216     h = (munit_uint32_t)(h << 5) + h + (munit_uint32_t)*p;
1217 
1218   return h;
1219 }
1220 
munit_splice(int from,int to)1221 static void munit_splice(int from, int to) {
1222   munit_uint8_t buf[1024];
1223 #if !defined(_WIN32)
1224   ssize_t len;
1225   ssize_t bytes_written;
1226   ssize_t write_res;
1227 #else
1228   int len;
1229   int bytes_written;
1230   int write_res;
1231 #endif
1232   do {
1233     len = read(from, buf, sizeof(buf));
1234     if (len > 0) {
1235       bytes_written = 0;
1236       do {
1237         write_res = write(to, buf + bytes_written,
1238 #if !defined(_WIN32)
1239                           (size_t)
1240 #else
1241                           (unsigned int)
1242 #endif
1243                             (len - bytes_written));
1244         if (write_res < 0)
1245           break;
1246         bytes_written += write_res;
1247       } while (bytes_written < len);
1248     } else
1249       break;
1250   } while (1);
1251 }
1252 
1253 /* This is the part that should be handled in the child process */
munit_test_runner_exec(MunitTestRunner * runner,const MunitTest * test,const MunitParameter params[],MunitReport * report)1254 static MunitResult munit_test_runner_exec(MunitTestRunner *runner,
1255                                           const MunitTest *test,
1256                                           const MunitParameter params[],
1257                                           MunitReport *report) {
1258   unsigned int iterations = runner->iterations;
1259   MunitResult result = MUNIT_FAIL;
1260 #if defined(MUNIT_ENABLE_TIMING)
1261   struct PsnipClockTimespec wall_clock_begin =
1262                               {
1263                                 0,
1264                               },
1265                             wall_clock_end = {
1266                               0,
1267                             };
1268   struct PsnipClockTimespec cpu_clock_begin =
1269                               {
1270                                 0,
1271                               },
1272                             cpu_clock_end = {
1273                               0,
1274                             };
1275 #endif
1276   unsigned int i = 0;
1277 
1278   if ((test->options & MUNIT_TEST_OPTION_SINGLE_ITERATION) ==
1279       MUNIT_TEST_OPTION_SINGLE_ITERATION)
1280     iterations = 1;
1281   else if (iterations == 0)
1282     iterations = runner->suite->iterations;
1283 
1284   munit_rand_seed(runner->seed);
1285 
1286   do {
1287     void *data = (test->setup == NULL) ? runner->user_data
1288                                        : test->setup(params, runner->user_data);
1289 
1290 #if defined(MUNIT_ENABLE_TIMING)
1291     psnip_clock_get_time(PSNIP_CLOCK_TYPE_WALL, &wall_clock_begin);
1292     psnip_clock_get_time(PSNIP_CLOCK_TYPE_CPU, &cpu_clock_begin);
1293 #endif
1294 
1295     result = test->test(params, data);
1296 
1297 #if defined(MUNIT_ENABLE_TIMING)
1298     psnip_clock_get_time(PSNIP_CLOCK_TYPE_WALL, &wall_clock_end);
1299     psnip_clock_get_time(PSNIP_CLOCK_TYPE_CPU, &cpu_clock_end);
1300 #endif
1301 
1302     if (test->tear_down != NULL)
1303       test->tear_down(data);
1304 
1305     if (MUNIT_LIKELY(result == MUNIT_OK)) {
1306       report->successful++;
1307 #if defined(MUNIT_ENABLE_TIMING)
1308       report->wall_clock +=
1309         munit_clock_get_elapsed(&wall_clock_begin, &wall_clock_end);
1310       report->cpu_clock +=
1311         munit_clock_get_elapsed(&cpu_clock_begin, &cpu_clock_end);
1312 #endif
1313     } else {
1314       switch ((int)result) {
1315       case MUNIT_SKIP:
1316         report->skipped++;
1317         break;
1318       case MUNIT_FAIL:
1319         report->failed++;
1320         break;
1321       case MUNIT_ERROR:
1322         report->errored++;
1323         break;
1324       default:
1325         break;
1326       }
1327       break;
1328     }
1329   } while (++i < iterations);
1330 
1331   return result;
1332 }
1333 
1334 #if defined(MUNIT_EMOTICON)
1335 #  define MUNIT_RESULT_STRING_OK ":)"
1336 #  define MUNIT_RESULT_STRING_SKIP ":|"
1337 #  define MUNIT_RESULT_STRING_FAIL ":("
1338 #  define MUNIT_RESULT_STRING_ERROR ":o"
1339 #  define MUNIT_RESULT_STRING_TODO ":/"
1340 #else
1341 #  define MUNIT_RESULT_STRING_OK "OK   "
1342 #  define MUNIT_RESULT_STRING_SKIP "SKIP "
1343 #  define MUNIT_RESULT_STRING_FAIL "FAIL "
1344 #  define MUNIT_RESULT_STRING_ERROR "ERROR"
1345 #  define MUNIT_RESULT_STRING_TODO "TODO "
1346 #endif
1347 
munit_test_runner_print_color(const MunitTestRunner * runner,const char * string,char color)1348 static void munit_test_runner_print_color(const MunitTestRunner *runner,
1349                                           const char *string, char color) {
1350   if (runner->colorize)
1351     fprintf(MUNIT_OUTPUT_FILE, "\x1b[3%cm%s\x1b[39m", color, string);
1352   else
1353     fputs(string, MUNIT_OUTPUT_FILE);
1354 }
1355 
1356 #if !defined(MUNIT_NO_BUFFER)
munit_replace_stderr(FILE * stderr_buf)1357 static int munit_replace_stderr(FILE *stderr_buf) {
1358   if (stderr_buf != NULL) {
1359     const int orig_stderr = dup(STDERR_FILENO);
1360 
1361     int errfd = fileno(stderr_buf);
1362     if (MUNIT_UNLIKELY(errfd == -1)) {
1363       exit(EXIT_FAILURE);
1364     }
1365 
1366     dup2(errfd, STDERR_FILENO);
1367 
1368     return orig_stderr;
1369   }
1370 
1371   return -1;
1372 }
1373 
munit_restore_stderr(int orig_stderr)1374 static void munit_restore_stderr(int orig_stderr) {
1375   if (orig_stderr != -1) {
1376     dup2(orig_stderr, STDERR_FILENO);
1377     close(orig_stderr);
1378   }
1379 }
1380 #endif /* !defined(MUNIT_NO_BUFFER) */
1381 
1382 /* Run a test with the specified parameters. */
1383 static void
munit_test_runner_run_test_with_params(MunitTestRunner * runner,const MunitTest * test,const MunitParameter params[])1384 munit_test_runner_run_test_with_params(MunitTestRunner *runner,
1385                                        const MunitTest *test,
1386                                        const MunitParameter params[]) {
1387   MunitResult result = MUNIT_OK;
1388   MunitReport report = {0, 0, 0, 0,
1389 #if defined(MUNIT_ENABLE_TIMING)
1390                         0, 0
1391 #endif
1392   };
1393   unsigned int output_l;
1394   munit_bool first;
1395   const MunitParameter *param;
1396   FILE *stderr_buf;
1397 #if !defined(MUNIT_NO_FORK)
1398   int pipefd[2];
1399   pid_t fork_pid;
1400   ssize_t bytes_written = 0;
1401   ssize_t write_res;
1402   ssize_t bytes_read = 0;
1403   ssize_t read_res;
1404   int status = 0;
1405   pid_t changed_pid;
1406 #endif
1407 
1408   if (params != NULL) {
1409     output_l = 2;
1410     fputs("  ", MUNIT_OUTPUT_FILE);
1411     first = 1;
1412     for (param = params; param != NULL && param->name != NULL; param++) {
1413       if (!first) {
1414         fputs(", ", MUNIT_OUTPUT_FILE);
1415         output_l += 2;
1416       } else {
1417         first = 0;
1418       }
1419 
1420       output_l += (unsigned int)fprintf(MUNIT_OUTPUT_FILE, "%s=%s", param->name,
1421                                         param->value);
1422     }
1423     while (output_l++ < MUNIT_TEST_NAME_LEN) {
1424       fputc(' ', MUNIT_OUTPUT_FILE);
1425     }
1426   }
1427 
1428   fflush(MUNIT_OUTPUT_FILE);
1429 
1430   stderr_buf = NULL;
1431 #if !defined(_WIN32) || defined(__MINGW32__)
1432   stderr_buf = tmpfile();
1433 #else
1434   tmpfile_s(&stderr_buf);
1435 #endif
1436   if (stderr_buf == NULL) {
1437     munit_log_errno(MUNIT_LOG_ERROR, stderr,
1438                     "unable to create buffer for stderr");
1439     result = MUNIT_ERROR;
1440     goto print_result;
1441   }
1442 
1443 #if !defined(MUNIT_NO_FORK)
1444   if (runner->fork) {
1445     pipefd[0] = -1;
1446     pipefd[1] = -1;
1447     if (pipe(pipefd) != 0) {
1448       munit_log_errno(MUNIT_LOG_ERROR, stderr, "unable to create pipe");
1449       result = MUNIT_ERROR;
1450       goto print_result;
1451     }
1452 
1453     fork_pid = fork();
1454     if (fork_pid == 0) {
1455       int orig_stderr;
1456 
1457       close(pipefd[0]);
1458 
1459       orig_stderr = munit_replace_stderr(stderr_buf);
1460       munit_test_runner_exec(runner, test, params, &report);
1461 
1462       /* Note that we don't restore stderr.  This is so we can buffer
1463        * things written to stderr later on (such as by
1464        * asan/tsan/ubsan, valgrind, etc.) */
1465       close(orig_stderr);
1466 
1467       do {
1468         write_res =
1469           write(pipefd[1], ((munit_uint8_t *)(&report)) + bytes_written,
1470                 sizeof(report) - (size_t)bytes_written);
1471         if (write_res < 0) {
1472           if (stderr_buf != NULL) {
1473             munit_log_errno(MUNIT_LOG_ERROR, stderr, "unable to write to pipe");
1474           }
1475           exit(EXIT_FAILURE);
1476         }
1477         bytes_written += write_res;
1478       } while ((size_t)bytes_written < sizeof(report));
1479 
1480       if (stderr_buf != NULL)
1481         fclose(stderr_buf);
1482       close(pipefd[1]);
1483 
1484       exit(EXIT_SUCCESS);
1485     } else if (fork_pid == -1) {
1486       close(pipefd[0]);
1487       close(pipefd[1]);
1488       if (stderr_buf != NULL) {
1489         munit_log_errno(MUNIT_LOG_ERROR, stderr, "unable to fork");
1490       }
1491       report.errored++;
1492       result = MUNIT_ERROR;
1493     } else {
1494       close(pipefd[1]);
1495       do {
1496         read_res = read(pipefd[0], ((munit_uint8_t *)(&report)) + bytes_read,
1497                         sizeof(report) - (size_t)bytes_read);
1498         if (read_res < 1)
1499           break;
1500         bytes_read += read_res;
1501       } while (bytes_read < (ssize_t)sizeof(report));
1502 
1503       changed_pid = waitpid(fork_pid, &status, 0);
1504 
1505       if (MUNIT_LIKELY(changed_pid == fork_pid) &&
1506           MUNIT_LIKELY(WIFEXITED(status))) {
1507         if (bytes_read != sizeof(report)) {
1508           munit_logf_internal(MUNIT_LOG_ERROR, stderr_buf,
1509                               "child exited unexpectedly with status %d",
1510                               WEXITSTATUS(status));
1511           report.errored++;
1512         } else if (WEXITSTATUS(status) != EXIT_SUCCESS) {
1513           munit_logf_internal(MUNIT_LOG_ERROR, stderr_buf,
1514                               "child exited with status %d",
1515                               WEXITSTATUS(status));
1516           report.errored++;
1517         }
1518       } else {
1519         if (WIFSIGNALED(status)) {
1520 #  if defined(_XOPEN_VERSION) && (_XOPEN_VERSION >= 700)
1521           munit_logf_internal(MUNIT_LOG_ERROR, stderr_buf,
1522                               "child killed by signal %d (%s)",
1523                               WTERMSIG(status), strsignal(WTERMSIG(status)));
1524 #  else
1525           munit_logf_internal(MUNIT_LOG_ERROR, stderr_buf,
1526                               "child killed by signal %d", WTERMSIG(status));
1527 #  endif
1528         } else if (WIFSTOPPED(status)) {
1529           munit_logf_internal(MUNIT_LOG_ERROR, stderr_buf,
1530                               "child stopped by signal %d", WSTOPSIG(status));
1531         }
1532         report.errored++;
1533       }
1534 
1535       close(pipefd[0]);
1536       waitpid(fork_pid, NULL, 0);
1537     }
1538   } else
1539 #endif
1540   {
1541 #if !defined(MUNIT_NO_BUFFER)
1542     const volatile int orig_stderr = munit_replace_stderr(stderr_buf);
1543 #endif
1544 
1545 #if defined(MUNIT_THREAD_LOCAL)
1546     if (MUNIT_UNLIKELY(setjmp(munit_error_jmp_buf) != 0)) {
1547       result = MUNIT_FAIL;
1548       report.failed++;
1549     } else {
1550       munit_error_jmp_buf_valid = 1;
1551       result = munit_test_runner_exec(runner, test, params, &report);
1552     }
1553 #else
1554     result = munit_test_runner_exec(runner, test, params, &report);
1555 #endif
1556 
1557 #if !defined(MUNIT_NO_BUFFER)
1558     munit_restore_stderr(orig_stderr);
1559 #endif
1560 
1561     /* Here just so that the label is used on Windows and we don't get
1562      * a warning */
1563     goto print_result;
1564   }
1565 
1566 print_result:
1567 
1568   fputs("[ ", MUNIT_OUTPUT_FILE);
1569   if ((test->options & MUNIT_TEST_OPTION_TODO) == MUNIT_TEST_OPTION_TODO) {
1570     if (report.failed != 0 || report.errored != 0 || report.skipped != 0) {
1571       munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_TODO, '3');
1572       result = MUNIT_OK;
1573     } else {
1574       munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_ERROR, '1');
1575       if (MUNIT_LIKELY(stderr_buf != NULL))
1576         munit_log_internal(MUNIT_LOG_ERROR, stderr_buf,
1577                            "Test marked TODO, but was successful.");
1578       runner->report.failed++;
1579       result = MUNIT_ERROR;
1580     }
1581   } else if (report.failed > 0) {
1582     munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_FAIL, '1');
1583     runner->report.failed++;
1584     result = MUNIT_FAIL;
1585   } else if (report.errored > 0) {
1586     munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_ERROR, '1');
1587     runner->report.errored++;
1588     result = MUNIT_ERROR;
1589   } else if (report.skipped > 0) {
1590     munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_SKIP, '3');
1591     runner->report.skipped++;
1592     result = MUNIT_SKIP;
1593   } else if (report.successful > 1) {
1594     munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_OK, '2');
1595 #if defined(MUNIT_ENABLE_TIMING)
1596     fputs(" ] [ ", MUNIT_OUTPUT_FILE);
1597     munit_print_time(MUNIT_OUTPUT_FILE, report.wall_clock / report.successful);
1598     fputs(" / ", MUNIT_OUTPUT_FILE);
1599     munit_print_time(MUNIT_OUTPUT_FILE, report.cpu_clock / report.successful);
1600     fprintf(MUNIT_OUTPUT_FILE,
1601             " CPU ]\n  %-" MUNIT_XSTRINGIFY(MUNIT_TEST_NAME_LEN) "s Total: [ ",
1602             "");
1603     munit_print_time(MUNIT_OUTPUT_FILE, report.wall_clock);
1604     fputs(" / ", MUNIT_OUTPUT_FILE);
1605     munit_print_time(MUNIT_OUTPUT_FILE, report.cpu_clock);
1606     fputs(" CPU", MUNIT_OUTPUT_FILE);
1607 #endif
1608     runner->report.successful++;
1609     result = MUNIT_OK;
1610   } else if (report.successful > 0) {
1611     munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_OK, '2');
1612 #if defined(MUNIT_ENABLE_TIMING)
1613     fputs(" ] [ ", MUNIT_OUTPUT_FILE);
1614     munit_print_time(MUNIT_OUTPUT_FILE, report.wall_clock);
1615     fputs(" / ", MUNIT_OUTPUT_FILE);
1616     munit_print_time(MUNIT_OUTPUT_FILE, report.cpu_clock);
1617     fputs(" CPU", MUNIT_OUTPUT_FILE);
1618 #endif
1619     runner->report.successful++;
1620     result = MUNIT_OK;
1621   }
1622   fputs(" ]\n", MUNIT_OUTPUT_FILE);
1623 
1624   if (stderr_buf != NULL) {
1625     if (result == MUNIT_FAIL || result == MUNIT_ERROR || runner->show_stderr) {
1626       fflush(MUNIT_OUTPUT_FILE);
1627 
1628       rewind(stderr_buf);
1629       munit_splice(fileno(stderr_buf), STDERR_FILENO);
1630 
1631       fflush(stderr);
1632     }
1633 
1634     fclose(stderr_buf);
1635   }
1636 }
1637 
munit_test_runner_run_test_wild(MunitTestRunner * runner,const MunitTest * test,const char * test_name,MunitParameter * params,MunitParameter * p)1638 static void munit_test_runner_run_test_wild(MunitTestRunner *runner,
1639                                             const MunitTest *test,
1640                                             const char *test_name,
1641                                             MunitParameter *params,
1642                                             MunitParameter *p) {
1643   const MunitParameterEnum *pe;
1644   char **values;
1645   MunitParameter *next;
1646 
1647   for (pe = test->parameters; pe != NULL && pe->name != NULL; pe++) {
1648     if (p->name == pe->name)
1649       break;
1650   }
1651 
1652   if (pe == NULL)
1653     return;
1654 
1655   for (values = pe->values; *values != NULL; values++) {
1656     next = p + 1;
1657     p->value = *values;
1658     if (next->name == NULL) {
1659       munit_test_runner_run_test_with_params(runner, test, params);
1660     } else {
1661       munit_test_runner_run_test_wild(runner, test, test_name, params, next);
1662     }
1663     if (runner->fatal_failures &&
1664         (runner->report.failed != 0 || runner->report.errored != 0))
1665       break;
1666   }
1667 }
1668 
1669 /* Run a single test, with every combination of parameters
1670  * requested. */
munit_test_runner_run_test(MunitTestRunner * runner,const MunitTest * test,const char * prefix)1671 static void munit_test_runner_run_test(MunitTestRunner *runner,
1672                                        const MunitTest *test,
1673                                        const char *prefix) {
1674   char *test_name =
1675     munit_maybe_concat(NULL, (char *)prefix, (char *)test->name);
1676   /* The array of parameters to pass to
1677    * munit_test_runner_run_test_with_params */
1678   MunitParameter *params = NULL;
1679   size_t params_l = 0;
1680   /* Wildcard parameters are parameters which have possible values
1681    * specified in the test, but no specific value was passed to the
1682    * CLI.  That means we want to run the test once for every
1683    * possible combination of parameter values or, if --single was
1684    * passed to the CLI, a single time with a random set of
1685    * parameters. */
1686   MunitParameter *wild_params = NULL;
1687   size_t wild_params_l = 0;
1688   const MunitParameterEnum *pe;
1689   const MunitParameter *cli_p;
1690   munit_bool filled;
1691   unsigned int possible;
1692   char **vals;
1693   size_t first_wild;
1694   const MunitParameter *wp;
1695   int pidx;
1696 
1697   munit_rand_seed(runner->seed);
1698 
1699   fprintf(MUNIT_OUTPUT_FILE, "%-" MUNIT_XSTRINGIFY(MUNIT_TEST_NAME_LEN) "s",
1700           test_name);
1701 
1702   if (test->parameters == NULL) {
1703     /* No parameters.  Simple, nice. */
1704     munit_test_runner_run_test_with_params(runner, test, NULL);
1705   } else {
1706     fputc('\n', MUNIT_OUTPUT_FILE);
1707 
1708     for (pe = test->parameters; pe != NULL && pe->name != NULL; pe++) {
1709       /* Did we received a value for this parameter from the CLI? */
1710       filled = 0;
1711       for (cli_p = runner->parameters; cli_p != NULL && cli_p->name != NULL;
1712            cli_p++) {
1713         if (strcmp(cli_p->name, pe->name) == 0) {
1714           if (MUNIT_UNLIKELY(munit_parameters_add(&params_l, &params, pe->name,
1715                                                   cli_p->value) != MUNIT_OK))
1716             goto cleanup;
1717           filled = 1;
1718           break;
1719         }
1720       }
1721       if (filled)
1722         continue;
1723 
1724       /* Nothing from CLI, is the enum NULL/empty?  We're not a
1725        * fuzzer… */
1726       if (pe->values == NULL || pe->values[0] == NULL)
1727         continue;
1728 
1729       /* If --single was passed to the CLI, choose a value from the
1730        * list of possibilities randomly. */
1731       if (runner->single_parameter_mode) {
1732         possible = 0;
1733         for (vals = pe->values; *vals != NULL; vals++)
1734           possible++;
1735         /* We want the tests to be reproducible, even if you're only
1736          * running a single test, but we don't want every test with
1737          * the same number of parameters to choose the same parameter
1738          * number, so use the test name as a primitive salt. */
1739         pidx = (int)munit_rand_at_most(munit_str_hash(test_name), possible - 1);
1740         if (MUNIT_UNLIKELY(munit_parameters_add(&params_l, &params, pe->name,
1741                                                 pe->values[pidx]) != MUNIT_OK))
1742           goto cleanup;
1743       } else {
1744         /* We want to try every permutation.  Put in a placeholder
1745          * entry, we'll iterate through them later. */
1746         if (MUNIT_UNLIKELY(munit_parameters_add(&wild_params_l, &wild_params,
1747                                                 pe->name, NULL) != MUNIT_OK))
1748           goto cleanup;
1749       }
1750     }
1751 
1752     if (wild_params_l != 0) {
1753       first_wild = params_l;
1754       for (wp = wild_params; wp != NULL && wp->name != NULL; wp++) {
1755         for (pe = test->parameters;
1756              pe != NULL && pe->name != NULL && pe->values != NULL; pe++) {
1757           if (strcmp(wp->name, pe->name) == 0) {
1758             if (MUNIT_UNLIKELY(munit_parameters_add(&params_l, &params,
1759                                                     pe->name,
1760                                                     pe->values[0]) != MUNIT_OK))
1761               goto cleanup;
1762           }
1763         }
1764       }
1765 
1766       munit_test_runner_run_test_wild(runner, test, test_name, params,
1767                                       params + first_wild);
1768     } else {
1769       munit_test_runner_run_test_with_params(runner, test, params);
1770     }
1771 
1772   cleanup:
1773     free(params);
1774     free(wild_params);
1775   }
1776 
1777   munit_maybe_free_concat(test_name, prefix, test->name);
1778 }
1779 
1780 /* Recurse through the suite and run all the tests.  If a list of
1781  * tests to run was provied on the command line, run only those
1782  * tests.  */
munit_test_runner_run_suite(MunitTestRunner * runner,const MunitSuite * suite,const char * prefix)1783 static void munit_test_runner_run_suite(MunitTestRunner *runner,
1784                                         const MunitSuite *suite,
1785                                         const char *prefix) {
1786   size_t pre_l;
1787   char *pre = munit_maybe_concat(&pre_l, (char *)prefix, (char *)suite->prefix);
1788   const MunitTest *test;
1789   const char **test_name;
1790   const MunitSuite *child_suite;
1791 
1792   /* Run the tests. */
1793   for (test = suite->tests; test != NULL && test->test != NULL; test++) {
1794     if (runner->tests != NULL) { /* Specific tests were requested on the CLI */
1795       for (test_name = runner->tests; test_name != NULL && *test_name != NULL;
1796            test_name++) {
1797         if ((pre_l == 0 || strncmp(pre, *test_name, pre_l) == 0) &&
1798             strncmp(test->name, *test_name + pre_l,
1799                     strlen(*test_name + pre_l)) == 0) {
1800           munit_test_runner_run_test(runner, test, pre);
1801           if (runner->fatal_failures &&
1802               (runner->report.failed != 0 || runner->report.errored != 0))
1803             goto cleanup;
1804         }
1805       }
1806     } else { /* Run all tests */
1807       munit_test_runner_run_test(runner, test, pre);
1808     }
1809   }
1810 
1811   if (runner->fatal_failures &&
1812       (runner->report.failed != 0 || runner->report.errored != 0))
1813     goto cleanup;
1814 
1815   /* Run any child suites. */
1816   for (child_suite = suite->suites;
1817        child_suite != NULL && child_suite->prefix != NULL; child_suite++) {
1818     munit_test_runner_run_suite(runner, child_suite, pre);
1819   }
1820 
1821 cleanup:
1822 
1823   munit_maybe_free_concat(pre, prefix, suite->prefix);
1824 }
1825 
munit_test_runner_run(MunitTestRunner * runner)1826 static void munit_test_runner_run(MunitTestRunner *runner) {
1827   munit_test_runner_run_suite(runner, runner->suite, NULL);
1828 }
1829 
munit_print_help(int argc,char * const * argv,void * user_data,const MunitArgument arguments[])1830 static void munit_print_help(int argc, char *const *argv, void *user_data,
1831                              const MunitArgument arguments[]) {
1832   const MunitArgument *arg;
1833   (void)argc;
1834 
1835   printf("USAGE: %s [OPTIONS...] [TEST...]\n\n", argv[0]);
1836   puts(
1837     " --seed SEED\n"
1838     "           Value used to seed the PRNG.  Must be a 32-bit integer in "
1839     "decimal\n"
1840     "           notation with no separators (commas, decimals, spaces, "
1841     "etc.), or\n"
1842     "           hexidecimal prefixed by \"0x\".\n"
1843     " --iterations N\n"
1844     "           Run each test N times.  0 means the default number.\n"
1845     " --param name value\n"
1846     "           A parameter key/value pair which will be passed to any test "
1847     "with\n"
1848     "           takes a parameter of that name.  If not provided, the test "
1849     "will be\n"
1850     "           run once for each possible parameter value.\n"
1851     " --list    Write a list of all available tests.\n"
1852     " --list-params\n"
1853     "           Write a list of all available tests and their possible "
1854     "parameters.\n"
1855     " --single  Run each parameterized test in a single configuration "
1856     "instead of\n"
1857     "           every possible combination\n"
1858     " --log-visible debug|info|warning|error\n"
1859     " --log-fatal debug|info|warning|error\n"
1860     "           Set the level at which messages of different severities are "
1861     "visible,\n"
1862     "           or cause the test to terminate.\n"
1863 #if !defined(MUNIT_NO_FORK)
1864     " --no-fork Do not execute tests in a child process.  If this option is "
1865     "supplied\n"
1866     "           and a test crashes (including by failing an assertion), no "
1867     "further\n"
1868     "           tests will be performed.\n"
1869 #endif
1870     " --fatal-failures\n"
1871     "           Stop executing tests as soon as a failure is found.\n"
1872     " --show-stderr\n"
1873     "           Show data written to stderr by the tests, even if the test "
1874     "succeeds.\n"
1875     " --color auto|always|never\n"
1876     "           Colorize (or don't) the output.\n"
1877     /* 12345678901234567890123456789012345678901234567890123456789012345678901234567890
1878      */
1879     " --help    Print this help message and exit.\n");
1880 #if defined(MUNIT_NL_LANGINFO)
1881   setlocale(LC_ALL, "");
1882   fputs((strcasecmp("UTF-8", nl_langinfo(CODESET)) == 0) ? "µnit" : "munit",
1883         stdout);
1884 #else
1885   puts("munit");
1886 #endif
1887   printf(" %d.%d.%d\n"
1888          "Full documentation at: https://nemequ.github.io/munit/\n",
1889          (MUNIT_CURRENT_VERSION >> 16) & 0xff,
1890          (MUNIT_CURRENT_VERSION >> 8) & 0xff,
1891          (MUNIT_CURRENT_VERSION >> 0) & 0xff);
1892   for (arg = arguments; arg != NULL && arg->name != NULL; arg++)
1893     arg->write_help(arg, user_data);
1894 }
1895 
1896 static const MunitArgument *
munit_arguments_find(const MunitArgument arguments[],const char * name)1897 munit_arguments_find(const MunitArgument arguments[], const char *name) {
1898   const MunitArgument *arg;
1899 
1900   for (arg = arguments; arg != NULL && arg->name != NULL; arg++)
1901     if (strcmp(arg->name, name) == 0)
1902       return arg;
1903 
1904   return NULL;
1905 }
1906 
munit_suite_list_tests(const MunitSuite * suite,munit_bool show_params,const char * prefix)1907 static void munit_suite_list_tests(const MunitSuite *suite,
1908                                    munit_bool show_params, const char *prefix) {
1909   size_t pre_l;
1910   char *pre = munit_maybe_concat(&pre_l, (char *)prefix, (char *)suite->prefix);
1911   const MunitTest *test;
1912   const MunitParameterEnum *params;
1913   munit_bool first;
1914   char **val;
1915   const MunitSuite *child_suite;
1916 
1917   for (test = suite->tests; test != NULL && test->name != NULL; test++) {
1918     if (pre != NULL)
1919       fputs(pre, stdout);
1920     puts(test->name);
1921 
1922     if (show_params) {
1923       for (params = test->parameters; params != NULL && params->name != NULL;
1924            params++) {
1925         fprintf(stdout, " - %s: ", params->name);
1926         if (params->values == NULL) {
1927           puts("Any");
1928         } else {
1929           first = 1;
1930           for (val = params->values; *val != NULL; val++) {
1931             if (!first) {
1932               fputs(", ", stdout);
1933             } else {
1934               first = 0;
1935             }
1936             fputs(*val, stdout);
1937           }
1938           putc('\n', stdout);
1939         }
1940       }
1941     }
1942   }
1943 
1944   for (child_suite = suite->suites;
1945        child_suite != NULL && child_suite->prefix != NULL; child_suite++) {
1946     munit_suite_list_tests(child_suite, show_params, pre);
1947   }
1948 
1949   munit_maybe_free_concat(pre, prefix, suite->prefix);
1950 }
1951 
munit_stream_supports_ansi(FILE * stream)1952 static munit_bool munit_stream_supports_ansi(FILE *stream) {
1953 #if !defined(_WIN32)
1954   return isatty(fileno(stream));
1955 #else
1956 
1957 #  if !defined(__MINGW32__)
1958   size_t ansicon_size = 0;
1959 #  endif
1960 
1961   if (isatty(fileno(stream))) {
1962 #  if !defined(__MINGW32__)
1963     getenv_s(&ansicon_size, NULL, 0, "ANSICON");
1964     return ansicon_size != 0;
1965 #  else
1966     return getenv("ANSICON") != NULL;
1967 #  endif
1968   }
1969   return 0;
1970 #endif
1971 }
1972 
munit_suite_main_custom(const MunitSuite * suite,void * user_data,int argc,char * const * argv,const MunitArgument arguments[])1973 int munit_suite_main_custom(const MunitSuite *suite, void *user_data, int argc,
1974                             char *const *argv,
1975                             const MunitArgument arguments[]) {
1976   int result = EXIT_FAILURE;
1977   MunitTestRunner runner;
1978   size_t parameters_size = 0;
1979   size_t tests_size = 0;
1980   int arg;
1981 
1982   char *envptr;
1983   unsigned long ts;
1984   char *endptr;
1985   unsigned long long iterations;
1986   MunitLogLevel level;
1987   const MunitArgument *argument;
1988   const char **runner_tests;
1989   unsigned int tests_run;
1990   unsigned int tests_total;
1991 
1992   runner.prefix = NULL;
1993   runner.suite = NULL;
1994   runner.tests = NULL;
1995   runner.seed = 0;
1996   runner.iterations = 0;
1997   runner.parameters = NULL;
1998   runner.single_parameter_mode = 0;
1999   runner.user_data = NULL;
2000 
2001   runner.report.successful = 0;
2002   runner.report.skipped = 0;
2003   runner.report.failed = 0;
2004   runner.report.errored = 0;
2005 #if defined(MUNIT_ENABLE_TIMING)
2006   runner.report.cpu_clock = 0;
2007   runner.report.wall_clock = 0;
2008 #endif
2009 
2010   runner.colorize = 0;
2011 #if !defined(_WIN32)
2012   runner.fork = 1;
2013 #else
2014   runner.fork = 0;
2015 #endif
2016   runner.show_stderr = 0;
2017   runner.fatal_failures = 0;
2018   runner.suite = suite;
2019   runner.user_data = user_data;
2020   runner.seed = munit_rand_generate_seed();
2021   runner.colorize = munit_stream_supports_ansi(MUNIT_OUTPUT_FILE);
2022 
2023   for (arg = 1; arg < argc; arg++) {
2024     if (strncmp("--", argv[arg], 2) == 0) {
2025       if (strcmp("seed", argv[arg] + 2) == 0) {
2026         if (arg + 1 >= argc) {
2027           munit_logf_internal(MUNIT_LOG_ERROR, stderr,
2028                               "%s requires an argument", argv[arg]);
2029           goto cleanup;
2030         }
2031 
2032         envptr = argv[arg + 1];
2033         ts = strtoul(argv[arg + 1], &envptr, 0);
2034         if (*envptr != '\0' || ts > (~((munit_uint32_t)0U))) {
2035           munit_logf_internal(MUNIT_LOG_ERROR, stderr,
2036                               "invalid value ('%s') passed to %s",
2037                               argv[arg + 1], argv[arg]);
2038           goto cleanup;
2039         }
2040         runner.seed = (munit_uint32_t)ts;
2041 
2042         arg++;
2043       } else if (strcmp("iterations", argv[arg] + 2) == 0) {
2044         if (arg + 1 >= argc) {
2045           munit_logf_internal(MUNIT_LOG_ERROR, stderr,
2046                               "%s requires an argument", argv[arg]);
2047           goto cleanup;
2048         }
2049 
2050         endptr = argv[arg + 1];
2051         iterations = strtoul(argv[arg + 1], &endptr, 0);
2052         if (*endptr != '\0' || iterations > UINT_MAX) {
2053           munit_logf_internal(MUNIT_LOG_ERROR, stderr,
2054                               "invalid value ('%s') passed to %s",
2055                               argv[arg + 1], argv[arg]);
2056           goto cleanup;
2057         }
2058 
2059         runner.iterations = (unsigned int)iterations;
2060 
2061         arg++;
2062       } else if (strcmp("param", argv[arg] + 2) == 0) {
2063         if (arg + 2 >= argc) {
2064           munit_logf_internal(MUNIT_LOG_ERROR, stderr,
2065                               "%s requires two arguments", argv[arg]);
2066           goto cleanup;
2067         }
2068 
2069         runner.parameters = realloc(runner.parameters, sizeof(MunitParameter) *
2070                                                          (parameters_size + 2));
2071         if (runner.parameters == NULL) {
2072           munit_log_internal(MUNIT_LOG_ERROR, stderr,
2073                              "failed to allocate memory");
2074           goto cleanup;
2075         }
2076         runner.parameters[parameters_size].name = (char *)argv[arg + 1];
2077         runner.parameters[parameters_size].value = (char *)argv[arg + 2];
2078         parameters_size++;
2079         runner.parameters[parameters_size].name = NULL;
2080         runner.parameters[parameters_size].value = NULL;
2081         arg += 2;
2082       } else if (strcmp("color", argv[arg] + 2) == 0) {
2083         if (arg + 1 >= argc) {
2084           munit_logf_internal(MUNIT_LOG_ERROR, stderr,
2085                               "%s requires an argument", argv[arg]);
2086           goto cleanup;
2087         }
2088 
2089         if (strcmp(argv[arg + 1], "always") == 0)
2090           runner.colorize = 1;
2091         else if (strcmp(argv[arg + 1], "never") == 0)
2092           runner.colorize = 0;
2093         else if (strcmp(argv[arg + 1], "auto") == 0)
2094           runner.colorize = munit_stream_supports_ansi(MUNIT_OUTPUT_FILE);
2095         else {
2096           munit_logf_internal(MUNIT_LOG_ERROR, stderr,
2097                               "invalid value ('%s') passed to %s",
2098                               argv[arg + 1], argv[arg]);
2099           goto cleanup;
2100         }
2101 
2102         arg++;
2103       } else if (strcmp("help", argv[arg] + 2) == 0) {
2104         munit_print_help(argc, argv, user_data, arguments);
2105         result = EXIT_SUCCESS;
2106         goto cleanup;
2107       } else if (strcmp("single", argv[arg] + 2) == 0) {
2108         runner.single_parameter_mode = 1;
2109       } else if (strcmp("show-stderr", argv[arg] + 2) == 0) {
2110         runner.show_stderr = 1;
2111 #if !defined(_WIN32)
2112       } else if (strcmp("no-fork", argv[arg] + 2) == 0) {
2113         runner.fork = 0;
2114 #endif
2115       } else if (strcmp("fatal-failures", argv[arg] + 2) == 0) {
2116         runner.fatal_failures = 1;
2117       } else if (strcmp("log-visible", argv[arg] + 2) == 0 ||
2118                  strcmp("log-fatal", argv[arg] + 2) == 0) {
2119         if (arg + 1 >= argc) {
2120           munit_logf_internal(MUNIT_LOG_ERROR, stderr,
2121                               "%s requires an argument", argv[arg]);
2122           goto cleanup;
2123         }
2124 
2125         if (strcmp(argv[arg + 1], "debug") == 0)
2126           level = MUNIT_LOG_DEBUG;
2127         else if (strcmp(argv[arg + 1], "info") == 0)
2128           level = MUNIT_LOG_INFO;
2129         else if (strcmp(argv[arg + 1], "warning") == 0)
2130           level = MUNIT_LOG_WARNING;
2131         else if (strcmp(argv[arg + 1], "error") == 0)
2132           level = MUNIT_LOG_ERROR;
2133         else {
2134           munit_logf_internal(MUNIT_LOG_ERROR, stderr,
2135                               "invalid value ('%s') passed to %s",
2136                               argv[arg + 1], argv[arg]);
2137           goto cleanup;
2138         }
2139 
2140         if (strcmp("log-visible", argv[arg] + 2) == 0)
2141           munit_log_level_visible = level;
2142         else
2143           munit_log_level_fatal = level;
2144 
2145         arg++;
2146       } else if (strcmp("list", argv[arg] + 2) == 0) {
2147         munit_suite_list_tests(suite, 0, NULL);
2148         result = EXIT_SUCCESS;
2149         goto cleanup;
2150       } else if (strcmp("list-params", argv[arg] + 2) == 0) {
2151         munit_suite_list_tests(suite, 1, NULL);
2152         result = EXIT_SUCCESS;
2153         goto cleanup;
2154       } else {
2155         argument = munit_arguments_find(arguments, argv[arg] + 2);
2156         if (argument == NULL) {
2157           munit_logf_internal(MUNIT_LOG_ERROR, stderr,
2158                               "unknown argument ('%s')", argv[arg]);
2159           goto cleanup;
2160         }
2161 
2162         if (!argument->parse_argument(suite, user_data, &arg, argc, argv))
2163           goto cleanup;
2164       }
2165     } else {
2166       runner_tests =
2167         realloc((void *)runner.tests, sizeof(char *) * (tests_size + 2));
2168       if (runner_tests == NULL) {
2169         munit_log_internal(MUNIT_LOG_ERROR, stderr,
2170                            "failed to allocate memory");
2171         goto cleanup;
2172       }
2173       runner.tests = runner_tests;
2174       runner.tests[tests_size++] = argv[arg];
2175       runner.tests[tests_size] = NULL;
2176     }
2177   }
2178 
2179   fflush(stderr);
2180   fprintf(MUNIT_OUTPUT_FILE,
2181           "Running test suite with seed 0x%08" PRIx32 "...\n", runner.seed);
2182 
2183   munit_test_runner_run(&runner);
2184 
2185   tests_run =
2186     runner.report.successful + runner.report.failed + runner.report.errored;
2187   tests_total = tests_run + runner.report.skipped;
2188   if (tests_run == 0) {
2189     fprintf(stderr, "No tests run, %d (100%%) skipped.\n",
2190             runner.report.skipped);
2191   } else {
2192     fprintf(MUNIT_OUTPUT_FILE,
2193             "%d of %d (%0.0f%%) tests successful, %d (%0.0f%%) test skipped.\n",
2194             runner.report.successful, tests_run,
2195             (((double)runner.report.successful) / ((double)tests_run)) * 100.0,
2196             runner.report.skipped,
2197             (((double)runner.report.skipped) / ((double)tests_total)) * 100.0);
2198   }
2199 
2200   if (runner.report.failed == 0 && runner.report.errored == 0) {
2201     result = EXIT_SUCCESS;
2202   }
2203 
2204 cleanup:
2205   free(runner.parameters);
2206   free((void *)runner.tests);
2207 
2208   return result;
2209 }
2210 
munit_suite_main(const MunitSuite * suite,void * user_data,int argc,char * const * argv)2211 int munit_suite_main(const MunitSuite *suite, void *user_data, int argc,
2212                      char *const *argv) {
2213   return munit_suite_main_custom(suite, user_data, argc, argv, NULL);
2214 }
2215 
2216 static uint8_t hexchars[] = "0123456789abcdef";
2217 
hexdump_addr(uint8_t * dest,size_t addr)2218 static uint8_t *hexdump_addr(uint8_t *dest, size_t addr) {
2219   size_t i;
2220   uint8_t a;
2221 
2222   for (i = 0; i < 4; ++i) {
2223     a = (addr >> (3 - i) * 8) & 0xff;
2224 
2225     *dest++ = hexchars[a >> 4];
2226     *dest++ = hexchars[a & 0xf];
2227   }
2228 
2229   return dest;
2230 }
2231 
asciidump(uint8_t * dest,const uint8_t * data,size_t datalen)2232 static uint8_t *asciidump(uint8_t *dest, const uint8_t *data, size_t datalen) {
2233   size_t i;
2234 
2235   *dest++ = '|';
2236 
2237   for (i = 0; i < datalen; ++i) {
2238     if (0x20 <= data[i] && data[i] <= 0x7e) {
2239       *dest++ = data[i];
2240     } else {
2241       *dest++ = '.';
2242     }
2243   }
2244 
2245   *dest++ = '|';
2246 
2247   return dest;
2248 }
2249 
hexdump8(uint8_t * dest,const uint8_t * data,size_t datalen)2250 static uint8_t *hexdump8(uint8_t *dest, const uint8_t *data, size_t datalen) {
2251   size_t i;
2252 
2253   for (i = 0; i < datalen; ++i) {
2254     *dest++ = hexchars[data[i] >> 4];
2255     *dest++ = hexchars[data[i] & 0xf];
2256     *dest++ = ' ';
2257   }
2258 
2259   for (; i < 8; ++i) {
2260     *dest++ = ' ';
2261     *dest++ = ' ';
2262     *dest++ = ' ';
2263   }
2264 
2265   return dest;
2266 }
2267 
hexdump16(uint8_t * dest,const uint8_t * data,size_t datalen)2268 static uint8_t *hexdump16(uint8_t *dest, const uint8_t *data, size_t datalen) {
2269   dest = hexdump8(dest, data, datalen < 8 ? datalen : 8);
2270   *dest++ = ' ';
2271 
2272   if (datalen < 8) {
2273     data = NULL;
2274     datalen = 0;
2275   } else {
2276     data += 8;
2277     datalen -= 8;
2278   }
2279 
2280   dest = hexdump8(dest, data, datalen);
2281   *dest++ = ' ';
2282 
2283   return dest;
2284 }
2285 
hexdump_line(uint8_t * dest,const uint8_t * data,size_t datalen,size_t addr)2286 static uint8_t *hexdump_line(uint8_t *dest, const uint8_t *data, size_t datalen,
2287                              size_t addr) {
2288   dest = hexdump_addr(dest, addr);
2289   *dest++ = ' ';
2290   *dest++ = ' ';
2291 
2292   dest = hexdump16(dest, data, datalen);
2293 
2294   dest = asciidump(dest, data, datalen);
2295 
2296   return dest;
2297 }
2298 
munit_hexdump(FILE * fp,const void * data,size_t datalen)2299 int munit_hexdump(FILE *fp, const void *data, size_t datalen) {
2300   size_t offset = 0, n, len;
2301   uint8_t buf[128], *p;
2302   const uint8_t *s;
2303   int repeated = 0;
2304 
2305   if (datalen == 0) {
2306     return 0;
2307   }
2308 
2309   for (; offset < datalen; offset += 16) {
2310     n = datalen - offset;
2311     s = (const uint8_t *)data + offset;
2312 
2313     if (n >= 16) {
2314       n = 16;
2315 
2316       if (offset > 0) {
2317         if (memcmp(s - 16, s, 16) == 0) {
2318           if (repeated) {
2319             continue;
2320           }
2321 
2322           repeated = 1;
2323 
2324           if (fwrite("*\n", 1, 2, fp) < 2) {
2325             return -1;
2326           }
2327 
2328           continue;
2329         }
2330 
2331         repeated = 0;
2332       }
2333     }
2334 
2335     p = hexdump_line(buf, s, n, offset);
2336     *p++ = '\n';
2337 
2338     len = (size_t)(p - buf);
2339 
2340     if (fwrite(buf, 1, len, fp) < len) {
2341       return -1;
2342     }
2343   }
2344 
2345   p = hexdump_addr(buf, datalen);
2346   *p++ = '\n';
2347 
2348   len = (size_t)(p - buf);
2349 
2350   if (fwrite(buf, 1, len, fp) < len) {
2351     return -1;
2352   }
2353 
2354   return 0;
2355 }
2356 
munit_hexdump_diff(FILE * fp,const void * a,size_t alen,const void * b,size_t blen)2357 int munit_hexdump_diff(FILE *fp, const void *a, size_t alen, const void *b,
2358                        size_t blen) {
2359   size_t offset = 0, k, i, len, ncomp, maxlen, adoff = 0;
2360   uint8_t buf[128], *p;
2361   const uint8_t mk[2] = {'-', '+'};
2362   struct datasource {
2363     const uint8_t *data;
2364     size_t datalen;
2365     const uint8_t *s;
2366     size_t n;
2367   } ds[] = {{a, alen, NULL, 0}, {b, blen, NULL, 0}}, *dp;
2368 
2369   maxlen = alen < blen ? blen : alen;
2370 
2371   for (; offset < maxlen; offset += 16) {
2372     for (k = 0; k < 2; ++k) {
2373       dp = &ds[k];
2374 
2375       if (offset < dp->datalen) {
2376         dp->s = (const uint8_t *)dp->data + offset;
2377         dp->n = dp->datalen - offset;
2378 
2379         if (dp->n > 16) {
2380           dp->n = 16;
2381         }
2382       } else {
2383         dp->s = NULL;
2384         dp->n = 0;
2385       }
2386     }
2387 
2388     if (ds[0].n == ds[1].n && memcmp(ds[0].s, ds[1].s, ds[0].n) == 0) {
2389       continue;
2390     }
2391 
2392     for (k = 0; k < 2; ++k) {
2393       dp = &ds[k];
2394 
2395       if (!dp->n) {
2396         continue;
2397       }
2398 
2399       p = buf;
2400       *p++ = mk[k];
2401       *p++ = mk[k];
2402       *p++ = mk[k];
2403       *p++ = mk[k];
2404 
2405       p = hexdump_line(p, dp->s, dp->n, offset);
2406       *p++ = '\n';
2407 
2408       len = (size_t)(p - buf);
2409 
2410       if (fwrite(buf, 1, len, fp) < len) {
2411         return -1;
2412       }
2413     }
2414 
2415     if (!ds[0].n || !ds[1].n) {
2416       continue;
2417     }
2418 
2419     ncomp = ds[0].n < ds[1].n ? ds[0].n : ds[1].n;
2420 
2421     p = buf + 4 + 10;
2422 
2423     memset(buf, ' ', 4 + 78);
2424 
2425     for (i = 0; i < ncomp; ++i) {
2426       if (ds[0].s[i] == ds[1].s[i]) {
2427         *p++ = ' ';
2428         *p++ = ' ';
2429       } else {
2430         adoff = 4 + 10 + 51 + i;
2431         *(buf + adoff) = '^';
2432 
2433         *p++ = '^';
2434         *p++ = '^';
2435       }
2436 
2437       *p++ = ' ';
2438 
2439       if (i == 7) {
2440         *p++ = ' ';
2441       }
2442     }
2443 
2444     if (adoff) {
2445       len = adoff + 1;
2446     } else {
2447       len = (size_t)(p - buf);
2448     }
2449 
2450     buf[len++] = '\n';
2451 
2452     if (fwrite(buf, 1, len, fp) < len) {
2453       return -1;
2454     }
2455   }
2456 
2457   return 0;
2458 }
2459