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