You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1794 lines
57 KiB

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