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