2 libtap - Write tests in C
3 Copyright 2012 Jake Gelbman <gelbman@gmail.com>
4 This file is licensed under the LGPL
7 #define _DEFAULT_SOURCE 1
13 #include <sys/types.h>
17 static int expected_tests = NO_PLAN;
18 static int failed_tests;
19 static int current_test;
20 static char *todo_mesg;
23 vstrdupf (const char *fmt, va_list args) {
30 size = vsnprintf(NULL, 0, fmt, args2) + 2;
33 perror("malloc error");
36 vsprintf(str, fmt, args);
42 tap_plan (int tests, const char *fmt, ...) {
43 expected_tests = tests;
44 if (tests == SKIP_ALL) {
48 why = vstrdupf(fmt, args);
51 diag("SKIP %s\n", why);
54 if (tests != NO_PLAN) {
55 printf("1..%d\n", tests);
60 vok_at_loc (const char *file, int line, int test, const char *fmt,
63 char *name = vstrdupf(fmt, args);
67 printf("ok %d", ++current_test);
69 printf(" - %s", name);
73 printf(" %s", todo_mesg);
82 printf("'%s'\n# ", name);
83 printf("at %s line %d.\n", file, line);
92 ok_at_loc (const char *file, int line, int test, const char *fmt, ...) {
95 vok_at_loc(file, line, test, fmt, args);
101 mystrcmp (const char *a, const char *b) {
102 return a == b ? 0 : !a ? -1 : !b ? 1 : strcmp(a, b);
105 #define eq(a, b) (!mystrcmp(a, b))
106 #define ne(a, b) (mystrcmp(a, b))
109 is_at_loc (const char *file, int line, const char *got, const char *expected,
110 const char *fmt, ...)
112 int test = eq(got, expected);
115 vok_at_loc(file, line, test, fmt, args);
118 diag(" got: '%s'", got);
119 diag(" expected: '%s'", expected);
125 isnt_at_loc (const char *file, int line, const char *got, const char *expected,
126 const char *fmt, ...)
128 int test = ne(got, expected);
131 vok_at_loc(file, line, test, fmt, args);
134 diag(" got: '%s'", got);
135 diag(" expected: anything else");
141 cmp_ok_at_loc (const char *file, int line, int a, const char *op, int b,
142 const char *fmt, ...)
144 int test = 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 : eq(op, "*") ? a * b
160 : eq(op, "/") ? a / b
161 : eq(op, "%") ? a % b
162 : diag("unrecognized operator '%s'", op);
165 vok_at_loc(file, line, test, fmt, args);
176 find_mem_diff (const char *a, const char *b, size_t n, size_t *offset) {
182 for (i = 0; i < n; i++) {
192 cmp_mem_at_loc (const char *file, int line, const void *got,
193 const void *expected, size_t n, const char *fmt, ...)
196 int diff = find_mem_diff(got, expected, n, &offset);
199 vok_at_loc(file, line, !diff, fmt, args);
202 diag(" Difference starts at offset %d", offset);
203 diag(" got: 0x%02x", ((unsigned char *)got)[offset]);
204 diag(" expected: 0x%02x", ((unsigned char *)expected)[offset]);
206 else if (diff == 2) {
207 diag(" got: %s", got ? "not NULL" : "NULL");
208 diag(" expected: %s", expected ? "not NULL" : "NULL");
214 diag (const char *fmt, ...) {
223 mesg = vstrdupf(fmt, args);
225 for (i = 0; *line; i++) {
227 if (!c || c == '\n') {
229 printf("# %s\n", line);
244 if (expected_tests == NO_PLAN) {
245 printf("1..%d\n", current_test);
247 else if (current_test != expected_tests) {
248 diag("Looks like you planned %d test%s but ran %d.",
249 expected_tests, expected_tests > 1 ? "s" : "", current_test);
253 diag("Looks like you failed %d test%s of %d run.",
254 failed_tests, failed_tests > 1 ? "s" : "", current_test);
261 bail_out (int ignore, const char *fmt, ...) {
265 printf("Bail out! ");
274 tap_skip (int n, const char *fmt, ...) {
278 why = vstrdupf(fmt, args);
281 printf("ok %d ", ++current_test);
282 diag("skip %s\n", why);
288 tap_todo (int ignore, const char *fmt, ...) {
292 todo_mesg = vstrdupf(fmt, args);
303 #include <sys/mman.h>
304 #include <sys/param.h>
307 #ifndef MAP_ANONYMOUS
309 #define MAP_ANONYMOUS MAP_ANON
311 #error "System does not support mapping anonymous pages"
315 /* Create a shared memory int to keep track of whether a piece of code executed
316 dies. to be used in the dies_ok and lives_ok macros. */
318 tap_test_died (int status) {
319 static int *test_died = NULL;
322 test_died = mmap(0, sizeof (int), PROT_READ | PROT_WRITE,
323 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
332 like_at_loc (int for_match, const char *file, int line, const char *got,
333 const char *expected, const char *fmt, ...)
338 int err = regcomp(&re, expected, REG_EXTENDED);
341 regerror(err, &re, errbuf, sizeof errbuf);
342 fprintf(stderr, "Unable to compile regex '%s': %s at %s line %d\n",
343 expected, errbuf, file, line);
346 err = regexec(&re, got, 0, NULL, 0);
348 test = for_match ? !err : err;
350 vok_at_loc(file, line, test, fmt, args);
355 diag(" doesn't match: '%s'", expected);
359 diag(" matches: '%s'", expected);