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