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