mailmap: add mail alias
[transsip.git] / src / test / tap.c
blob2aaf326763c12c44684722c47e9afa89a0440939
1 /*
2 * transsip - the telephony toolkit
3 * libtap (Write tests in C, by Jake Gelbman)
4 * Copyright 2012 Jake Gelbman <gelbman@gmail.com>
5 * Copyright 2012 Daniel Borkmann <borkmann@iogearbox.net>
6 * Subject to the GPL, version 2.
7 */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <stdarg.h>
12 #include <string.h>
13 #include <sys/mman.h>
14 #include <sys/param.h>
15 #include <regex.h>
17 #include "tap.h"
18 #include "../die.h"
19 #include "../xmalloc.h"
20 #include "../xutils.h"
22 static int expected_tests = NO_PLAN, failed_tests, current_test;
23 static char *todo_mesg;
25 static char *vstrdupf(const char *fmt, va_list args)
27 char *str;
28 int size;
29 va_list args2;
31 va_copy(args2, args);
32 if (!fmt)
33 fmt = "";
35 size = vsnprintf(NULL, 0, fmt, args2) + 2;
36 str = xmalloc(size);
38 vsprintf(str, fmt, args);
39 va_end(args2);
41 return str;
44 void cplan(int tests, const char *fmt, ...)
46 expected_tests = tests;
48 if (tests == SKIP_ALL) {
49 char *why;
50 va_list args;
52 va_start(args, fmt);
53 why = vstrdupf(fmt, args);
54 va_end(args);
56 printf("1..0 ");
57 note("SKIP %s\n", why);
59 die();
62 if (tests != NO_PLAN)
63 printf("1..%d\n", tests);
66 int vok_at_loc(const char *file, int line, int test, const char *fmt,
67 va_list args)
69 char *name = vstrdupf(fmt, args);
71 printf("%sok %d", test ? colorize_start(green) colorize_start(bold) :
72 colorize_start(red) colorize_start(bold) "not ", ++current_test);
74 if (*name)
75 printf(" - %s", name);
76 if (todo_mesg) {
77 printf(" # TODO");
78 if (*todo_mesg)
79 printf(" %s", todo_mesg);
82 printf("%s\n", colorize_end());
84 if (!test) {
85 if (*name)
86 diag(" %sFailed%s test '%s'\n at %s line %d.%s",
87 colorize_start(red), todo_mesg ? " (TODO)" : "",
88 name, file, line, colorize_end());
89 else
90 diag(" %sFailed%s test at %s line %d.%s",
91 colorize_start(red), todo_mesg ? " (TODO)" : "",
92 file, line, colorize_end());
93 if (!todo_mesg)
94 failed_tests++;
97 xfree(name);
98 return test;
101 int ok_at_loc(const char *file, int line, int test, const char *fmt, ...)
103 va_list args;
105 va_start(args, fmt);
106 vok_at_loc(file, line, test, fmt, args);
107 va_end(args);
109 return test;
112 static inline int mystrcmp (const char *a, const char *b)
114 return a == b ? 0 : !a ? -1 : !b ? 1 : strcmp(a, b);
117 #define eq(a, b) (!mystrcmp(a, b))
118 #define ne(a, b) (mystrcmp(a, b))
120 int is_at_loc(const char *file, int line, const char *got, const char *expected,
121 const char *fmt, ...)
123 int test = eq(got, expected);
124 va_list args;
126 va_start(args, fmt);
127 vok_at_loc(file, line, test, fmt, args);
128 va_end(args);
130 if (!test) {
131 diag(" %sgot: '%s'", colorize_start(red), got);
132 diag(" expected: '%s'%s", expected, colorize_end());
135 return test;
138 int isnt_at_loc(const char *file, int line, const char *got,
139 const char *expected, const char *fmt, ...)
141 int test = ne(got, expected);
142 va_list args;
144 va_start(args, fmt);
145 vok_at_loc(file, line, test, fmt, args);
146 va_end(args);
148 if (!test) {
149 diag(" %sgot: '%s'", colorize_start(red), got);
150 diag(" expected: anything else%s", colorize_end());
153 return test;
156 int cmp_ok_at_loc(const char *file, int line, int a, const char *op, int b,
157 const char *fmt, ...)
159 va_list args;
160 int test = eq(op, "||") ? a || b
161 : eq(op, "&&") ? a && b
162 : eq(op, "|") ? a | b
163 : eq(op, "^") ? a ^ b
164 : eq(op, "&") ? a & b
165 : eq(op, "==") ? a == b
166 : eq(op, "!=") ? a != b
167 : eq(op, "<") ? a < b
168 : eq(op, ">") ? a > b
169 : eq(op, "<=") ? a <= b
170 : eq(op, ">=") ? a >= b
171 : eq(op, "<<") ? a << b
172 : eq(op, ">>") ? a >> b
173 : eq(op, "+") ? a + b
174 : eq(op, "-") ? a - b
175 : eq(op, "*") ? a * b
176 : eq(op, "/") ? a / b
177 : eq(op, "%") ? a % b
178 : diag("unrecognized operator '%s'", op);
180 va_start(args, fmt);
181 vok_at_loc(file, line, test, fmt, args);
182 va_end(args);
184 if (!test) {
185 diag(" %s%d", colorize_start(red), a);
186 diag(" %s", op);
187 diag(" %d%s", b, colorize_end());
190 return test;
193 static void vdiag_to_fh(FILE *fh, const char *fmt, va_list args)
195 int i;
196 char *mesg, *line;
198 if (!fmt)
199 return;
201 mesg = vstrdupf(fmt, args);
202 line = mesg;
204 for (i = 0; *line; i++) {
205 char c = mesg[i];
206 if (!c || c == '\n') {
207 mesg[i] = '\0';
208 fprintf(fh, "%s# %s%s\n", colorize_start(red),
209 line, colorize_end());
210 if (!c)
211 break;
212 mesg[i] = c;
213 line = mesg + i + 1;
217 xfree(mesg);
218 return;
221 int diag(const char *fmt, ...)
223 va_list args;
225 va_start(args, fmt);
226 vdiag_to_fh(stderr, fmt, args);
227 va_end(args);
229 return 0;
232 int note(const char *fmt, ...)
234 va_list args;
236 va_start(args, fmt);
237 vdiag_to_fh(stdout, fmt, args);
238 va_end(args);
240 return 0;
243 int exit_status(void)
245 int retval = 0;
247 if (expected_tests == NO_PLAN) {
248 printf("1..%d\n", current_test);
249 } else if (current_test != expected_tests) {
250 diag("Looks like you planned %d test%s but ran %d.",
251 expected_tests, expected_tests > 1 ? "s" : "",
252 current_test);
254 retval = 255;
257 if (failed_tests) {
258 diag("Looks like you failed %d test%s of %d run.",
259 failed_tests, failed_tests > 1 ? "s" : "",
260 current_test);
262 if (expected_tests == NO_PLAN)
263 retval = failed_tests;
264 else
265 retval = expected_tests - current_test + failed_tests;
268 return retval;
271 int bail_out(int ignore, const char *fmt, ...)
273 va_list args;
275 va_start(args, fmt);
276 printf("Bail out! ");
277 vprintf(fmt, args);
278 printf("\n");
279 va_end(args);
281 exit(255);
282 return 0;
285 void skippy(int n, const char *fmt, ...)
287 char *why;
288 va_list args;
290 va_start(args, fmt);
291 why = vstrdupf(fmt, args);
292 va_end(args);
294 while (n --> 0) {
295 printf("ok %d ", ++current_test);
296 note("skip %s\n", why);
299 xfree(why);
302 void ctodo(int ignore, const char *fmt, ...)
304 va_list args;
306 va_start(args, fmt);
307 todo_mesg = vstrdupf(fmt, args);
308 va_end(args);
311 void cendtodo(void)
313 xfree(todo_mesg);
314 todo_mesg = NULL;
317 /* Create a shared memory int to keep track of whether a piece of code
318 * executed dies. to be used in the dies_ok and lives_ok macros */
319 int tap_test_died(int status)
321 int prev;
322 static int *test_died = NULL;
324 if (!test_died) {
325 test_died = mmap(0, sizeof (int), PROT_READ | PROT_WRITE,
326 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
327 *test_died = 0;
330 prev = *test_died;
331 *test_died = status;
333 return prev;
336 int like_at_loc(int for_match, const char *file, int line, const char *got,
337 const char *expected, const char *fmt, ...)
339 int test, err;
340 regex_t re;
341 va_list args;
343 err = regcomp(&re, expected, REG_EXTENDED);
344 if (err) {
345 char errbuf[256];
346 regerror(err, &re, errbuf, sizeof errbuf);
347 fprintf(stderr, "Unable to compile regex '%s': %s "
348 "at %s line %d\n", expected, errbuf, file, line);
349 exit(255);
352 err = regexec(&re, got, 0, NULL, 0);
353 regfree(&re);
355 test = for_match ? !err : err;
357 va_start(args, fmt);
358 vok_at_loc(file, line, test, fmt, args);
359 va_end(args);
361 if (!test) {
362 if (for_match) {
363 diag(" '%s'", got);
364 diag(" doesn't match: '%s'", expected);
365 } else {
366 diag(" '%s'", got);
367 diag(" matches: '%s'", expected);
371 return test;