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