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(¶ms_l, ¶ms, 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(¶ms_l, ¶ms, 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(¶ms_l, ¶ms,
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