Clean-up: run format-cpp on the tree
[lttng-tools.git] / tests / utils / tap / tap.c
1 /*
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (C) 2004 Nik Clayton
5 * Copyright (C) 2017 Jérémie Galarneau
6 */
7
8 #include "tap.h"
9
10 #include <assert.h>
11 #include <ctype.h>
12 #include <limits.h>
13 #include <stdarg.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17
18 static int no_plan = 0;
19 static int skip_all = 0;
20 static int have_plan = 0;
21 static unsigned int test_count = 0; /* Number of tests that have been run */
22 static unsigned int e_tests = 0; /* Expected number of tests to run */
23 static unsigned int failures = 0; /* Number of tests that failed */
24 static char *todo_msg = NULL;
25 static const char *todo_msg_fixed = "libtap malloc issue";
26 static int todo = 0;
27 static 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>
33 static 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
41 static void _expected_tests(unsigned int);
42 static void _tap_init(void);
43 static void _cleanup(void);
44
45 #ifdef __MINGW32__
46 static inline void flockfile(FILE *filehandle)
47 {
48 return;
49 }
50
51 static inline void funlockfile(FILE *filehandle)
52 {
53 return;
54 }
55 #endif
56
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 */
64 unsigned int _gen_result(
65 int ok, const char *func, const char *file, unsigned int line, const char *test_name, ...)
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 */
78 if (test_name != NULL) {
79 va_start(ap, test_name);
80 if (vasprintf(&local_test_name, test_name, ap) == -1) {
81 local_test_name = NULL;
82 }
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 */
88 if (local_test_name) {
89 name_is_digits = 1;
90 for (c = local_test_name; *c != '\0'; c++) {
91 if (!isdigit((unsigned char) *c) && !isspace((unsigned char) *c)) {
92 name_is_digits = 0;
93 break;
94 }
95 }
96
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);
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
145 if (!ok) {
146 if (getenv("HARNESS_ACTIVE") != NULL)
147 fputs("\n", stderr);
148
149 diag(" Failed %stest (%s:%s() at line %d)",
150 todo ? "(TODO) " : "",
151 file,
152 func,
153 line);
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 */
168 void _tap_init(void)
169 {
170 static int run_once = 0;
171
172 if (!run_once) {
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 */
186 int plan_no_plan(void)
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;
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 */
210 int plan_skip_all(const char *reason)
211 {
212 LOCK;
213
214 _tap_init();
215
216 skip_all = 1;
217
218 printf("1..0");
219
220 if (reason != NULL)
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 */
233 int plan_tests(unsigned int tests)
234 {
235 LOCK;
236
237 _tap_init();
238
239 if (have_plan != 0) {
240 fprintf(stderr, "You tried to plan twice!\n");
241 test_died = 1;
242 UNLOCK;
243 exit(255);
244 }
245
246 if (tests == 0) {
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
262 unsigned int diag(const char *fmt, ...)
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
277 void diag_multiline(const char *val)
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
298 void _expected_tests(unsigned int tests)
299 {
300 printf("1..%d\n", tests);
301 e_tests = tests;
302 }
303
304 int skip(unsigned int n, const char *fmt, ...)
305 {
306 va_list ap;
307 char *skip_msg = NULL;
308
309 LOCK;
310
311 va_start(ap, fmt);
312 if (vasprintf(&skip_msg, fmt, ap) == -1) {
313 skip_msg = NULL;
314 }
315 va_end(ap);
316
317 while (n-- > 0) {
318 test_count++;
319 printf("ok %d # skip %s\n",
320 test_count,
321 skip_msg != NULL ? skip_msg : "libtap():malloc() failed");
322 }
323
324 free(skip_msg);
325
326 UNLOCK;
327
328 return 1;
329 }
330
331 void todo_start(const char *fmt, ...)
332 {
333 va_list ap;
334
335 LOCK;
336
337 va_start(ap, fmt);
338 if (vasprintf(&todo_msg, fmt, ap) == -1) {
339 todo_msg = NULL;
340 }
341 va_end(ap);
342
343 todo = 1;
344
345 UNLOCK;
346 }
347
348 void todo_end(void)
349 {
350 LOCK;
351
352 todo = 0;
353 free(todo_msg);
354
355 UNLOCK;
356 }
357
358 int exit_status(void)
359 {
360 int r;
361
362 LOCK;
363
364 /* If there's no plan, just return the number of failures */
365 if (no_plan || !have_plan) {
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 */
372 if (e_tests < test_count) {
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 */
390 void _cleanup(void)
391 {
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 */
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 }
402
403 if (test_died) {
404 diag("Looks like your test died just after %d.", test_count);
405 UNLOCK;
406 return;
407 }
408
409 /* No plan provided, but now we know how many tests were run, and can
410 print the header at the end */
411 if (!skip_all && (no_plan || !have_plan)) {
412 printf("1..%d\n", test_count);
413 }
414
415 if ((have_plan && !no_plan) && e_tests < test_count) {
416 diag("Looks like you planned %d %s but ran %d extra.",
417 e_tests,
418 e_tests == 1 ? "test" : "tests",
419 test_count - e_tests);
420 UNLOCK;
421 return;
422 }
423
424 if ((have_plan || !no_plan) && e_tests > test_count) {
425 diag("Looks like you planned %d %s but only ran %d.",
426 e_tests,
427 e_tests == 1 ? "test" : "tests",
428 test_count);
429 UNLOCK;
430 return;
431 }
432
433 if (failures)
434 diag("Looks like you failed %d %s of %d.",
435 failures,
436 failures == 1 ? "test" : "tests",
437 test_count);
438
439 UNLOCK;
440 }
This page took 0.037444 seconds and 4 git commands to generate.