]> eyrie.org Git - kerberos/krb5-strength.git/blob - tests/tap/basic.c
Update to rra-c-util 5.3 and C TAP Harness 3.0
[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, 2014
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  * Registered diag files.  Any output found in these files will be printed out
106  * as if it were passed to diag() before any other output we do.  This allows
107  * background processes to log to a file and have that output interleved with
108  * the test output.
109  */
110 struct diag_file {
111     char *name;
112     FILE *file;
113     char *buffer;
114     size_t bufsize;
115     struct diag_file *next;
116 };
117 static struct diag_file *diag_files = NULL;
118
119 /*
120  * Print a specified prefix and then the test description.  Handles turning
121  * the argument list into a va_args structure suitable for passing to
122  * print_desc, which has to be done in a macro.  Assumes that format is the
123  * argument immediately before the variadic arguments.
124  */
125 #define PRINT_DESC(prefix, format)              \
126     do {                                        \
127         if (format != NULL) {                   \
128             va_list args;                       \
129             if (prefix != NULL)                 \
130                 printf("%s", prefix);           \
131             va_start(args, format);             \
132             vprintf(format, args);              \
133             va_end(args);                       \
134         }                                       \
135     } while (0)
136
137
138 /*
139  * Check all registered diag_files for any output.  We only print out the
140  * output if we see a complete line; otherwise, we wait for the next newline.
141  */
142 static void
143 check_diag_files(void)
144 {
145     struct diag_file *file;
146     fpos_t where;
147     size_t length;
148     int incomplete;
149
150     /*
151      * Walk through each file and read each line of output available.  The
152      * general scheme here used is as follows: try to read a line of output at
153      * a time.  If we get NULL, check for EOF; on EOF, advance to the next
154      * file.
155      *
156      * If we get some data, see if it ends in a newline.  If it doesn't end in
157      * a newline, we have one of two cases: our buffer isn't large enough, in
158      * which case we resize it and try again, or we have incomplete data in
159      * the file, in which case we rewind the file and will try again next
160      * time.
161      */
162     for (file = diag_files; file != NULL; file = file->next) {
163         clearerr(file->file);
164
165         /* Store the current position in case we have to rewind. */
166         if (fgetpos(file->file, &where) < 0)
167             sysbail("cannot get position in %s", file->name);
168
169         /* Continue until we get EOF or an incomplete line of data. */
170         incomplete = 0;
171         while (!feof(file->file) && !incomplete) {
172             if (fgets(file->buffer, file->bufsize, file->file) == NULL) {
173                 if (ferror(file->file))
174                     sysbail("cannot read from %s", file->name);
175                 continue;
176             }
177
178             /*
179              * See if the line ends in a newline.  If not, see which error
180              * case we have.
181              */
182             length = strlen(file->buffer);
183             if (file->buffer[length - 1] != '\n') {
184                 if (length < file->bufsize - 1)
185                     incomplete = 1;
186                 else {
187                     file->bufsize += BUFSIZ;
188                     file->buffer = brealloc(file->buffer, file->bufsize);
189                 }
190
191                 /*
192                  * On either incomplete lines or too small of a buffer, rewind
193                  * and read the file again (on the next pass, if incomplete).
194                  * It's simpler than trying to double-buffer the file.
195                  */
196                 if (fsetpos(file->file, &where) < 0)
197                     sysbail("cannot set position in %s", file->name);
198                 continue;
199             }
200
201             /* We saw a complete line.  Print it out. */
202             printf("# %s", file->buffer);
203         }
204     }
205 }
206
207
208 /*
209  * Our exit handler.  Called on completion of the test to report a summary of
210  * results provided we're still in the original process.  This also handles
211  * printing out the plan if we used plan_lazy(), although that's suppressed if
212  * we never ran a test (due to an early bail, for example), and running any
213  * registered cleanup functions.
214  */
215 static void
216 finish(void)
217 {
218     int success, primary;
219     struct cleanup_func *current;
220     unsigned long highest = testnum - 1;
221     struct diag_file *file, *tmp;
222
223     /* Check for pending diag_file output. */
224     check_diag_files();
225
226     /* Free the diag_files. */
227     file = diag_files;
228     while (file != NULL) {
229         tmp = file;
230         file = file->next;
231         fclose(tmp->file);
232         free(tmp->name);
233         free(tmp->buffer);
234         free(tmp);
235     }
236     diag_files = NULL;
237
238     /*
239      * Determine whether all tests were successful, which is needed before
240      * calling cleanup functions since we pass that fact to the functions.
241      */
242     if (_planned == 0 && _lazy)
243         _planned = highest;
244     success = (!_aborted && _planned == highest && _failed == 0);
245
246     /*
247      * If there are any registered cleanup functions, we run those first.  We
248      * always run them, even if we didn't run a test.  Don't do anything
249      * except free the diag_files and call cleanup functions if we aren't the
250      * primary process (the process in which plan or plan_lazy was called),
251      * and tell the cleanup functions that fact.
252      */
253     primary = (_process == 0 || getpid() == _process);
254     while (cleanup_funcs != NULL) {
255         cleanup_funcs->func(success, primary);
256         current = cleanup_funcs;
257         cleanup_funcs = cleanup_funcs->next;
258         free(current);
259     }
260     if (!primary)
261         return;
262
263     /* Don't do anything further if we never planned a test. */
264     if (_planned == 0)
265         return;
266
267     /* If we're aborting due to bail, don't print summaries. */
268     if (_aborted)
269         return;
270
271     /* Print out the lazy plan if needed. */
272     fflush(stderr);
273     if (_lazy && _planned > 0)
274         printf("1..%lu\n", _planned);
275
276     /* Print out a summary of the results. */
277     if (_planned > highest)
278         diag("Looks like you planned %lu test%s but only ran %lu", _planned,
279              (_planned > 1 ? "s" : ""), highest);
280     else if (_planned < highest)
281         diag("Looks like you planned %lu test%s but ran %lu extra", _planned,
282              (_planned > 1 ? "s" : ""), highest - _planned);
283     else if (_failed > 0)
284         diag("Looks like you failed %lu test%s of %lu", _failed,
285              (_failed > 1 ? "s" : ""), _planned);
286     else if (_planned != 1)
287         diag("All %lu tests successful or skipped", _planned);
288     else
289         diag("%lu test successful or skipped", _planned);
290 }
291
292
293 /*
294  * Initialize things.  Turns on line buffering on stdout and then prints out
295  * the number of tests in the test suite.  We intentionally don't check for
296  * pending diag_file output here, since it should really come after the plan.
297  */
298 void
299 plan(unsigned long count)
300 {
301     if (setvbuf(stdout, NULL, _IOLBF, BUFSIZ) != 0)
302         sysdiag("cannot set stdout to line buffered");
303     fflush(stderr);
304     printf("1..%lu\n", count);
305     testnum = 1;
306     _planned = count;
307     _process = getpid();
308     if (atexit(finish) != 0) {
309         sysdiag("cannot register exit handler");
310         diag("cleanups will not be run");
311     }
312 }
313
314
315 /*
316  * Initialize things for lazy planning, where we'll automatically print out a
317  * plan at the end of the program.  Turns on line buffering on stdout as well.
318  */
319 void
320 plan_lazy(void)
321 {
322     if (setvbuf(stdout, NULL, _IOLBF, BUFSIZ) != 0)
323         sysdiag("cannot set stdout to line buffered");
324     testnum = 1;
325     _process = getpid();
326     _lazy = 1;
327     if (atexit(finish) != 0)
328         sysbail("cannot register exit handler to display plan");
329 }
330
331
332 /*
333  * Skip the entire test suite and exits.  Should be called instead of plan(),
334  * not after it, since it prints out a special plan line.  Ignore diag_file
335  * output here, since it's not clear if it's allowed before the plan.
336  */
337 void
338 skip_all(const char *format, ...)
339 {
340     fflush(stderr);
341     printf("1..0 # skip");
342     PRINT_DESC(" ", format);
343     putchar('\n');
344     exit(0);
345 }
346
347
348 /*
349  * Takes a boolean success value and assumes the test passes if that value
350  * is true and fails if that value is false.
351  */
352 void
353 ok(int success, const char *format, ...)
354 {
355     fflush(stderr);
356     check_diag_files();
357     printf("%sok %lu", success ? "" : "not ", testnum++);
358     if (!success)
359         _failed++;
360     PRINT_DESC(" - ", format);
361     putchar('\n');
362 }
363
364
365 /*
366  * Same as ok(), but takes the format arguments as a va_list.
367  */
368 void
369 okv(int success, const char *format, va_list args)
370 {
371     fflush(stderr);
372     check_diag_files();
373     printf("%sok %lu", success ? "" : "not ", testnum++);
374     if (!success)
375         _failed++;
376     if (format != NULL) {
377         printf(" - ");
378         vprintf(format, args);
379     }
380     putchar('\n');
381 }
382
383
384 /*
385  * Skip a test.
386  */
387 void
388 skip(const char *reason, ...)
389 {
390     fflush(stderr);
391     check_diag_files();
392     printf("ok %lu # skip", testnum++);
393     PRINT_DESC(" ", reason);
394     putchar('\n');
395 }
396
397
398 /*
399  * Report the same status on the next count tests.
400  */
401 void
402 ok_block(unsigned long count, int status, const char *format, ...)
403 {
404     unsigned long i;
405
406     fflush(stderr);
407     check_diag_files();
408     for (i = 0; i < count; i++) {
409         printf("%sok %lu", status ? "" : "not ", testnum++);
410         if (!status)
411             _failed++;
412         PRINT_DESC(" - ", format);
413         putchar('\n');
414     }
415 }
416
417
418 /*
419  * Skip the next count tests.
420  */
421 void
422 skip_block(unsigned long count, const char *reason, ...)
423 {
424     unsigned long i;
425
426     fflush(stderr);
427     check_diag_files();
428     for (i = 0; i < count; i++) {
429         printf("ok %lu # skip", testnum++);
430         PRINT_DESC(" ", reason);
431         putchar('\n');
432     }
433 }
434
435
436 /*
437  * Takes an expected integer and a seen integer and assumes the test passes
438  * if those two numbers match.
439  */
440 void
441 is_int(long wanted, long seen, const char *format, ...)
442 {
443     fflush(stderr);
444     check_diag_files();
445     if (wanted == seen)
446         printf("ok %lu", testnum++);
447     else {
448         diag("wanted: %ld", wanted);
449         diag("  seen: %ld", seen);
450         printf("not ok %lu", testnum++);
451         _failed++;
452     }
453     PRINT_DESC(" - ", format);
454     putchar('\n');
455 }
456
457
458 /*
459  * Takes a string and what the string should be, and assumes the test passes
460  * if those strings match (using strcmp).
461  */
462 void
463 is_string(const char *wanted, const char *seen, const char *format, ...)
464 {
465     if (wanted == NULL)
466         wanted = "(null)";
467     if (seen == NULL)
468         seen = "(null)";
469     fflush(stderr);
470     check_diag_files();
471     if (strcmp(wanted, seen) == 0)
472         printf("ok %lu", testnum++);
473     else {
474         diag("wanted: %s", wanted);
475         diag("  seen: %s", seen);
476         printf("not ok %lu", testnum++);
477         _failed++;
478     }
479     PRINT_DESC(" - ", format);
480     putchar('\n');
481 }
482
483
484 /*
485  * Takes an expected unsigned long and a seen unsigned long and assumes the
486  * test passes if the two numbers match.  Otherwise, reports them in hex.
487  */
488 void
489 is_hex(unsigned long wanted, unsigned long seen, const char *format, ...)
490 {
491     fflush(stderr);
492     check_diag_files();
493     if (wanted == seen)
494         printf("ok %lu", testnum++);
495     else {
496         diag("wanted: %lx", (unsigned long) wanted);
497         diag("  seen: %lx", (unsigned long) seen);
498         printf("not ok %lu", testnum++);
499         _failed++;
500     }
501     PRINT_DESC(" - ", format);
502     putchar('\n');
503 }
504
505
506 /*
507  * Bail out with an error.
508  */
509 void
510 bail(const char *format, ...)
511 {
512     va_list args;
513
514     _aborted = 1;
515     fflush(stderr);
516     check_diag_files();
517     fflush(stdout);
518     printf("Bail out! ");
519     va_start(args, format);
520     vprintf(format, args);
521     va_end(args);
522     printf("\n");
523     exit(255);
524 }
525
526
527 /*
528  * Bail out with an error, appending strerror(errno).
529  */
530 void
531 sysbail(const char *format, ...)
532 {
533     va_list args;
534     int oerrno = errno;
535
536     _aborted = 1;
537     fflush(stderr);
538     check_diag_files();
539     fflush(stdout);
540     printf("Bail out! ");
541     va_start(args, format);
542     vprintf(format, args);
543     va_end(args);
544     printf(": %s\n", strerror(oerrno));
545     exit(255);
546 }
547
548
549 /*
550  * Report a diagnostic to stderr.
551  */
552 void
553 diag(const char *format, ...)
554 {
555     va_list args;
556
557     fflush(stderr);
558     check_diag_files();
559     fflush(stdout);
560     printf("# ");
561     va_start(args, format);
562     vprintf(format, args);
563     va_end(args);
564     printf("\n");
565 }
566
567
568 /*
569  * Report a diagnostic to stderr, appending strerror(errno).
570  */
571 void
572 sysdiag(const char *format, ...)
573 {
574     va_list args;
575     int oerrno = errno;
576
577     fflush(stderr);
578     check_diag_files();
579     fflush(stdout);
580     printf("# ");
581     va_start(args, format);
582     vprintf(format, args);
583     va_end(args);
584     printf(": %s\n", strerror(oerrno));
585 }
586
587
588 /*
589  * Register a new file for diag_file processing.
590  */
591 void
592 diag_file_add(const char *name)
593 {
594     struct diag_file *file, *prev;
595
596     file = bcalloc(1, sizeof(struct diag_file));
597     file->name = bstrdup(name);
598     file->file = fopen(file->name, "r");
599     if (file->file == NULL)
600         sysbail("cannot open %s", name);
601     file->buffer = bmalloc(BUFSIZ);
602     file->bufsize = BUFSIZ;
603     if (diag_files == NULL)
604         diag_files = file;
605     else {
606         for (prev = diag_files; prev->next != NULL; prev = prev->next)
607             ;
608         prev->next = file;
609     }
610 }
611
612
613 /*
614  * Remove a file from diag_file processing.  If the file is not found, do
615  * nothing, since there are some situations where it can be removed twice
616  * (such as if it's removed from a cleanup function, since cleanup functions
617  * are called after freeing all the diag_files).
618  */
619 void
620 diag_file_remove(const char *name)
621 {
622     struct diag_file *file;
623     struct diag_file **prev = &diag_files;
624
625     for (file = diag_files; file != NULL; file = file->next) {
626         if (strcmp(file->name, name) == 0) {
627             *prev = file->next;
628             fclose(file->file);
629             free(file->name);
630             free(file->buffer);
631             free(file);
632             return;
633         }
634         prev = &file->next;
635     }
636 }
637
638
639 /*
640  * Allocate cleared memory, reporting a fatal error with bail on failure.
641  */
642 void *
643 bcalloc(size_t n, size_t size)
644 {
645     void *p;
646
647     p = calloc(n, size);
648     if (p == NULL)
649         sysbail("failed to calloc %lu", (unsigned long)(n * size));
650     return p;
651 }
652
653
654 /*
655  * Allocate memory, reporting a fatal error with bail on failure.
656  */
657 void *
658 bmalloc(size_t size)
659 {
660     void *p;
661
662     p = malloc(size);
663     if (p == NULL)
664         sysbail("failed to malloc %lu", (unsigned long) size);
665     return p;
666 }
667
668
669 /*
670  * Reallocate memory, reporting a fatal error with bail on failure.
671  */
672 void *
673 brealloc(void *p, size_t size)
674 {
675     p = realloc(p, size);
676     if (p == NULL)
677         sysbail("failed to realloc %lu bytes", (unsigned long) size);
678     return p;
679 }
680
681
682 /*
683  * Copy a string, reporting a fatal error with bail on failure.
684  */
685 char *
686 bstrdup(const char *s)
687 {
688     char *p;
689     size_t len;
690
691     len = strlen(s) + 1;
692     p = malloc(len);
693     if (p == NULL)
694         sysbail("failed to strdup %lu bytes", (unsigned long) len);
695     memcpy(p, s, len);
696     return p;
697 }
698
699
700 /*
701  * Copy up to n characters of a string, reporting a fatal error with bail on
702  * failure.  Don't use the system strndup function, since it may not exist and
703  * the TAP library doesn't assume any portability support.
704  */
705 char *
706 bstrndup(const char *s, size_t n)
707 {
708     const char *p;
709     char *copy;
710     size_t length;
711
712     /* Don't assume that the source string is nul-terminated. */
713     for (p = s; (size_t) (p - s) < n && *p != '\0'; p++)
714         ;
715     length = p - s;
716     copy = malloc(length + 1);
717     if (p == NULL)
718         sysbail("failed to strndup %lu bytes", (unsigned long) length);
719     memcpy(copy, s, length);
720     copy[length] = '\0';
721     return copy;
722 }
723
724
725 /*
726  * Locate a test file.  Given the partial path to a file, look under BUILD and
727  * then SOURCE for the file and return the full path to the file.  Returns
728  * NULL if the file doesn't exist.  A non-NULL return should be freed with
729  * test_file_path_free().
730  *
731  * This function uses sprintf because it attempts to be independent of all
732  * other portability layers.  The use immediately after a memory allocation
733  * should be safe without using snprintf or strlcpy/strlcat.
734  */
735 char *
736 test_file_path(const char *file)
737 {
738     char *base;
739     char *path = NULL;
740     size_t length;
741     const char *envs[] = { "BUILD", "SOURCE", NULL };
742     int i;
743
744     for (i = 0; envs[i] != NULL; i++) {
745         base = getenv(envs[i]);
746         if (base == NULL)
747             continue;
748         length = strlen(base) + 1 + strlen(file) + 1;
749         path = bmalloc(length);
750         sprintf(path, "%s/%s", base, file);
751         if (access(path, R_OK) == 0)
752             break;
753         free(path);
754         path = NULL;
755     }
756     return path;
757 }
758
759
760 /*
761  * Free a path returned from test_file_path().  This function exists primarily
762  * for Windows, where memory must be freed from the same library domain that
763  * it was allocated from.
764  */
765 void
766 test_file_path_free(char *path)
767 {
768     free(path);
769 }
770
771
772 /*
773  * Create a temporary directory, tmp, under BUILD if set and the current
774  * directory if it does not.  Returns the path to the temporary directory in
775  * newly allocated memory, and calls bail on any failure.  The return value
776  * should be freed with test_tmpdir_free.
777  *
778  * This function uses sprintf because it attempts to be independent of all
779  * other portability layers.  The use immediately after a memory allocation
780  * should be safe without using snprintf or strlcpy/strlcat.
781  */
782 char *
783 test_tmpdir(void)
784 {
785     const char *build;
786     char *path = NULL;
787     size_t length;
788
789     build = getenv("BUILD");
790     if (build == NULL)
791         build = ".";
792     length = strlen(build) + strlen("/tmp") + 1;
793     path = bmalloc(length);
794     sprintf(path, "%s/tmp", build);
795     if (access(path, X_OK) < 0)
796         if (mkdir(path, 0777) < 0)
797             sysbail("error creating temporary directory %s", path);
798     return path;
799 }
800
801
802 /*
803  * Free a path returned from test_tmpdir() and attempt to remove the
804  * directory.  If we can't delete the directory, don't worry; something else
805  * that hasn't yet cleaned up may still be using it.
806  */
807 void
808 test_tmpdir_free(char *path)
809 {
810     if (path != NULL)
811         rmdir(path);
812     free(path);
813 }
814
815
816 /*
817  * Register a cleanup function that is called when testing ends.  All such
818  * registered functions will be run by finish.
819  */
820 void
821 test_cleanup_register(test_cleanup_func func)
822 {
823     struct cleanup_func *cleanup, **last;
824
825     cleanup = bmalloc(sizeof(struct cleanup_func));
826     cleanup->func = func;
827     cleanup->next = NULL;
828     last = &cleanup_funcs;
829     while (*last != NULL)
830         last = &(*last)->next;
831     *last = cleanup;
832 }