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