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