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