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