]> begriffs open source - libtap/blob - tap.c
Format code a bit differently.
[libtap] / tap.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdarg.h>
4 #include <string.h>
5 #include "tap.h"
6 \r
7 static int expected_tests = NO_PLAN;\r
8 static int failed_tests;\r
9 static int current_test;
10 static char *todo_mesg;\r
11
12 void
13 plan (int tests) {\r
14     expected_tests = tests;
15     if (tests != NO_PLAN)\r
16         printf("1..%d\n", tests);\r
17 }
18
19 static char *
20 vstrdupf (const char *fmt, va_list args) {
21     char *str;
22     int size = vsnprintf(NULL, 0, fmt, args) + 1;
23     str = malloc(size);
24     vsprintf(str, fmt, args);
25     return str;
26 }
27
28 static int
29 vok_at_loc (const char *file, int line, int test, const char *fmt,
30             va_list args)
31 {
32     char *name = vstrdupf(fmt, args);
33     printf("%sok %d", test ? "" : "not ", ++current_test);
34     if (*name)
35         printf(" - %s", name);
36     if (todo_mesg) {
37         printf(" # TODO");
38         if (*todo_mesg)
39             printf(" %s", todo_mesg);
40     }
41     printf("\n");\r
42     if (!test) {
43         if (*name)\r
44             diag("  Failed%s test '%s'\n  at %s line %d.",
45                 todo_mesg ? " (TODO)" : "", name, file, line);\r
46         else\r
47             diag("  Failed%s test at %s line %d.",
48                 todo_mesg ? " (TODO)" : "", file, line);
49         if (!todo_mesg)\r
50             failed_tests++;\r
51     }\r
52     free(name);
53     return test;
54 }
55 \r
56 int
57 ok_at_loc (const char *file, int line, int test, const char *fmt, ...) {
58     va_list args;
59     va_start(args, fmt);
60     vok_at_loc(file, line, test, fmt, args);
61     va_end(args);
62     return test;\r
63 }\r
64
65 static int
66 mystrcmp (const char *a, const char *b) {
67     return a == b ? 0 : !a ? -1 : !b ? 1 : strcmp(a, b);
68 }
69
70 int
71 is_at_loc (const char *file, int line, const char *got, const char *expected,
72            const char *fmt, ...)
73 {
74     int test = !mystrcmp(got, expected);
75     va_list args;
76     va_start(args, fmt);
77     vok_at_loc(file, line, test, fmt, args);
78     va_end(args);
79     if (!test) {
80         diag("         got: '%s'", got);
81         diag("    expected: '%s'", expected);
82     }
83     return test;
84 }
85
86 int
87 isnt_at_loc (const char *file, int line, const char *got, const char *expected,
88              const char *fmt, ...)
89 {
90     int test = mystrcmp(got, expected);
91     va_list args;
92     va_start(args, fmt);
93     vok_at_loc(file, line, test, fmt, args);
94     va_end(args);
95     if (!test) {
96         diag("         got: '%s'", got);
97         diag("    expected: anything else");
98     }
99     return test;
100 }
101
102 static void
103 vdiag_to_fh (FILE *fh, const char *fmt, va_list args) {\r
104     char *mesg, *line;
105     int i;\r
106     if (!fmt)
107         return;\r
108     mesg = vstrdupf(fmt, args);\r
109     line = mesg;\r
110     for (i = 0; *line; i++) {\r
111         char c = mesg[i];\r
112         if (!c || c == '\n') {\r
113             mesg[i] = '\0';\r
114             fprintf(fh, "# %s\n", line);\r
115             if (!c) break;\r
116             mesg[i] = c;\r
117             line = &mesg[i+1];\r
118         }\r
119     }\r
120     free(mesg);
121     return;\r
122 }\r
123
124 int
125 diag (const char *fmt, ...) {
126     va_list args;
127     va_start(args, fmt);
128     vdiag_to_fh(stderr, fmt, args);
129     va_end(args);
130     return 1;
131 }
132
133 int
134 note (const char *fmt, ...) {
135     va_list args;
136     va_start(args, fmt);
137     vdiag_to_fh(stdout, fmt, args);
138     va_end(args);
139     return 1;
140 }
141 \r
142 int
143 exit_status () {\r
144     int retval = 0;\r
145     if (expected_tests == NO_PLAN) {\r
146         printf("1..%d\n", current_test);\r
147     }\r
148     else if (current_test != expected_tests) {\r
149         diag("Looks like you planned %d test%s but ran %d.",\r
150             expected_tests, expected_tests > 1 ? "s" : "", current_test);\r
151         retval = 255;\r
152     }\r
153     if (failed_tests) {\r
154         diag("Looks like you failed %d test%s of %d run.",\r
155             failed_tests, failed_tests > 1 ? "s" : "", current_test);
156         if (expected_tests == NO_PLAN)\r
157             retval = failed_tests;
158         else
159             retval = expected_tests - current_test + failed_tests;\r
160     }\r
161     return retval;\r
162 }
163
164 void
165 skippy (int n, const char *fmt, ...) {
166     char *why;
167     va_list args;
168     va_start(args, fmt);
169     why = vstrdupf(fmt, args);
170     va_end(args);
171     while (n --> 0) {
172         printf("ok %d ", ++current_test);
173         note("skip %s\n", why);
174     }
175     free(why);
176 }
177
178 void
179 ctodo (int ignore, const char *fmt, ...) {
180     va_list args;
181     va_start(args, fmt);
182     todo_mesg = vstrdupf(fmt, args);
183     va_end(args);
184 }
185
186 void
187 cendtodo () {
188     free(todo_mesg);
189     todo_mesg = NULL;
190 }
191
192 #ifndef _WIN32
193 #include <sys/mman.h>
194 #include <regex.h>
195
196 /* Create a shared memory int to keep track of whether a piece of code executed
197 dies. to be used in the dies_ok and lives_ok macros  */
198 int
199 tap_test_died (int status) {
200     static int *test_died = NULL;
201     int prev;
202     if (!test_died) {
203         test_died = mmap(0, sizeof (int), PROT_READ | PROT_WRITE,
204                          MAP_SHARED | MAP_ANONYMOUS, -1, 0);
205         *test_died = 0;
206     }
207     prev = *test_died;
208     *test_died = status;
209     return prev;
210 }
211
212 int
213 like_at_loc (int for_match, const char *file, int line, const char *got,
214              const char *expected, const char *fmt, ...)
215 {
216     int test;
217     regex_t re;
218     int err = regcomp(&re, expected, REG_EXTENDED);
219     if (err) {
220         char errbuf[256];
221         regerror(err, &re, errbuf, sizeof errbuf);
222         fprintf(stderr, "Unable to compile regex '%s': %s at %s line %d\n",
223                         expected, errbuf, file, line);
224         exit(255);
225     }
226     err = regexec(&re, got, 0, NULL, 0);
227     regfree(&re);
228     test = for_match ? !err : err;
229     va_list args;
230     va_start(args, fmt);
231     vok_at_loc(file, line, test, fmt, args);
232     va_end(args);
233     if (!test) {
234         if (for_match) {
235             diag("                   '%s'", got);
236             diag("    doesn't match: '%s'", expected);
237         }
238         else {
239             diag("                   '%s'", got);
240             diag("          matches: '%s'", expected);
241         }
242     }
243     return test;
244 }
245 #endif
246