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