Serene Runtime 1.0.0-dev
C runtime for the Serene programming language
Loading...
Searching...
No Matches
acutest.h
Go to the documentation of this file.
1/*
2 * Acutest -- Another C/C++ Unit Test facility
3 * <https://github.com/mity/acutest>
4 *
5 * Copyright 2013-2023 Martin Mitáš
6 * Copyright 2019 Garrett D'Amore
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 * IN THE SOFTWARE.
25 */
26
27#ifndef ACUTEST_H
28#define ACUTEST_H
29
30/* Try to auto-detect whether we need to disable C++ exception handling.
31 * If the detection fails, you may always define TEST_NO_EXCEPTIONS before
32 * including "acutest.h" manually. */
33#ifdef __cplusplus
34# if (__cplusplus >= 199711L && !defined __cpp_exceptions) || \
35 ((defined(__GNUC__) || defined(__clang__)) && !defined __EXCEPTIONS)
36# ifndef TEST_NO_EXCEPTIONS
37# define TEST_NO_EXCEPTIONS
38# endif
39# endif
40#endif
41
42/************************
43 *** Public interface ***
44 ************************/
45
46/* By default, "acutest.h" provides the main program entry point (function
47 * main()). However, if the test suite is composed of multiple source files
48 * which include "acutest.h", then this causes a problem of multiple main()
49 * definitions. To avoid this problem, #define macro TEST_NO_MAIN in all
50 * compilation units but one.
51 */
52
53/* Macro to specify list of unit tests in the suite.
54 * The unit test implementation MUST provide list of unit tests it implements
55 * with this macro:
56 *
57 * TEST_LIST = {
58 * { "test1_name", test1_func_ptr },
59 * { "test2_name", test2_func_ptr },
60 * ...
61 * { NULL, NULL } // zeroed record marking the end of the list
62 * };
63 *
64 * The list specifies names of each test (must be unique) and pointer to
65 * a function implementing it. The function does not take any arguments
66 * and has no return values, i.e. every test function has to be compatible
67 * with this prototype:
68 *
69 * void test_func(void);
70 *
71 * Note the list has to be ended with a zeroed record.
72 */
73#define TEST_LIST const struct acutest_test_ acutest_list_[]
74
75/* Macros for testing whether an unit test succeeds or fails. These macros
76 * can be used arbitrarily in functions implementing the unit tests.
77 *
78 * If any condition fails throughout execution of a test, the test fails.
79 *
80 * TEST_CHECK takes only one argument (the condition), TEST_CHECK_ allows
81 * also to specify an error message to print out if the condition fails.
82 * (It expects printf-like format string and its parameters). The macros
83 * return non-zero (condition passes) or 0 (condition fails).
84 *
85 * That can be useful when more conditions should be checked only if some
86 * preceding condition passes, as illustrated in this code snippet:
87 *
88 * SomeStruct* ptr = allocate_some_struct();
89 * if(TEST_CHECK(ptr != NULL)) {
90 * TEST_CHECK(ptr->member1 < 100);
91 * TEST_CHECK(ptr->member2 > 200);
92 * }
93 */
94#define TEST_CHECK_(cond, ...) acutest_check_(!!(cond), __FILE__, __LINE__, __VA_ARGS__)
95#define TEST_CHECK(cond) acutest_check_(!!(cond), __FILE__, __LINE__, "%s", #cond)
96
97/* These macros are the same as TEST_CHECK_ and TEST_CHECK except that if the
98 * condition fails, the currently executed unit test is immediately aborted.
99 *
100 * That is done either by calling abort() if the unit test is executed as a
101 * child process; or via longjmp() if the unit test is executed within the
102 * main Acutest process.
103 *
104 * As a side effect of such abortion, your unit tests may cause memory leaks,
105 * unflushed file descriptors, and other phenomena caused by the abortion.
106 *
107 * Therefore you should not use these as a general replacement for TEST_CHECK.
108 * Use it with some caution, especially if your test causes some other side
109 * effects to the outside world (e.g. communicating with some server, inserting
110 * into a database etc.).
111 */
112#define TEST_ASSERT_(cond, ...) \
113 do { \
114 if (!acutest_check_(!!(cond), __FILE__, __LINE__, __VA_ARGS__)) \
115 acutest_abort_(); \
116 } while (0)
117#define TEST_ASSERT(cond) \
118 do { \
119 if (!acutest_check_(!!(cond), __FILE__, __LINE__, "%s", #cond)) \
120 acutest_abort_(); \
121 } while (0)
122
123#ifdef __cplusplus
124# ifndef TEST_NO_EXCEPTIONS
125/* Macros to verify that the code (the 1st argument) throws exception of given
126 * type (the 2nd argument). (Note these macros are only available in C++.)
127 *
128 * TEST_EXCEPTION_ is like TEST_EXCEPTION but accepts custom printf-like
129 * message.
130 *
131 * For example:
132 *
133 * TEST_EXCEPTION(function_that_throw(), ExpectedExceptionType);
134 *
135 * If the function_that_throw() throws ExpectedExceptionType, the check passes.
136 * If the function throws anything incompatible with ExpectedExceptionType
137 * (or if it does not thrown an exception at all), the check fails.
138 */
139# define TEST_EXCEPTION(code, exctype) \
140 do { \
141 bool exc_ok_ = false; \
142 const char *msg_ = NULL; \
143 try { \
144 code; \
145 msg_ = "No exception thrown."; \
146 } catch (exctype const &) { \
147 exc_ok_ = true; \
148 } catch (...) { \
149 msg_ = "Unexpected exception thrown."; \
150 } \
151 acutest_check_(exc_ok_, __FILE__, __LINE__, #code " throws " #exctype); \
152 if (msg_ != NULL) \
153 acutest_message_("%s", msg_); \
154 } while (0)
155# define TEST_EXCEPTION_(code, exctype, ...) \
156 do { \
157 bool exc_ok_ = false; \
158 const char *msg_ = NULL; \
159 try { \
160 code; \
161 msg_ = "No exception thrown."; \
162 } catch (exctype const &) { \
163 exc_ok_ = true; \
164 } catch (...) { \
165 msg_ = "Unexpected exception thrown."; \
166 } \
167 acutest_check_(exc_ok_, __FILE__, __LINE__, __VA_ARGS__); \
168 if (msg_ != NULL) \
169 acutest_message_("%s", msg_); \
170 } while (0)
171# endif /* #ifndef TEST_NO_EXCEPTIONS */
172#endif /* #ifdef __cplusplus */
173
174/* Sometimes it is useful to split execution of more complex unit tests to some
175 * smaller parts and associate those parts with some names.
176 *
177 * This is especially handy if the given unit test is implemented as a loop
178 * over some vector of multiple testing inputs. Using these macros allow to use
179 * sort of subtitle for each iteration of the loop (e.g. outputting the input
180 * itself or a name associated to it), so that if any TEST_CHECK condition
181 * fails in the loop, it can be easily seen which iteration triggers the
182 * failure, without the need to manually output the iteration-specific data in
183 * every single TEST_CHECK inside the loop body.
184 *
185 * TEST_CASE allows to specify only single string as the name of the case,
186 * TEST_CASE_ provides all the power of printf-like string formatting.
187 *
188 * Note that the test cases cannot be nested. Starting a new test case ends
189 * implicitly the previous one. To end the test case explicitly (e.g. to end
190 * the last test case after exiting the loop), you may use TEST_CASE(NULL).
191 */
192#define TEST_CASE_(...) acutest_case_(__VA_ARGS__)
193#define TEST_CASE(name) acutest_case_("%s", name)
194
195/* Maximal output per TEST_CASE call. Longer messages are cut.
196 * You may define another limit prior including "acutest.h"
197 */
198#ifndef TEST_CASE_MAXSIZE
199# define TEST_CASE_MAXSIZE 64
200#endif
201
202/* printf-like macro for outputting an extra information about a failure.
203 *
204 * Intended use is to output some computed output versus the expected value,
205 * e.g. like this:
206 *
207 * if(!TEST_CHECK(produced == expected)) {
208 * TEST_MSG("Expected: %d", expected);
209 * TEST_MSG("Produced: %d", produced);
210 * }
211 *
212 * Note the message is only written down if the most recent use of any checking
213 * macro (like e.g. TEST_CHECK or TEST_EXCEPTION) in the current test failed.
214 * This means the above is equivalent to just this:
215 *
216 * TEST_CHECK(produced == expected);
217 * TEST_MSG("Expected: %d", expected);
218 * TEST_MSG("Produced: %d", produced);
219 *
220 * The macro can deal with multi-line output fairly well. It also automatically
221 * adds a final new-line if there is none present.
222 */
223#define TEST_MSG(...) acutest_message_(__VA_ARGS__)
224
225/* Maximal output per TEST_MSG call. Longer messages are cut.
226 * You may define another limit prior including "acutest.h"
227 */
228#ifndef TEST_MSG_MAXSIZE
229# define TEST_MSG_MAXSIZE 1024
230#endif
231
232/* Macro for dumping a block of memory.
233 *
234 * Its intended use is very similar to what TEST_MSG is for, but instead of
235 * generating any printf-like message, this is for dumping raw block of a
236 * memory in a hexadecimal form:
237 *
238 * TEST_CHECK(size_produced == size_expected &&
239 * memcmp(addr_produced, addr_expected, size_produced) == 0);
240 * TEST_DUMP("Expected:", addr_expected, size_expected);
241 * TEST_DUMP("Produced:", addr_produced, size_produced);
242 */
243#define TEST_DUMP(title, addr, size) acutest_dump_(title, addr, size)
244
245/* Maximal output per TEST_DUMP call (in bytes to dump). Longer blocks are cut.
246 * You may define another limit prior including "acutest.h"
247 */
248#ifndef TEST_DUMP_MAXSIZE
249# define TEST_DUMP_MAXSIZE 1024
250#endif
251
252/* Macros for marking the test as SKIPPED.
253 * Note it can only be used at the beginning of a test, before any other
254 * checking.
255 *
256 * Once used, the best practice is to return from the test routine as soon
257 * as possible.
258 */
259#define TEST_SKIP(...) acutest_skip_(__FILE__, __LINE__, __VA_ARGS__)
260
261/* Common test initialisation/clean-up
262 *
263 * In some test suites, it may be needed to perform some sort of the same
264 * initialization and/or clean-up in all the tests.
265 *
266 * Such test suites may use macros TEST_INIT and/or TEST_FINI prior including
267 * this header. The expansion of the macro is then used as a body of helper
268 * function called just before executing every single (TEST_INIT) or just after
269 * it ends (TEST_FINI).
270 *
271 * Examples of various ways how to use the macro TEST_INIT:
272 *
273 * #define TEST_INIT my_init_func();
274 * #define TEST_INIT my_init_func() // Works even without the
275 * semicolon #define TEST_INIT setlocale(LC_ALL, NULL); #define TEST_INIT
276 * { setlocale(LC_ALL, NULL); my_init_func(); }
277 *
278 * TEST_FINI is to be used in the same way.
279 */
280
281/**********************
282 *** Implementation ***
283 **********************/
284
285/* The unit test files should not rely on anything below. */
286
287#include <stdlib.h>
288
289/* Enable the use of the non-standard keyword __attribute__ to silence warnings
290 * under some compilers */
291#if defined(__GNUC__) || defined(__clang__)
292# define ACUTEST_ATTRIBUTE_(attr) __attribute__((attr))
293#else
294# define ACUTEST_ATTRIBUTE_(attr)
295#endif
296
297#ifdef __cplusplus
298extern "C" {
299#endif
300
312
313int acutest_check_(int cond, const char *file, int line, const char *fmt, ...);
314void acutest_case_(const char *fmt, ...);
315void acutest_message_(const char *fmt, ...);
316void acutest_dump_(const char *title, const void *addr, size_t size);
317void acutest_abort_(void) ACUTEST_ATTRIBUTE_(noreturn);
318#ifdef __cplusplus
319} /* extern "C" */
320#endif
321
322#ifndef TEST_NO_MAIN
323
324# include <ctype.h>
325# include <setjmp.h>
326# include <stdarg.h>
327# include <stdio.h>
328# include <string.h>
329
330# if defined(unix) || defined(__unix__) || defined(__unix) || defined(__APPLE__)
331# define ACUTEST_UNIX_ 1
332# include <errno.h>
333# include <libgen.h>
334# include <signal.h>
335# include <sys/types.h>
336# include <sys/wait.h>
337# include <time.h>
338# include <unistd.h>
339
340# if defined CLOCK_PROCESS_CPUTIME_ID && defined CLOCK_MONOTONIC
341# define ACUTEST_HAS_POSIX_TIMER_ 1
342# endif
343# endif
344
345# if defined(_gnu_linux_) || defined(__linux__)
346# define ACUTEST_LINUX_ 1
347# include <fcntl.h>
348# include <sys/stat.h>
349# endif
350
351# if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)
352# define ACUTEST_WIN_ 1
353# include <io.h>
354# include <windows.h>
355# endif
356
357# if defined(__APPLE__)
358# define ACUTEST_MACOS_
359# include <assert.h>
360# include <stdbool.h>
361# include <sys/sysctl.h>
362# include <sys/types.h>
363# include <unistd.h>
364# endif
365
366# ifdef __cplusplus
367# ifndef TEST_NO_EXCEPTIONS
368# include <exception>
369# endif
370# endif
371
372# ifdef __has_include
373# if __has_include(<valgrind.h>)
374# include <valgrind.h>
375# endif
376# endif
377
378/* Note our global private identifiers end with '_' to mitigate risk of clash
379 * with the unit tests implementation. */
380
381# ifdef __cplusplus
382extern "C" {
383# endif
384
385# ifdef _MSC_VER
386/* In the multi-platform code like ours, we cannot use the non-standard
387 * "safe" functions from Microsoft C lib like e.g. sprintf_s() instead of
388 * standard sprintf(). Hence, lets disable the warning C4996. */
389# pragma warning(push)
390# pragma warning(disable : 4996)
391# endif
392
394 const char *name;
395 void (*func)(void);
396};
397
402
403extern const struct acutest_test_ acutest_list_[];
404
405static char *acutest_argv0_ = NULL;
406static int acutest_list_size_ = 0;
408static int acutest_no_exec_ = -1;
409static int acutest_no_summary_ = 0;
410static int acutest_tap_ = 0;
412static int acutest_worker_ = 0;
414static int acutest_cond_failed_ = 0;
415static FILE *acutest_xml_output_ = NULL;
416
417static const struct acutest_test_ *acutest_current_test_ = NULL;
422static char acutest_test_skip_reason_[256] = "";
427static int acutest_colorize_ = 0;
428static int acutest_timer_ = 0;
429
432
433static int acutest_count_(enum acutest_state_ state) {
434 int i, n;
435
436 for (i = 0, n = 0; i < acutest_list_size_; i++) {
437 if (acutest_test_data_[i].state == state) {
438 n++;
439 }
440 }
441
442 return n;
443}
444
445static void acutest_cleanup_(void) { free((void *)acutest_test_data_); }
446
447static void ACUTEST_ATTRIBUTE_(noreturn) acutest_exit_(int exit_code) {
449 exit(exit_code);
450}
451
452# if defined ACUTEST_WIN_
453typedef LARGE_INTEGER acutest_timer_type_;
454static LARGE_INTEGER acutest_timer_freq_;
457
458static void acutest_timer_init_(void) { QueryPerformanceFrequency(&acutest_timer_freq_); }
459
460static void acutest_timer_get_time_(LARGE_INTEGER *ts) { QueryPerformanceCounter(ts); }
461
462static double acutest_timer_diff_(LARGE_INTEGER start, LARGE_INTEGER end) {
463 double duration = (double)(end.QuadPart - start.QuadPart);
464 duration /= (double)acutest_timer_freq_.QuadPart;
465 return duration;
466}
467
468static void acutest_timer_print_diff_(void) {
470}
471# elif defined ACUTEST_HAS_POSIX_TIMER_
472static clockid_t acutest_timer_id_;
473typedef struct timespec acutest_timer_type_;
476
477static void acutest_timer_init_(void) {
478 if (acutest_timer_ == 1) {
479 acutest_timer_id_ = CLOCK_MONOTONIC;
480 } else if (acutest_timer_ == 2) {
481 acutest_timer_id_ = CLOCK_PROCESS_CPUTIME_ID;
482 }
483}
484
485static void acutest_timer_get_time_(struct timespec *ts) { clock_gettime(acutest_timer_id_, ts); }
486
487static double acutest_timer_diff_(struct timespec start, struct timespec end) {
488 return (double)(end.tv_sec - start.tv_sec) + (double)(end.tv_nsec - start.tv_nsec) / 1e9;
489}
490
491static void acutest_timer_print_diff_(void) {
493}
494# else
498
500
501static void acutest_timer_get_time_(int *ts) { (void)ts; }
502
503static double acutest_timer_diff_(int start, int end) {
504 (void)start;
505 (void)end;
506 return 0.0;
507}
508
509static void acutest_timer_print_diff_(void) {}
510# endif
511
512# define ACUTEST_COLOR_DEFAULT_ 0
513# define ACUTEST_COLOR_RED_ 1
514# define ACUTEST_COLOR_GREEN_ 2
515# define ACUTEST_COLOR_YELLOW_ 3
516# define ACUTEST_COLOR_DEFAULT_INTENSIVE_ 10
517# define ACUTEST_COLOR_RED_INTENSIVE_ 11
518# define ACUTEST_COLOR_GREEN_INTENSIVE_ 12
519# define ACUTEST_COLOR_YELLOW_INTENSIVE_ 13
520
521static int
522ACUTEST_ATTRIBUTE_(format(printf, 2, 3)) acutest_colored_printf_(int color, const char *fmt, ...) {
523 va_list args;
524 char buffer[256];
525 int n;
526
530 buffer[sizeof(buffer) - 1] = '\0';
531
533 return printf("%s", buffer);
534 }
535
536# if defined ACUTEST_UNIX_
537 {
538 const char *col_str;
539 switch (color) {
541 col_str = "\033[0;31m";
542 break;
544 col_str = "\033[0;32m";
545 break;
547 col_str = "\033[0;33m";
548 break;
550 col_str = "\033[1;31m";
551 break;
553 col_str = "\033[1;32m";
554 break;
556 col_str = "\033[1;33m";
557 break;
559 col_str = "\033[1m";
560 break;
561 default:
562 col_str = "\033[0m";
563 break;
564 }
565 printf("%s", col_str);
566 n = printf("%s", buffer);
567 printf("\033[0m");
568 return n;
569 }
570# elif defined ACUTEST_WIN_
571 {
572 HANDLE h;
573 CONSOLE_SCREEN_BUFFER_INFO info;
574 WORD attr;
575
576 h = GetStdHandle(STD_OUTPUT_HANDLE);
577 GetConsoleScreenBufferInfo(h, &info);
578
579 switch (color) {
581 attr = FOREGROUND_RED;
582 break;
584 attr = FOREGROUND_GREEN;
585 break;
587 attr = FOREGROUND_RED | FOREGROUND_GREEN;
588 break;
590 attr = FOREGROUND_RED | FOREGROUND_INTENSITY;
591 break;
593 attr = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
594 break;
596 attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
597 break;
599 attr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
600 break;
601 default:
602 attr = 0;
603 break;
604 }
605 if (attr != 0) {
606 SetConsoleTextAttribute(h, attr);
607 }
608 n = printf("%s", buffer);
609 SetConsoleTextAttribute(h, info.wAttributes);
610 return n;
611 }
612# else
613 n = printf("%s", buffer);
614 return n;
615# endif
616}
617
618static const char *acutest_basename_(const char *path) {
619 const char *name;
620
621 name = strrchr(path, '/');
622 if (name != NULL) {
623 name++;
624 } else {
625 name = path;
626 }
627
628# ifdef ACUTEST_WIN_
629 {
630 const char *alt_name;
631
632 alt_name = strrchr(path, '\\');
633 if (alt_name != NULL) {
634 alt_name++;
635 } else {
636 alt_name = path;
637 }
638
639 if (alt_name > name) {
640 name = alt_name;
641 }
642 }
643# endif
644
645 return name;
646}
647
648static void acutest_begin_test_line_(const struct acutest_test_ *test) {
649 if (!acutest_tap_) {
650 if (acutest_verbose_level_ >= 3) {
651 acutest_colored_printf_(ACUTEST_COLOR_DEFAULT_INTENSIVE_, "Test %s:\n", test->name);
653 } else if (acutest_verbose_level_ >= 1) {
654 int n;
655 char spaces[48];
656
657 n = acutest_colored_printf_(ACUTEST_COLOR_DEFAULT_INTENSIVE_, "Test %s... ", test->name);
658 memset(spaces, ' ', sizeof(spaces));
659 if (n < (int)sizeof(spaces)) {
660 printf("%.*s", (int)sizeof(spaces) - n, spaces);
661 }
662 } else {
664 }
665 }
666}
667
669 if (acutest_tap_) {
670 printf(
671 "%s %d - %s%s\n",
672 (state == ACUTEST_STATE_SUCCESS || state == ACUTEST_STATE_SKIPPED) ? "ok" : "not ok",
674 (state == ACUTEST_STATE_SKIPPED) ? " # SKIP" : ""
675 );
676
677 if (state == ACUTEST_STATE_SUCCESS && acutest_timer_) {
678 printf("# Duration: ");
680 printf("\n");
681 }
682 } else {
683 int color;
684 const char *str;
685
686 switch (state) {
689 str = "OK";
690 break;
693 str = "SKIPPED";
694 break;
695 case ACUTEST_STATE_FAILED: /* Fall through. */
696 default:
698 str = "FAILED";
699 break;
700 }
701
702 printf("[ ");
703 acutest_colored_printf_(color, "%s", str);
704 printf(" ]");
705
706 if (state == ACUTEST_STATE_SUCCESS && acutest_timer_) {
707 printf(" ");
709 }
710
711 printf("\n");
712 }
713}
714
715static void acutest_line_indent_(int level) {
716 static const char spaces[] = " ";
717 int n = level * 2;
718
719 if (acutest_tap_ && n > 0) {
720 n--;
721 printf("#");
722 }
723
724 while (n > 16) {
725 printf("%s", spaces);
726 n -= 16;
727 }
728 printf("%.*s", n, spaces);
729}
730
731void ACUTEST_ATTRIBUTE_(format(printf, 3, 4)) acutest_skip_(
732 const char *file, int line, const char *fmt, ...
733) {
734 va_list args;
736
737 va_start(args, fmt);
739 va_end(args);
741
742 /* Remove final dot, if provided; that collides with our other logic. */
747
749 acutest_check_(0, file, line, "Cannot skip, already performed some checks");
750 return;
751 }
752
754 const char *result_str = "skipped";
756
759 }
761
763
764 if (file != NULL) {
766 printf("%s:%d: ", file, line);
767 }
768
769 printf("%s... ", acutest_test_skip_reason_);
770 acutest_colored_printf_(result_color, "%s", result_str);
771 printf("\n");
773 }
774
776}
777
778int ACUTEST_ATTRIBUTE_(format(printf, 4, 5)) acutest_check_(
779 int cond, const char *file, int line, const char *fmt, ...
780) {
781 const char *result_str;
784
786 /* We've skipped the test. We shouldn't be here: The test implementation
787 * should have already return before. So lets suppress the following
788 * output. */
789 cond = 1;
790 goto skip_check;
791 }
792
793 if (cond) {
794 result_str = "ok";
796 verbose_level = 3;
797 } else {
800 }
801
804
805 result_str = "failed";
807 verbose_level = 2;
808 }
809
811 va_list args;
812
815 acutest_colored_printf_(ACUTEST_COLOR_DEFAULT_INTENSIVE_, "Case %s:\n", acutest_case_name_);
818 }
819
821 if (file != NULL) {
823 printf("%s:%d: ", file, line);
824 }
825
826 va_start(args, fmt);
827 vprintf(fmt, args);
828 va_end(args);
829
830 printf("... ");
831 acutest_colored_printf_(result_color, "%s", result_str);
832 printf("\n");
834 }
835
837
838skip_check:
839 acutest_cond_failed_ = (cond == 0);
841}
842
843void ACUTEST_ATTRIBUTE_(format(printf, 1, 2)) acutest_case_(const char *fmt, ...) {
844 va_list args;
845
847 return;
848 }
849
854
855 if (fmt == NULL) {
856 return;
857 }
858
859 va_start(args, fmt);
861 va_end(args);
862 acutest_case_name_[sizeof(acutest_case_name_) - 1] = '\0';
863
864 if (acutest_verbose_level_ >= 3) {
866 acutest_colored_printf_(ACUTEST_COLOR_DEFAULT_INTENSIVE_, "Case %s:\n", acutest_case_name_);
869 }
870}
871
872void ACUTEST_ATTRIBUTE_(format(printf, 1, 2)) acutest_message_(const char *fmt, ...) {
874 char *line_beg;
875 char *line_end;
876 va_list args;
877
878 if (acutest_verbose_level_ < 2) {
879 return;
880 }
881
882 /* We allow extra message only when something is already wrong in the
883 * current test. */
885 return;
886 }
887
888 va_start(args, fmt);
890 va_end(args);
891 buffer[TEST_MSG_MAXSIZE - 1] = '\0';
892
894 while (1) {
895 line_end = strchr(line_beg, '\n');
896 if (line_end == NULL) {
897 break;
898 }
900 printf("%.*s\n", (int)(line_end - line_beg), line_beg);
901 line_beg = line_end + 1;
902 }
903 if (line_beg[0] != '\0') {
905 printf("%s\n", line_beg);
906 }
907}
908
909void acutest_dump_(const char *title, const void *addr, size_t size) {
910 static const size_t BYTES_PER_LINE = 16;
911 size_t line_beg;
912 size_t truncate = 0;
913
914 if (acutest_verbose_level_ < 2) {
915 return;
916 }
917
918 /* We allow extra message only when something is already wrong in the
919 * current test. */
921 return;
922 }
923
924 if (size > TEST_DUMP_MAXSIZE) {
925 truncate = size - TEST_DUMP_MAXSIZE;
926 size = TEST_DUMP_MAXSIZE;
927 }
928
930 printf((title[strlen(title) - 1] == ':') ? "%s\n" : "%s:\n", title);
931
932 for (line_beg = 0; line_beg < size; line_beg += BYTES_PER_LINE) {
933 size_t line_end = line_beg + BYTES_PER_LINE;
934 size_t off;
935
937 printf("%08lx: ", (unsigned long)line_beg);
938 for (off = line_beg; off < line_end; off++) {
939 if (off < size) {
940 printf(" %02x", ((const unsigned char *)addr)[off]);
941 } else {
942 printf(" ");
943 }
944 }
945
946 printf(" ");
947 for (off = line_beg; off < line_end; off++) {
948 unsigned char byte = ((const unsigned char *)addr)[off];
949 if (off < size) {
950 printf("%c", (iscntrl(byte) ? '.' : byte));
951 } else {
952 break;
953 }
954 }
955
956 printf("\n");
957 }
958
959 if (truncate > 0) {
961 printf(" ... (and more %u bytes)\n", (unsigned)truncate);
962 }
963}
964
965/* This is called just before each test */
966static void acutest_init_(const char *test_name) {
967# ifdef TEST_INIT
968 TEST_INIT; /* Allow for a single unterminated function call */
969# endif
970
971 /* Suppress any warnings about unused variable. */
972 (void)test_name;
973}
974
975/* This is called after each test */
976static void acutest_fini_(const char *test_name) {
977# ifdef TEST_FINI
978 TEST_FINI; /* Allow for a single unterminated function call */
979# endif
980
981 /* Suppress any warnings about unused variable. */
982 (void)test_name;
983}
984
985void acutest_abort_(void) {
987 longjmp(acutest_abort_jmp_buf_, 1);
988 } else {
989 if (acutest_current_test_ != NULL) {
991 }
992 fflush(stdout);
993 fflush(stderr);
994 acutest_exit_(ACUTEST_STATE_FAILED);
995 }
996}
997
998static void acutest_list_names_(void) {
999 const struct acutest_test_ *test;
1000
1001 printf("Unit tests:\n");
1002 for (test = &acutest_list_[0]; test->func != NULL; test++) {
1003 printf(" %s\n", test->name);
1004 }
1005}
1006
1007static int acutest_name_contains_word_(const char *name, const char *pattern) {
1008 static const char word_delim[] = " \t-_/.,:;";
1009 const char *substr;
1010 size_t pattern_len;
1011
1012 pattern_len = strlen(pattern);
1013
1014 substr = strstr(name, pattern);
1015 while (substr != NULL) {
1016 int starts_on_word_boundary = (substr == name || strchr(word_delim, substr[-1]) != NULL);
1017 int ends_on_word_boundary =
1018 (substr[pattern_len] == '\0' || strchr(word_delim, substr[pattern_len]) != NULL);
1019
1020 if (starts_on_word_boundary && ends_on_word_boundary) {
1021 return 1;
1022 }
1023
1024 substr = strstr(substr + 1, pattern);
1025 }
1026
1027 return 0;
1028}
1029
1030static int acutest_select_(const char *pattern) {
1031 int i;
1032 int n = 0;
1033
1034 /* Try exact match. */
1035 for (i = 0; i < acutest_list_size_; i++) {
1036 if (strcmp(acutest_list_[i].name, pattern) == 0) {
1038 n++;
1039 break;
1040 }
1041 }
1042 if (n > 0) {
1043 return n;
1044 }
1045
1046 /* Try word match. */
1047 for (i = 0; i < acutest_list_size_; i++) {
1050 n++;
1051 }
1052 }
1053 if (n > 0) {
1054 return n;
1055 }
1056
1057 /* Try relaxed match. */
1058 for (i = 0; i < acutest_list_size_; i++) {
1059 if (strstr(acutest_list_[i].name, pattern) != NULL) {
1061 n++;
1062 }
1063 }
1064
1065 return n;
1066}
1067
1068/* Called if anything goes bad in Acutest, or if the unit test ends in other
1069 * way then by normal returning from its function (e.g. exception or some
1070 * abnormal child process termination). */
1071static void ACUTEST_ATTRIBUTE_(format(printf, 1, 2)) acutest_error_(const char *fmt, ...) {
1072 if (acutest_verbose_level_ == 0) {
1073 return;
1074 }
1075
1076 if (acutest_verbose_level_ >= 2) {
1077 va_list args;
1078
1080 if (acutest_verbose_level_ >= 3) {
1081 acutest_colored_printf_(ACUTEST_COLOR_RED_INTENSIVE_, "ERROR: ");
1082 }
1083 va_start(args, fmt);
1084 vprintf(fmt, args);
1085 va_end(args);
1086 printf("\n");
1087 }
1088
1089 if (acutest_verbose_level_ >= 3) {
1090 printf("\n");
1091 }
1092}
1093
1094/* Call directly the given test unit function. */
1095static enum acutest_state_ acutest_do_run_(const struct acutest_test_ *test, int index) {
1097
1098 acutest_current_test_ = test;
1099 acutest_current_index_ = index;
1105
1106# ifdef __cplusplus
1107# ifndef TEST_NO_EXCEPTIONS
1108 try {
1109# endif
1110# endif
1111 acutest_init_(test->name);
1113
1114 /* This is good to do in case the test unit crashes. */
1115 fflush(stdout);
1116 fflush(stderr);
1117
1118 if (!acutest_worker_) {
1120 if (setjmp(acutest_abort_jmp_buf_) != 0) {
1121 goto aborted;
1122 }
1123 }
1124
1126 test->func();
1127
1128 aborted:
1131
1132 if (acutest_test_failures_ > 0) {
1133 state = ACUTEST_STATE_FAILED;
1134 } else if (acutest_test_skip_count_ > 0) {
1135 state = ACUTEST_STATE_SKIPPED;
1136 } else {
1137 state = ACUTEST_STATE_SUCCESS;
1138 }
1139
1142 }
1143
1144 if (acutest_verbose_level_ >= 3) {
1146 switch (state) {
1148 acutest_colored_printf_(ACUTEST_COLOR_GREEN_INTENSIVE_, "SUCCESS: ");
1149 printf("All conditions have passed.\n");
1150
1151 if (acutest_timer_) {
1153 printf("Duration: ");
1155 printf("\n");
1156 }
1157 break;
1158
1160 acutest_colored_printf_(ACUTEST_COLOR_YELLOW_INTENSIVE_, "SKIPPED: ");
1161 printf("%s.\n", acutest_test_skip_reason_);
1162 break;
1163
1164 default:
1165 acutest_colored_printf_(ACUTEST_COLOR_RED_INTENSIVE_, "FAILED: ");
1166 printf(
1167 "%d condition%s %s failed.\n", acutest_test_failures_,
1168 (acutest_test_failures_ == 1) ? "" : "s", (acutest_test_failures_ == 1) ? "has" : "have"
1169 );
1170 break;
1171 }
1172 printf("\n");
1173 }
1174
1175# ifdef __cplusplus
1176# ifndef TEST_NO_EXCEPTIONS
1177 } catch (std::exception &e) {
1178 const char *what = e.what();
1179 acutest_check_(0, NULL, 0, "Threw std::exception");
1180 if (what != NULL) {
1181 acutest_message_("std::exception::what(): %s", what);
1182 }
1183
1184 if (acutest_verbose_level_ >= 3) {
1186 acutest_colored_printf_(ACUTEST_COLOR_RED_INTENSIVE_, "FAILED: ");
1187 printf("C++ exception.\n\n");
1188 }
1189 } catch (...) {
1190 acutest_check_(0, NULL, 0, "Threw an exception");
1191
1192 if (acutest_verbose_level_ >= 3) {
1194 acutest_colored_printf_(ACUTEST_COLOR_RED_INTENSIVE_, "FAILED: ");
1195 printf("C++ exception.\n\n");
1196 }
1197 }
1198# endif
1199# endif
1200
1201 acutest_fini_(test->name);
1202 acutest_case_(NULL);
1203 acutest_current_test_ = NULL;
1204
1205 return state;
1206}
1207
1208/* Trigger the unit test. If possible (and not suppressed) it starts a child
1209 * process who calls acutest_do_run_(), otherwise it calls acutest_do_run_()
1210 * directly. */
1211static void acutest_run_(const struct acutest_test_ *test, int index, int master_index) {
1213 acutest_timer_type_ start, end;
1214
1215 acutest_current_test_ = test;
1218
1219 if (!acutest_no_exec_) {
1220
1221# if defined(ACUTEST_UNIX_)
1222
1223 pid_t pid;
1224 int exit_code;
1225
1226 /* Make sure the child starts with empty I/O buffers. */
1227 fflush(stdout);
1228 fflush(stderr);
1229
1230 pid = fork();
1231 if (pid == (pid_t)-1) {
1232 acutest_error_("Cannot fork. %s [%d]", strerror(errno), errno);
1233 } else if (pid == 0) {
1234 /* Child: Do the test. */
1235 acutest_worker_ = 1;
1236 state = acutest_do_run_(test, index);
1237 acutest_exit_((int)state);
1238 } else {
1239 /* Parent: Wait until child terminates and analyze its exit code. */
1240 waitpid(pid, &exit_code, 0);
1241 if (WIFEXITED(exit_code)) {
1242 state = (enum acutest_state_)WEXITSTATUS(exit_code);
1243 } else if (WIFSIGNALED(exit_code)) {
1244 char tmp[32];
1245 const char *signame;
1246 switch (WTERMSIG(exit_code)) {
1247 case SIGINT:
1248 signame = "SIGINT";
1249 break;
1250 case SIGHUP:
1251 signame = "SIGHUP";
1252 break;
1253 case SIGQUIT:
1254 signame = "SIGQUIT";
1255 break;
1256 case SIGABRT:
1257 signame = "SIGABRT";
1258 break;
1259 case SIGKILL:
1260 signame = "SIGKILL";
1261 break;
1262 case SIGSEGV:
1263 signame = "SIGSEGV";
1264 break;
1265 case SIGILL:
1266 signame = "SIGILL";
1267 break;
1268 case SIGTERM:
1269 signame = "SIGTERM";
1270 break;
1271 default:
1272 snprintf(tmp, sizeof(tmp), "signal %d", WTERMSIG(exit_code));
1273 signame = tmp;
1274 break;
1275 }
1276 acutest_error_("Test interrupted by %s.", signame);
1277 } else {
1278 acutest_error_("Test ended in an unexpected way [%d].", exit_code);
1279 }
1280 }
1281
1282# elif defined(ACUTEST_WIN_)
1283
1284 char buffer[512] = {0};
1285 STARTUPINFOA startupInfo;
1286 PROCESS_INFORMATION processInfo;
1287 DWORD exitCode;
1288
1289 /* Windows has no fork(). So we propagate all info into the child
1290 * through a command line arguments. */
1291 snprintf(
1292 buffer, sizeof(buffer),
1293 "%s --worker=%d %s --no-exec --no-summary %s --verbose=%d "
1294 "--color=%s -- \"%s\"",
1295 acutest_argv0_, index, acutest_timer_ ? "--time" : "", acutest_tap_ ? "--tap" : "",
1296 acutest_verbose_level_, acutest_colorize_ ? "always" : "never", test->name
1297 );
1298 memset(&startupInfo, 0, sizeof(startupInfo));
1299 startupInfo.cb = sizeof(STARTUPINFO);
1300 if (
1301 CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo)
1302 ) {
1303 WaitForSingleObject(processInfo.hProcess, INFINITE);
1304 GetExitCodeProcess(processInfo.hProcess, &exitCode);
1305 CloseHandle(processInfo.hThread);
1306 CloseHandle(processInfo.hProcess);
1307 switch (exitCode) {
1308 case 0:
1309 state = ACUTEST_STATE_SUCCESS;
1310 break;
1311 case 1:
1312 state = ACUTEST_STATE_FAILED;
1313 break;
1314 case 2:
1315 state = ACUTEST_STATE_SKIPPED;
1316 break;
1317 case 3:
1318 acutest_error_("Aborted.");
1319 break;
1320 case 0xC0000005:
1321 acutest_error_("Access violation.");
1322 break;
1323 default:
1324 acutest_error_("Test ended in an unexpected way [%lu].", exitCode);
1325 break;
1326 }
1327 } else {
1328 acutest_error_("Cannot create unit test subprocess [%ld].", GetLastError());
1329 }
1330
1331# else
1332
1333 /* A platform where we don't know how to run child process. */
1334 state = acutest_do_run_(test, index);
1335
1336# endif
1337
1338 } else {
1339 /* Child processes suppressed through --no-exec. */
1340 state = acutest_do_run_(test, index);
1341 }
1343
1344 acutest_current_test_ = NULL;
1345
1346 acutest_test_data_[master_index].state = state;
1347 acutest_test_data_[master_index].duration = acutest_timer_diff_(start, end);
1348}
1349
1350# if defined(ACUTEST_WIN_)
1351/* Callback for SEH events. */
1352static LONG CALLBACK acutest_seh_exception_filter_(EXCEPTION_POINTERS *ptrs) {
1353 acutest_check_(0, NULL, 0, "Unhandled SEH exception");
1354 acutest_message_("Exception code: 0x%08lx", ptrs->ExceptionRecord->ExceptionCode);
1355 acutest_message_("Exception address: 0x%p", ptrs->ExceptionRecord->ExceptionAddress);
1356
1357 fflush(stdout);
1358 fflush(stderr);
1359
1360 return EXCEPTION_EXECUTE_HANDLER;
1361}
1362# endif
1363
1364# define ACUTEST_CMDLINE_OPTFLAG_OPTIONALARG_ 0x0001
1365# define ACUTEST_CMDLINE_OPTFLAG_REQUIREDARG_ 0x0002
1366
1367# define ACUTEST_CMDLINE_OPTID_NONE_ 0
1368# define ACUTEST_CMDLINE_OPTID_UNKNOWN_ (-0x7fffffff + 0)
1369# define ACUTEST_CMDLINE_OPTID_MISSINGARG_ (-0x7fffffff + 1)
1370# define ACUTEST_CMDLINE_OPTID_BOGUSARG_ (-0x7fffffff + 2)
1371
1372typedef struct acutest_test_CMDLINE_OPTION_ {
1373 char shortname;
1374 const char *longname;
1375 int id;
1376 unsigned flags;
1377} ACUTEST_CMDLINE_OPTION_;
1378
1380 const ACUTEST_CMDLINE_OPTION_ *options, const char *arggroup,
1381 int (*callback)(int /*optval*/, const char * /*arg*/)
1382) {
1383 const ACUTEST_CMDLINE_OPTION_ *opt;
1384 int i;
1385 int ret = 0;
1386
1387 for (i = 0; arggroup[i] != '\0'; i++) {
1388 for (opt = options; opt->id != 0; opt++) {
1389 if (arggroup[i] == opt->shortname) {
1390 break;
1391 }
1392 }
1393
1394 if (opt->id != 0 && !(opt->flags & ACUTEST_CMDLINE_OPTFLAG_REQUIREDARG_)) {
1395 ret = callback(opt->id, NULL);
1396 } else {
1397 /* Unknown option. */
1398 char badoptname[3];
1399 badoptname[0] = '-';
1400 badoptname[1] = arggroup[i];
1401 badoptname[2] = '\0';
1402 ret = callback(
1404 badoptname
1405 );
1406 }
1407
1408 if (ret != 0) {
1409 break;
1410 }
1411 }
1412
1413 return ret;
1414}
1415
1416# define ACUTEST_CMDLINE_AUXBUF_SIZE_ 32
1417
1419 const ACUTEST_CMDLINE_OPTION_ *options, int argc, char **argv,
1420 int (*callback)(int /*optval*/, const char * /*arg*/)
1421) {
1422
1423 const ACUTEST_CMDLINE_OPTION_ *opt;
1424 char auxbuf[ACUTEST_CMDLINE_AUXBUF_SIZE_ + 1];
1425 int after_doubledash = 0;
1426 int i = 1;
1427 int ret = 0;
1428
1429 auxbuf[ACUTEST_CMDLINE_AUXBUF_SIZE_] = '\0';
1430
1431 while (i < argc) {
1432 if (after_doubledash || strcmp(argv[i], "-") == 0) {
1433 /* Non-option argument. */
1434 ret = callback(ACUTEST_CMDLINE_OPTID_NONE_, argv[i]);
1435 } else if (strcmp(argv[i], "--") == 0) {
1436 /* End of options. All the remaining members are non-option arguments. */
1437 after_doubledash = 1;
1438 } else if (argv[i][0] != '-') {
1439 /* Non-option argument. */
1440 ret = callback(ACUTEST_CMDLINE_OPTID_NONE_, argv[i]);
1441 } else {
1442 for (opt = options; opt->id != 0; opt++) {
1443 if (opt->longname != NULL && strncmp(argv[i], "--", 2) == 0) {
1444 size_t len = strlen(opt->longname);
1445 if (strncmp(argv[i] + 2, opt->longname, len) == 0) {
1446 /* Regular long option. */
1447 if (argv[i][2 + len] == '\0') {
1448 /* with no argument provided. */
1449 if (!(opt->flags & ACUTEST_CMDLINE_OPTFLAG_REQUIREDARG_)) {
1450 ret = callback(opt->id, NULL);
1451 } else {
1452 ret = callback(ACUTEST_CMDLINE_OPTID_MISSINGARG_, argv[i]);
1453 }
1454 break;
1455 } else if (argv[i][2 + len] == '=') {
1456 /* with an argument provided. */
1457 if (
1458 opt->flags &
1460 ) {
1461 ret = callback(opt->id, argv[i] + 2 + len + 1);
1462 } else {
1463 snprintf(auxbuf, sizeof(auxbuf), "--%s", opt->longname);
1464 ret = callback(ACUTEST_CMDLINE_OPTID_BOGUSARG_, auxbuf);
1465 }
1466 break;
1467 } else {
1468 continue;
1469 }
1470 }
1471 } else if (opt->shortname != '\0' && argv[i][0] == '-') {
1472 if (argv[i][1] == opt->shortname) {
1473 /* Regular short option. */
1474 if (opt->flags & ACUTEST_CMDLINE_OPTFLAG_REQUIREDARG_) {
1475 if (argv[i][2] != '\0') {
1476 ret = callback(opt->id, argv[i] + 2);
1477 } else if (i + 1 < argc) {
1478 ret = callback(opt->id, argv[++i]);
1479 } else {
1480 ret = callback(ACUTEST_CMDLINE_OPTID_MISSINGARG_, argv[i]);
1481 }
1482 break;
1483 } else {
1484 ret = callback(opt->id, NULL);
1485
1486 /* There might be more (argument-less) short options
1487 * grouped together. */
1488 if (ret == 0 && argv[i][2] != '\0') {
1489 ret = acutest_cmdline_handle_short_opt_group_(options, argv[i] + 2, callback);
1490 }
1491 break;
1492 }
1493 }
1494 }
1495 }
1496
1497 if (opt->id == 0) { /* still not handled? */
1498 if (argv[i][0] != '-') {
1499 /* Non-option argument. */
1500 ret = callback(ACUTEST_CMDLINE_OPTID_NONE_, argv[i]);
1501 } else {
1502 /* Unknown option. */
1503 char *badoptname = argv[i];
1504
1505 if (strncmp(badoptname, "--", 2) == 0) {
1506 /* Strip any argument from the long option. */
1507 char *assignment = strchr(badoptname, '=');
1508 if (assignment != NULL) {
1509 size_t len = (size_t)(assignment - badoptname);
1510 if (len > ACUTEST_CMDLINE_AUXBUF_SIZE_) {
1512 }
1513 strncpy(auxbuf, badoptname, len);
1514 auxbuf[len] = '\0';
1515 badoptname = auxbuf;
1516 }
1517 }
1518
1519 ret = callback(ACUTEST_CMDLINE_OPTID_UNKNOWN_, badoptname);
1520 }
1521 }
1522 }
1523
1524 if (ret != 0) {
1525 return ret;
1526 }
1527 i++;
1528 }
1529
1530 return ret;
1531}
1532
1533static void acutest_help_(void) {
1534 printf("Usage: %s [options] [test...]\n", acutest_argv0_);
1535 printf("\n");
1536 printf(
1537 "Run the specified unit tests; or if the option '--exclude' is used, "
1538 "run all\n"
1539 );
1540 printf(
1541 "tests in the suite but those listed. By default, if no tests are "
1542 "specified\n"
1543 );
1544 printf("on the command line, all unit tests in the suite are run.\n");
1545 printf("\n");
1546 printf("Options:\n");
1547 printf(" -X, --exclude Execute all unit tests but the listed ones\n");
1548 printf(
1549 " --exec[=WHEN] If supported, execute unit tests as child "
1550 "processes\n"
1551 );
1552 printf(" (WHEN is one of 'auto', 'always', 'never')\n");
1553 printf(" -E, --no-exec Same as --exec=never\n");
1554# if defined ACUTEST_WIN_
1555 printf(" -t, --time Measure test duration\n");
1556# elif defined ACUTEST_HAS_POSIX_TIMER_
1557 printf(" -t, --time Measure test duration (real time)\n");
1558 printf(" --time=TIMER Measure test duration, using given timer\n");
1559 printf(" (TIMER is one of 'real', 'cpu')\n");
1560# endif
1561 printf(" --no-summary Suppress printing of test results summary\n");
1562 printf(" --tap Produce TAP-compliant output\n");
1563 printf(" (See https://testanything.org/)\n");
1564 printf(" -x, --xml-output=FILE Enable XUnit output to the given file\n");
1565 printf(" -l, --list List unit tests in the suite and exit\n");
1566 printf(" -v, --verbose Make output more verbose\n");
1567 printf(" --verbose=LEVEL Set verbose level to LEVEL:\n");
1568 printf(" 0 ... Be silent\n");
1569 printf(
1570 " 1 ... Output one line per test (and "
1571 "summary)\n"
1572 );
1573 printf(
1574 " 2 ... As 1 and failed conditions (this is "
1575 "default)\n"
1576 );
1577 printf(
1578 " 3 ... As 1 and all conditions (and "
1579 "extended summary)\n"
1580 );
1581 printf(" -q, --quiet Same as --verbose=0\n");
1582 printf(" --color[=WHEN] Enable colorized output\n");
1583 printf(" (WHEN is one of 'auto', 'always', 'never')\n");
1584 printf(" --no-color Same as --color=never\n");
1585 printf(" -h, --help Display this help and exit\n");
1586
1587 if (acutest_list_size_ < 16) {
1588 printf("\n");
1590 }
1591}
1592
1593static const ACUTEST_CMDLINE_OPTION_ acutest_cmdline_options_[] = {
1594 {'X', "exclude", 'X', 0},
1595 {'s', "skip", 'X', 0}, /* kept for compatibility, use --exclude instead */
1596 {0, "exec", 'e', ACUTEST_CMDLINE_OPTFLAG_OPTIONALARG_},
1597 {'E', "no-exec", 'E', 0},
1598# if defined ACUTEST_WIN_
1599 {'t', "time", 't', 0},
1600 {0, "timer", 't', 0}, /* kept for compatibility */
1601# elif defined ACUTEST_HAS_POSIX_TIMER_
1602 {'t', "time", 't', ACUTEST_CMDLINE_OPTFLAG_OPTIONALARG_},
1603 {0, "timer", 't', ACUTEST_CMDLINE_OPTFLAG_OPTIONALARG_}, /* kept for compatibility */
1604# endif
1605 {0, "no-summary", 'S', 0},
1606 {0, "tap", 'T', 0},
1607 {'l', "list", 'l', 0},
1608 {'v', "verbose", 'v', ACUTEST_CMDLINE_OPTFLAG_OPTIONALARG_},
1609 {'q', "quiet", 'q', 0},
1610 {0, "color", 'c', ACUTEST_CMDLINE_OPTFLAG_OPTIONALARG_},
1611 {0, "no-color", 'C', 0},
1612 {'h', "help", 'h', 0},
1613 {0, "worker", 'w', ACUTEST_CMDLINE_OPTFLAG_REQUIREDARG_}, /* internal */
1614 {'x', "xml-output", 'x', ACUTEST_CMDLINE_OPTFLAG_REQUIREDARG_},
1615 {0, NULL, 0, 0}
1616};
1617
1618static int acutest_cmdline_callback_(int id, const char *arg) {
1619 switch (id) {
1620 case 'X':
1622 break;
1623
1624 case 'e':
1625 if (arg == NULL || strcmp(arg, "always") == 0) {
1626 acutest_no_exec_ = 0;
1627 } else if (strcmp(arg, "never") == 0) {
1628 acutest_no_exec_ = 1;
1629 } else if (strcmp(arg, "auto") == 0) {
1630 /*noop*/
1631 } else {
1632 fprintf(stderr, "%s: Unrecognized argument '%s' for option --exec.\n", acutest_argv0_, arg);
1633 fprintf(stderr, "Try '%s --help' for more information.\n", acutest_argv0_);
1634 acutest_exit_(2);
1635 }
1636 break;
1637
1638 case 'E':
1639 acutest_no_exec_ = 1;
1640 break;
1641
1642 case 't':
1643# if defined ACUTEST_WIN_ || defined ACUTEST_HAS_POSIX_TIMER_
1644 if (arg == NULL || strcmp(arg, "real") == 0) {
1645 acutest_timer_ = 1;
1646# ifndef ACUTEST_WIN_
1647 } else if (strcmp(arg, "cpu") == 0) {
1648 acutest_timer_ = 2;
1649# endif
1650 } else {
1651 fprintf(stderr, "%s: Unrecognized argument '%s' for option --time.\n", acutest_argv0_, arg);
1652 fprintf(stderr, "Try '%s --help' for more information.\n", acutest_argv0_);
1653 acutest_exit_(2);
1654 }
1655# endif
1656 break;
1657
1658 case 'S':
1660 break;
1661
1662 case 'T':
1663 acutest_tap_ = 1;
1664 break;
1665
1666 case 'l':
1668 acutest_exit_(0);
1669 break;
1670
1671 case 'v':
1672 acutest_verbose_level_ = (arg != NULL ? atoi(arg) : acutest_verbose_level_ + 1);
1673 break;
1674
1675 case 'q':
1677 break;
1678
1679 case 'c':
1680 if (arg == NULL || strcmp(arg, "always") == 0) {
1682 } else if (strcmp(arg, "never") == 0) {
1684 } else if (strcmp(arg, "auto") == 0) {
1685 /*noop*/
1686 } else {
1687 fprintf(stderr, "%s: Unrecognized argument '%s' for option --color.\n", acutest_argv0_, arg);
1688 fprintf(stderr, "Try '%s --help' for more information.\n", acutest_argv0_);
1689 acutest_exit_(2);
1690 }
1691 break;
1692
1693 case 'C':
1695 break;
1696
1697 case 'h':
1698 acutest_help_();
1699 acutest_exit_(0);
1700 break;
1701
1702 case 'w':
1703 acutest_worker_ = 1;
1704 acutest_worker_index_ = atoi(arg);
1705 break;
1706 case 'x':
1707 acutest_xml_output_ = fopen(arg, "w");
1708 if (!acutest_xml_output_) {
1709 fprintf(stderr, "Unable to open '%s': %s\n", arg, strerror(errno));
1710 acutest_exit_(2);
1711 }
1712 break;
1713
1714 case 0:
1715 if (acutest_select_(arg) == 0) {
1716 fprintf(stderr, "%s: Unrecognized unit test '%s'\n", acutest_argv0_, arg);
1717 fprintf(stderr, "Try '%s --list' for list of unit tests.\n", acutest_argv0_);
1718 acutest_exit_(2);
1719 }
1720 break;
1721
1723 fprintf(stderr, "Unrecognized command line option '%s'.\n", arg);
1724 fprintf(stderr, "Try '%s --help' for more information.\n", acutest_argv0_);
1725 acutest_exit_(2);
1726 break;
1727
1729 fprintf(stderr, "The command line option '%s' requires an argument.\n", arg);
1730 fprintf(stderr, "Try '%s --help' for more information.\n", acutest_argv0_);
1731 acutest_exit_(2);
1732 break;
1733
1735 fprintf(stderr, "The command line option '%s' does not expect an argument.\n", arg);
1736 fprintf(stderr, "Try '%s --help' for more information.\n", acutest_argv0_);
1737 acutest_exit_(2);
1738 break;
1739 }
1740
1741 return 0;
1742}
1743
1744static int acutest_under_debugger_(void) {
1745# ifdef ACUTEST_LINUX_
1746 /* Scan /proc/self/status for line "TracerPid: [PID]". If such line exists
1747 * and the PID is non-zero, we're being debugged. */
1748 {
1749 static const int OVERLAP = 32;
1750 int fd;
1751 char buf[512];
1752 size_t n_read;
1753 pid_t tracer_pid = 0;
1754
1755 /* Little trick so that we can treat the 1st line the same as any other
1756 * and detect line start easily. */
1757 buf[0] = '\n';
1758 n_read = 1;
1759
1760 fd = open("/proc/self/status", O_RDONLY);
1761 if (fd != -1) {
1762 while (1) {
1763 static const char pattern[] = "\nTracerPid:";
1764 const char *field;
1765
1766 while (n_read < sizeof(buf) - 1) {
1767 ssize_t n;
1768
1769 n = read(fd, buf + n_read, sizeof(buf) - 1 - n_read);
1770 if (n <= 0) {
1771 break;
1772 }
1773 n_read += (size_t)n;
1774 }
1775 buf[n_read] = '\0';
1776
1777 field = strstr(buf, pattern);
1778 if (field != NULL && field < buf + sizeof(buf) - OVERLAP) {
1779 tracer_pid = (pid_t)atoi(field + sizeof(pattern) - 1);
1780 break;
1781 }
1782
1783 if (n_read == sizeof(buf) - 1) {
1784 /* Move the tail with the potentially incomplete line we're
1785 * be looking for to the beginning of the buffer.
1786 * (The OVERLAP must be large enough so the searched line
1787 * can fit in completely.) */
1788 memmove(buf, buf + sizeof(buf) - 1 - OVERLAP, OVERLAP);
1789 n_read = OVERLAP;
1790 } else {
1791 break;
1792 }
1793 }
1794
1795 close(fd);
1796
1797 if (tracer_pid != 0) {
1798 return 1;
1799 }
1800 }
1801 }
1802# endif
1803
1804# ifdef ACUTEST_MACOS_
1805 /* See https://developer.apple.com/library/archive/qa/qa1361/_index.html */
1806 {
1807 int mib[4];
1808 struct kinfo_proc info;
1809 size_t size;
1810
1811 mib[0] = CTL_KERN;
1812 mib[1] = KERN_PROC;
1813 mib[2] = KERN_PROC_PID;
1814 mib[3] = getpid();
1815
1816 size = sizeof(info);
1817 info.kp_proc.p_flag = 0;
1818 sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
1819
1820 if (info.kp_proc.p_flag & P_TRACED) {
1821 return 1;
1822 }
1823 }
1824# endif
1825
1826# ifdef ACUTEST_WIN_
1827 if (IsDebuggerPresent()) {
1828 return 1;
1829 }
1830# endif
1831
1832# ifdef RUNNING_ON_VALGRIND
1833 /* We treat Valgrind as a debugger of sorts.
1834 * (Macro RUNNING_ON_VALGRIND is provided by <valgrind.h>, if available.) */
1835 if (RUNNING_ON_VALGRIND) {
1836 return 1;
1837 }
1838# endif
1839
1840 return 0;
1841}
1842
1843int main(int argc, char **argv) {
1844 int i, index;
1845 int exit_code = 1;
1846
1847 acutest_argv0_ = argv[0];
1848
1849# if defined ACUTEST_UNIX_
1850 acutest_colorize_ = isatty(STDOUT_FILENO);
1851# elif defined ACUTEST_WIN_
1852# if defined _BORLANDC_
1853 acutest_colorize_ = isatty(_fileno(stdout));
1854# else
1855 acutest_colorize_ = _isatty(_fileno(stdout));
1856# endif
1857# else
1859# endif
1860
1861 /* Count all test units */
1863 for (i = 0; acutest_list_[i].func != NULL; i++) {
1865 }
1866
1868 (struct acutest_test_data_ *)calloc(acutest_list_size_, sizeof(struct acutest_test_data_));
1869 if (acutest_test_data_ == NULL) {
1870 fprintf(stderr, "Out of memory.\n");
1871 acutest_exit_(2);
1872 }
1873
1874 /* Parse options */
1876
1877 /* Initialize the proper timer. */
1879
1880# if defined(ACUTEST_WIN_)
1881 SetUnhandledExceptionFilter(acutest_seh_exception_filter_);
1882# ifdef _MSC_VER
1883 _set_abort_behavior(0, _WRITE_ABORT_MSG);
1884# endif
1885# endif
1886
1887 /* Determine what to run. */
1889 enum acutest_state_ if_selected;
1890 enum acutest_state_ if_unselected;
1891
1892 if (!acutest_exclude_mode_) {
1893 if_selected = ACUTEST_STATE_NEEDTORUN;
1894 if_unselected = ACUTEST_STATE_EXCLUDED;
1895 } else {
1896 if_selected = ACUTEST_STATE_EXCLUDED;
1897 if_unselected = ACUTEST_STATE_NEEDTORUN;
1898 }
1899
1900 for (i = 0; acutest_list_[i].func != NULL; i++) {
1902 acutest_test_data_[i].state = if_selected;
1903 } else {
1904 acutest_test_data_[i].state = if_unselected;
1905 }
1906 }
1907 } else {
1908 /* By default, we want to run all tests. */
1909 for (i = 0; acutest_list_[i].func != NULL; i++) {
1911 }
1912 }
1913
1914 /* By default, we want to suppress running tests as child processes if we
1915 * run just one test, or if we're under debugger: Debugging tests is then
1916 * so much easier. */
1917 if (acutest_no_exec_ < 0) {
1919 acutest_no_exec_ = 1;
1920 } else {
1921 acutest_no_exec_ = 0;
1922 }
1923 }
1924
1925 if (acutest_tap_) {
1926 /* TAP requires we know test result ("ok", "not ok") before we output
1927 * anything about the test, and this gets problematic for larger verbose
1928 * levels. */
1929 if (acutest_verbose_level_ > 2) {
1931 }
1932
1933 /* TAP harness should provide some summary. */
1935
1936 if (!acutest_worker_) {
1937 printf("1..%d\n", acutest_count_(ACUTEST_STATE_NEEDTORUN));
1938 }
1939 }
1940
1941 index = acutest_worker_index_;
1942 for (i = 0; acutest_list_[i].func != NULL; i++) {
1944 acutest_run_(&acutest_list_[i], index++, i);
1945 }
1946 }
1947
1948 /* Write a summary */
1950 int n_run, n_success, n_failed;
1951
1955
1956 if (acutest_verbose_level_ >= 3) {
1957 acutest_colored_printf_(ACUTEST_COLOR_DEFAULT_INTENSIVE_, "Summary:\n");
1958
1959 printf(" Count of run unit tests: %4d\n", n_run);
1960 printf(" Count of successful unit tests: %4d\n", n_success);
1961 printf(" Count of failed unit tests: %4d\n", n_failed);
1962 }
1963
1964 if (n_failed == 0) {
1965 acutest_colored_printf_(ACUTEST_COLOR_GREEN_INTENSIVE_, "SUCCESS:");
1966 printf(" No unit tests have failed.\n");
1967 } else {
1968 acutest_colored_printf_(ACUTEST_COLOR_RED_INTENSIVE_, "FAILED:");
1969 printf(
1970 " %d of %d unit tests %s failed.\n", n_failed, n_run, (n_failed == 1) ? "has" : "have"
1971 );
1972 }
1973
1974 if (acutest_verbose_level_ >= 3) {
1975 printf("\n");
1976 }
1977 }
1978
1979 if (acutest_xml_output_) {
1980 const char *suite_name = acutest_basename_(argv[0]);
1981 fprintf(acutest_xml_output_, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1982 fprintf(
1984 "<testsuite name=\"%s\" tests=\"%d\" errors=\"0\" failures=\"%d\" "
1985 "skip=\"%d\">\n",
1988 );
1989 for (i = 0; acutest_list_[i].func != NULL; i++) {
1990 struct acutest_test_data_ *details = &acutest_test_data_[i];
1991 const char *str_state;
1992 fprintf(
1993 acutest_xml_output_, " <testcase name=\"%s\" time=\"%.2f\">\n", acutest_list_[i].name,
1994 details->duration
1995 );
1996
1997 switch (details->state) {
1999 str_state = NULL;
2000 break;
2001 case ACUTEST_STATE_EXCLUDED: /* Fall through. */
2003 str_state = "<skipped />";
2004 break;
2005 case ACUTEST_STATE_FAILED: /* Fall through. */
2006 default:
2007 str_state = "<failure />";
2008 break;
2009 }
2010
2011 if (str_state != NULL) {
2012 fprintf(acutest_xml_output_, " %s\n", str_state);
2013 }
2014 fprintf(acutest_xml_output_, " </testcase>\n");
2015 }
2016 fprintf(acutest_xml_output_, "</testsuite>\n");
2017 fclose(acutest_xml_output_);
2018 }
2019
2021 /* If we are the child process, we need to propagate the test state
2022 * without any moderation. */
2023 for (i = 0; acutest_list_[i].func != NULL; i++) {
2025 exit_code = (int)acutest_test_data_[i].state;
2026 break;
2027 }
2028 }
2029 } else {
2031 exit_code = 1;
2032 } else {
2033 exit_code = 0;
2034 }
2035 }
2036
2038 return exit_code;
2039}
2040
2041#endif /* #ifndef TEST_NO_MAIN */
2042
2043#ifdef _MSC_VER
2044# pragma warning(pop)
2045#endif
2046
2047#ifdef __cplusplus
2048} /* extern "C" */
2049#endif
2050
2051#endif /* #ifndef ACUTEST_H */
int main(void)
Definition 01_hello.c:41
#define ACUTEST_CMDLINE_OPTID_NONE_
#define ACUTEST_ATTRIBUTE_(attr)
Definition acutest.h:294
vsnprintf(buffer, sizeof(buffer), fmt, args)
static void acutest_init_(const char *test_name)
Definition acutest.h:966
static int const char * fmt
Definition acutest.h:522
#define ACUTEST_COLOR_DEFAULT_INTENSIVE_
Definition acutest.h:516
static const ACUTEST_CMDLINE_OPTION_ acutest_cmdline_options_[]
Definition acutest.h:1593
static void static int acutest_cmdline_handle_short_opt_group_(const ACUTEST_CMDLINE_OPTION_ *options, const char *arggroup, int(*callback)(int, const char *))
Definition acutest.h:1379
static void acutest_line_indent_(int level)
Definition acutest.h:715
#define ACUTEST_COLOR_GREEN_INTENSIVE_
Definition acutest.h:518
static int acutest_name_contains_word_(const char *name, const char *pattern)
Definition acutest.h:1007
static int acutest_test_already_logged_
Definition acutest.h:423
static int acutest_no_exec_
Definition acutest.h:408
static void acutest_finish_test_line_(enum acutest_state_ state)
Definition acutest.h:668
void acutest_dump_(const char *title, const void *addr, size_t size)
Definition acutest.h:909
#define TEST_MSG_MAXSIZE
Definition acutest.h:229
static FILE * acutest_xml_output_
Definition acutest.h:415
int acutest_check_(int cond, const char *file, int line, const char *fmt,...)
int const char * file
Definition acutest.h:779
acutest_state_
Definition acutest.h:301
@ ACUTEST_STATE_SKIPPED
Definition acutest.h:310
@ ACUTEST_STATE_FAILED
Definition acutest.h:309
@ ACUTEST_STATE_SUCCESS
Definition acutest.h:308
@ ACUTEST_STATE_SELECTED
Definition acutest.h:303
@ ACUTEST_STATE_INITIAL
Definition acutest.h:302
@ ACUTEST_STATE_NEEDTORUN
Definition acutest.h:304
@ ACUTEST_STATE_EXCLUDED
Definition acutest.h:307
static int acutest_worker_
Definition acutest.h:412
static int acutest_colorize_
Definition acutest.h:427
static char acutest_case_name_[TEST_CASE_MAXSIZE]
Definition acutest.h:419
int acutest_timer_type_
Definition acutest.h:495
static void acutest_cleanup_(void)
Definition acutest.h:445
va_end(args)
int verbose_level
Definition acutest.h:783
static void acutest_timer_print_diff_(void)
Definition acutest.h:509
#define ACUTEST_COLOR_GREEN_
Definition acutest.h:514
static int acutest_case_already_logged_
Definition acutest.h:424
int n
Definition acutest.h:525
static int const char char buffer[256]
Definition acutest.h:524
static const struct acutest_test_ * acutest_current_test_
Definition acutest.h:417
#define TEST_CASE_MAXSIZE
Definition acutest.h:199
static int acutest_list_size_
Definition acutest.h:406
static void acutest_help_(void)
Definition acutest.h:1533
static int acutest_cond_failed_
Definition acutest.h:414
static int acutest_timer_
Definition acutest.h:428
#define ACUTEST_CMDLINE_OPTID_MISSINGARG_
static void acutest_fini_(const char *test_name)
Definition acutest.h:976
static void acutest_timer_get_time_(int *ts)
Definition acutest.h:501
#define ACUTEST_CMDLINE_OPTID_UNKNOWN_
#define ACUTEST_CMDLINE_OPTID_BOGUSARG_
static void acutest_list_names_(void)
Definition acutest.h:998
static int acutest_cmdline_read_(const ACUTEST_CMDLINE_OPTION_ *options, int argc, char **argv, int(*callback)(int, const char *))
Definition acutest.h:1418
static int acutest_verbose_level_
Definition acutest.h:425
const struct acutest_test_ acutest_list_[]
void acutest_timer_init_(void)
Definition acutest.h:499
#define ACUTEST_CMDLINE_AUXBUF_SIZE_
Definition acutest.h:1416
static int acutest_abort_has_jmp_buf_
Definition acutest.h:430
static void acutest_begin_test_line_(const struct acutest_test_ *test)
Definition acutest.h:648
void char * line_beg
Definition acutest.h:874
char * line_end
Definition acutest.h:875
static int acutest_test_skip_count_
Definition acutest.h:421
va_list args
Definition acutest.h:876
int const char int const char int result_color
Definition acutest.h:782
static char acutest_test_skip_reason_[256]
Definition acutest.h:422
static int acutest_under_debugger_(void)
Definition acutest.h:1744
static double acutest_timer_diff_(int start, int end)
Definition acutest.h:503
void acutest_abort_(void) ACUTEST_ATTRIBUTE_(noreturn)
Definition acutest.h:985
static int acutest_count_(enum acutest_state_ state)
Definition acutest.h:433
#define ACUTEST_CMDLINE_OPTFLAG_REQUIREDARG_
static int acutest_worker_index_
Definition acutest.h:413
static int acutest_cmdline_callback_(int id, const char *arg)
Definition acutest.h:1618
static int acutest_test_failures_
Definition acutest.h:426
#define ACUTEST_COLOR_YELLOW_
Definition acutest.h:515
static jmp_buf acutest_abort_jmp_buf_
Definition acutest.h:431
#define ACUTEST_COLOR_RED_INTENSIVE_
Definition acutest.h:517
static int acutest_test_check_count_
Definition acutest.h:420
void int const char size_t reason_len
Definition acutest.h:735
static int acutest_select_(const char *pattern)
Definition acutest.h:1030
result_str
Definition acutest.h:805
void int line
Definition acutest.h:732
static int acutest_tap_
Definition acutest.h:410
#define ACUTEST_COLOR_RED_
Definition acutest.h:513
#define TEST_DUMP_MAXSIZE
Definition acutest.h:249
static acutest_timer_type_ acutest_timer_start_
Definition acutest.h:496
va_start(args, fmt)
static int acutest_current_index_
Definition acutest.h:418
static int acutest_no_summary_
Definition acutest.h:409
static char * acutest_argv0_
Definition acutest.h:405
static acutest_timer_type_ acutest_timer_end_
Definition acutest.h:497
#define ACUTEST_CMDLINE_OPTFLAG_OPTIONALARG_
void acutest_case_(const char *fmt,...)
static const char * acutest_basename_(const char *path)
Definition acutest.h:618
void acutest_message_(const char *fmt,...)
#define ACUTEST_COLOR_YELLOW_INTENSIVE_
Definition acutest.h:519
static int acutest_exclude_mode_
Definition acutest.h:411
The fiber facing IO API: blocking looking calls a fiber uses to do IO.
const char * name
Definition acutest.h:394
void(* func)(void)
Definition acutest.h:395
enum acutest_state_ state
Definition acutest.h:399