]> git.ozlabs.org Git - ccan/blob - ccan/tap/tap.c
commiting _info to json convertor
[ccan] / ccan / tap / tap.c
1 /*-
2  * Copyright (c) 2004 Nik Clayton
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 #define _GNU_SOURCE
27 #include <ctype.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32
33 #include "tap.h"
34
35 static int no_plan = 0;
36 static int skip_all = 0;
37 static int have_plan = 0;
38 static unsigned int test_count = 0; /* Number of tests that have been run */
39 static unsigned int e_tests = 0; /* Expected number of tests to run */
40 static unsigned int failures = 0; /* Number of tests that failed */
41 static char *todo_msg = NULL;
42 static char *todo_msg_fixed = "libtap malloc issue";
43 static int todo = 0;
44 static int test_died = 0;
45 static int test_pid;
46
47 /* Encapsulate the pthread code in a conditional.  In the absence of
48    libpthread the code does nothing */
49 #ifdef HAVE_LIBPTHREAD
50 #include <pthread.h>
51 static pthread_mutex_t M = PTHREAD_MUTEX_INITIALIZER;
52 # define LOCK pthread_mutex_lock(&M)
53 # define UNLOCK pthread_mutex_unlock(&M)
54 #else
55 # define LOCK
56 # define UNLOCK
57 #endif
58
59 static void
60 _expected_tests(unsigned int tests)
61 {
62
63         printf("1..%d\n", tests);
64         e_tests = tests;
65 }
66
67 static void
68 diagv(char *fmt, va_list ap)
69 {
70         fputs("# ", stderr);
71         vfprintf(stderr, fmt, ap);
72         fputs("\n", stderr);
73 }
74
75 static void
76 _diag(char *fmt, ...)
77 {
78         va_list ap;
79         va_start(ap, fmt);
80         diagv(fmt, ap);
81         va_end(ap);
82 }
83
84 /*
85  * Generate a test result.
86  *
87  * ok -- boolean, indicates whether or not the test passed.
88  * test_name -- the name of the test, may be NULL
89  * test_comment -- a comment to print afterwards, may be NULL
90  */
91 unsigned int
92 _gen_result(int ok, const char *func, char *file, unsigned int line, 
93             char *test_name, ...)
94 {
95         va_list ap;
96         char *local_test_name = NULL;
97         char *c;
98         int name_is_digits;
99
100         LOCK;
101
102         test_count++;
103
104         /* Start by taking the test name and performing any printf()
105            expansions on it */
106         if(test_name != NULL) {
107                 va_start(ap, test_name);
108                 vasprintf(&local_test_name, test_name, ap);
109                 va_end(ap);
110
111                 /* Make sure the test name contains more than digits
112                    and spaces.  Emit an error message and exit if it
113                    does */
114                 if(local_test_name) {
115                         name_is_digits = 1;
116                         for(c = local_test_name; *c != '\0'; c++) {
117                                 if(!isdigit(*c) && !isspace(*c)) {
118                                         name_is_digits = 0;
119                                         break;
120                                 }
121                         }
122
123                         if(name_is_digits) {
124                                 _diag("    You named your test '%s'.  You shouldn't use numbers for your test names.", local_test_name);
125                                 _diag("    Very confusing.");
126                         }
127                 }
128         }
129
130         if(!ok) {
131                 printf("not ");
132                 failures++;
133         }
134
135         printf("ok %d", test_count);
136
137         if(test_name != NULL) {
138                 printf(" - ");
139
140                 /* Print the test name, escaping any '#' characters it
141                    might contain */
142                 if(local_test_name != NULL) {
143                         flockfile(stdout);
144                         for(c = local_test_name; *c != '\0'; c++) {
145                                 if(*c == '#')
146                                         fputc('\\', stdout);
147                                 fputc((int)*c, stdout);
148                         }
149                         funlockfile(stdout);
150                 } else {        /* vasprintf() failed, use a fixed message */
151                         printf("%s", todo_msg_fixed);
152                 }
153         }
154
155         /* If we're in a todo_start() block then flag the test as being
156            TODO.  todo_msg should contain the message to print at this
157            point.  If it's NULL then asprintf() failed, and we should
158            use the fixed message.
159
160            This is not counted as a failure, so decrement the counter if
161            the test failed. */
162         if(todo) {
163                 printf(" # TODO %s", todo_msg ? todo_msg : todo_msg_fixed);
164                 if(!ok)
165                         failures--;
166         }
167
168         printf("\n");
169
170         if(!ok)
171                 _diag("    Failed %stest (%s:%s() at line %d)", 
172                       todo ? "(TODO) " : "", file, func, line);
173
174         free(local_test_name);
175
176         UNLOCK;
177
178         /* We only care (when testing) that ok is positive, but here we
179            specifically only want to return 1 or 0 */
180         return ok ? 1 : 0;
181 }
182
183 /*
184  * Cleanup at the end of the run, produce any final output that might be
185  * required.
186  */
187 static void
188 _cleanup(void)
189 {
190         /* If we forked, don't do cleanup in child! */
191         if (getpid() != test_pid)
192                 return;
193
194         LOCK;
195
196         /* If plan_no_plan() wasn't called, and we don't have a plan,
197            and we're not skipping everything, then something happened
198            before we could produce any output */
199         if(!no_plan && !have_plan && !skip_all) {
200                 _diag("Looks like your test died before it could output anything.");
201                 UNLOCK;
202                 return;
203         }
204
205         if(test_died) {
206                 _diag("Looks like your test died just after %d.", test_count);
207                 UNLOCK;
208                 return;
209         }
210
211
212         /* No plan provided, but now we know how many tests were run, and can
213            print the header at the end */
214         if(!skip_all && (no_plan || !have_plan)) {
215                 printf("1..%d\n", test_count);
216         }
217
218         if((have_plan && !no_plan) && e_tests < test_count) {
219                 _diag("Looks like you planned %d tests but ran %d extra.",
220                       e_tests, test_count - e_tests);
221                 UNLOCK;
222                 return;
223         }
224
225         if((have_plan || !no_plan) && e_tests > test_count) {
226                 _diag("Looks like you planned %d tests but only ran %d.",
227                       e_tests, test_count);
228                 if(failures) {
229                         _diag("Looks like you failed %d tests of %d run.", 
230                               failures, test_count);
231                 }
232                 UNLOCK;
233                 return;
234         }
235
236         if(failures)
237                 _diag("Looks like you failed %d tests of %d.", 
238                       failures, test_count);
239
240         UNLOCK;
241 }
242
243 /*
244  * Initialise the TAP library.  Will only do so once, however many times it's
245  * called.
246  */
247 static void
248 _tap_init(void)
249 {
250         static int run_once = 0;
251
252         if(!run_once) {
253                 test_pid = getpid();
254                 atexit(_cleanup);
255
256                 /* stdout needs to be unbuffered so that the output appears
257                    in the same place relative to stderr output as it does 
258                    with Test::Harness */
259                 setbuf(stdout, 0);
260                 run_once = 1;
261         }
262 }
263
264 /*
265  * Note that there's no plan.
266  */
267 void
268 plan_no_plan(void)
269 {
270
271         LOCK;
272
273         _tap_init();
274
275         if(have_plan != 0) {
276                 fprintf(stderr, "You tried to plan twice!\n");
277                 test_died = 1;
278                 UNLOCK;
279                 exit(255);
280         }
281
282         have_plan = 1;
283         no_plan = 1;
284
285         UNLOCK;
286 }
287
288 /*
289  * Note that the plan is to skip all tests
290  */
291 void
292 plan_skip_all(char *reason)
293 {
294
295         LOCK;
296
297         _tap_init();
298
299         skip_all = 1;
300
301         printf("1..0");
302
303         if(reason != NULL)
304                 printf(" # Skip %s", reason);
305
306         printf("\n");
307
308         UNLOCK;
309 }
310
311 /*
312  * Note the number of tests that will be run.
313  */
314 void
315 plan_tests(unsigned int tests)
316 {
317
318         LOCK;
319
320         _tap_init();
321
322         if(have_plan != 0) {
323                 fprintf(stderr, "You tried to plan twice!\n");
324                 test_died = 1;
325                 UNLOCK;
326                 exit(255);
327         }
328
329         if(tests == 0) {
330                 fprintf(stderr, "You said to run 0 tests!  You've got to run something.\n");
331                 test_died = 1;
332                 UNLOCK;
333                 exit(255);
334         }
335
336         have_plan = 1;
337
338         _expected_tests(tests);
339
340         UNLOCK;
341 }
342
343 void
344 diag(char *fmt, ...)
345 {
346         va_list ap;
347
348         LOCK;
349
350         va_start(ap, fmt);
351         diagv(fmt, ap);
352         va_end(ap);
353
354         UNLOCK;
355 }
356
357 void
358 skip(unsigned int n, char *fmt, ...)
359 {
360         va_list ap;
361         char *skip_msg;
362
363         LOCK;
364
365         va_start(ap, fmt);
366         vasprintf(&skip_msg, fmt, ap);
367         va_end(ap);
368
369         while(n-- > 0) {
370                 test_count++;
371                 printf("ok %d # skip %s\n", test_count, 
372                        skip_msg != NULL ? 
373                        skip_msg : "libtap():malloc() failed");
374         }
375
376         free(skip_msg);
377
378         UNLOCK;
379 }
380
381 void
382 todo_start(char *fmt, ...)
383 {
384         va_list ap;
385
386         LOCK;
387
388         va_start(ap, fmt);
389         vasprintf(&todo_msg, fmt, ap);
390         va_end(ap);
391
392         todo = 1;
393
394         UNLOCK;
395 }
396
397 void
398 todo_end(void)
399 {
400
401         LOCK;
402
403         todo = 0;
404         free(todo_msg);
405
406         UNLOCK;
407 }
408
409 int
410 exit_status(void)
411 {
412         int r;
413
414         LOCK;
415
416         /* If there's no plan, just return the number of failures */
417         if(no_plan || !have_plan) {
418                 UNLOCK;
419                 return failures;
420         }
421
422         /* Ran too many tests?  Return the number of tests that were run
423            that shouldn't have been */
424         if(e_tests < test_count) {
425                 r = test_count - e_tests;
426                 UNLOCK;
427                 return r;
428         }
429
430         /* Return the number of tests that failed + the number of tests 
431            that weren't run */
432         r = failures + e_tests - test_count;
433         UNLOCK;
434
435         return r;
436 }