Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/openzfs/tests/unit/munit.c
289319 views
1
// SPDX-License-Identifier: MIT
2
/* µnit Testing Framework
3
* Copyright (c) 2013-2018 Evan Nemerson <[email protected]>
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)
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)
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
222
static void munit_log_internal(MunitLogLevel level, FILE *fp,
223
const char *message) {
224
munit_logf_internal(level, fp, "%s", message);
225
}
226
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
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
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
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 <[email protected]>
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
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
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
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
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
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
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
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
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
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. */
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
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)
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
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
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))
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
972
static munit_uint32_t munit_rand_next_state(munit_uint32_t state) {
973
return state * MUNIT_PRNG_MULTIPLIER + MUNIT_PRNG_INCREMENT;
974
}
975
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
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
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
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
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
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
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
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
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
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
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
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)
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. */
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 "". */
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. */
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. */
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
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 */
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
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)
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
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
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
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. */
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. */
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
1826
static void munit_test_runner_run(MunitTestRunner *runner) {
1827
munit_test_runner_run_suite(runner, runner->suite, NULL);
1828
}
1829
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 *
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
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
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
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
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
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
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
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
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
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
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
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
2460