Code

check_host: Allocate a large-enough buffer for the host table.
[nagiosplug.git] / 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  */
27 #include <ctype.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <stdlib.h>
32 #include "tap.h"
34 static int no_plan = 0;
35 static int skip_all = 0;
36 static int have_plan = 0;
37 static unsigned int test_count = 0; /* Number of tests that have been run */
38 static unsigned int e_tests = 0; /* Expected number of tests to run */
39 static unsigned int failures = 0; /* Number of tests that failed */
40 static char *todo_msg = NULL;
41 static char *todo_msg_fixed = "libtap malloc issue";
42 static int todo = 0;
43 static int test_died = 0;
45 /* Encapsulate the pthread code in a conditional.  In the absence of
46    libpthread the code does nothing */
47 #ifdef HAVE_LIBPTHREAD
48 #include <pthread.h>
49 static pthread_mutex_t M = PTHREAD_MUTEX_INITIALIZER;
50 # define LOCK pthread_mutex_lock(&M);
51 # define UNLOCK pthread_mutex_unlock(&M);
52 #else
53 # define LOCK
54 # define UNLOCK
55 #endif
57 static void _expected_tests(unsigned int);
58 static void _tap_init(void);
59 static void _cleanup(void);
61 /*
62  * Generate a test result.
63  *
64  * ok -- boolean, indicates whether or not the test passed.
65  * test_name -- the name of the test, may be NULL
66  * test_comment -- a comment to print afterwards, may be NULL
67  */
68 unsigned int
69 _gen_result(int ok, const char *func, char *file, unsigned int line, 
70             char *test_name, ...)
71 {
72         va_list ap;
73         char *local_test_name = NULL;
74         char *c;
75         int name_is_digits;
77         LOCK;
79         test_count++;
81         /* Start by taking the test name and performing any printf()
82            expansions on it */
83         if(test_name != NULL) {
84                 va_start(ap, test_name);
85                 vasprintf(&local_test_name, test_name, ap);
86                 va_end(ap);
88                 /* Make sure the test name contains more than digits
89                    and spaces.  Emit an error message and exit if it
90                    does */
91                 if(local_test_name) {
92                         name_is_digits = 1;
93                         for(c = local_test_name; *c != '\0'; c++) {
94                                 if(!isdigit(*c) && !isspace(*c)) {
95                                         name_is_digits = 0;
96                                         break;
97                                 }
98                         }
100                         if(name_is_digits) {
101                                 diag("    You named your test '%s'.  You shouldn't use numbers for your test names.", local_test_name);
102                                 diag("    Very confusing.");
103                         }
104                 }
105         }
107         if(!ok) {
108                 printf("not ");
109                 failures++;
110         }
112         printf("ok %d", test_count);
114         if(test_name != NULL) {
115                 printf(" - ");
117                 /* Print the test name, escaping any '#' characters it
118                    might contain */
119                 if(local_test_name != NULL) {
120                         flockfile(stdout);
121                         for(c = local_test_name; *c != '\0'; c++) {
122                                 if(*c == '#')
123                                         fputc('\\', stdout);
124                                 fputc((int)*c, stdout);
125                         }
126                         funlockfile(stdout);
127                 } else {        /* vasprintf() failed, use a fixed message */
128                         printf("%s", todo_msg_fixed);
129                 }
130         }
132         /* If we're in a todo_start() block then flag the test as being
133            TODO.  todo_msg should contain the message to print at this
134            point.  If it's NULL then asprintf() failed, and we should
135            use the fixed message.
137            This is not counted as a failure, so decrement the counter if
138            the test failed. */
139         if(todo) {
140                 printf(" # TODO %s", todo_msg ? todo_msg : todo_msg_fixed);
141                 if(!ok)
142                         failures--;
143         }
145         printf("\n");
147         if(!ok)
148                 diag("    Failed %stest (%s:%s() at line %d)", 
149                      todo ? "(TODO) " : "", file, func, line);
151         free(local_test_name);
153         UNLOCK;
155         /* We only care (when testing) that ok is positive, but here we
156            specifically only want to return 1 or 0 */
157         return ok ? 1 : 0;
160 /*
161  * Initialise the TAP library.  Will only do so once, however many times it's
162  * called.
163  */
164 void
165 _tap_init(void)
167         static int run_once = 0;
169         LOCK;
171         if(!run_once) {
172                 atexit(_cleanup);
174                 /* stdout needs to be unbuffered so that the output appears
175                    in the same place relative to stderr output as it does 
176                    with Test::Harness */
177                 setbuf(stdout, 0);
178                 run_once = 1;
179         }
181         UNLOCK;
184 /*
185  * Note that there's no plan.
186  */
187 int
188 plan_no_plan(void)
191         LOCK;
193         _tap_init();
195         if(have_plan != 0) {
196                 fprintf(stderr, "You tried to plan twice!\n");
197                 test_died = 1;
198                 UNLOCK;
199                 exit(255);
200         }
202         have_plan = 1;
203         no_plan = 1;
205         UNLOCK;
207         return 0;
210 /*
211  * Note that the plan is to skip all tests
212  */
213 int
214 plan_skip_all(char *reason)
217         LOCK;
219         _tap_init();
221         skip_all = 1;
223         printf("1..0");
225         if(reason != NULL)
226                 printf(" # Skip %s", reason);
228         printf("\n");
230         UNLOCK;
232         exit(0);
235 /*
236  * Note the number of tests that will be run.
237  */
238 int
239 plan_tests(unsigned int tests)
242         LOCK;
244         _tap_init();
246         if(have_plan != 0) {
247                 fprintf(stderr, "You tried to plan twice!\n");
248                 test_died = 1;
249                 UNLOCK;
250                 exit(255);
251         }
253         if(tests == 0) {
254                 fprintf(stderr, "You said to run 0 tests!  You've got to run something.\n");
255                 test_died = 1;
256                 UNLOCK;
257                 exit(255);
258         }
260         have_plan = 1;
262         _expected_tests(tests);
264         UNLOCK;
266         return 0;
269 unsigned int
270 diag(char *fmt, ...)
272         va_list ap;
274         LOCK;
276         fputs("# ", stderr);
278         va_start(ap, fmt);
279         vfprintf(stderr, fmt, ap);
280         va_end(ap);
282         fputs("\n", stderr);
284         UNLOCK;
286         return 0;
289 void
290 _expected_tests(unsigned int tests)
293         LOCK;
295         printf("1..%d\n", tests);
296         e_tests = tests;
298         UNLOCK;
301 int
302 skip(unsigned int n, char *fmt, ...)
304         va_list ap;
305         char *skip_msg;
307         LOCK;
309         va_start(ap, fmt);
310         asprintf(&skip_msg, fmt, ap);
311         va_end(ap);
313         while(n-- > 0) {
314                 test_count++;
315                 printf("ok %d # skip %s\n", test_count, 
316                        skip_msg != NULL ? 
317                        skip_msg : "libtap():malloc() failed");
318         }
320         free(skip_msg);
322         UNLOCK;
324         return 1;
327 void
328 todo_start(char *fmt, ...)
330         va_list ap;
332         LOCK;
334         va_start(ap, fmt);
335         vasprintf(&todo_msg, fmt, ap);
336         va_end(ap);
338         todo = 1;
340         UNLOCK;
343 void
344 todo_end(void)
347         LOCK;
349         todo = 0;
350         free(todo_msg);
352         UNLOCK;
355 int
356 exit_status(void)
358         int r;
360         LOCK;
362         /* If there's no plan, just return the number of failures */
363         if(no_plan || !have_plan) {
364                 UNLOCK;
365                 return failures;
366         }
368         /* Ran too many tests?  Return the number of tests that were run
369            that shouldn't have been */
370         if(e_tests < test_count) {
371                 r = test_count - e_tests;
372                 UNLOCK;
373                 return r;
374         }
376         /* Return the number of tests that failed + the number of tests 
377            that weren't run */
378         r = failures + e_tests - test_count;
379         UNLOCK;
381         return r;
384 /*
385  * Cleanup at the end of the run, produce any final output that might be
386  * required.
387  */
388 void
389 _cleanup(void)
392         LOCK;
394         /* If plan_no_plan() wasn't called, and we don't have a plan,
395            and we're not skipping everything, then something happened
396            before we could produce any output */
397         if(!no_plan && !have_plan && !skip_all) {
398                 diag("Looks like your test died before it could output anything.");
399                 UNLOCK;
400                 return;
401         }
403         if(test_died) {
404                 diag("Looks like your test died just after %d.", test_count);
405                 UNLOCK;
406                 return;
407         }
410         /* No plan provided, but now we know how many tests were run, and can
411            print the header at the end */
412         if(!skip_all && (no_plan || !have_plan)) {
413                 printf("1..%d\n", test_count);
414         }
416         if((have_plan && !no_plan) && e_tests < test_count) {
417                 diag("Looks like you planned %d tests but ran %d extra.",
418                      e_tests, test_count - e_tests);
419                 UNLOCK;
420                 return;
421         }
423         if((have_plan || !no_plan) && e_tests > test_count) {
424                 diag("Looks like you planned %d tests but only ran %d.",
425                      e_tests, test_count);
426                 UNLOCK;
427                 return;
428         }
430         if(failures)
431                 diag("Looks like you failed %d tests of %d.", 
432                      failures, test_count);
434         UNLOCK;