]> eyrie.org Git - kerberos/krb5-strength.git/blob - tests/tap/basic.c
Update to rra-c-util 4.12 and C TAP Harness 2.3
[kerberos/krb5-strength.git] / tests / tap / basic.c
1 /*
2  * Some utility routines for writing tests.
3  *
4  * Here are a variety of utility routines for writing tests compatible with
5  * the TAP protocol.  All routines of the form ok() or is*() take a test
6  * number and some number of appropriate arguments, check to be sure the
7  * results match the expected output using the arguments, and print out
8  * something appropriate for that test number.  Other utility routines help in
9  * constructing more complex tests, skipping tests, reporting errors, setting
10  * up the TAP output format, or finding things in the test environment.
11  *
12  * This file is part of C TAP Harness.  The current version plus supporting
13  * documentation is at <http://www.eyrie.org/~eagle/software/c-tap-harness/>.
14  *
15  * Copyright 2009, 2010, 2011, 2012, 2013 Russ Allbery <eagle@eyrie.org>
16  * Copyright 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2011, 2012, 2013
17  *     The Board of Trustees of the Leland Stanford Junior University
18  *
19  * Permission is hereby granted, free of charge, to any person obtaining a
20  * copy of this software and associated documentation files (the "Software"),
21  * to deal in the Software without restriction, including without limitation
22  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
23  * and/or sell copies of the Software, and to permit persons to whom the
24  * Software is furnished to do so, subject to the following conditions:
25  *
26  * The above copyright notice and this permission notice shall be included in
27  * all copies or substantial portions of the Software.
28  *
29  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
32  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
34  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
35  * DEALINGS IN THE SOFTWARE.
36  */
37
38 #include <errno.h>
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #ifdef _WIN32
44 # include <direct.h>
45 #else
46 # include <sys/stat.h>
47 #endif
48 #include <sys/types.h>
49 #include <unistd.h>
50
51 #include <tests/tap/basic.h>
52
53 /* Windows provides mkdir and rmdir under different names. */
54 #ifdef _WIN32
55 # define mkdir(p, m) _mkdir(p)
56 # define rmdir(p)    _rmdir(p)
57 #endif
58
59 /*
60  * The test count.  Always contains the number that will be used for the next
61  * test status.  This is exported to callers of the library.
62  */
63 unsigned long testnum = 1;
64
65 /*
66  * Status information stored so that we can give a test summary at the end of
67  * the test case.  We store the planned final test and the count of failures.
68  * We can get the highest test count from testnum.
69  */
70 static unsigned long _planned = 0;
71 static unsigned long _failed  = 0;
72
73 /*
74  * Store the PID of the process that called plan() and only summarize
75  * results when that process exits, so as to not misreport results in forked
76  * processes.
77  */
78 static pid_t _process = 0;
79
80 /*
81  * If true, we're doing lazy planning and will print out the plan based on the
82  * last test number at the end of testing.
83  */
84 static int _lazy = 0;
85
86 /*
87  * If true, the test was aborted by calling bail().  Currently, this is only
88  * used to ensure that we pass a false value to any cleanup functions even if
89  * all tests to that point have passed.
90  */
91 static int _aborted = 0;
92
93 /*
94  * Registered cleanup functions.  These are stored as a linked list and run in
95  * registered order by finish when the test program exits.  Each function is
96  * passed a boolean value indicating whether all tests were successful.
97  */
98 struct cleanup_func {
99     test_cleanup_func func;
100     struct cleanup_func *next;
101 };
102 static struct cleanup_func *cleanup_funcs = NULL;
103
104 /*
105  * Print a specified prefix and then the test description.  Handles turning
106  * the argument list into a va_args structure suitable for passing to
107  * print_desc, which has to be done in a macro.  Assumes that format is the
108  * argument immediately before the variadic arguments.
109  */
110 #define PRINT_DESC(prefix, format)              \
111     do {                                        \
112         if (format != NULL) {                   \
113             va_list args;                       \
114             if (prefix != NULL)                 \
115                 printf("%s", prefix);           \
116             va_start(args, format);             \
117             vprintf(format, args);              \
118             va_end(args);                       \
119         }                                       \
120     } while (0)
121
122
123 /*
124  * Our exit handler.  Called on completion of the test to report a summary of
125  * results provided we're still in the original process.  This also handles
126  * printing out the plan if we used plan_lazy(), although that's suppressed if
127  * we never ran a test (due to an early bail, for example), and running any
128  * registered cleanup functions.
129  */
130 static void
131 finish(void)
132 {
133     int success;
134     struct cleanup_func *current;
135     unsigned long highest = testnum - 1;
136
137     /*
138      * Don't do anything except free the cleanup functions if we aren't the
139      * primary process (the process in which plan or plan_lazy was called).
140      */
141     if (_process != 0 && getpid() != _process) {
142         while (cleanup_funcs != NULL) {
143             current = cleanup_funcs;
144             cleanup_funcs = cleanup_funcs->next;
145             free(current);
146         }
147         return;
148     }
149
150     /*
151      * Determine whether all tests were successful, which is needed before
152      * calling cleanup functions since we pass that fact to the functions.
153      */
154     if (_planned == 0 && _lazy)
155         _planned = highest;
156     success = (!_aborted && _planned == highest && _failed == 0);
157
158     /*
159      * If there are any registered cleanup functions, we run those first.  We
160      * always run them, even if we didn't run a test.
161      */
162     while (cleanup_funcs != NULL) {
163         cleanup_funcs->func(success);
164         current = cleanup_funcs;
165         cleanup_funcs = cleanup_funcs->next;
166         free(current);
167     }
168
169     /* Don't do anything further if we never planned a test. */
170     if (_planned == 0)
171         return;
172
173     /* If we're aborting due to bail, don't print summaries. */
174     if (_aborted)
175         return;
176
177     /* Print out the lazy plan if needed. */
178     fflush(stderr);
179     if (_lazy && _planned > 0)
180         printf("1..%lu\n", _planned);
181
182     /* Print out a summary of the results. */
183     if (_planned > highest)
184         diag("Looks like you planned %lu test%s but only ran %lu", _planned,
185              (_planned > 1 ? "s" : ""), highest);
186     else if (_planned < highest)
187         diag("Looks like you planned %lu test%s but ran %lu extra", _planned,
188              (_planned > 1 ? "s" : ""), highest - _planned);
189     else if (_failed > 0)
190         diag("Looks like you failed %lu test%s of %lu", _failed,
191              (_failed > 1 ? "s" : ""), _planned);
192     else if (_planned != 1)
193         diag("All %lu tests successful or skipped", _planned);
194     else
195         diag("%lu test successful or skipped", _planned);
196 }
197
198
199 /*
200  * Initialize things.  Turns on line buffering on stdout and then prints out
201  * the number of tests in the test suite.
202  */
203 void
204 plan(unsigned long count)
205 {
206     if (setvbuf(stdout, NULL, _IOLBF, BUFSIZ) != 0)
207         sysdiag("cannot set stdout to line buffered");
208     fflush(stderr);
209     printf("1..%lu\n", count);
210     testnum = 1;
211     _planned = count;
212     _process = getpid();
213     if (atexit(finish) != 0) {
214         sysdiag("cannot register exit handler");
215         diag("cleanups will not be run");
216     }
217 }
218
219
220 /*
221  * Initialize things for lazy planning, where we'll automatically print out a
222  * plan at the end of the program.  Turns on line buffering on stdout as well.
223  */
224 void
225 plan_lazy(void)
226 {
227     if (setvbuf(stdout, NULL, _IOLBF, BUFSIZ) != 0)
228         sysdiag("cannot set stdout to line buffered");
229     testnum = 1;
230     _process = getpid();
231     _lazy = 1;
232     if (atexit(finish) != 0)
233         sysbail("cannot register exit handler to display plan");
234 }
235
236
237 /*
238  * Skip the entire test suite and exits.  Should be called instead of plan(),
239  * not after it, since it prints out a special plan line.
240  */
241 void
242 skip_all(const char *format, ...)
243 {
244     fflush(stderr);
245     printf("1..0 # skip");
246     PRINT_DESC(" ", format);
247     putchar('\n');
248     exit(0);
249 }
250
251
252 /*
253  * Takes a boolean success value and assumes the test passes if that value
254  * is true and fails if that value is false.
255  */
256 void
257 ok(int success, const char *format, ...)
258 {
259     fflush(stderr);
260     printf("%sok %lu", success ? "" : "not ", testnum++);
261     if (!success)
262         _failed++;
263     PRINT_DESC(" - ", format);
264     putchar('\n');
265 }
266
267
268 /*
269  * Same as ok(), but takes the format arguments as a va_list.
270  */
271 void
272 okv(int success, const char *format, va_list args)
273 {
274     fflush(stderr);
275     printf("%sok %lu", success ? "" : "not ", testnum++);
276     if (!success)
277         _failed++;
278     if (format != NULL) {
279         printf(" - ");
280         vprintf(format, args);
281     }
282     putchar('\n');
283 }
284
285
286 /*
287  * Skip a test.
288  */
289 void
290 skip(const char *reason, ...)
291 {
292     fflush(stderr);
293     printf("ok %lu # skip", testnum++);
294     PRINT_DESC(" ", reason);
295     putchar('\n');
296 }
297
298
299 /*
300  * Report the same status on the next count tests.
301  */
302 void
303 ok_block(unsigned long count, int status, const char *format, ...)
304 {
305     unsigned long i;
306
307     fflush(stderr);
308     for (i = 0; i < count; i++) {
309         printf("%sok %lu", status ? "" : "not ", testnum++);
310         if (!status)
311             _failed++;
312         PRINT_DESC(" - ", format);
313         putchar('\n');
314     }
315 }
316
317
318 /*
319  * Skip the next count tests.
320  */
321 void
322 skip_block(unsigned long count, const char *reason, ...)
323 {
324     unsigned long i;
325
326     fflush(stderr);
327     for (i = 0; i < count; i++) {
328         printf("ok %lu # skip", testnum++);
329         PRINT_DESC(" ", reason);
330         putchar('\n');
331     }
332 }
333
334
335 /*
336  * Takes an expected integer and a seen integer and assumes the test passes
337  * if those two numbers match.
338  */
339 void
340 is_int(long wanted, long seen, const char *format, ...)
341 {
342     fflush(stderr);
343     if (wanted == seen)
344         printf("ok %lu", testnum++);
345     else {
346         diag("wanted: %ld", wanted);
347         diag("  seen: %ld", seen);
348         printf("not ok %lu", testnum++);
349         _failed++;
350     }
351     PRINT_DESC(" - ", format);
352     putchar('\n');
353 }
354
355
356 /*
357  * Takes a string and what the string should be, and assumes the test passes
358  * if those strings match (using strcmp).
359  */
360 void
361 is_string(const char *wanted, const char *seen, const char *format, ...)
362 {
363     if (wanted == NULL)
364         wanted = "(null)";
365     if (seen == NULL)
366         seen = "(null)";
367     fflush(stderr);
368     if (strcmp(wanted, seen) == 0)
369         printf("ok %lu", testnum++);
370     else {
371         diag("wanted: %s", wanted);
372         diag("  seen: %s", seen);
373         printf("not ok %lu", testnum++);
374         _failed++;
375     }
376     PRINT_DESC(" - ", format);
377     putchar('\n');
378 }
379
380
381 /*
382  * Takes an expected unsigned long and a seen unsigned long and assumes the
383  * test passes if the two numbers match.  Otherwise, reports them in hex.
384  */
385 void
386 is_hex(unsigned long wanted, unsigned long seen, const char *format, ...)
387 {
388     fflush(stderr);
389     if (wanted == seen)
390         printf("ok %lu", testnum++);
391     else {
392         diag("wanted: %lx", (unsigned long) wanted);
393         diag("  seen: %lx", (unsigned long) seen);
394         printf("not ok %lu", testnum++);
395         _failed++;
396     }
397     PRINT_DESC(" - ", format);
398     putchar('\n');
399 }
400
401
402 /*
403  * Bail out with an error.
404  */
405 void
406 bail(const char *format, ...)
407 {
408     va_list args;
409
410     _aborted = 1;
411     fflush(stderr);
412     fflush(stdout);
413     printf("Bail out! ");
414     va_start(args, format);
415     vprintf(format, args);
416     va_end(args);
417     printf("\n");
418     exit(255);
419 }
420
421
422 /*
423  * Bail out with an error, appending strerror(errno).
424  */
425 void
426 sysbail(const char *format, ...)
427 {
428     va_list args;
429     int oerrno = errno;
430
431     _aborted = 1;
432     fflush(stderr);
433     fflush(stdout);
434     printf("Bail out! ");
435     va_start(args, format);
436     vprintf(format, args);
437     va_end(args);
438     printf(": %s\n", strerror(oerrno));
439     exit(255);
440 }
441
442
443 /*
444  * Report a diagnostic to stderr.
445  */
446 void
447 diag(const char *format, ...)
448 {
449     va_list args;
450
451     fflush(stderr);
452     fflush(stdout);
453     printf("# ");
454     va_start(args, format);
455     vprintf(format, args);
456     va_end(args);
457     printf("\n");
458 }
459
460
461 /*
462  * Report a diagnostic to stderr, appending strerror(errno).
463  */
464 void
465 sysdiag(const char *format, ...)
466 {
467     va_list args;
468     int oerrno = errno;
469
470     fflush(stderr);
471     fflush(stdout);
472     printf("# ");
473     va_start(args, format);
474     vprintf(format, args);
475     va_end(args);
476     printf(": %s\n", strerror(oerrno));
477 }
478
479
480 /*
481  * Allocate cleared memory, reporting a fatal error with bail on failure.
482  */
483 void *
484 bcalloc(size_t n, size_t size)
485 {
486     void *p;
487
488     p = calloc(n, size);
489     if (p == NULL)
490         sysbail("failed to calloc %lu", (unsigned long)(n * size));
491     return p;
492 }
493
494
495 /*
496  * Allocate memory, reporting a fatal error with bail on failure.
497  */
498 void *
499 bmalloc(size_t size)
500 {
501     void *p;
502
503     p = malloc(size);
504     if (p == NULL)
505         sysbail("failed to malloc %lu", (unsigned long) size);
506     return p;
507 }
508
509
510 /*
511  * Reallocate memory, reporting a fatal error with bail on failure.
512  */
513 void *
514 brealloc(void *p, size_t size)
515 {
516     p = realloc(p, size);
517     if (p == NULL)
518         sysbail("failed to realloc %lu bytes", (unsigned long) size);
519     return p;
520 }
521
522
523 /*
524  * Copy a string, reporting a fatal error with bail on failure.
525  */
526 char *
527 bstrdup(const char *s)
528 {
529     char *p;
530     size_t len;
531
532     len = strlen(s) + 1;
533     p = malloc(len);
534     if (p == NULL)
535         sysbail("failed to strdup %lu bytes", (unsigned long) len);
536     memcpy(p, s, len);
537     return p;
538 }
539
540
541 /*
542  * Copy up to n characters of a string, reporting a fatal error with bail on
543  * failure.  Don't use the system strndup function, since it may not exist and
544  * the TAP library doesn't assume any portability support.
545  */
546 char *
547 bstrndup(const char *s, size_t n)
548 {
549     const char *p;
550     char *copy;
551     size_t length;
552
553     /* Don't assume that the source string is nul-terminated. */
554     for (p = s; (size_t) (p - s) < n && *p != '\0'; p++)
555         ;
556     length = p - s;
557     copy = malloc(length + 1);
558     if (p == NULL)
559         sysbail("failed to strndup %lu bytes", (unsigned long) length);
560     memcpy(copy, s, length);
561     copy[length] = '\0';
562     return copy;
563 }
564
565
566 /*
567  * Locate a test file.  Given the partial path to a file, look under BUILD and
568  * then SOURCE for the file and return the full path to the file.  Returns
569  * NULL if the file doesn't exist.  A non-NULL return should be freed with
570  * test_file_path_free().
571  *
572  * This function uses sprintf because it attempts to be independent of all
573  * other portability layers.  The use immediately after a memory allocation
574  * should be safe without using snprintf or strlcpy/strlcat.
575  */
576 char *
577 test_file_path(const char *file)
578 {
579     char *base;
580     char *path = NULL;
581     size_t length;
582     const char *envs[] = { "BUILD", "SOURCE", NULL };
583     int i;
584
585     for (i = 0; envs[i] != NULL; i++) {
586         base = getenv(envs[i]);
587         if (base == NULL)
588             continue;
589         length = strlen(base) + 1 + strlen(file) + 1;
590         path = bmalloc(length);
591         sprintf(path, "%s/%s", base, file);
592         if (access(path, R_OK) == 0)
593             break;
594         free(path);
595         path = NULL;
596     }
597     return path;
598 }
599
600
601 /*
602  * Free a path returned from test_file_path().  This function exists primarily
603  * for Windows, where memory must be freed from the same library domain that
604  * it was allocated from.
605  */
606 void
607 test_file_path_free(char *path)
608 {
609     if (path != NULL)
610         free(path);
611 }
612
613
614 /*
615  * Create a temporary directory, tmp, under BUILD if set and the current
616  * directory if it does not.  Returns the path to the temporary directory in
617  * newly allocated memory, and calls bail on any failure.  The return value
618  * should be freed with test_tmpdir_free.
619  *
620  * This function uses sprintf because it attempts to be independent of all
621  * other portability layers.  The use immediately after a memory allocation
622  * should be safe without using snprintf or strlcpy/strlcat.
623  */
624 char *
625 test_tmpdir(void)
626 {
627     const char *build;
628     char *path = NULL;
629     size_t length;
630
631     build = getenv("BUILD");
632     if (build == NULL)
633         build = ".";
634     length = strlen(build) + strlen("/tmp") + 1;
635     path = bmalloc(length);
636     sprintf(path, "%s/tmp", build);
637     if (access(path, X_OK) < 0)
638         if (mkdir(path, 0777) < 0)
639             sysbail("error creating temporary directory %s", path);
640     return path;
641 }
642
643
644 /*
645  * Free a path returned from test_tmpdir() and attempt to remove the
646  * directory.  If we can't delete the directory, don't worry; something else
647  * that hasn't yet cleaned up may still be using it.
648  */
649 void
650 test_tmpdir_free(char *path)
651 {
652     rmdir(path);
653     if (path != NULL)
654         free(path);
655 }
656
657
658 /*
659  * Register a cleanup function that is called when testing ends.  All such
660  * registered functions will be run by finish.
661  */
662 void
663 test_cleanup_register(test_cleanup_func func)
664 {
665     struct cleanup_func *cleanup, **last;
666
667     cleanup = bmalloc(sizeof(struct cleanup_func));
668     cleanup->func = func;
669     cleanup->next = NULL;
670     last = &cleanup_funcs;
671     while (*last != NULL)
672         last = &(*last)->next;
673     *last = cleanup;
674 }