2 libtap - Write tests in C
3 Copyright 2012 Jake Gelbman <gelbman@gmail.com>
4 This file is licensed under the GPLv2 or any later version
15 static int expected_tests = NO_PLAN;
16 static int failed_tests;
17 static int current_test;
18 static char *todo_mesg;
21 vstrdupf (const char *fmt, va_list args) {
28 size = vsnprintf(NULL, 0, fmt, args2) + 2;
31 perror("malloc error");
34 vsprintf(str, fmt, args);
40 tap_plan (int tests, const char *fmt, ...) {
41 expected_tests = tests;
42 if (tests == SKIP_ALL) {
46 why = vstrdupf(fmt, args);
49 note("SKIP %s\n", why);
52 if (tests != NO_PLAN) {
53 printf("1..%d\n", tests);
58 vok_at_loc (const char *file, int line, int test, const char *fmt,
61 char *name = vstrdupf(fmt, args);
64 printf("ok %d", ++current_test);
66 printf(" - %s", name);
70 printf(" %s", todo_mesg);
74 fprintf(stderr, "# Failed ");
76 fprintf(stderr, "(TODO) ");
77 fprintf(stderr, "test ");
79 fprintf(stderr, "'%s'\n# ", name);
80 fprintf(stderr, "at %s line %d.\n", file, line);
89 ok_at_loc (const char *file, int line, int test, const char *fmt, ...) {
92 vok_at_loc(file, line, test, fmt, args);
98 mystrcmp (const char *a, const char *b) {
99 return a == b ? 0 : !a ? -1 : !b ? 1 : strcmp(a, b);
102 #define eq(a, b) (!mystrcmp(a, b))
103 #define ne(a, b) (mystrcmp(a, b))
106 is_at_loc (const char *file, int line, const char *got, const char *expected,
107 const char *fmt, ...)
109 int test = eq(got, expected);
112 vok_at_loc(file, line, test, fmt, args);
115 diag(" got: '%s'", got);
116 diag(" expected: '%s'", expected);
122 isnt_at_loc (const char *file, int line, const char *got, const char *expected,
123 const char *fmt, ...)
125 int test = ne(got, expected);
128 vok_at_loc(file, line, test, fmt, args);
131 diag(" got: '%s'", got);
132 diag(" expected: anything else");
138 cmp_ok_at_loc (const char *file, int line, int a, const char *op, int b,
139 const char *fmt, ...)
141 int test = 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 : eq(op, "<") ? a < b
149 : eq(op, ">") ? a > b
150 : eq(op, "<=") ? a <= b
151 : eq(op, ">=") ? a >= b
152 : eq(op, "<<") ? a << b
153 : eq(op, ">>") ? a >> b
154 : eq(op, "+") ? a + b
155 : eq(op, "-") ? a - b
156 : eq(op, "*") ? a * b
157 : eq(op, "/") ? a / b
158 : eq(op, "%") ? a % b
159 : diag("unrecognized operator '%s'", op);
162 vok_at_loc(file, line, test, fmt, args);
173 cmp_mem_at_loc (const char *file, int line, const void *got,
174 const void *expected, size_t n, const char *fmt, ...)
177 int test = 1; /* assume success */
179 if ((got == NULL) || (expected == NULL)) {
182 else if (got != expected) {
183 /* got and expected point to different memory: compare byte per byte */
184 for (i = 0; i < n; ++i) {
185 if (((char *)got)[i] != ((char *)expected)[i]) {
194 vok_at_loc(file, line, test, fmt, args);
198 if ((got == NULL) || (expected == NULL)) {
199 diag(" got and/or expected are NULL");
200 diag(" got: %s", got ? "not NULL" : "NULL");
201 diag(" expected: %s", expected ? "not NULL" : "NULL");
204 diag(" Difference starts at offset %d", i);
205 diag(" got: 0x%02x", ((unsigned char *)got)[i]);
206 diag(" expected: 0x%02x", ((unsigned char *)expected)[i]);
213 vdiag_to_fh (FILE *fh, const char *fmt, va_list args) {
218 mesg = vstrdupf(fmt, args);
220 for (i = 0; *line; i++) {
222 if (!c || c == '\n') {
224 fprintf(fh, "# %s\n", line);
236 diag (const char *fmt, ...) {
239 vdiag_to_fh(stderr, fmt, args);
245 note (const char *fmt, ...) {
248 vdiag_to_fh(stdout, fmt, args);
256 if (expected_tests == NO_PLAN) {
257 printf("1..%d\n", current_test);
259 else if (current_test != expected_tests) {
260 diag("Looks like you planned %d test%s but ran %d.",
261 expected_tests, expected_tests > 1 ? "s" : "", current_test);
265 diag("Looks like you failed %d test%s of %d run.",
266 failed_tests, failed_tests > 1 ? "s" : "", current_test);
267 if (expected_tests == NO_PLAN)
268 retval = failed_tests;
270 retval = expected_tests - current_test + failed_tests;
276 bail_out (int ignore, const char *fmt, ...) {
279 printf("Bail out! ");
288 tap_skip (int n, const char *fmt, ...) {
292 why = vstrdupf(fmt, args);
295 printf("ok %d ", ++current_test);
296 note("skip %s\n", why);
302 tap_todo (int ignore, const char *fmt, ...) {
305 todo_mesg = vstrdupf(fmt, args);
316 #include <sys/mman.h>
317 #include <sys/param.h>
320 #if defined __APPLE__ || defined BSD
321 #define MAP_ANONYMOUS MAP_ANON
324 /* Create a shared memory int to keep track of whether a piece of code executed
325 dies. to be used in the dies_ok and lives_ok macros. */
327 tap_test_died (int status) {
328 static int *test_died = NULL;
331 test_died = mmap(0, sizeof (int), PROT_READ | PROT_WRITE,
332 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
341 like_at_loc (int for_match, const char *file, int line, const char *got,
342 const char *expected, const char *fmt, ...)
347 int err = regcomp(&re, expected, REG_EXTENDED);
350 regerror(err, &re, errbuf, sizeof errbuf);
351 fprintf(stderr, "Unable to compile regex '%s': %s at %s line %d\n",
352 expected, errbuf, file, line);
355 err = regexec(&re, got, 0, NULL, 0);
357 test = for_match ? !err : err;
359 vok_at_loc(file, line, test, fmt, args);
364 diag(" doesn't match: '%s'", expected);
368 diag(" matches: '%s'", expected);