NeoMutt  2020-04-24
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 /* Call directly the given test unit function. */
929 static int
930 test_do_run_(const struct test_* test, int index)
931 {
932  test_was_aborted_ = 0;
933  test_current_unit_ = test;
934  test_current_index_ = index;
935  test_current_failures_ = 0;
936  test_current_already_logged_ = 0;
937  test_cond_failed_ = 0;
938 
939  test_begin_test_line_(test);
940 
941 #ifdef __cplusplus
942  try {
943 #endif
944 
945  /* This is good to do for case the test unit e.g. crashes. */
946  fflush(stdout);
947  fflush(stderr);
948 
949  if(!test_worker_) {
950  test_abort_has_jmp_buf_ = 1;
951  if(setjmp(test_abort_jmp_buf_) != 0) {
952  test_was_aborted_ = 1;
953  goto aborted;
954  }
955  }
956 
957  test_timer_get_time_(&test_timer_start_);
958  test->func();
959 aborted:
960  test_abort_has_jmp_buf_ = 0;
961  test_timer_get_time_(&test_timer_end_);
962 
963  if(test_verbose_level_ >= 3) {
965  if(test_current_failures_ == 0) {
966  test_print_in_color_(TEST_COLOR_GREEN_INTENSIVE_, "SUCCESS: ");
967  printf("All conditions have passed.\n");
968 
969  if(test_timer_) {
971  printf("Duration: ");
973  printf("\n");
974  }
975  } else {
976  test_print_in_color_(TEST_COLOR_RED_INTENSIVE_, "FAILED: ");
977  if(!test_was_aborted_) {
978  printf("%d condition%s %s failed.\n",
979  test_current_failures_,
980  (test_current_failures_ == 1) ? "" : "s",
981  (test_current_failures_ == 1) ? "has" : "have");
982  } else {
983  printf("Aborted.\n");
984  }
985  }
986  printf("\n");
987  } else if(test_verbose_level_ >= 1 && test_current_failures_ == 0) {
989  }
990 
991  test_case_(NULL);
992  test_current_unit_ = NULL;
993  return (test_current_failures_ == 0) ? 0 : -1;
994 
995 #ifdef __cplusplus
996  } catch(std::exception& e) {
997  const char* what = e.what();
998  test_check_(0, NULL, 0, "Threw std::exception");
999  if(what != NULL)
1000  test_message_("std::exception::what(): %s", what);
1001 
1002  if(test_verbose_level_ >= 3) {
1003  test_line_indent_(1);
1004  test_print_in_color_(TEST_COLOR_RED_INTENSIVE_, "FAILED: ");
1005  printf("C++ exception.\n\n");
1006  }
1007 
1008  return -1;
1009  } catch(...) {
1010  test_check_(0, NULL, 0, "Threw an exception");
1011 
1012  if(test_verbose_level_ >= 3) {
1013  test_line_indent_(1);
1014  test_print_in_color_(TEST_COLOR_RED_INTENSIVE_, "FAILED: ");
1015  printf("C++ exception.\n\n");
1016  }
1017 
1018  return -1;
1019  }
1020 #endif
1021 }
1022 
1023 /* Trigger the unit test. If possible (and not suppressed) it starts a child
1024  * process who calls test_do_run_(), otherwise it calls test_do_run_()
1025  * directly. */
1026 static void
1027 test_run_(const struct test_* test, int index, int master_index)
1028 {
1029  int failed = 1;
1030  test_timer_type_ start, end;
1031 
1032  test_current_unit_ = test;
1033  test_current_already_logged_ = 0;
1034  test_timer_get_time_(&start);
1035 
1036  if(!test_no_exec_) {
1037 
1038 #if defined(ACUTEST_UNIX_)
1039 
1040  pid_t pid;
1041  int exit_code;
1042 
1043  /* Make sure the child starts with empty I/O buffers. */
1044  fflush(stdout);
1045  fflush(stderr);
1046 
1047  pid = fork();
1048  if(pid == (pid_t)-1) {
1049  test_error_("Cannot fork. %s [%d]", strerror(errno), errno);
1050  failed = 1;
1051  } else if(pid == 0) {
1052  /* Child: Do the test. */
1053  test_worker_ = 1;
1054  failed = (test_do_run_(test, index) != 0);
1055  exit(failed ? 1 : 0);
1056  } else {
1057  /* Parent: Wait until child terminates and analyze its exit code. */
1058  waitpid(pid, &exit_code, 0);
1059  if(WIFEXITED(exit_code)) {
1060  switch(WEXITSTATUS(exit_code)) {
1061  case 0: failed = 0; break; /* test has passed. */
1062  case 1: /* noop */ break; /* "normal" failure. */
1063  default: test_error_("Unexpected exit code [%d]", WEXITSTATUS(exit_code));
1064  }
1065  } else if(WIFSIGNALED(exit_code)) {
1066  char tmp[32];
1067  const char* signame;
1068  switch(WTERMSIG(exit_code)) {
1069  case SIGINT: signame = "SIGINT"; break;
1070  case SIGHUP: signame = "SIGHUP"; break;
1071  case SIGQUIT: signame = "SIGQUIT"; break;
1072  case SIGABRT: signame = "SIGABRT"; break;
1073  case SIGKILL: signame = "SIGKILL"; break;
1074  case SIGSEGV: signame = "SIGSEGV"; break;
1075  case SIGILL: signame = "SIGILL"; break;
1076  case SIGTERM: signame = "SIGTERM"; break;
1077  default: sprintf(tmp, "signal %d", WTERMSIG(exit_code)); signame = tmp; break;
1078  }
1079  test_error_("Test interrupted by %s.", signame);
1080  } else {
1081  test_error_("Test ended in an unexpected way [%d].", exit_code);
1082  }
1083  }
1084 
1085 #elif defined(ACUTEST_WIN_)
1086 
1087  char buffer[512] = {0};
1088  STARTUPINFOA startupInfo;
1089  PROCESS_INFORMATION processInfo;
1090  DWORD exitCode;
1091 
1092  /* Windows has no fork(). So we propagate all info into the child
1093  * through a command line arguments. */
1094  _snprintf(buffer, sizeof(buffer)-1,
1095  "%s --worker=%d %s --no-exec --no-summary %s --verbose=%d --color=%s -- \"%s\"",
1096  test_argv0_, index, test_timer_ ? "--time" : "",
1097  test_tap_ ? "--tap" : "", test_verbose_level_,
1098  test_colorize_ ? "always" : "never",
1099  test->name);
1100  memset(&startupInfo, 0, sizeof(startupInfo));
1101  startupInfo.cb = sizeof(STARTUPINFO);
1102  if(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo)) {
1103  WaitForSingleObject(processInfo.hProcess, INFINITE);
1104  GetExitCodeProcess(processInfo.hProcess, &exitCode);
1105  CloseHandle(processInfo.hThread);
1106  CloseHandle(processInfo.hProcess);
1107  failed = (exitCode != 0);
1108  if(exitCode > 1) {
1109  switch(exitCode) {
1110  case 3: test_error_("Aborted."); break;
1111  case 0xC0000005: test_error_("Access violation."); break;
1112  default: test_error_("Test ended in an unexpected way [%lu].", exitCode); break;
1113  }
1114  }
1115  } else {
1116  test_error_("Cannot create unit test subprocess [%ld].", GetLastError());
1117  failed = 1;
1118  }
1119 
1120 #else
1121 
1122  /* A platform where we don't know how to run child process. */
1123  failed = (test_do_run_(test, index) != 0);
1124 
1125 #endif
1126 
1127  } else {
1128  /* Child processes suppressed through --no-exec. */
1129  failed = (test_do_run_(test, index) != 0);
1130  }
1131  test_timer_get_time_(&end);
1132 
1133  test_current_unit_ = NULL;
1134 
1135  test_stat_run_units_++;
1136  if(failed)
1137  test_stat_failed_units_++;
1138 
1139  test_set_success_(master_index, !failed);
1140  test_set_duration_(master_index, test_timer_diff_(start, end));
1141 }
1142 
1143 #if defined(ACUTEST_WIN_)
1144 /* Callback for SEH events. */
1145 static LONG CALLBACK
1146 test_seh_exception_filter_(EXCEPTION_POINTERS *ptrs)
1147 {
1148  test_check_(0, NULL, 0, "Unhandled SEH exception");
1149  test_message_("Exception code: 0x%08lx", ptrs->ExceptionRecord->ExceptionCode);
1150  test_message_("Exception address: 0x%p", ptrs->ExceptionRecord->ExceptionAddress);
1151 
1152  fflush(stdout);
1153  fflush(stderr);
1154 
1155  return EXCEPTION_EXECUTE_HANDLER;
1156 }
1157 #endif
1158 
1159 
1160 #define TEST_CMDLINE_OPTFLAG_OPTIONALARG_ 0x0001
1161 #define TEST_CMDLINE_OPTFLAG_REQUIREDARG_ 0x0002
1162 
1163 #define TEST_CMDLINE_OPTID_NONE_ 0
1164 #define TEST_CMDLINE_OPTID_UNKNOWN_ (-0x7fffffff + 0)
1165 #define TEST_CMDLINE_OPTID_MISSINGARG_ (-0x7fffffff + 1)
1166 #define TEST_CMDLINE_OPTID_BOGUSARG_ (-0x7fffffff + 2)
1167 
1168 typedef struct TEST_CMDLINE_OPTION_ {
1170  const char* longname;
1171  int id;
1172  unsigned flags;
1174 
1175 static int
1177  const char* arggroup,
1178  int (*callback)(int /*optval*/, const char* /*arg*/))
1179 {
1180  const TEST_CMDLINE_OPTION_* opt;
1181  int i;
1182  int ret = 0;
1183 
1184  for(i = 0; arggroup[i] != '\0'; i++) {
1185  for(opt = options; opt->id != 0; opt++) {
1186  if(arggroup[i] == opt->shortname)
1187  break;
1188  }
1189 
1190  if(opt->id != 0 && !(opt->flags & TEST_CMDLINE_OPTFLAG_REQUIREDARG_)) {
1191  ret = callback(opt->id, NULL);
1192  } else {
1193  /* Unknown option. */
1194  char badoptname[3];
1195  badoptname[0] = '-';
1196  badoptname[1] = arggroup[i];
1197  badoptname[2] = '\0';
1198  ret = callback((opt->id != 0 ? TEST_CMDLINE_OPTID_MISSINGARG_ : TEST_CMDLINE_OPTID_UNKNOWN_),
1199  badoptname);
1200  }
1201 
1202  if(ret != 0)
1203  break;
1204  }
1205 
1206  return ret;
1207 }
1208 
1209 #define TEST_CMDLINE_AUXBUF_SIZE_ 32
1210 
1211 static int
1212 test_cmdline_read_(const TEST_CMDLINE_OPTION_* options, int argc, char** argv,
1213  int (*callback)(int /*optval*/, const char* /*arg*/))
1214 {
1215 
1216  const TEST_CMDLINE_OPTION_* opt;
1217  char auxbuf[TEST_CMDLINE_AUXBUF_SIZE_+1];
1218  int after_doubledash = 0;
1219  int i = 1;
1220  int ret = 0;
1221 
1222  auxbuf[TEST_CMDLINE_AUXBUF_SIZE_] = '\0';
1223 
1224  while(i < argc) {
1225  if(after_doubledash || strcmp(argv[i], "-") == 0) {
1226  /* Non-option argument. */
1227  ret = callback(TEST_CMDLINE_OPTID_NONE_, argv[i]);
1228  } else if(strcmp(argv[i], "--") == 0) {
1229  /* End of options. All the remaining members are non-option arguments. */
1230  after_doubledash = 1;
1231  } else if(argv[i][0] != '-') {
1232  /* Non-option argument. */
1233  ret = callback(TEST_CMDLINE_OPTID_NONE_, argv[i]);
1234  } else {
1235  for(opt = options; opt->id != 0; opt++) {
1236  if(opt->longname != NULL && strncmp(argv[i], "--", 2) == 0) {
1237  size_t len = strlen(opt->longname);
1238  if(strncmp(argv[i]+2, opt->longname, len) == 0) {
1239  /* Regular long option. */
1240  if(argv[i][2+len] == '\0') {
1241  /* with no argument provided. */
1243  ret = callback(opt->id, NULL);
1244  else
1245  ret = callback(TEST_CMDLINE_OPTID_MISSINGARG_, argv[i]);
1246  break;
1247  } else if(argv[i][2+len] == '=') {
1248  /* with an argument provided. */
1250  ret = callback(opt->id, argv[i]+2+len+1);
1251  } else {
1252  sprintf(auxbuf, "--%s", opt->longname);
1253  ret = callback(TEST_CMDLINE_OPTID_BOGUSARG_, auxbuf);
1254  }
1255  break;
1256  } else {
1257  continue;
1258  }
1259  }
1260  } else if(opt->shortname != '\0' && argv[i][0] == '-') {
1261  if(argv[i][1] == opt->shortname) {
1262  /* Regular short option. */
1264  if(argv[i][2] != '\0')
1265  ret = callback(opt->id, argv[i]+2);
1266  else if(i+1 < argc)
1267  ret = callback(opt->id, argv[++i]);
1268  else
1269  ret = callback(TEST_CMDLINE_OPTID_MISSINGARG_, argv[i]);
1270  break;
1271  } else {
1272  ret = callback(opt->id, NULL);
1273 
1274  /* There might be more (argument-less) short options
1275  * grouped together. */
1276  if(ret == 0 && argv[i][2] != '\0')
1277  ret = test_cmdline_handle_short_opt_group_(options, argv[i]+2, callback);
1278  break;
1279  }
1280  }
1281  }
1282  }
1283 
1284  if(opt->id == 0) { /* still not handled? */
1285  if(argv[i][0] != '-') {
1286  /* Non-option argument. */
1287  ret = callback(TEST_CMDLINE_OPTID_NONE_, argv[i]);
1288  } else {
1289  /* Unknown option. */
1290  char* badoptname = argv[i];
1291 
1292  if(strncmp(badoptname, "--", 2) == 0) {
1293  /* Strip any argument from the long option. */
1294  char* assignment = strchr(badoptname, '=');
1295  if(assignment != NULL) {
1296  size_t len = assignment - badoptname;
1297  if(len > TEST_CMDLINE_AUXBUF_SIZE_)
1299  strncpy(auxbuf, badoptname, len);
1300  auxbuf[len] = '\0';
1301  badoptname = auxbuf;
1302  }
1303  }
1304 
1305  ret = callback(TEST_CMDLINE_OPTID_UNKNOWN_, badoptname);
1306  }
1307  }
1308  }
1309 
1310  if(ret != 0)
1311  return ret;
1312  i++;
1313  }
1314 
1315  return ret;
1316 }
1317 
1318 static void
1320 {
1321  printf("Usage: %s [options] [test...]\n", test_argv0_);
1322  printf("\n");
1323  printf("Run the specified unit tests; or if the option '--skip' is used, run all\n");
1324  printf("tests in the suite but those listed. By default, if no tests are specified\n");
1325  printf("on the command line, all unit tests in the suite are run.\n");
1326  printf("\n");
1327  printf("Options:\n");
1328  printf(" -s, --skip Execute all unit tests but the listed ones\n");
1329  printf(" --exec[=WHEN] If supported, execute unit tests as child processes\n");
1330  printf(" (WHEN is one of 'auto', 'always', 'never')\n");
1331  printf(" -E, --no-exec Same as --exec=never\n");
1332 #if defined ACUTEST_WIN_
1333  printf(" -t, --time Measure test duration\n");
1334 #elif defined ACUTEST_HAS_POSIX_TIMER_
1335  printf(" -t, --time Measure test duration (real time)\n");
1336  printf(" --time=TIMER Measure test duration, using given timer\n");
1337  printf(" (TIMER is one of 'real', 'cpu')\n");
1338 #endif
1339  printf(" --no-summary Suppress printing of test results summary\n");
1340  printf(" --tap Produce TAP-compliant output\n");
1341  printf(" (See https://testanything.org/)\n");
1342  printf(" -x, --xml-output=FILE Enable XUnit output to the given file\n");
1343  printf(" -l, --list List unit tests in the suite and exit\n");
1344  printf(" -v, --verbose Make output more verbose\n");
1345  printf(" --verbose=LEVEL Set verbose level to LEVEL:\n");
1346  printf(" 0 ... Be silent\n");
1347  printf(" 1 ... Output one line per test (and summary)\n");
1348  printf(" 2 ... As 1 and failed conditions (this is default)\n");
1349  printf(" 3 ... As 1 and all conditions (and extended summary)\n");
1350  printf(" -q, --quiet Same as --verbose=0\n");
1351  printf(" --color[=WHEN] Enable colorized output\n");
1352  printf(" (WHEN is one of 'auto', 'always', 'never')\n");
1353  printf(" --no-color Same as --color=never\n");
1354  printf(" -h, --help Display this help and exit\n");
1355 
1356  if(test_list_size_ < 16) {
1357  printf("\n");
1358  test_list_names_();
1359  }
1360 }
1361 
1363  { 's', "skip", 's', 0 },
1364  { 0, "exec", 'e', TEST_CMDLINE_OPTFLAG_OPTIONALARG_ },
1365  { 'E', "no-exec", 'E', 0 },
1366 #if defined ACUTEST_WIN_
1367  { 't', "time", 't', 0 },
1368  { 0, "timer", 't', 0 }, /* kept for compatibility */
1369 #elif defined ACUTEST_HAS_POSIX_TIMER_
1370  { 't', "time", 't', TEST_CMDLINE_OPTFLAG_OPTIONALARG_ },
1371  { 0, "timer", 't', TEST_CMDLINE_OPTFLAG_OPTIONALARG_ }, /* kept for compatibility */
1372 #endif
1373  { 0, "no-summary", 'S', 0 },
1374  { 0, "tap", 'T', 0 },
1375  { 'l', "list", 'l', 0 },
1376  { 'v', "verbose", 'v', TEST_CMDLINE_OPTFLAG_OPTIONALARG_ },
1377  { 'q', "quiet", 'q', 0 },
1378  { 0, "color", 'c', TEST_CMDLINE_OPTFLAG_OPTIONALARG_ },
1379  { 0, "no-color", 'C', 0 },
1380  { 'h', "help", 'h', 0 },
1381  { 0, "worker", 'w', TEST_CMDLINE_OPTFLAG_REQUIREDARG_ }, /* internal */
1382  { 'x', "xml-output", 'x', TEST_CMDLINE_OPTFLAG_REQUIREDARG_ },
1383  { 0, NULL, 0, 0 }
1384 };
1385 
1386 static int
1387 test_cmdline_callback_(int id, const char* arg)
1388 {
1389  switch(id) {
1390  case 's':
1391  test_skip_mode_ = 1;
1392  break;
1393 
1394  case 'e':
1395  if(arg == NULL || strcmp(arg, "always") == 0) {
1396  test_no_exec_ = 0;
1397  } else if(strcmp(arg, "never") == 0) {
1398  test_no_exec_ = 1;
1399  } else if(strcmp(arg, "auto") == 0) {
1400  /*noop*/
1401  } else {
1402  fprintf(stderr, "%s: Unrecognized argument '%s' for option --exec.\n", test_argv0_, arg);
1403  fprintf(stderr, "Try '%s --help' for more information.\n", test_argv0_);
1404  exit(2);
1405  }
1406  break;
1407 
1408  case 'E':
1409  test_no_exec_ = 1;
1410  break;
1411 
1412  case 't':
1413 #if defined ACUTEST_WIN_ || defined ACUTEST_HAS_POSIX_TIMER_
1414  if(arg == NULL || strcmp(arg, "real") == 0) {
1415  test_timer_ = 1;
1416  #ifndef ACUTEST_WIN_
1417  } else if(strcmp(arg, "cpu") == 0) {
1418  test_timer_ = 2;
1419  #endif
1420  } else {
1421  fprintf(stderr, "%s: Unrecognized argument '%s' for option --time.\n", test_argv0_, arg);
1422  fprintf(stderr, "Try '%s --help' for more information.\n", test_argv0_);
1423  exit(2);
1424  }
1425 #endif
1426  break;
1427 
1428  case 'S':
1429  test_no_summary_ = 1;
1430  break;
1431 
1432  case 'T':
1433  test_tap_ = 1;
1434  break;
1435 
1436  case 'l':
1437  test_list_names_();
1438  exit(0);
1439 
1440  case 'v':
1441  test_verbose_level_ = (arg != NULL ? atoi(arg) : test_verbose_level_+1);
1442  break;
1443 
1444  case 'q':
1445  test_verbose_level_ = 0;
1446  break;
1447 
1448  case 'c':
1449  if(arg == NULL || strcmp(arg, "always") == 0) {
1450  test_colorize_ = 1;
1451  } else if(strcmp(arg, "never") == 0) {
1452  test_colorize_ = 0;
1453  } else if(strcmp(arg, "auto") == 0) {
1454  /*noop*/
1455  } else {
1456  fprintf(stderr, "%s: Unrecognized argument '%s' for option --color.\n", test_argv0_, arg);
1457  fprintf(stderr, "Try '%s --help' for more information.\n", test_argv0_);
1458  exit(2);
1459  }
1460  break;
1461 
1462  case 'C':
1463  test_colorize_ = 0;
1464  break;
1465 
1466  case 'h':
1467  test_help_();
1468  exit(0);
1469 
1470  case 'w':
1471  test_worker_ = 1;
1472  test_worker_index_ = atoi(arg);
1473  break;
1474  case 'x':
1475  test_xml_output_ = fopen(arg, "w");
1476  if (!test_xml_output_) {
1477  fprintf(stderr, "Unable to open '%s': %s\n", arg, strerror(errno));
1478  exit(2);
1479  }
1480  break;
1481 
1482  case 0:
1483  if(test_lookup_(arg) == 0) {
1484  fprintf(stderr, "%s: Unrecognized unit test '%s'\n", test_argv0_, arg);
1485  fprintf(stderr, "Try '%s --list' for list of unit tests.\n", test_argv0_);
1486  exit(2);
1487  }
1488  break;
1489 
1491  fprintf(stderr, "Unrecognized command line option '%s'.\n", arg);
1492  fprintf(stderr, "Try '%s --help' for more information.\n", test_argv0_);
1493  exit(2);
1494 
1496  fprintf(stderr, "The command line option '%s' requires an argument.\n", arg);
1497  fprintf(stderr, "Try '%s --help' for more information.\n", test_argv0_);
1498  exit(2);
1499 
1501  fprintf(stderr, "The command line option '%s' does not expect an argument.\n", arg);
1502  fprintf(stderr, "Try '%s --help' for more information.\n", test_argv0_);
1503  exit(2);
1504  }
1505 
1506  return 0;
1507 }
1508 
1509 
1510 #ifdef ACUTEST_LINUX_
1511 static int
1512 test_is_tracer_present_(void)
1513 {
1514  /* Must be large enough so the line 'TracerPid: ${PID}' can fit in. */
1515  static const int OVERLAP = 32;
1516 
1517  char buf[256+OVERLAP+1];
1518  int tracer_present = 0;
1519  int fd;
1520  size_t n_read = 0;
1521 
1522  fd = open("/proc/self/status", O_RDONLY);
1523  if(fd == -1)
1524  return 0;
1525 
1526  while(1) {
1527  static const char pattern[] = "TracerPid:";
1528  const char* field;
1529 
1530  while(n_read < sizeof(buf) - 1) {
1531  ssize_t n;
1532 
1533  n = read(fd, buf + n_read, sizeof(buf) - 1 - n_read);
1534  if(n <= 0)
1535  break;
1536  n_read += n;
1537  }
1538  buf[n_read] = '\0';
1539 
1540  field = strstr(buf, pattern);
1541  if(field != NULL && field < buf + sizeof(buf) - OVERLAP) {
1542  pid_t tracer_pid = (pid_t) atoi(field + sizeof(pattern) - 1);
1543  tracer_present = (tracer_pid != 0);
1544  break;
1545  }
1546 
1547  if(n_read == sizeof(buf)-1) {
1548  memmove(buf, buf + sizeof(buf)-1 - OVERLAP, OVERLAP);
1549  n_read = OVERLAP;
1550  } else {
1551  break;
1552  }
1553  }
1554 
1555  close(fd);
1556  return tracer_present;
1557 }
1558 #endif
1559 
1560 int
1561 main(int argc, char** argv)
1562 {
1563  int i;
1564  test_argv0_ = argv[0];
1565 
1566 #if defined ACUTEST_UNIX_
1567  test_colorize_ = isatty(STDOUT_FILENO);
1568 #elif defined ACUTEST_WIN_
1569  #if defined _BORLANDC_
1570  test_colorize_ = isatty(_fileno(stdout));
1571  #else
1572  test_colorize_ = _isatty(_fileno(stdout));
1573  #endif
1574 #else
1575  test_colorize_ = 0;
1576 #endif
1577 
1578  /* Count all test units */
1579  test_list_size_ = 0;
1580  for(i = 0; test_list_[i].func != NULL; i++)
1581  test_list_size_++;
1582 
1583  test_details_ = (struct test_detail_*)calloc(test_list_size_, sizeof(struct test_detail_));
1584  if(test_details_ == NULL) {
1585  fprintf(stderr, "Out of memory.\n");
1586  exit(2);
1587  }
1588 
1589  /* Parse options */
1590  test_cmdline_read_(test_cmdline_options_, argc, argv, test_cmdline_callback_);
1591 
1592  /* Initialize the proper timer. */
1593  test_timer_init_();
1594 
1595 #if defined(ACUTEST_WIN_)
1596  SetUnhandledExceptionFilter(test_seh_exception_filter_);
1597 #ifdef _MSC_VER
1598  _set_abort_behavior(0, _WRITE_ABORT_MSG);
1599 #endif
1600 #endif
1601 
1602  /* By default, we want to run all tests. */
1603  if(test_count_ == 0) {
1604  for(i = 0; test_list_[i].func != NULL; i++)
1605  test_remember_(i);
1606  }
1607 
1608  /* Guess whether we want to run unit tests as child processes. */
1609  if(test_no_exec_ < 0) {
1610  test_no_exec_ = 0;
1611 
1612  if(test_count_ <= 1) {
1613  test_no_exec_ = 1;
1614  } else {
1615 #ifdef ACUTEST_WIN_
1616  if(IsDebuggerPresent())
1617  test_no_exec_ = 1;
1618 #endif
1619 #ifdef ACUTEST_LINUX_
1620  if(test_is_tracer_present_())
1621  test_no_exec_ = 1;
1622 #endif
1623 #ifdef RUNNING_ON_VALGRIND
1624  /* RUNNING_ON_VALGRIND is provided by valgrind.h */
1625  if(RUNNING_ON_VALGRIND)
1626  test_no_exec_ = 1;
1627 #endif
1628  }
1629  }
1630 
1631  if(test_tap_) {
1632  /* TAP requires we know test result ("ok", "not ok") before we output
1633  * anything about the test, and this gets problematic for larger verbose
1634  * levels. */
1635  if(test_verbose_level_ > 2)
1636  test_verbose_level_ = 2;
1637 
1638  /* TAP harness should provide some summary. */
1639  test_no_summary_ = 1;
1640 
1641  if(!test_worker_)
1642  printf("1..%d\n", (int) test_count_);
1643  }
1644 
1645  int index = test_worker_index_;
1646  for(i = 0; test_list_[i].func != NULL; i++) {
1647  int run = (test_details_[i].flags & TEST_FLAG_RUN_);
1648  if (test_skip_mode_) /* Run all tests except those listed. */
1649  run = !run;
1650  if(run)
1651  test_run_(&test_list_[i], index++, i);
1652  }
1653 
1654  /* Write a summary */
1655  if(!test_no_summary_ && test_verbose_level_ >= 1) {
1656  if(test_verbose_level_ >= 3) {
1657  test_print_in_color_(TEST_COLOR_DEFAULT_INTENSIVE_, "Summary:\n");
1658 
1659  printf(" Count of all unit tests: %4d\n", (int) test_list_size_);
1660  printf(" Count of run unit tests: %4d\n", test_stat_run_units_);
1661  printf(" Count of failed unit tests: %4d\n", test_stat_failed_units_);
1662  printf(" Count of skipped unit tests: %4d\n", (int) test_list_size_ - test_stat_run_units_);
1663  }
1664 
1665  if(test_stat_failed_units_ == 0) {
1666  test_print_in_color_(TEST_COLOR_GREEN_INTENSIVE_, "SUCCESS:");
1667  printf(" All unit tests have passed.\n");
1668  } else {
1669  test_print_in_color_(TEST_COLOR_RED_INTENSIVE_, "FAILED:");
1670  printf(" %d of %d unit tests %s failed.\n",
1671  test_stat_failed_units_, test_stat_run_units_,
1672  (test_stat_failed_units_ == 1) ? "has" : "have");
1673  }
1674 
1675  if(test_verbose_level_ >= 3)
1676  printf("\n");
1677  }
1678 
1679  if (test_xml_output_) {
1680 #if defined ACUTEST_UNIX_
1681  char *suite_name = basename(argv[0]);
1682 #elif defined ACUTEST_WIN_
1683  char suite_name[_MAX_FNAME];
1684  _splitpath(argv[0], NULL, NULL, suite_name, NULL);
1685 #else
1686  const char *suite_name = argv[0];
1687 #endif
1688  fprintf(test_xml_output_, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1689  fprintf(test_xml_output_, "<testsuite name=\"%s\" tests=\"%d\" errors=\"%d\" failures=\"%d\" skip=\"%d\">\n",
1690  suite_name, (int)test_list_size_, test_stat_failed_units_, test_stat_failed_units_,
1691  (int)test_list_size_ - test_stat_run_units_);
1692  for(i = 0; test_list_[i].func != NULL; i++) {
1693  struct test_detail_ *details = &test_details_[i];
1694  fprintf(test_xml_output_, " <testcase name=\"%s\" time=\"%.2f\">\n", test_list_[i].name, details->duration);
1695  if (details->flags & TEST_FLAG_FAILURE_)
1696  fprintf(test_xml_output_, " <failure />\n");
1697  if (!(details->flags & TEST_FLAG_FAILURE_) && !(details->flags & TEST_FLAG_SUCCESS_))
1698  fprintf(test_xml_output_, " <skipped />\n");
1699  fprintf(test_xml_output_, " </testcase>\n");
1700  }
1701  fprintf(test_xml_output_, "</testsuite>\n");
1702  fclose(test_xml_output_);
1703  }
1704 
1705  free((void*) test_details_);
1706 
1707  return (test_stat_failed_units_ == 0) ? 0 : 1;
1708 }
1709 
1710 
1711 #endif /* #ifndef TEST_NO_MAIN */
1712 
1713 #ifdef _MSC_VER
1714  #pragma warning(pop)
1715 #endif
1716 
1717 #ifdef __cplusplus
1718  } /* extern "C" */
1719 #endif
1720 
1721 #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 int test_do_run_(const struct test_ *test, int index)
Definition: acutest.h:930
#define TEST_CASE_MAXSIZE
Definition: acutest.h:189
#define TEST_CMDLINE_OPTFLAG_REQUIREDARG_
Definition: acutest.h:1161
static int test_cmdline_callback_(int id, const char *arg)
Definition: acutest.h:1387
const struct test_ test_list_[]
static void test_run_(const struct test_ *test, int index, int master_index)
Definition: acutest.h:1027
#define TEST_MSG_MAXSIZE
Definition: acutest.h:221
static int test_cond_failed_
Definition: acutest.h:357
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
static int test_cmdline_handle_short_opt_group_(const TEST_CMDLINE_OPTION_ *options, const char *arggroup, int(*callback)(int, const char *))
Definition: acutest.h:1176
#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
static struct UrlTest test[]
Definition: url_parse.c:41
time_t tv_sec
Definition: file.h:47
static void test_help_(void)
Definition: acutest.h:1319
#define TEST_CMDLINE_OPTID_MISSINGARG_
Definition: acutest.h:1165
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:1166
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:48
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:1362
#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:1561
#define TEST_CMDLINE_OPTFLAG_OPTIONALARG_
Definition: acutest.h:1160
#define TEST_CMDLINE_OPTID_NONE_
Definition: acutest.h:1163
struct TEST_CMDLINE_OPTION_ TEST_CMDLINE_OPTION_
Definition: acutest.h:320
#define TEST_CMDLINE_OPTID_UNKNOWN_
Definition: acutest.h:1164
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,...)
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:45
static void test_set_duration_(int i, double duration)
Definition: acutest.h:835
const char * longname
Definition: acutest.h:1170
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:1212
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:1209
static double test_timer_diff_(int start, int end)
Definition: acutest.h:468
va_end(args)