2
0

tap.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /*
  2. libtap - Write tests in C
  3. Copyright 2012 Jake Gelbman <gelbman@gmail.com>
  4. This file is licensed under the LGPL
  5. */
  6. #define _DEFAULT_SOURCE 1
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <stdarg.h>
  10. #include <string.h>
  11. #include "tap.h"
  12. static int expected_tests = NO_PLAN;
  13. static int failed_tests;
  14. static int current_test;
  15. static char *todo_mesg;
  16. static char *
  17. vstrdupf (const char *fmt, va_list args) {
  18. char *str;
  19. int size;
  20. va_list args2;
  21. va_copy(args2, args);
  22. if (!fmt)
  23. fmt = "";
  24. size = vsnprintf(NULL, 0, fmt, args2) + 2;
  25. str = malloc(size);
  26. if (!str) {
  27. perror("malloc error");
  28. exit(1);
  29. }
  30. vsprintf(str, fmt, args);
  31. va_end(args2);
  32. return str;
  33. }
  34. void
  35. tap_plan (int tests, const char *fmt, ...) {
  36. expected_tests = tests;
  37. if (tests == SKIP_ALL) {
  38. char *why;
  39. va_list args;
  40. va_start(args, fmt);
  41. why = vstrdupf(fmt, args);
  42. va_end(args);
  43. printf("1..0 ");
  44. diag("SKIP %s\n", why);
  45. exit(0);
  46. }
  47. if (tests != NO_PLAN) {
  48. printf("1..%d\n", tests);
  49. }
  50. }
  51. int
  52. vok_at_loc (const char *file, int line, int test, const char *fmt,
  53. va_list args)
  54. {
  55. char *name = vstrdupf(fmt, args);
  56. if (!test) {
  57. printf("not ");
  58. }
  59. printf("ok %d", ++current_test);
  60. if (*name)
  61. printf(" - %s", name);
  62. if (todo_mesg) {
  63. printf(" # TODO");
  64. if (*todo_mesg)
  65. printf(" %s", todo_mesg);
  66. }
  67. printf("\n");
  68. if (!test) {
  69. printf("# Failed ");
  70. if (todo_mesg)
  71. printf("(TODO) ");
  72. printf("test ");
  73. if (*name)
  74. printf("'%s'\n# ", name);
  75. printf("at %s line %d.\n", file, line);
  76. if (!todo_mesg)
  77. failed_tests++;
  78. }
  79. free(name);
  80. return test;
  81. }
  82. int
  83. ok_at_loc (const char *file, int line, int test, const char *fmt, ...) {
  84. va_list args;
  85. va_start(args, fmt);
  86. vok_at_loc(file, line, test, fmt, args);
  87. va_end(args);
  88. return test;
  89. }
  90. static int
  91. mystrcmp (const char *a, const char *b) {
  92. return a == b ? 0 : !a ? -1 : !b ? 1 : strcmp(a, b);
  93. }
  94. #define eq(a, b) (!mystrcmp(a, b))
  95. #define ne(a, b) (mystrcmp(a, b))
  96. int
  97. is_at_loc (const char *file, int line, const char *got, const char *expected,
  98. const char *fmt, ...)
  99. {
  100. int test = eq(got, expected);
  101. va_list args;
  102. va_start(args, fmt);
  103. vok_at_loc(file, line, test, fmt, args);
  104. va_end(args);
  105. if (!test) {
  106. diag(" got: '%s'", got);
  107. diag(" expected: '%s'", expected);
  108. }
  109. return test;
  110. }
  111. int
  112. isnt_at_loc (const char *file, int line, const char *got, const char *expected,
  113. const char *fmt, ...)
  114. {
  115. int test = ne(got, expected);
  116. va_list args;
  117. va_start(args, fmt);
  118. vok_at_loc(file, line, test, fmt, args);
  119. va_end(args);
  120. if (!test) {
  121. diag(" got: '%s'", got);
  122. diag(" expected: anything else");
  123. }
  124. return test;
  125. }
  126. int
  127. cmp_ok_at_loc (const char *file, int line, int a, const char *op, int b,
  128. const char *fmt, ...)
  129. {
  130. int test = eq(op, "||") ? a || b
  131. : eq(op, "&&") ? a && b
  132. : eq(op, "|") ? a | b
  133. : eq(op, "^") ? a ^ b
  134. : eq(op, "&") ? a & b
  135. : eq(op, "==") ? a == b
  136. : eq(op, "!=") ? a != b
  137. : eq(op, "<") ? a < b
  138. : eq(op, ">") ? a > b
  139. : eq(op, "<=") ? a <= b
  140. : eq(op, ">=") ? a >= b
  141. : eq(op, "<<") ? a << b
  142. : eq(op, ">>") ? a >> b
  143. : eq(op, "+") ? a + b
  144. : eq(op, "-") ? a - b
  145. : eq(op, "*") ? a * b
  146. : eq(op, "/") ? a / b
  147. : eq(op, "%") ? a % b
  148. : diag("unrecognized operator '%s'", op);
  149. va_list args;
  150. va_start(args, fmt);
  151. vok_at_loc(file, line, test, fmt, args);
  152. va_end(args);
  153. if (!test) {
  154. diag(" %d", a);
  155. diag(" %s", op);
  156. diag(" %d", b);
  157. }
  158. return test;
  159. }
  160. static int
  161. find_mem_diff (const char *a, const char *b, size_t n, size_t *offset) {
  162. size_t i;
  163. if (a == b)
  164. return 0;
  165. if (!a || !b)
  166. return 2;
  167. for (i = 0; i < n; i++) {
  168. if (a[i] != b[i]) {
  169. *offset = i;
  170. return 1;
  171. }
  172. }
  173. return 0;
  174. }
  175. int
  176. cmp_mem_at_loc (const char *file, int line, const void *got,
  177. const void *expected, size_t n, const char *fmt, ...)
  178. {
  179. size_t offset;
  180. int diff = find_mem_diff(got, expected, n, &offset);
  181. va_list args;
  182. va_start(args, fmt);
  183. vok_at_loc(file, line, !diff, fmt, args);
  184. va_end(args);
  185. if (diff == 1) {
  186. diag(" Difference starts at offset %d", offset);
  187. diag(" got: 0x%02x", ((unsigned char *)got)[offset]);
  188. diag(" expected: 0x%02x", ((unsigned char *)expected)[offset]);
  189. }
  190. else if (diff == 2) {
  191. diag(" got: %s", got ? "not NULL" : "NULL");
  192. diag(" expected: %s", expected ? "not NULL" : "NULL");
  193. }
  194. return !diff;
  195. }
  196. int
  197. diag (const char *fmt, ...) {
  198. va_list args;
  199. char *mesg, *line;
  200. int i;
  201. va_start(args, fmt);
  202. if (!fmt)
  203. return 0;
  204. mesg = vstrdupf(fmt, args);
  205. line = mesg;
  206. for (i = 0; *line; i++) {
  207. char c = mesg[i];
  208. if (!c || c == '\n') {
  209. mesg[i] = '\0';
  210. printf("# %s\n", line);
  211. if (!c)
  212. break;
  213. mesg[i] = c;
  214. line = mesg + i + 1;
  215. }
  216. }
  217. free(mesg);
  218. va_end(args);
  219. return 0;
  220. }
  221. int
  222. exit_status () {
  223. int retval = 0;
  224. if (expected_tests == NO_PLAN) {
  225. printf("1..%d\n", current_test);
  226. }
  227. else if (current_test != expected_tests) {
  228. diag("Looks like you planned %d test%s but ran %d.",
  229. expected_tests, expected_tests > 1 ? "s" : "", current_test);
  230. retval = 2;
  231. }
  232. if (failed_tests) {
  233. diag("Looks like you failed %d test%s of %d run.",
  234. failed_tests, failed_tests > 1 ? "s" : "", current_test);
  235. retval = 1;
  236. }
  237. return retval;
  238. }
  239. int
  240. bail_out (int ignore, const char *fmt, ...) {
  241. va_list args;
  242. va_start(args, fmt);
  243. printf("Bail out! ");
  244. vprintf(fmt, args);
  245. printf("\n");
  246. va_end(args);
  247. exit(255);
  248. return 0;
  249. }
  250. void
  251. tap_skip (int n, const char *fmt, ...) {
  252. char *why;
  253. va_list args;
  254. va_start(args, fmt);
  255. why = vstrdupf(fmt, args);
  256. va_end(args);
  257. while (n --> 0) {
  258. printf("ok %d ", ++current_test);
  259. diag("skip %s\n", why);
  260. }
  261. free(why);
  262. }
  263. void
  264. tap_todo (int ignore, const char *fmt, ...) {
  265. va_list args;
  266. va_start(args, fmt);
  267. todo_mesg = vstrdupf(fmt, args);
  268. va_end(args);
  269. }
  270. void
  271. tap_end_todo () {
  272. free(todo_mesg);
  273. todo_mesg = NULL;
  274. }
  275. #ifndef _WIN32
  276. #include <sys/mman.h>
  277. #include <sys/param.h>
  278. #include <regex.h>
  279. #if defined __APPLE__ || defined BSD
  280. #define MAP_ANONYMOUS MAP_ANON
  281. #endif
  282. /* Create a shared memory int to keep track of whether a piece of code executed
  283. dies. to be used in the dies_ok and lives_ok macros. */
  284. int
  285. tap_test_died (int status) {
  286. static int *test_died = NULL;
  287. int prev;
  288. if (!test_died) {
  289. test_died = mmap(0, sizeof (int), PROT_READ | PROT_WRITE,
  290. MAP_SHARED | MAP_ANONYMOUS, -1, 0);
  291. *test_died = 0;
  292. }
  293. prev = *test_died;
  294. *test_died = status;
  295. return prev;
  296. }
  297. int
  298. like_at_loc (int for_match, const char *file, int line, const char *got,
  299. const char *expected, const char *fmt, ...)
  300. {
  301. int test;
  302. regex_t re;
  303. va_list args;
  304. int err = regcomp(&re, expected, REG_EXTENDED);
  305. if (err) {
  306. char errbuf[256];
  307. regerror(err, &re, errbuf, sizeof errbuf);
  308. fprintf(stderr, "Unable to compile regex '%s': %s at %s line %d\n",
  309. expected, errbuf, file, line);
  310. exit(255);
  311. }
  312. err = regexec(&re, got, 0, NULL, 0);
  313. regfree(&re);
  314. test = for_match ? !err : err;
  315. va_start(args, fmt);
  316. vok_at_loc(file, line, test, fmt, args);
  317. va_end(args);
  318. if (!test) {
  319. if (for_match) {
  320. diag(" '%s'", got);
  321. diag(" doesn't match: '%s'", expected);
  322. }
  323. else {
  324. diag(" '%s'", got);
  325. diag(" matches: '%s'", expected);
  326. }
  327. }
  328. return test;
  329. }
  330. #endif