tdb2: copy tdb1's changed expansion logic.
[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 #include "config.h"
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 const 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
50    If you have multiple threads calling ok() etc. at the same time you would
51    need this, but in that case your test numbers will be random and I'm not
52    sure it makes sense. --RR
53 */
54 #ifdef WANT_PTHREAD
55 #include <pthread.h>
56 static pthread_mutex_t M = PTHREAD_MUTEX_INITIALIZER;
57 # define LOCK pthread_mutex_lock(&M)
58 # define UNLOCK pthread_mutex_unlock(&M)
59 #else
60 # define LOCK
61 # define UNLOCK
62 #endif
63
64 static void
65 _expected_tests(unsigned int tests)
66 {
67
68         printf("1..%d\n", tests);
69         e_tests = tests;
70 }
71
72 static void
73 diagv(const char *fmt, va_list ap)
74 {
75         fputs("# ", stdout);
76         vfprintf(stdout, fmt, ap);
77         fputs("\n", stdout);
78 }
79
80 static void
81 _diag(const char *fmt, ...)
82 {
83         va_list ap;
84         va_start(ap, fmt);
85         diagv(fmt, ap);
86         va_end(ap);
87 }
88
89 /*
90  * Generate a test result.
91  *
92  * ok -- boolean, indicates whether or not the test passed.
93  * test_name -- the name of the test, may be NULL
94  * test_comment -- a comment to print afterwards, may be NULL
95  */
96 unsigned int
97 _gen_result(int ok, const char *func, const char *file, unsigned int line,
98             const char *test_name, ...)
99 {
100         va_list ap;
101         char *local_test_name = NULL;
102         char *c;
103         int name_is_digits;
104
105         LOCK;
106
107         test_count++;
108
109         /* Start by taking the test name and performing any printf()
110            expansions on it */
111         if(test_name != NULL) {
112                 va_start(ap, test_name);
113                 if (vasprintf(&local_test_name, test_name, ap) < 0)
114                         local_test_name = NULL;
115                 va_end(ap);
116
117                 /* Make sure the test name contains more than digits
118                    and spaces.  Emit an error message and exit if it
119                    does */
120                 if(local_test_name) {
121                         name_is_digits = 1;
122                         for(c = local_test_name; *c != '\0'; c++) {
123                                 if(!isdigit((unsigned char)*c)
124                                    && !isspace((unsigned char)*c)) {
125                                         name_is_digits = 0;
126                                         break;
127                                 }
128                         }
129
130                         if(name_is_digits) {
131                                 _diag("    You named your test '%s'.  You shouldn't use numbers for your test names.", local_test_name);
132                                 _diag("    Very confusing.");
133                         }
134                 }
135         }
136
137         if(!ok) {
138                 printf("not ");
139                 failures++;
140         }
141
142         printf("ok %d", test_count);
143
144         if(test_name != NULL) {
145                 printf(" - ");
146
147                 /* Print the test name, escaping any '#' characters it
148                    might contain */
149                 if(local_test_name != NULL) {
150                         flockfile(stdout);
151                         for(c = local_test_name; *c != '\0'; c++) {
152                                 if(*c == '#')
153                                         fputc('\\', stdout);
154                                 fputc((int)*c, stdout);
155                         }
156                         funlockfile(stdout);
157                 } else {        /* vasprintf() failed, use a fixed message */
158                         printf("%s", todo_msg_fixed);
159                 }
160         }
161
162         /* If we're in a todo_start() block then flag the test as being
163            TODO.  todo_msg should contain the message to print at this
164            point.  If it's NULL then asprintf() failed, and we should
165            use the fixed message.
166
167            This is not counted as a failure, so decrement the counter if
168            the test failed. */
169         if(todo) {
170                 printf(" # TODO %s", todo_msg ? todo_msg : todo_msg_fixed);
171                 if(!ok)
172                         failures--;
173         }
174
175         printf("\n");
176
177         if(!ok)
178                 _diag("    Failed %stest (%s:%s() at line %d)",
179                       todo ? "(TODO) " : "", file, func, line);
180
181         free(local_test_name);
182
183         UNLOCK;
184
185         if (!ok && tap_fail_callback)
186                 tap_fail_callback();
187
188         /* We only care (when testing) that ok is positive, but here we
189            specifically only want to return 1 or 0 */
190         return ok ? 1 : 0;
191 }
192
193 /*
194  * Cleanup at the end of the run, produce any final output that might be
195  * required.
196  */
197 static void
198 _cleanup(void)
199 {
200         /* If we forked, don't do cleanup in child! */
201         if (getpid() != test_pid)
202                 return;
203
204         LOCK;
205
206         /* If plan_no_plan() wasn't called, and we don't have a plan,
207            and we're not skipping everything, then something happened
208            before we could produce any output */
209         if(!no_plan && !have_plan && !skip_all) {
210                 _diag("Looks like your test died before it could output anything.");
211                 UNLOCK;
212                 return;
213         }
214
215         if(test_died) {
216                 _diag("Looks like your test died just after %d.", test_count);
217                 UNLOCK;
218                 return;
219         }
220
221
222         /* No plan provided, but now we know how many tests were run, and can
223            print the header at the end */
224         if(!skip_all && (no_plan || !have_plan)) {
225                 printf("1..%d\n", test_count);
226         }
227
228         if((have_plan && !no_plan) && e_tests < test_count) {
229                 _diag("Looks like you planned %d tests but ran %d extra.",
230                       e_tests, test_count - e_tests);
231                 UNLOCK;
232                 return;
233         }
234
235         if((have_plan || !no_plan) && e_tests > test_count) {
236                 _diag("Looks like you planned %d tests but only ran %d.",
237                       e_tests, test_count);
238                 if(failures) {
239                         _diag("Looks like you failed %d tests of %d run.",
240                               failures, test_count);
241                 }
242                 UNLOCK;
243                 return;
244         }
245
246         if(failures)
247                 _diag("Looks like you failed %d tests of %d.",
248                       failures, test_count);
249
250         UNLOCK;
251 }
252
253 /*
254  * Initialise the TAP library.  Will only do so once, however many times it's
255  * called.
256  */
257 static void
258 _tap_init(void)
259 {
260         static int run_once = 0;
261
262         if(!run_once) {
263                 test_pid = getpid();
264                 atexit(_cleanup);
265
266                 /* stdout needs to be unbuffered so that the output appears
267                    in the same place relative to stderr output as it does
268                    with Test::Harness */
269 //              setbuf(stdout, 0);
270                 run_once = 1;
271         }
272 }
273
274 /*
275  * Note that there's no plan.
276  */
277 void
278 plan_no_plan(void)
279 {
280
281         LOCK;
282
283         _tap_init();
284
285         if(have_plan != 0) {
286                 fprintf(stderr, "You tried to plan twice!\n");
287                 test_died = 1;
288                 UNLOCK;
289                 exit(255);
290         }
291
292         have_plan = 1;
293         no_plan = 1;
294
295         UNLOCK;
296 }
297
298 /*
299  * Note that the plan is to skip all tests
300  */
301 void
302 plan_skip_all(const char *reason)
303 {
304
305         LOCK;
306
307         _tap_init();
308
309         skip_all = 1;
310
311         printf("1..0");
312
313         if(reason != NULL)
314                 printf(" # Skip %s", reason);
315
316         printf("\n");
317
318         UNLOCK;
319 }
320
321 /*
322  * Note the number of tests that will be run.
323  */
324 void
325 plan_tests(unsigned int tests)
326 {
327
328         LOCK;
329
330         _tap_init();
331
332         if(have_plan != 0) {
333                 fprintf(stderr, "You tried to plan twice!\n");
334                 test_died = 1;
335                 UNLOCK;
336                 exit(255);
337         }
338
339         if(tests == 0) {
340                 fprintf(stderr, "You said to run 0 tests!  You've got to run something.\n");
341                 test_died = 1;
342                 UNLOCK;
343                 exit(255);
344         }
345
346         have_plan = 1;
347
348         _expected_tests(tests);
349
350         UNLOCK;
351 }
352
353 void
354 diag(const char *fmt, ...)
355 {
356         va_list ap;
357
358         LOCK;
359
360         va_start(ap, fmt);
361         diagv(fmt, ap);
362         va_end(ap);
363
364         UNLOCK;
365 }
366
367 void
368 skip(unsigned int n, const char *fmt, ...)
369 {
370         va_list ap;
371         char *skip_msg;
372
373         LOCK;
374
375         va_start(ap, fmt);
376         if (vasprintf(&skip_msg, fmt, ap) < 0)
377                 skip_msg = NULL;
378         va_end(ap);
379
380         while(n-- > 0) {
381                 test_count++;
382                 printf("ok %d # skip %s\n", test_count,
383                        skip_msg != NULL ?
384                        skip_msg : "libtap():malloc() failed");
385         }
386
387         free(skip_msg);
388
389         UNLOCK;
390 }
391
392 void
393 todo_start(const char *fmt, ...)
394 {
395         va_list ap;
396
397         LOCK;
398
399         va_start(ap, fmt);
400         if (vasprintf(&todo_msg, fmt, ap) < 0)
401                 todo_msg = NULL;
402         va_end(ap);
403
404         todo = 1;
405
406         UNLOCK;
407 }
408
409 void
410 todo_end(void)
411 {
412
413         LOCK;
414
415         todo = 0;
416         free(todo_msg);
417
418         UNLOCK;
419 }
420
421 static int
422 exit_status_(void)
423 {
424         int r;
425
426         LOCK;
427
428         /* If there's no plan, just return the number of failures */
429         if(no_plan || !have_plan) {
430                 UNLOCK;
431                 return failures;
432         }
433
434         /* Ran too many tests?  Return the number of tests that were run
435            that shouldn't have been */
436         if(e_tests < test_count) {
437                 r = test_count - e_tests;
438                 UNLOCK;
439                 return r;
440         }
441
442         /* Return the number of tests that failed + the number of tests
443            that weren't run */
444         r = failures + e_tests - test_count;
445         UNLOCK;
446
447         return r;
448 }
449
450 int
451 exit_status(void)
452 {
453         int r = exit_status_();
454         if (r > 255)
455                 r = 255;
456         return r;
457 }