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

ctest.h 16 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. /* Copyright 2011-2015 Bas van den Berg
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. #ifndef CTEST_H
  16. #define CTEST_H
  17. #if defined _WIN32 || defined __CYGWIN__
  18. #ifndef WIN32
  19. #define WIN32
  20. #endif
  21. #endif
  22. #ifndef WIN32
  23. #define WEAK __attribute__ ((weak))
  24. #else
  25. #define WEAK
  26. #endif
  27. #include <inttypes.h> /* intmax_t, uintmax_t, PRI* */
  28. #include <stddef.h> /* size_t */
  29. typedef void (*SetupFunc)(void*);
  30. typedef void (*TearDownFunc)(void*);
  31. struct ctest {
  32. const char* ssname; // suite name
  33. const char* ttname; // test name
  34. void (*run)();
  35. int skip;
  36. void* data;
  37. SetupFunc setup;
  38. TearDownFunc teardown;
  39. unsigned int magic;
  40. };
  41. #define __FNAME(sname, tname) __ctest_##sname##_##tname##_run
  42. #define __TNAME(sname, tname) __ctest_##sname##_##tname
  43. #define __CTEST_MAGIC (0xdeadbeef)
  44. #ifdef __APPLE__
  45. #define __Test_Section __attribute__ ((used, section ("__DATA, .ctest")))
  46. #else
  47. #define __Test_Section __attribute__ ((used, section (".ctest")))
  48. #endif
  49. #define __CTEST_STRUCT(sname, tname, _skip, __data, __setup, __teardown) \
  50. static struct ctest __TNAME(sname, tname) __Test_Section = { \
  51. .ssname=#sname, \
  52. .ttname=#tname, \
  53. .run = __FNAME(sname, tname), \
  54. .skip = _skip, \
  55. .data = __data, \
  56. .setup = (SetupFunc)__setup, \
  57. .teardown = (TearDownFunc)__teardown, \
  58. .magic = __CTEST_MAGIC };
  59. #define CTEST_DATA(sname) struct sname##_data
  60. #define CTEST_SETUP(sname) \
  61. void WEAK sname##_setup(struct sname##_data* data)
  62. #define CTEST_TEARDOWN(sname) \
  63. void WEAK sname##_teardown(struct sname##_data* data)
  64. #define __CTEST_INTERNAL(sname, tname, _skip) \
  65. void __FNAME(sname, tname)(); \
  66. __CTEST_STRUCT(sname, tname, _skip, NULL, NULL, NULL) \
  67. void __FNAME(sname, tname)()
  68. #ifdef __APPLE__
  69. #define SETUP_FNAME(sname) NULL
  70. #define TEARDOWN_FNAME(sname) NULL
  71. #else
  72. #define SETUP_FNAME(sname) sname##_setup
  73. #define TEARDOWN_FNAME(sname) sname##_teardown
  74. #endif
  75. #define __CTEST2_INTERNAL(sname, tname, _skip) \
  76. static struct sname##_data __ctest_##sname##_data; \
  77. CTEST_SETUP(sname); \
  78. CTEST_TEARDOWN(sname); \
  79. void __FNAME(sname, tname)(struct sname##_data* data); \
  80. __CTEST_STRUCT(sname, tname, _skip, &__ctest_##sname##_data, SETUP_FNAME(sname), TEARDOWN_FNAME(sname)) \
  81. void __FNAME(sname, tname)(struct sname##_data* data)
  82. void CTEST_LOG(const char* fmt, ...);
  83. void CTEST_ERR(const char* fmt, ...); // doesn't return
  84. #define CTEST(sname, tname) __CTEST_INTERNAL(sname, tname, 0)
  85. #define CTEST_SKIP(sname, tname) __CTEST_INTERNAL(sname, tname, 1)
  86. #define CTEST2(sname, tname) __CTEST2_INTERNAL(sname, tname, 0)
  87. #define CTEST2_SKIP(sname, tname) __CTEST2_INTERNAL(sname, tname, 1)
  88. void assert_str(const char* exp, const char* real, const char* caller, int line);
  89. #define ASSERT_STR(exp, real) assert_str(exp, real, __FILE__, __LINE__)
  90. void assert_data(const unsigned char* exp, size_t expsize,
  91. const unsigned char* real, size_t realsize,
  92. const char* caller, int line);
  93. #define ASSERT_DATA(exp, expsize, real, realsize) \
  94. assert_data(exp, expsize, real, realsize, __FILE__, __LINE__)
  95. void assert_equal(intmax_t exp, intmax_t real, const char* caller, int line);
  96. #define ASSERT_EQUAL(exp, real) assert_equal(exp, real, __FILE__, __LINE__)
  97. void assert_equal_u(uintmax_t exp, uintmax_t real, const char* caller, int line);
  98. #define ASSERT_EQUAL_U(exp, real) assert_equal_u(exp, real, __FILE__, __LINE__)
  99. void assert_not_equal(intmax_t exp, intmax_t real, const char* caller, int line);
  100. #define ASSERT_NOT_EQUAL(exp, real) assert_not_equal(exp, real, __FILE__, __LINE__)
  101. void assert_not_equal_u(uintmax_t exp, uintmax_t real, const char* caller, int line);
  102. #define ASSERT_NOT_EQUAL_U(exp, real) assert_not_equal_u(exp, real, __FILE__, __LINE__)
  103. void assert_null(void* real, const char* caller, int line);
  104. #define ASSERT_NULL(real) assert_null((void*)real, __FILE__, __LINE__)
  105. void assert_not_null(const void* real, const char* caller, int line);
  106. #define ASSERT_NOT_NULL(real) assert_not_null(real, __FILE__, __LINE__)
  107. void assert_true(int real, const char* caller, int line);
  108. #define ASSERT_TRUE(real) assert_true(real, __FILE__, __LINE__)
  109. void assert_false(int real, const char* caller, int line);
  110. #define ASSERT_FALSE(real) assert_false(real, __FILE__, __LINE__)
  111. void assert_fail(const char* caller, int line);
  112. #define ASSERT_FAIL() assert_fail(__FILE__, __LINE__)
  113. void assert_dbl_near(double exp, double real, double tol, const char* caller, int line);
  114. #define ASSERT_DBL_NEAR(exp, real) assert_dbl_near(exp, real, 1e-4, __FILE__, __LINE__)
  115. #define ASSERT_DBL_NEAR_TOL(exp, real, tol) assert_dbl_near(exp, real, tol, __FILE__, __LINE__)
  116. void assert_dbl_far(double exp, double real, double tol, const char* caller, int line);
  117. #define ASSERT_DBL_FAR(exp, real) assert_dbl_far(exp, real, 1e-4, __FILE__, __LINE__)
  118. #define ASSERT_DBL_FAR_TOL(exp, real, tol) assert_dbl_far(exp, real, tol, __FILE__, __LINE__)
  119. #ifdef CTEST_MAIN
  120. #include <setjmp.h>
  121. #include <stdarg.h>
  122. #include <stdio.h>
  123. #include <string.h>
  124. #include <sys/time.h>
  125. #include <unistd.h>
  126. #include <stdint.h>
  127. #include <stdlib.h>
  128. #ifdef __APPLE__
  129. #include <dlfcn.h>
  130. #endif
  131. static size_t ctest_errorsize;
  132. static char* ctest_errormsg;
  133. #define MSG_SIZE 4096
  134. static char ctest_errorbuffer[MSG_SIZE];
  135. static jmp_buf ctest_err;
  136. static int color_output = 1;
  137. static const char* suite_name;
  138. typedef int (*filter_func)(struct ctest*);
  139. #define ANSI_BLACK "\033[0;30m"
  140. #define ANSI_RED "\033[0;31m"
  141. #define ANSI_GREEN "\033[0;32m"
  142. #define ANSI_YELLOW "\033[0;33m"
  143. #define ANSI_BLUE "\033[0;34m"
  144. #define ANSI_MAGENTA "\033[0;35m"
  145. #define ANSI_CYAN "\033[0;36m"
  146. #define ANSI_GREY "\033[0;37m"
  147. #define ANSI_DARKGREY "\033[01;30m"
  148. #define ANSI_BRED "\033[01;31m"
  149. #define ANSI_BGREEN "\033[01;32m"
  150. #define ANSI_BYELLOW "\033[01;33m"
  151. #define ANSI_BBLUE "\033[01;34m"
  152. #define ANSI_BMAGENTA "\033[01;35m"
  153. #define ANSI_BCYAN "\033[01;36m"
  154. #define ANSI_WHITE "\033[01;37m"
  155. #define ANSI_NORMAL "\033[0m"
  156. static CTEST(suite, test) { }
  157. inline static void vprint_errormsg(const char* const fmt, va_list ap) {
  158. // (v)snprintf returns the number that would have been written
  159. const int ret = vsnprintf(ctest_errormsg, ctest_errorsize, fmt, ap);
  160. if (ret < 0) {
  161. ctest_errormsg[0] = 0x00;
  162. } else {
  163. const size_t size = (size_t) ret;
  164. const size_t s = (ctest_errorsize <= size ? size -ctest_errorsize : size);
  165. // ctest_errorsize may overflow at this point
  166. ctest_errorsize -= s;
  167. ctest_errormsg += s;
  168. }
  169. }
  170. inline static void print_errormsg(const char* const fmt, ...) {
  171. va_list argp;
  172. va_start(argp, fmt);
  173. vprint_errormsg(fmt, argp);
  174. va_end(argp);
  175. }
  176. static void msg_start(const char* color, const char* title) {
  177. if (color_output) {
  178. print_errormsg("%s", color);
  179. }
  180. print_errormsg(" %s: ", title);
  181. }
  182. static void msg_end() {
  183. if (color_output) {
  184. print_errormsg(ANSI_NORMAL);
  185. }
  186. print_errormsg("\n");
  187. }
  188. void CTEST_LOG(const char* fmt, ...)
  189. {
  190. va_list argp;
  191. msg_start(ANSI_BLUE, "LOG");
  192. va_start(argp, fmt);
  193. vprint_errormsg(fmt, argp);
  194. va_end(argp);
  195. msg_end();
  196. }
  197. void CTEST_ERR(const char* fmt, ...)
  198. {
  199. va_list argp;
  200. msg_start(ANSI_YELLOW, "ERR");
  201. va_start(argp, fmt);
  202. vprint_errormsg(fmt, argp);
  203. va_end(argp);
  204. msg_end();
  205. longjmp(ctest_err, 1);
  206. }
  207. void assert_str(const char* exp, const char* real, const char* caller, int line) {
  208. if ((exp == NULL && real != NULL) ||
  209. (exp != NULL && real == NULL) ||
  210. (exp && real && strcmp(exp, real) != 0)) {
  211. CTEST_ERR("%s:%d expected '%s', got '%s'", caller, line, exp, real);
  212. }
  213. }
  214. void assert_data(const unsigned char* exp, size_t expsize,
  215. const unsigned char* real, size_t realsize,
  216. const char* caller, int line) {
  217. size_t i;
  218. if (expsize != realsize) {
  219. CTEST_ERR("%s:%d expected %" PRIuMAX " bytes, got %" PRIuMAX, caller, line, (uintmax_t) expsize, (uintmax_t) realsize);
  220. }
  221. for (i=0; i<expsize; i++) {
  222. if (exp[i] != real[i]) {
  223. CTEST_ERR("%s:%d expected 0x%02x at offset %" PRIuMAX " got 0x%02x",
  224. caller, line, exp[i], (uintmax_t) i, real[i]);
  225. }
  226. }
  227. }
  228. void assert_equal(intmax_t exp, intmax_t real, const char* caller, int line) {
  229. if (exp != real) {
  230. CTEST_ERR("%s:%d expected %" PRIdMAX ", got %" PRIdMAX, caller, line, exp, real);
  231. }
  232. }
  233. void assert_equal_u(uintmax_t exp, uintmax_t real, const char* caller, int line) {
  234. if (exp != real) {
  235. CTEST_ERR("%s:%d expected %" PRIuMAX ", got %" PRIuMAX, caller, line, exp, real);
  236. }
  237. }
  238. void assert_not_equal(intmax_t exp, intmax_t real, const char* caller, int line) {
  239. if ((exp) == (real)) {
  240. CTEST_ERR("%s:%d should not be %" PRIdMAX, caller, line, real);
  241. }
  242. }
  243. void assert_not_equal_u(uintmax_t exp, uintmax_t real, const char* caller, int line) {
  244. if ((exp) == (real)) {
  245. CTEST_ERR("%s:%d should not be %" PRIuMAX, caller, line, real);
  246. }
  247. }
  248. void assert_dbl_near(double exp, double real, double tol, const char* caller, int line) {
  249. double diff = exp - real;
  250. double absdiff = diff;
  251. /* avoid using fabs and linking with a math lib */
  252. if(diff < 0) {
  253. absdiff *= -1;
  254. }
  255. if (absdiff > tol) {
  256. CTEST_ERR("%s:%d expected %0.3e, got %0.3e (diff %0.3e, tol %0.3e)", caller, line, exp, real, diff, tol);
  257. }
  258. }
  259. void assert_dbl_far(double exp, double real, double tol, const char* caller, int line) {
  260. double diff = exp - real;
  261. double absdiff = diff;
  262. /* avoid using fabs and linking with a math lib */
  263. if(diff < 0) {
  264. absdiff *= -1;
  265. }
  266. if (absdiff <= tol) {
  267. CTEST_ERR("%s:%d expected %0.3e, got %0.3e (diff %0.3e, tol %0.3e)", caller, line, exp, real, diff, tol);
  268. }
  269. }
  270. void assert_null(void* real, const char* caller, int line) {
  271. if ((real) != NULL) {
  272. CTEST_ERR("%s:%d should be NULL", caller, line);
  273. }
  274. }
  275. void assert_not_null(const void* real, const char* caller, int line) {
  276. if (real == NULL) {
  277. CTEST_ERR("%s:%d should not be NULL", caller, line);
  278. }
  279. }
  280. void assert_true(int real, const char* caller, int line) {
  281. if ((real) == 0) {
  282. CTEST_ERR("%s:%d should be true", caller, line);
  283. }
  284. }
  285. void assert_false(int real, const char* caller, int line) {
  286. if ((real) != 0) {
  287. CTEST_ERR("%s:%d should be false", caller, line);
  288. }
  289. }
  290. void assert_fail(const char* caller, int line) {
  291. CTEST_ERR("%s:%d shouldn't come here", caller, line);
  292. }
  293. static int suite_all(struct ctest* t) {
  294. (void) t; // fix unused parameter warning
  295. return 1;
  296. }
  297. static int suite_filter(struct ctest* t) {
  298. return strncmp(suite_name, t->ssname, strlen(suite_name)) == 0;
  299. }
  300. static uint64_t getCurrentTime() {
  301. struct timeval now;
  302. gettimeofday(&now, NULL);
  303. uint64_t now64 = (uint64_t) now.tv_sec;
  304. now64 *= 1000000;
  305. now64 += ((uint64_t) now.tv_usec);
  306. return now64;
  307. }
  308. static void color_print(const char* color, const char* text) {
  309. if (color_output)
  310. printf("%s%s"ANSI_NORMAL"\n", color, text);
  311. else
  312. printf("%s\n", text);
  313. }
  314. #ifdef __APPLE__
  315. static void *find_symbol(struct ctest *test, const char *fname)
  316. {
  317. size_t len = strlen(test->ssname) + 1 + strlen(fname);
  318. char *symbol_name = (char *) malloc(len + 1);
  319. memset(symbol_name, 0, len + 1);
  320. snprintf(symbol_name, len + 1, "%s_%s", test->ssname, fname);
  321. //fprintf(stderr, ">>>> dlsym: loading %s\n", symbol_name);
  322. void *symbol = dlsym(RTLD_DEFAULT, symbol_name);
  323. if (!symbol) {
  324. //fprintf(stderr, ">>>> ERROR: %s\n", dlerror());
  325. }
  326. // returns NULL on error
  327. free(symbol_name);
  328. return symbol;
  329. }
  330. #endif
  331. #ifdef CTEST_SEGFAULT
  332. #include <signal.h>
  333. static void sighandler(int signum)
  334. {
  335. char msg[128];
  336. sprintf(msg, "[SIGNAL %d: %s]", signum, sys_siglist[signum]);
  337. color_print(ANSI_BRED, msg);
  338. fflush(stdout);
  339. /* "Unregister" the signal handler and send the signal back to the process
  340. * so it can terminate as expected */
  341. signal(signum, SIG_DFL);
  342. kill(getpid(), signum);
  343. }
  344. #endif
  345. int ctest_main(int argc, const char *argv[])
  346. {
  347. static int total = 0;
  348. static int num_ok = 0;
  349. static int num_fail = 0;
  350. static int num_skip = 0;
  351. static int index = 1;
  352. static filter_func filter = suite_all;
  353. #ifdef CTEST_SEGFAULT
  354. signal(SIGSEGV, sighandler);
  355. #endif
  356. if (argc == 2) {
  357. suite_name = argv[1];
  358. filter = suite_filter;
  359. }
  360. #ifdef CTEST_NO_COLORS
  361. color_output = 0;
  362. #else
  363. color_output = isatty(1);
  364. #endif
  365. uint64_t t1 = getCurrentTime();
  366. struct ctest* ctest_begin = &__TNAME(suite, test);
  367. struct ctest* ctest_end = &__TNAME(suite, test);
  368. // find begin and end of section by comparing magics
  369. while (1) {
  370. struct ctest* t = ctest_begin-1;
  371. if (t->magic != __CTEST_MAGIC) break;
  372. ctest_begin--;
  373. }
  374. while (1) {
  375. struct ctest* t = ctest_end+1;
  376. if (t->magic != __CTEST_MAGIC) break;
  377. ctest_end++;
  378. }
  379. ctest_end++; // end after last one
  380. static struct ctest* test;
  381. for (test = ctest_begin; test != ctest_end; test++) {
  382. if (test == &__TNAME(suite, test)) continue;
  383. if (filter(test)) total++;
  384. }
  385. for (test = ctest_begin; test != ctest_end; test++) {
  386. if (test == &__TNAME(suite, test)) continue;
  387. if (filter(test)) {
  388. ctest_errorbuffer[0] = 0;
  389. ctest_errorsize = MSG_SIZE-1;
  390. ctest_errormsg = ctest_errorbuffer;
  391. printf("TEST %d/%d %s:%s ", index, total, test->ssname, test->ttname);
  392. fflush(stdout);
  393. if (test->skip) {
  394. color_print(ANSI_BYELLOW, "[SKIPPED]");
  395. num_skip++;
  396. } else {
  397. int result = setjmp(ctest_err);
  398. if (result == 0) {
  399. #ifdef __APPLE__
  400. if (!test->setup) {
  401. test->setup = (SetupFunc) find_symbol(test, "setup");
  402. }
  403. if (!test->teardown) {
  404. test->teardown = (TearDownFunc) find_symbol(test, "teardown");
  405. }
  406. #endif
  407. if (test->setup) test->setup(test->data);
  408. if (test->data)
  409. test->run(test->data);
  410. else
  411. test->run();
  412. if (test->teardown) test->teardown(test->data);
  413. // if we got here it's ok
  414. #ifdef CTEST_COLOR_OK
  415. color_print(ANSI_BGREEN, "[OK]");
  416. #else
  417. printf("[OK]\n");
  418. #endif
  419. num_ok++;
  420. } else {
  421. color_print(ANSI_BRED, "[FAIL]");
  422. num_fail++;
  423. }
  424. if (ctest_errorsize != MSG_SIZE-1) printf("%s", ctest_errorbuffer);
  425. }
  426. index++;
  427. }
  428. }
  429. uint64_t t2 = getCurrentTime();
  430. const char* color = (num_fail) ? ANSI_BRED : ANSI_GREEN;
  431. char results[80];
  432. sprintf(results, "RESULTS: %d tests (%d ok, %d failed, %d skipped) ran in %" PRIu64 " ms", total, num_ok, num_fail, num_skip, (t2 - t1)/1000);
  433. color_print(color, results);
  434. return num_fail;
  435. }
  436. #endif
  437. #endif