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