1 /*
2  * Run a set of tests, reporting results.
3  *
4  * Test suite driver that runs a set of tests implementing a subset of the
5  * Test Anything Protocol (TAP) and reports the results.
6  *
7  * Any bug reports, bug fixes, and improvements are very much welcome and
8  * should be sent to the e-mail address below.  This program is part of C TAP
9  * Harness <https://www.eyrie.org/~eagle/software/c-tap-harness/>.
10  *
11  * Copyright 2000-2001, 2004, 2006-2019 Russ Allbery <eagle@eyrie.org>
12  *
13  * Permission is hereby granted, free of charge, to any person obtaining a
14  * copy of this software and associated documentation files (the "Software"),
15  * to deal in the Software without restriction, including without limitation
16  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17  * and/or sell copies of the Software, and to permit persons to whom the
18  * Software is furnished to do so, subject to the following conditions:
19  *
20  * The above copyright notice and this permission notice shall be included in
21  * all copies or substantial portions of the Software.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
26  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29  * DEALINGS IN THE SOFTWARE.
30  *
31  * SPDX-License-Identifier: MIT
32  */
33 
34 /*
35  * Usage:
36  *
37  *      runtests [-hv] [-b <build-dir>] [-s <source-dir>] -l <test-list>
38  *      runtests [-hv] [-b <build-dir>] [-s <source-dir>] <test> [<test> ...]
39  *      runtests -o [-h] [-b <build-dir>] [-s <source-dir>] <test>
40  *
41  * In the first case, expects a list of executables located in the given file,
42  * one line per executable, possibly followed by a space-separated list of
43  * options.  For each one, runs it as part of a test suite, reporting results.
44  * In the second case, use the same infrastructure, but run only the tests
45  * listed on the command line.
46  *
47  * Test output should start with a line containing the number of tests
48  * (numbered from 1 to this number), optionally preceded by "1..", although
49  * that line may be given anywhere in the output.  Each additional line should
50  * be in the following format:
51  *
52  *      ok <number>
53  *      not ok <number>
54  *      ok <number> # skip
55  *      not ok <number> # todo
56  *
57  * where <number> is the number of the test.  An optional comment is permitted
58  * after the number if preceded by whitespace.  ok indicates success, not ok
59  * indicates failure.  "# skip" and "# todo" are a special cases of a comment,
60  * and must start with exactly that formatting.  They indicate the test was
61  * skipped for some reason (maybe because it doesn't apply to this platform)
62  * or is testing something known to currently fail.  The text following either
63  * "# skip" or "# todo" and whitespace is the reason.
64  *
65  * As a special case, the first line of the output may be in the form:
66  *
67  *      1..0 # skip some reason
68  *
69  * which indicates that this entire test case should be skipped and gives a
70  * reason.
71  *
72  * Any other lines are ignored, although for compliance with the TAP protocol
73  * all lines other than the ones in the above format should be sent to
74  * standard error rather than standard output and start with #.
75  *
76  * This is a subset of TAP as documented in Test::Harness::TAP or
77  * TAP::Parser::Grammar, which comes with Perl.
78  *
79  * If the -o option is given, instead run a single test and display all of its
80  * output.  This is intended for use with failing tests so that the person
81  * running the test suite can get more details about what failed.
82  *
83  * If built with the C preprocessor symbols C_TAP_SOURCE and C_TAP_BUILD
84  * defined, C TAP Harness will export those values in the environment so that
85  * tests can find the source and build directory and will look for tests under
86  * both directories.  These paths can also be set with the -b and -s
87  * command-line options, which will override anything set at build time.
88  *
89  * If the -v option is given, or the C_TAP_VERBOSE environment variable is set,
90  * display the full output of each test as it runs rather than showing a
91  * summary of the results of each test.
92  */
93 
94 /* Required for fdopen(), getopt(), and putenv(). */
95 #if defined(__STRICT_ANSI__) || defined(PEDANTIC)
96 #    ifndef _XOPEN_SOURCE
97 #        define _XOPEN_SOURCE 500
98 #    endif
99 #endif
100 
101 #include <ctype.h>
102 #include <errno.h>
103 #include <fcntl.h>
104 #include <limits.h>
105 #include <stdarg.h>
106 #include <stddef.h>
107 #include <stdio.h>
108 #include <stdlib.h>
109 #include <string.h>
110 #include <strings.h>
111 #include <sys/stat.h>
112 #include <sys/time.h>
113 #include <sys/types.h>
114 #include <sys/wait.h>
115 #include <time.h>
116 #include <unistd.h>
117 
118 /* sys/time.h must be included before sys/resource.h on some platforms. */
119 #include <sys/resource.h>
120 
121 /* AIX 6.1 (and possibly later) doesn't have WCOREDUMP. */
122 #ifndef WCOREDUMP
123 #    define WCOREDUMP(status) ((unsigned) (status) &0x80)
124 #endif
125 
126 /*
127  * POSIX requires that these be defined in <unistd.h>, but they're not always
128  * available.  If one of them has been defined, all the rest almost certainly
129  * have.
130  */
131 #ifndef STDIN_FILENO
132 #    define STDIN_FILENO  0
133 #    define STDOUT_FILENO 1
134 #    define STDERR_FILENO 2
135 #endif
136 
137 /*
138  * Used for iterating through arrays.  Returns the number of elements in the
139  * array (useful for a < upper bound in a for loop).
140  */
141 #define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
142 
143 /*
144  * The source and build versions of the tests directory.  This is used to set
145  * the C_TAP_SOURCE and C_TAP_BUILD environment variables (and the SOURCE and
146  * BUILD environment variables set for backward compatibility) and find test
147  * programs, if set.  Normally, this should be set as part of the build
148  * process to the test subdirectories of $(abs_top_srcdir) and
149  * $(abs_top_builddir) respectively.
150  */
151 #ifndef C_TAP_SOURCE
152 #    define C_TAP_SOURCE NULL
153 #endif
154 #ifndef C_TAP_BUILD
155 #    define C_TAP_BUILD NULL
156 #endif
157 
158 /* Test status codes. */
159 enum test_status
160 {
161     TEST_FAIL,
162     TEST_PASS,
163     TEST_SKIP,
164     TEST_INVALID
165 };
166 
167 /* Really, just a boolean, but this is more self-documenting. */
168 enum test_verbose
169 {
170     CONCISE = 0,
171     VERBOSE = 1
172 };
173 
174 /* Indicates the state of our plan. */
175 enum plan_status
176 {
177     PLAN_INIT,    /* Nothing seen yet. */
178     PLAN_FIRST,   /* Plan seen before any tests. */
179     PLAN_PENDING, /* Test seen and no plan yet. */
180     PLAN_FINAL    /* Plan seen after some tests. */
181 };
182 
183 /* Error exit statuses for test processes. */
184 #define CHILDERR_DUP    100 /* Couldn't redirect stderr or stdout. */
185 #define CHILDERR_EXEC   101 /* Couldn't exec child process. */
186 #define CHILDERR_STDIN  102 /* Couldn't open stdin file. */
187 #define CHILDERR_STDERR 103 /* Couldn't open stderr file. */
188 
189 /* Structure to hold data for a set of tests. */
190 struct testset {
191     char *file;                /* The file name of the test. */
192     char **command;            /* The argv vector to run the command. */
193     enum plan_status plan;     /* The status of our plan. */
194     unsigned long count;       /* Expected count of tests. */
195     unsigned long current;     /* The last seen test number. */
196     unsigned int length;       /* The length of the last status message. */
197     unsigned long passed;      /* Count of passing tests. */
198     unsigned long failed;      /* Count of failing lists. */
199     unsigned long skipped;     /* Count of skipped tests (passed). */
200     unsigned long allocated;   /* The size of the results table. */
201     enum test_status *results; /* Table of results by test number. */
202     unsigned int aborted;      /* Whether the set was aborted. */
203     unsigned int reported;     /* Whether the results were reported. */
204     int status;                /* The exit status of the test. */
205     unsigned int all_skipped;  /* Whether all tests were skipped. */
206     char *reason;              /* Why all tests were skipped. */
207 };
208 
209 /* Structure to hold a linked list of test sets. */
210 struct testlist {
211     struct testset *ts;
212     struct testlist *next;
213 };
214 
215 /*
216  * Usage message.  Should be used as a printf format with four arguments: the
217  * path to runtests, given three times, and the usage_description.  This is
218  * split into variables to satisfy the pedantic ISO C90 limit on strings.
219  */
220 static const char usage_message[] = "\
221 Usage: %s [-hv] [-b <build-dir>] [-s <source-dir>] <test> ...\n\
222        %s [-hv] [-b <build-dir>] [-s <source-dir>] -l <test-list>\n\
223        %s -o [-h] [-b <build-dir>] [-s <source-dir>] <test>\n\
224 \n\
225 Options:\n\
226     -b <build-dir>      Set the build directory to <build-dir>\n\
227 %s";
228 static const char usage_extra[] = "\
229     -l <list>           Take the list of tests to run from <test-list>\n\
230     -o                  Run a single test rather than a list of tests\n\
231     -s <source-dir>     Set the source directory to <source-dir>\n\
232     -v                  Show the full output of each test\n\
233 \n\
234 runtests normally runs each test listed on the command line.  With the -l\n\
235 option, it instead runs every test listed in a file.  With the -o option,\n\
236 it instead runs a single test and shows its complete output.\n";
237 
238 /*
239  * Header used for test output.  %s is replaced by the file name of the list
240  * of tests.
241  */
242 static const char banner[] = "\n\
243 Running all tests listed in %s.  If any tests fail, run the failing\n\
244 test program with runtests -o to see more details.\n\n";
245 
246 /* Header for reports of failed tests. */
247 static const char header[] = "\n\
248 Failed Set                 Fail/Total (%) Skip Stat  Failing Tests\n\
249 -------------------------- -------------- ---- ----  ------------------------";
250 
251 /* Include the file name and line number in malloc failures. */
252 #define xcalloc(n, type) \
253     ((type *) x_calloc((n), sizeof(type), __FILE__, __LINE__))
254 #define xmalloc(size)     ((char *) x_malloc((size), __FILE__, __LINE__))
255 #define xstrdup(p)        x_strdup((p), __FILE__, __LINE__)
256 #define xstrndup(p, size) x_strndup((p), (size), __FILE__, __LINE__)
257 #define xreallocarray(p, n, type) \
258     ((type *) x_reallocarray((p), (n), sizeof(type), __FILE__, __LINE__))
259 
260 /*
261  * __attribute__ is available in gcc 2.5 and later, but only with gcc 2.7
262  * could you use the __format__ form of the attributes, which is what we use
263  * (to avoid confusion with other macros).
264  */
265 #ifndef __attribute__
266 #    if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
267 #        define __attribute__(spec) /* empty */
268 #    endif
269 #endif
270 
271 /*
272  * We use __alloc_size__, but it was only available in fairly recent versions
273  * of GCC.  Suppress warnings about the unknown attribute if GCC is too old.
274  * We know that we're GCC at this point, so we can use the GCC variadic macro
275  * extension, which will still work with versions of GCC too old to have C99
276  * variadic macro support.
277  */
278 #if !defined(__attribute__) && !defined(__alloc_size__)
279 #    if defined(__GNUC__) && !defined(__clang__)
280 #        if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3)
281 #            define __alloc_size__(spec, args...) /* empty */
282 #        endif
283 #    endif
284 #endif
285 
286 /*
287  * LLVM and Clang pretend to be GCC but don't support all of the __attribute__
288  * settings that GCC does.  For them, suppress warnings about unknown
289  * attributes on declarations.  This unfortunately will affect the entire
290  * compilation context, but there's no push and pop available.
291  */
292 #if !defined(__attribute__) && (defined(__llvm__) || defined(__clang__))
293 #    pragma GCC diagnostic ignored "-Wattributes"
294 #endif
295 
296 /* Declare internal functions that benefit from compiler attributes. */
297 static void die(const char *, ...)
298     __attribute__((__nonnull__, __noreturn__, __format__(printf, 1, 2)));
299 static void sysdie(const char *, ...)
300     __attribute__((__nonnull__, __noreturn__, __format__(printf, 1, 2)));
301 static void *x_calloc(size_t, size_t, const char *, int)
302     __attribute__((__alloc_size__(1, 2), __malloc__, __nonnull__));
303 static void *x_malloc(size_t, const char *, int)
304     __attribute__((__alloc_size__(1), __malloc__, __nonnull__));
305 static void *x_reallocarray(void *, size_t, size_t, const char *, int)
306     __attribute__((__alloc_size__(2, 3), __malloc__, __nonnull__(4)));
307 static char *x_strdup(const char *, const char *, int)
308     __attribute__((__malloc__, __nonnull__));
309 static char *x_strndup(const char *, size_t, const char *, int)
310     __attribute__((__malloc__, __nonnull__));
311 
312 
313 /*
314  * Report a fatal error and exit.
315  */
316 static void
die(const char * format,...)317 die(const char *format, ...)
318 {
319     va_list args;
320 
321     fflush(stdout);
322     fprintf(stderr, "runtests: ");
323     va_start(args, format);
324     vfprintf(stderr, format, args);
325     va_end(args);
326     fprintf(stderr, "\n");
327     exit(1);
328 }
329 
330 
331 /*
332  * Report a fatal error, including the results of strerror, and exit.
333  */
334 static void
sysdie(const char * format,...)335 sysdie(const char *format, ...)
336 {
337     int oerrno;
338     va_list args;
339 
340     oerrno = errno;
341     fflush(stdout);
342     fprintf(stderr, "runtests: ");
343     va_start(args, format);
344     vfprintf(stderr, format, args);
345     va_end(args);
346     fprintf(stderr, ": %s\n", strerror(oerrno));
347     exit(1);
348 }
349 
350 
351 /*
352  * Allocate zeroed memory, reporting a fatal error and exiting on failure.
353  */
354 static void *
x_calloc(size_t n,size_t size,const char * file,int line)355 x_calloc(size_t n, size_t size, const char *file, int line)
356 {
357     void *p;
358 
359     n = (n > 0) ? n : 1;
360     size = (size > 0) ? size : 1;
361     p = calloc(n, size);
362     if (p == NULL)
363         sysdie("failed to calloc %lu bytes at %s line %d",
364                (unsigned long) size, file, line);
365     return p;
366 }
367 
368 
369 /*
370  * Allocate memory, reporting a fatal error and exiting on failure.
371  */
372 static void *
x_malloc(size_t size,const char * file,int line)373 x_malloc(size_t size, const char *file, int line)
374 {
375     void *p;
376 
377     p = malloc(size);
378     if (p == NULL)
379         sysdie("failed to malloc %lu bytes at %s line %d",
380                (unsigned long) size, file, line);
381     return p;
382 }
383 
384 
385 /*
386  * Reallocate memory, reporting a fatal error and exiting on failure.
387  *
388  * We should technically use SIZE_MAX here for the overflow check, but
389  * SIZE_MAX is C99 and we're only assuming C89 + SUSv3, which does not
390  * guarantee that it exists.  They do guarantee that UINT_MAX exists, and we
391  * can assume that UINT_MAX <= SIZE_MAX.  And we should not be allocating
392  * anything anywhere near that large.
393  *
394  * (In theory, C89 and C99 permit size_t to be smaller than unsigned int, but
395  * I disbelieve in the existence of such systems and they will have to cope
396  * without overflow checks.)
397  */
398 static void *
x_reallocarray(void * p,size_t n,size_t size,const char * file,int line)399 x_reallocarray(void *p, size_t n, size_t size, const char *file, int line)
400 {
401     n = (n > 0) ? n : 1;
402     size = (size > 0) ? size : 1;
403 
404     if (UINT_MAX / n <= size)
405         sysdie("realloc too large at %s line %d", file, line);
406     p = realloc(p, n * size);
407     if (p == NULL)
408         sysdie("failed to realloc %lu bytes at %s line %d",
409                (unsigned long) (n * size), file, line);
410     return p;
411 }
412 
413 
414 /*
415  * Copy a string, reporting a fatal error and exiting on failure.
416  */
417 static char *
x_strdup(const char * s,const char * file,int line)418 x_strdup(const char *s, const char *file, int line)
419 {
420     char *p;
421     size_t len;
422 
423     len = strlen(s) + 1;
424     p = (char *) malloc(len);
425     if (p == NULL)
426         sysdie("failed to strdup %lu bytes at %s line %d", (unsigned long) len,
427                file, line);
428     memcpy(p, s, len);
429     return p;
430 }
431 
432 
433 /*
434  * Copy the first n characters of a string, reporting a fatal error and
435  * existing on failure.
436  *
437  * Avoid using the system strndup function since it may not exist (on Mac OS
438  * X, for example), and there's no need to introduce another portability
439  * requirement.
440  */
441 char *
x_strndup(const char * s,size_t size,const char * file,int line)442 x_strndup(const char *s, size_t size, const char *file, int line)
443 {
444     const char *p;
445     size_t len;
446     char *copy;
447 
448     /* Don't assume that the source string is nul-terminated. */
449     for (p = s; (size_t)(p - s) < size && *p != '\0'; p++)
450         ;
451     len = (size_t)(p - s);
452     copy = (char *) malloc(len + 1);
453     if (copy == NULL)
454         sysdie("failed to strndup %lu bytes at %s line %d",
455                (unsigned long) len, file, line);
456     memcpy(copy, s, len);
457     copy[len] = '\0';
458     return copy;
459 }
460 
461 
462 /*
463  * Form a new string by concatenating multiple strings.  The arguments must be
464  * terminated by (const char *) 0.
465  *
466  * This function only exists because we can't assume asprintf.  We can't
467  * simulate asprintf with snprintf because we're only assuming SUSv3, which
468  * does not require that snprintf with a NULL buffer return the required
469  * length.  When those constraints are relaxed, this should be ripped out and
470  * replaced with asprintf or a more trivial replacement with snprintf.
471  */
472 static char *
concat(const char * first,...)473 concat(const char *first, ...)
474 {
475     va_list args;
476     char *result;
477     const char *string;
478     size_t offset;
479     size_t length = 0;
480 
481     /*
482      * Find the total memory required.  Ensure we don't overflow length.  We
483      * aren't guaranteed to have SIZE_MAX, so use UINT_MAX as an acceptable
484      * substitute (see the x_nrealloc comments).
485      */
486     va_start(args, first);
487     for (string = first; string != NULL; string = va_arg(args, const char *)) {
488         if (length >= UINT_MAX - strlen(string)) {
489             errno = EINVAL;
490             sysdie("strings too long in concat");
491         }
492         length += strlen(string);
493     }
494     va_end(args);
495     length++;
496 
497     /* Create the string. */
498     result = xmalloc(length);
499     va_start(args, first);
500     offset = 0;
501     for (string = first; string != NULL; string = va_arg(args, const char *)) {
502         memcpy(result + offset, string, strlen(string));
503         offset += strlen(string);
504     }
505     va_end(args);
506     result[offset] = '\0';
507     return result;
508 }
509 
510 
511 /*
512  * Given a struct timeval, return the number of seconds it represents as a
513  * double.  Use difftime() to convert a time_t to a double.
514  */
515 static double
tv_seconds(const struct timeval * tv)516 tv_seconds(const struct timeval *tv)
517 {
518     return difftime(tv->tv_sec, 0) + (double) tv->tv_usec * 1e-6;
519 }
520 
521 
522 /*
523  * Given two struct timevals, return the difference in seconds.
524  */
525 static double
tv_diff(const struct timeval * tv1,const struct timeval * tv0)526 tv_diff(const struct timeval *tv1, const struct timeval *tv0)
527 {
528     return tv_seconds(tv1) - tv_seconds(tv0);
529 }
530 
531 
532 /*
533  * Given two struct timevals, return the sum in seconds as a double.
534  */
535 static double
tv_sum(const struct timeval * tv1,const struct timeval * tv2)536 tv_sum(const struct timeval *tv1, const struct timeval *tv2)
537 {
538     return tv_seconds(tv1) + tv_seconds(tv2);
539 }
540 
541 
542 /*
543  * Given a pointer to a string, skip any leading whitespace and return a
544  * pointer to the first non-whitespace character.
545  */
546 static const char *
skip_whitespace(const char * p)547 skip_whitespace(const char *p)
548 {
549     while (isspace((unsigned char) (*p)))
550         p++;
551     return p;
552 }
553 
554 
555 /*
556  * Given a pointer to a string, skip any non-whitespace characters and return
557  * a pointer to the first whitespace character, or to the end of the string.
558  */
559 static const char *
skip_non_whitespace(const char * p)560 skip_non_whitespace(const char *p)
561 {
562     while (*p != '\0' && !isspace((unsigned char) (*p)))
563         p++;
564     return p;
565 }
566 
567 
568 /*
569  * Start a program, connecting its stdout to a pipe on our end and its stderr
570  * to /dev/null, and storing the file descriptor to read from in the two
571  * argument.  Returns the PID of the new process.  Errors are fatal.
572  */
573 static pid_t
test_start(char * const * command,int * fd)574 test_start(char *const *command, int *fd)
575 {
576     int fds[2], infd, errfd;
577     pid_t child;
578 
579     /* Create a pipe used to capture the output from the test program. */
580     if (pipe(fds) == -1) {
581         puts("ABORTED");
582         fflush(stdout);
583         sysdie("can't create pipe");
584     }
585 
586     /* Fork a child process, massage the file descriptors, and exec. */
587     child = fork();
588     switch (child) {
589     case -1:
590         puts("ABORTED");
591         fflush(stdout);
592         sysdie("can't fork");
593 
594     /* In the child.  Set up our standard output. */
595     case 0:
596         close(fds[0]);
597         close(STDOUT_FILENO);
598         if (dup2(fds[1], STDOUT_FILENO) < 0)
599             _exit(CHILDERR_DUP);
600         close(fds[1]);
601 
602         /* Point standard input at /dev/null. */
603         close(STDIN_FILENO);
604         infd = open("/dev/null", O_RDONLY);
605         if (infd < 0)
606             _exit(CHILDERR_STDIN);
607         if (infd != STDIN_FILENO) {
608             if (dup2(infd, STDIN_FILENO) < 0)
609                 _exit(CHILDERR_DUP);
610             close(infd);
611         }
612 
613         /* Point standard error at /dev/null. */
614         close(STDERR_FILENO);
615         errfd = open("/dev/null", O_WRONLY);
616         if (errfd < 0)
617             _exit(CHILDERR_STDERR);
618         if (errfd != STDERR_FILENO) {
619             if (dup2(errfd, STDERR_FILENO) < 0)
620                 _exit(CHILDERR_DUP);
621             close(errfd);
622         }
623 
624         /* Now, exec our process. */
625         if (execv(command[0], command) == -1)
626             _exit(CHILDERR_EXEC);
627         break;
628 
629     /* In parent.  Close the extra file descriptor. */
630     default:
631         close(fds[1]);
632         break;
633     }
634     *fd = fds[0];
635     return child;
636 }
637 
638 
639 /*
640  * Back up over the output saying what test we were executing.
641  */
642 static void
test_backspace(struct testset * ts)643 test_backspace(struct testset *ts)
644 {
645     unsigned int i;
646 
647     if (!isatty(STDOUT_FILENO))
648         return;
649     for (i = 0; i < ts->length; i++)
650         putchar('\b');
651     for (i = 0; i < ts->length; i++)
652         putchar(' ');
653     for (i = 0; i < ts->length; i++)
654         putchar('\b');
655     ts->length = 0;
656 }
657 
658 
659 /*
660  * Allocate or resize the array of test results to be large enough to contain
661  * the test number in.
662  */
663 static void
resize_results(struct testset * ts,unsigned long n)664 resize_results(struct testset *ts, unsigned long n)
665 {
666     unsigned long i;
667     size_t s;
668 
669     /* If there's already enough space, return quickly. */
670     if (n <= ts->allocated)
671         return;
672 
673     /*
674      * If no space has been allocated, do the initial allocation.  Otherwise,
675      * resize.  Start with 32 test cases and then add 1024 with each resize to
676      * try to reduce the number of reallocations.
677      */
678     if (ts->allocated == 0) {
679         s = (n > 32) ? n : 32;
680         ts->results = xcalloc(s, enum test_status);
681     } else {
682         s = (n > ts->allocated + 1024) ? n : ts->allocated + 1024;
683         ts->results = xreallocarray(ts->results, s, enum test_status);
684     }
685 
686     /* Set the results for the newly-allocated test array. */
687     for (i = ts->allocated; i < s; i++)
688         ts->results[i] = TEST_INVALID;
689     ts->allocated = s;
690 }
691 
692 
693 /*
694  * Report an invalid test number and set the appropriate flags.  Pulled into a
695  * separate function since we do this in several places.
696  */
697 static void
invalid_test_number(struct testset * ts,long n,enum test_verbose verbose)698 invalid_test_number(struct testset *ts, long n, enum test_verbose verbose)
699 {
700     if (!verbose)
701         test_backspace(ts);
702     printf("ABORTED (invalid test number %ld)\n", n);
703     ts->aborted = 1;
704     ts->reported = 1;
705 }
706 
707 
708 /*
709  * Read the plan line of test output, which should contain the range of test
710  * numbers.  We may initialize the testset structure here if we haven't yet
711  * seen a test.  Return true if initialization succeeded and the test should
712  * continue, false otherwise.
713  */
714 static int
test_plan(const char * line,struct testset * ts,enum test_verbose verbose)715 test_plan(const char *line, struct testset *ts, enum test_verbose verbose)
716 {
717     long n;
718 
719     /*
720      * Accept a plan without the leading 1.. for compatibility with older
721      * versions of runtests.  This will only be allowed if we've not yet seen
722      * a test result.
723      */
724     line = skip_whitespace(line);
725     if (strncmp(line, "1..", 3) == 0)
726         line += 3;
727 
728     /*
729      * Get the count and check it for validity.
730      *
731      * If we have something of the form "1..0 # skip foo", the whole file was
732      * skipped; record that.  If we do skip the whole file, zero out all of
733      * our statistics, since they're no longer relevant.
734      *
735      * strtol is called with a second argument to advance the line pointer
736      * past the count to make it simpler to detect the # skip case.
737      */
738     n = strtol(line, (char **) &line, 10);
739     if (n == 0) {
740         line = skip_whitespace(line);
741         if (*line == '#') {
742             line = skip_whitespace(line + 1);
743             if (strncasecmp(line, "skip", 4) == 0) {
744                 line = skip_whitespace(line + 4);
745                 if (*line != '\0') {
746                     ts->reason = xstrdup(line);
747                     ts->reason[strlen(ts->reason) - 1] = '\0';
748                 }
749                 ts->all_skipped = 1;
750                 ts->aborted = 1;
751                 ts->count = 0;
752                 ts->passed = 0;
753                 ts->skipped = 0;
754                 ts->failed = 0;
755                 return 0;
756             }
757         }
758     }
759     if (n <= 0) {
760         puts("ABORTED (invalid test count)");
761         ts->aborted = 1;
762         ts->reported = 1;
763         return 0;
764     }
765 
766     /*
767      * If we are doing lazy planning, check the plan against the largest test
768      * number that we saw and fail now if we saw a check outside the plan
769      * range.
770      */
771     if (ts->plan == PLAN_PENDING && (unsigned long) n < ts->count) {
772         invalid_test_number(ts, (long) ts->count, verbose);
773         return 0;
774     }
775 
776     /*
777      * Otherwise, allocated or resize the results if needed and update count,
778      * and then record that we've seen a plan.
779      */
780     resize_results(ts, (unsigned long) n);
781     ts->count = (unsigned long) n;
782     if (ts->plan == PLAN_INIT)
783         ts->plan = PLAN_FIRST;
784     else if (ts->plan == PLAN_PENDING)
785         ts->plan = PLAN_FINAL;
786     return 1;
787 }
788 
789 
790 /*
791  * Given a single line of output from a test, parse it and return the success
792  * status of that test.  Anything printed to stdout not matching the form
793  * /^(not )?ok \d+/ is ignored.  Sets ts->current to the test number that just
794  * reported status.
795  */
796 static void
test_checkline(const char * line,struct testset * ts,enum test_verbose verbose)797 test_checkline(const char *line, struct testset *ts, enum test_verbose verbose)
798 {
799     enum test_status status = TEST_PASS;
800     const char *bail;
801     char *end;
802     long number;
803     unsigned long current;
804     int outlen;
805 
806     /* Before anything, check for a test abort. */
807     bail = strstr(line, "Bail out!");
808     if (bail != NULL) {
809         bail = skip_whitespace(bail + strlen("Bail out!"));
810         if (*bail != '\0') {
811             size_t length;
812 
813             length = strlen(bail);
814             if (bail[length - 1] == '\n')
815                 length--;
816             if (!verbose)
817                 test_backspace(ts);
818             printf("ABORTED (%.*s)\n", (int) length, bail);
819             ts->reported = 1;
820         }
821         ts->aborted = 1;
822         return;
823     }
824 
825     /*
826      * If the given line isn't newline-terminated, it was too big for an
827      * fgets(), which means ignore it.
828      */
829     if (line[strlen(line) - 1] != '\n')
830         return;
831 
832     /* If the line begins with a hash mark, ignore it. */
833     if (line[0] == '#')
834         return;
835 
836     /* If we haven't yet seen a plan, look for one. */
837     if (ts->plan == PLAN_INIT && isdigit((unsigned char) (*line))) {
838         if (!test_plan(line, ts, verbose))
839             return;
840     } else if (strncmp(line, "1..", 3) == 0) {
841         if (ts->plan == PLAN_PENDING) {
842             if (!test_plan(line, ts, verbose))
843                 return;
844         } else {
845             if (!verbose)
846                 test_backspace(ts);
847             puts("ABORTED (multiple plans)");
848             ts->aborted = 1;
849             ts->reported = 1;
850             return;
851         }
852     }
853 
854     /* Parse the line, ignoring something we can't parse. */
855     if (strncmp(line, "not ", 4) == 0) {
856         status = TEST_FAIL;
857         line += 4;
858     }
859     if (strncmp(line, "ok", 2) != 0)
860         return;
861     line = skip_whitespace(line + 2);
862     errno = 0;
863     number = strtol(line, &end, 10);
864     if (errno != 0 || end == line)
865         current = ts->current + 1;
866     else if (number <= 0) {
867         invalid_test_number(ts, number, verbose);
868         return;
869     } else
870         current = (unsigned long) number;
871     if (current > ts->count && ts->plan == PLAN_FIRST) {
872         invalid_test_number(ts, (long) current, verbose);
873         return;
874     }
875 
876     /* We have a valid test result.  Tweak the results array if needed. */
877     if (ts->plan == PLAN_INIT || ts->plan == PLAN_PENDING) {
878         ts->plan = PLAN_PENDING;
879         resize_results(ts, current);
880         if (current > ts->count)
881             ts->count = current;
882     }
883 
884     /*
885      * Handle directives.  We should probably do something more interesting
886      * with unexpected passes of todo tests.
887      */
888     while (isdigit((unsigned char) (*line)))
889         line++;
890     line = skip_whitespace(line);
891     if (*line == '#') {
892         line = skip_whitespace(line + 1);
893         if (strncasecmp(line, "skip", 4) == 0)
894             status = TEST_SKIP;
895         if (strncasecmp(line, "todo", 4) == 0)
896             status = (status == TEST_FAIL) ? TEST_SKIP : TEST_FAIL;
897     }
898 
899     /* Make sure that the test number is in range and not a duplicate. */
900     if (ts->results[current - 1] != TEST_INVALID) {
901         if (!verbose)
902             test_backspace(ts);
903         printf("ABORTED (duplicate test number %lu)\n", current);
904         ts->aborted = 1;
905         ts->reported = 1;
906         return;
907     }
908 
909     /* Good results.  Increment our various counters. */
910     switch (status) {
911     case TEST_PASS:
912         ts->passed++;
913         break;
914     case TEST_FAIL:
915         ts->failed++;
916         break;
917     case TEST_SKIP:
918         ts->skipped++;
919         break;
920     case TEST_INVALID:
921         break;
922     }
923     ts->current = current;
924     ts->results[current - 1] = status;
925     if (!verbose && isatty(STDOUT_FILENO)) {
926         test_backspace(ts);
927         if (ts->plan == PLAN_PENDING)
928             outlen = printf("%lu/?", current);
929         else
930             outlen = printf("%lu/%lu", current, ts->count);
931         ts->length = (outlen >= 0) ? (unsigned int) outlen : 0;
932         fflush(stdout);
933     }
934 }
935 
936 
937 /*
938  * Print out a range of test numbers, returning the number of characters it
939  * took up.  Takes the first number, the last number, the number of characters
940  * already printed on the line, and the limit of number of characters the line
941  * can hold.  Add a comma and a space before the range if chars indicates that
942  * something has already been printed on the line, and print ... instead if
943  * chars plus the space needed would go over the limit (use a limit of 0 to
944  * disable this).
945  */
946 static unsigned int
test_print_range(unsigned long first,unsigned long last,unsigned long chars,unsigned int limit)947 test_print_range(unsigned long first, unsigned long last, unsigned long chars,
948                  unsigned int limit)
949 {
950     unsigned int needed = 0;
951     unsigned long n;
952 
953     for (n = first; n > 0; n /= 10)
954         needed++;
955     if (last > first) {
956         for (n = last; n > 0; n /= 10)
957             needed++;
958         needed++;
959     }
960     if (chars > 0)
961         needed += 2;
962     if (limit > 0 && chars + needed > limit) {
963         needed = 0;
964         if (chars <= limit) {
965             if (chars > 0) {
966                 printf(", ");
967                 needed += 2;
968             }
969             printf("...");
970             needed += 3;
971         }
972     } else {
973         if (chars > 0)
974             printf(", ");
975         if (last > first)
976             printf("%lu-", first);
977         printf("%lu", last);
978     }
979     return needed;
980 }
981 
982 
983 /*
984  * Summarize a single test set.  The second argument is 0 if the set exited
985  * cleanly, a positive integer representing the exit status if it exited
986  * with a non-zero status, and a negative integer representing the signal
987  * that terminated it if it was killed by a signal.
988  */
989 static void
test_summarize(struct testset * ts,int status)990 test_summarize(struct testset *ts, int status)
991 {
992     unsigned long i;
993     unsigned long missing = 0;
994     unsigned long failed = 0;
995     unsigned long first = 0;
996     unsigned long last = 0;
997 
998     if (ts->aborted) {
999         fputs("ABORTED", stdout);
1000         if (ts->count > 0)
1001             printf(" (passed %lu/%lu)", ts->passed, ts->count - ts->skipped);
1002     } else {
1003         for (i = 0; i < ts->count; i++) {
1004             if (ts->results[i] == TEST_INVALID) {
1005                 if (missing == 0)
1006                     fputs("MISSED ", stdout);
1007                 if (first && i == last)
1008                     last = i + 1;
1009                 else {
1010                     if (first)
1011                         test_print_range(first, last, missing - 1, 0);
1012                     missing++;
1013                     first = i + 1;
1014                     last = i + 1;
1015                 }
1016             }
1017         }
1018         if (first)
1019             test_print_range(first, last, missing - 1, 0);
1020         first = 0;
1021         last = 0;
1022         for (i = 0; i < ts->count; i++) {
1023             if (ts->results[i] == TEST_FAIL) {
1024                 if (missing && !failed)
1025                     fputs("; ", stdout);
1026                 if (failed == 0)
1027                     fputs("FAILED ", stdout);
1028                 if (first && i == last)
1029                     last = i + 1;
1030                 else {
1031                     if (first)
1032                         test_print_range(first, last, failed - 1, 0);
1033                     failed++;
1034                     first = i + 1;
1035                     last = i + 1;
1036                 }
1037             }
1038         }
1039         if (first)
1040             test_print_range(first, last, failed - 1, 0);
1041         if (!missing && !failed) {
1042             fputs(!status ? "ok" : "dubious", stdout);
1043             if (ts->skipped > 0) {
1044                 if (ts->skipped == 1)
1045                     printf(" (skipped %lu test)", ts->skipped);
1046                 else
1047                     printf(" (skipped %lu tests)", ts->skipped);
1048             }
1049         }
1050     }
1051     if (status > 0)
1052         printf(" (exit status %d)", status);
1053     else if (status < 0)
1054         printf(" (killed by signal %d%s)", -status,
1055                WCOREDUMP(ts->status) ? ", core dumped" : "");
1056     putchar('\n');
1057 }
1058 
1059 
1060 /*
1061  * Given a test set, analyze the results, classify the exit status, handle a
1062  * few special error messages, and then pass it along to test_summarize() for
1063  * the regular output.  Returns true if the test set ran successfully and all
1064  * tests passed or were skipped, false otherwise.
1065  */
1066 static int
test_analyze(struct testset * ts)1067 test_analyze(struct testset *ts)
1068 {
1069     if (ts->reported)
1070         return 0;
1071     if (ts->all_skipped) {
1072         if (ts->reason == NULL)
1073             puts("skipped");
1074         else
1075             printf("skipped (%s)\n", ts->reason);
1076         return 1;
1077     } else if (WIFEXITED(ts->status) && WEXITSTATUS(ts->status) != 0) {
1078         switch (WEXITSTATUS(ts->status)) {
1079         case CHILDERR_DUP:
1080             if (!ts->reported)
1081                 puts("ABORTED (can't dup file descriptors)");
1082             break;
1083         case CHILDERR_EXEC:
1084             if (!ts->reported)
1085                 puts("ABORTED (execution failed -- not found?)");
1086             break;
1087         case CHILDERR_STDIN:
1088         case CHILDERR_STDERR:
1089             if (!ts->reported)
1090                 puts("ABORTED (can't open /dev/null)");
1091             break;
1092         default:
1093             test_summarize(ts, WEXITSTATUS(ts->status));
1094             break;
1095         }
1096         return 0;
1097     } else if (WIFSIGNALED(ts->status)) {
1098         test_summarize(ts, -WTERMSIG(ts->status));
1099         return 0;
1100     } else if (ts->plan != PLAN_FIRST && ts->plan != PLAN_FINAL) {
1101         puts("ABORTED (no valid test plan)");
1102         ts->aborted = 1;
1103         return 0;
1104     } else {
1105         test_summarize(ts, 0);
1106         return (ts->failed == 0);
1107     }
1108 }
1109 
1110 
1111 /*
1112  * Runs a single test set, accumulating and then reporting the results.
1113  * Returns true if the test set was successfully run and all tests passed,
1114  * false otherwise.
1115  */
1116 static int
test_run(struct testset * ts,enum test_verbose verbose)1117 test_run(struct testset *ts, enum test_verbose verbose)
1118 {
1119     pid_t testpid, child;
1120     int outfd, status;
1121     unsigned long i;
1122     FILE *output;
1123     char buffer[BUFSIZ];
1124 
1125     /* Run the test program. */
1126     testpid = test_start(ts->command, &outfd);
1127     output = fdopen(outfd, "r");
1128     if (!output) {
1129         puts("ABORTED");
1130         fflush(stdout);
1131         sysdie("fdopen failed");
1132     }
1133 
1134     /*
1135      * Pass each line of output to test_checkline(), and print the line if
1136      * verbosity is requested.
1137      */
1138     while (!ts->aborted && fgets(buffer, sizeof(buffer), output)) {
1139         if (verbose)
1140             printf("%s", buffer);
1141         test_checkline(buffer, ts, verbose);
1142     }
1143     if (ferror(output) || ts->plan == PLAN_INIT)
1144         ts->aborted = 1;
1145     if (!verbose)
1146         test_backspace(ts);
1147 
1148     /*
1149      * Consume the rest of the test output, close the output descriptor,
1150      * retrieve the exit status, and pass that information to test_analyze()
1151      * for eventual output.
1152      */
1153     while (fgets(buffer, sizeof(buffer), output))
1154         if (verbose)
1155             printf("%s", buffer);
1156     fclose(output);
1157     child = waitpid(testpid, &ts->status, 0);
1158     if (child == (pid_t) -1) {
1159         if (!ts->reported) {
1160             puts("ABORTED");
1161             fflush(stdout);
1162         }
1163         sysdie("waitpid for %u failed", (unsigned int) testpid);
1164     }
1165     if (ts->all_skipped)
1166         ts->aborted = 0;
1167     status = test_analyze(ts);
1168 
1169     /* Convert missing tests to failed tests. */
1170     for (i = 0; i < ts->count; i++) {
1171         if (ts->results[i] == TEST_INVALID) {
1172             ts->failed++;
1173             ts->results[i] = TEST_FAIL;
1174             status = 0;
1175         }
1176     }
1177     return status;
1178 }
1179 
1180 
1181 /* Summarize a list of test failures. */
1182 static void
test_fail_summary(const struct testlist * fails)1183 test_fail_summary(const struct testlist *fails)
1184 {
1185     struct testset *ts;
1186     unsigned int chars;
1187     unsigned long i, first, last, total;
1188     double failed;
1189 
1190     puts(header);
1191 
1192     /* Failed Set                 Fail/Total (%) Skip Stat  Failing (25)
1193        -------------------------- -------------- ---- ----  -------------- */
1194     for (; fails; fails = fails->next) {
1195         ts = fails->ts;
1196         total = ts->count - ts->skipped;
1197         failed = (double) ts->failed;
1198         printf("%-26.26s %4lu/%-4lu %3.0f%% %4lu ", ts->file, ts->failed,
1199                total, total ? (failed * 100.0) / (double) total : 0,
1200                ts->skipped);
1201         if (WIFEXITED(ts->status))
1202             printf("%4d  ", WEXITSTATUS(ts->status));
1203         else
1204             printf("  --  ");
1205         if (ts->aborted) {
1206             puts("aborted");
1207             continue;
1208         }
1209         chars = 0;
1210         first = 0;
1211         last = 0;
1212         for (i = 0; i < ts->count; i++) {
1213             if (ts->results[i] == TEST_FAIL) {
1214                 if (first != 0 && i == last)
1215                     last = i + 1;
1216                 else {
1217                     if (first != 0)
1218                         chars += test_print_range(first, last, chars, 19);
1219                     first = i + 1;
1220                     last = i + 1;
1221                 }
1222             }
1223         }
1224         if (first != 0)
1225             test_print_range(first, last, chars, 19);
1226         putchar('\n');
1227     }
1228 }
1229 
1230 
1231 /*
1232  * Check whether a given file path is a valid test.  Currently, this checks
1233  * whether it is executable and is a regular file.  Returns true or false.
1234  */
1235 static int
is_valid_test(const char * path)1236 is_valid_test(const char *path)
1237 {
1238     struct stat st;
1239 
1240     if (access(path, X_OK) < 0)
1241         return 0;
1242     if (stat(path, &st) < 0)
1243         return 0;
1244     if (!S_ISREG(st.st_mode))
1245         return 0;
1246     return 1;
1247 }
1248 
1249 
1250 /*
1251  * Given the name of a test, a pointer to the testset struct, and the source
1252  * and build directories, find the test.  We try first relative to the current
1253  * directory, then in the build directory (if not NULL), then in the source
1254  * directory.  In each of those directories, we first try a "-t" extension and
1255  * then a ".t" extension.  When we find an executable program, we return the
1256  * path to that program.  If none of those paths are executable, just fill in
1257  * the name of the test as is.
1258  *
1259  * The caller is responsible for freeing the path member of the testset
1260  * struct.
1261  */
1262 static char *
find_test(const char * name,const char * source,const char * build)1263 find_test(const char *name, const char *source, const char *build)
1264 {
1265     char *path = NULL;
1266     const char *bases[3], *suffix, *base;
1267     unsigned int i, j;
1268     const char *suffixes[3] = {"-t", ".t", ""};
1269 
1270     /* Possible base directories. */
1271     bases[0] = ".";
1272     bases[1] = build;
1273     bases[2] = source;
1274 
1275     /* Try each suffix with each base. */
1276     for (i = 0; i < ARRAY_SIZE(suffixes); i++) {
1277         suffix = suffixes[i];
1278         for (j = 0; j < ARRAY_SIZE(bases); j++) {
1279             base = bases[j];
1280             if (base == NULL)
1281                 continue;
1282             path = concat(base, "/", name, suffix, (const char *) 0);
1283             if (is_valid_test(path))
1284                 return path;
1285             free(path);
1286             path = NULL;
1287         }
1288     }
1289     if (path == NULL)
1290         path = xstrdup(name);
1291     return path;
1292 }
1293 
1294 
1295 /*
1296  * Parse a single line of a test list and store the test name and command to
1297  * execute it in the given testset struct.
1298  *
1299  * Normally, each line is just the name of the test, which is located in the
1300  * test directory and turned into a command to run.  However, each line may
1301  * have whitespace-separated options, which change the command that's run.
1302  * Current supported options are:
1303  *
1304  * valgrind
1305  *     Run the test under valgrind if C_TAP_VALGRIND is set.  The contents
1306  *     of that environment variable are taken as the valgrind command (with
1307  *     options) to run.  The command is parsed with a simple split on
1308  *     whitespace and no quoting is supported.
1309  *
1310  * libtool
1311  *     If running under valgrind, use libtool to invoke valgrind.  This avoids
1312  *     running valgrind on the wrapper shell script generated by libtool.  If
1313  *     set, C_TAP_LIBTOOL must be set to the full path to the libtool program
1314  *     to use to run valgrind and thus the test.  Ignored if the test isn't
1315  *     being run under valgrind.
1316  */
1317 static void
parse_test_list_line(const char * line,struct testset * ts,const char * source,const char * build)1318 parse_test_list_line(const char *line, struct testset *ts, const char *source,
1319                      const char *build)
1320 {
1321     const char *p, *end, *option, *libtool;
1322     const char *valgrind = NULL;
1323     unsigned int use_libtool = 0;
1324     unsigned int use_valgrind = 0;
1325     size_t len, i;
1326 
1327     /* Determine the name of the test. */
1328     p = skip_non_whitespace(line);
1329     ts->file = xstrndup(line, p - line);
1330 
1331     /* Check if any test options are set. */
1332     p = skip_whitespace(p);
1333     while (*p != '\0') {
1334         end = skip_non_whitespace(p);
1335         if (strncmp(p, "libtool", end - p) == 0) {
1336             use_libtool = 1;
1337         } else if (strncmp(p, "valgrind", end - p) == 0) {
1338             valgrind = getenv("C_TAP_VALGRIND");
1339             use_valgrind = (valgrind != NULL);
1340         } else {
1341             option = xstrndup(p, end - p);
1342             die("unknown test list option %s", option);
1343         }
1344         p = skip_whitespace(end);
1345     }
1346 
1347     /* Construct the argv to run the test.  First, find the length. */
1348     len = 1;
1349     if (use_valgrind && valgrind != NULL) {
1350         p = skip_whitespace(valgrind);
1351         while (*p != '\0') {
1352             len++;
1353             p = skip_whitespace(skip_non_whitespace(p));
1354         }
1355         if (use_libtool)
1356             len += 2;
1357     }
1358 
1359     /* Now, build the command. */
1360     ts->command = xcalloc(len + 1, char *);
1361     i = 0;
1362     if (use_valgrind && valgrind != NULL) {
1363         if (use_libtool) {
1364             libtool = getenv("C_TAP_LIBTOOL");
1365             if (libtool == NULL)
1366                 die("valgrind with libtool requested, but C_TAP_LIBTOOL is not"
1367                     " set");
1368             ts->command[i++] = xstrdup(libtool);
1369             ts->command[i++] = xstrdup("--mode=execute");
1370         }
1371         p = skip_whitespace(valgrind);
1372         while (*p != '\0') {
1373             end = skip_non_whitespace(p);
1374             ts->command[i++] = xstrndup(p, end - p);
1375             p = skip_whitespace(end);
1376         }
1377     }
1378     if (i != len - 1)
1379         die("internal error while constructing command line");
1380     ts->command[i++] = find_test(ts->file, source, build);
1381     ts->command[i] = NULL;
1382 }
1383 
1384 
1385 /*
1386  * Read a list of tests from a file, returning the list of tests as a struct
1387  * testlist, or NULL if there were no tests (such as a file containing only
1388  * comments).  Reports an error to standard error and exits if the list of
1389  * tests cannot be read.
1390  */
1391 static struct testlist *
read_test_list(const char * filename,const char * source,const char * build)1392 read_test_list(const char *filename, const char *source, const char *build)
1393 {
1394     FILE *file;
1395     unsigned int line;
1396     size_t length;
1397     char buffer[BUFSIZ];
1398     const char *start;
1399     struct testlist *listhead, *current;
1400 
1401     /* Create the initial container list that will hold our results. */
1402     listhead = xcalloc(1, struct testlist);
1403     current = NULL;
1404 
1405     /*
1406      * Open our file of tests to run and read it line by line, creating a new
1407      * struct testlist and struct testset for each line.
1408      */
1409     file = fopen(filename, "r");
1410     if (file == NULL)
1411         sysdie("can't open %s", filename);
1412     line = 0;
1413     while (fgets(buffer, sizeof(buffer), file)) {
1414         line++;
1415         length = strlen(buffer) - 1;
1416         if (buffer[length] != '\n') {
1417             fprintf(stderr, "%s:%u: line too long\n", filename, line);
1418             exit(1);
1419         }
1420         buffer[length] = '\0';
1421 
1422         /* Skip comments, leading spaces, and blank lines. */
1423         start = skip_whitespace(buffer);
1424         if (strlen(start) == 0)
1425             continue;
1426         if (start[0] == '#')
1427             continue;
1428 
1429         /* Allocate the new testset structure. */
1430         if (current == NULL)
1431             current = listhead;
1432         else {
1433             current->next = xcalloc(1, struct testlist);
1434             current = current->next;
1435         }
1436         current->ts = xcalloc(1, struct testset);
1437         current->ts->plan = PLAN_INIT;
1438 
1439         /* Parse the line and store the results in the testset struct. */
1440         parse_test_list_line(start, current->ts, source, build);
1441     }
1442     fclose(file);
1443 
1444     /* If there were no tests, current is still NULL. */
1445     if (current == NULL) {
1446         free(listhead);
1447         return NULL;
1448     }
1449 
1450     /* Return the results. */
1451     return listhead;
1452 }
1453 
1454 
1455 /*
1456  * Build a list of tests from command line arguments.  Takes the argv and argc
1457  * representing the command line arguments and returns a newly allocated test
1458  * list, or NULL if there were no tests.  The caller is responsible for
1459  * freeing.
1460  */
1461 static struct testlist *
build_test_list(char * argv[],int argc,const char * source,const char * build)1462 build_test_list(char *argv[], int argc, const char *source, const char *build)
1463 {
1464     int i;
1465     struct testlist *listhead, *current;
1466 
1467     /* Create the initial container list that will hold our results. */
1468     listhead = xcalloc(1, struct testlist);
1469     current = NULL;
1470 
1471     /* Walk the list of arguments and create test sets for them. */
1472     for (i = 0; i < argc; i++) {
1473         if (current == NULL)
1474             current = listhead;
1475         else {
1476             current->next = xcalloc(1, struct testlist);
1477             current = current->next;
1478         }
1479         current->ts = xcalloc(1, struct testset);
1480         current->ts->plan = PLAN_INIT;
1481         current->ts->file = xstrdup(argv[i]);
1482         current->ts->command = xcalloc(2, char *);
1483         current->ts->command[0] = find_test(current->ts->file, source, build);
1484         current->ts->command[1] = NULL;
1485     }
1486 
1487     /* If there were no tests, current is still NULL. */
1488     if (current == NULL) {
1489         free(listhead);
1490         return NULL;
1491     }
1492 
1493     /* Return the results. */
1494     return listhead;
1495 }
1496 
1497 
1498 /* Free a struct testset. */
1499 static void
free_testset(struct testset * ts)1500 free_testset(struct testset *ts)
1501 {
1502     size_t i;
1503 
1504     free(ts->file);
1505     for (i = 0; ts->command[i] != NULL; i++)
1506         free(ts->command[i]);
1507     free(ts->command);
1508     free(ts->results);
1509     free(ts->reason);
1510     free(ts);
1511 }
1512 
1513 
1514 /*
1515  * Run a batch of tests.  Takes two additional parameters: the root of the
1516  * source directory and the root of the build directory.  Test programs will
1517  * be first searched for in the current directory, then the build directory,
1518  * then the source directory.  Returns true iff all tests passed, and always
1519  * frees the test list that's passed in.
1520  */
1521 static int
test_batch(struct testlist * tests,enum test_verbose verbose)1522 test_batch(struct testlist *tests, enum test_verbose verbose)
1523 {
1524     size_t length, i;
1525     size_t longest = 0;
1526     unsigned int count = 0;
1527     struct testset *ts;
1528     struct timeval start, end;
1529     struct rusage stats;
1530     struct testlist *failhead = NULL;
1531     struct testlist *failtail = NULL;
1532     struct testlist *current, *next;
1533     int succeeded;
1534     unsigned long total = 0;
1535     unsigned long passed = 0;
1536     unsigned long skipped = 0;
1537     unsigned long failed = 0;
1538     unsigned long aborted = 0;
1539 
1540     /* Walk the list of tests to find the longest name. */
1541     for (current = tests; current != NULL; current = current->next) {
1542         length = strlen(current->ts->file);
1543         if (length > longest)
1544             longest = length;
1545     }
1546 
1547     /*
1548      * Add two to longest and round up to the nearest tab stop.  This is how
1549      * wide the column for printing the current test name will be.
1550      */
1551     longest += 2;
1552     if (longest % 8)
1553         longest += 8 - (longest % 8);
1554 
1555     /* Start the wall clock timer. */
1556     gettimeofday(&start, NULL);
1557 
1558     /* Now, plow through our tests again, running each one. */
1559     for (current = tests; current != NULL; current = current->next) {
1560         ts = current->ts;
1561 
1562         /* Print out the name of the test file. */
1563         fputs(ts->file, stdout);
1564         if (verbose)
1565             fputs("\n\n", stdout);
1566         else
1567             for (i = strlen(ts->file); i < longest; i++)
1568                 putchar('.');
1569         if (isatty(STDOUT_FILENO))
1570             fflush(stdout);
1571 
1572         /* Run the test. */
1573         succeeded = test_run(ts, verbose);
1574         fflush(stdout);
1575         if (verbose)
1576             putchar('\n');
1577 
1578         /* Record cumulative statistics. */
1579         aborted += ts->aborted;
1580         total += ts->count + ts->all_skipped;
1581         passed += ts->passed;
1582         skipped += ts->skipped + ts->all_skipped;
1583         failed += ts->failed;
1584         count++;
1585 
1586         /* If the test fails, we shuffle it over to the fail list. */
1587         if (!succeeded) {
1588             if (failhead == NULL) {
1589                 failhead = xcalloc(1, struct testlist);
1590                 failtail = failhead;
1591             } else {
1592                 failtail->next = xcalloc(1, struct testlist);
1593                 failtail = failtail->next;
1594             }
1595             failtail->ts = ts;
1596             failtail->next = NULL;
1597         }
1598     }
1599     total -= skipped;
1600 
1601     /* Stop the timer and get our child resource statistics. */
1602     gettimeofday(&end, NULL);
1603     getrusage(RUSAGE_CHILDREN, &stats);
1604 
1605     /* Summarize the failures and free the failure list. */
1606     if (failhead != NULL) {
1607         test_fail_summary(failhead);
1608         while (failhead != NULL) {
1609             next = failhead->next;
1610             free(failhead);
1611             failhead = next;
1612         }
1613     }
1614 
1615     /* Free the memory used by the test lists. */
1616     while (tests != NULL) {
1617         next = tests->next;
1618         free_testset(tests->ts);
1619         free(tests);
1620         tests = next;
1621     }
1622 
1623     /* Print out the final test summary. */
1624     putchar('\n');
1625     if (aborted != 0) {
1626         if (aborted == 1)
1627             printf("Aborted %lu test set", aborted);
1628         else
1629             printf("Aborted %lu test sets", aborted);
1630         printf(", passed %lu/%lu tests", passed, total);
1631     } else if (failed == 0)
1632         fputs("All tests successful", stdout);
1633     else
1634         printf("Failed %lu/%lu tests, %.2f%% okay", failed, total,
1635                (double) (total - failed) * 100.0 / (double) total);
1636     if (skipped != 0) {
1637         if (skipped == 1)
1638             printf(", %lu test skipped", skipped);
1639         else
1640             printf(", %lu tests skipped", skipped);
1641     }
1642     puts(".");
1643     printf("Files=%u,  Tests=%lu", count, total);
1644     printf(",  %.2f seconds", tv_diff(&end, &start));
1645     printf(" (%.2f usr + %.2f sys = %.2f CPU)\n", tv_seconds(&stats.ru_utime),
1646            tv_seconds(&stats.ru_stime),
1647            tv_sum(&stats.ru_utime, &stats.ru_stime));
1648     return (failed == 0 && aborted == 0);
1649 }
1650 
1651 
1652 /*
1653  * Run a single test case.  This involves just running the test program after
1654  * having done the environment setup and finding the test program.
1655  */
1656 static void
test_single(const char * program,const char * source,const char * build)1657 test_single(const char *program, const char *source, const char *build)
1658 {
1659     char *path;
1660 
1661     path = find_test(program, source, build);
1662     if (execl(path, path, (char *) 0) == -1)
1663         sysdie("cannot exec %s", path);
1664 }
1665 
1666 
1667 /*
1668  * Main routine.  Set the C_TAP_SOURCE, C_TAP_BUILD, SOURCE, and BUILD
1669  * environment variables and then, given a file listing tests, run each test
1670  * listed.
1671  */
1672 int
main(int argc,char * argv[])1673 main(int argc, char *argv[])
1674 {
1675     int option;
1676     int status = 0;
1677     int single = 0;
1678     enum test_verbose verbose = CONCISE;
1679     char *c_tap_source_env = NULL;
1680     char *c_tap_build_env = NULL;
1681     char *source_env = NULL;
1682     char *build_env = NULL;
1683     const char *program;
1684     const char *shortlist;
1685     const char *list = NULL;
1686     const char *source = C_TAP_SOURCE;
1687     const char *build = C_TAP_BUILD;
1688     struct testlist *tests;
1689 
1690     program = argv[0];
1691     while ((option = getopt(argc, argv, "b:hl:os:v")) != EOF) {
1692         switch (option) {
1693         case 'b':
1694             build = optarg;
1695             break;
1696         case 'h':
1697             printf(usage_message, program, program, program, usage_extra);
1698             exit(0);
1699         case 'l':
1700             list = optarg;
1701             break;
1702         case 'o':
1703             single = 1;
1704             break;
1705         case 's':
1706             source = optarg;
1707             break;
1708         case 'v':
1709             verbose = VERBOSE;
1710             break;
1711         default:
1712             exit(1);
1713         }
1714     }
1715     argv += optind;
1716     argc -= optind;
1717     if ((list == NULL && argc < 1) || (list != NULL && argc > 0)) {
1718         fprintf(stderr, usage_message, program, program, program, usage_extra);
1719         exit(1);
1720     }
1721 
1722     /*
1723      * If C_TAP_VERBOSE is set in the environment, that also turns on verbose
1724      * mode.
1725      */
1726     if (getenv("C_TAP_VERBOSE") != NULL)
1727         verbose = VERBOSE;
1728 
1729     /*
1730      * Set C_TAP_SOURCE and C_TAP_BUILD environment variables.  Also set
1731      * SOURCE and BUILD for backward compatibility, although we're trying to
1732      * migrate to the ones with a C_TAP_* prefix.
1733      */
1734     if (source != NULL) {
1735         c_tap_source_env = concat("C_TAP_SOURCE=", source, (const char *) 0);
1736         if (putenv(c_tap_source_env) != 0)
1737             sysdie("cannot set C_TAP_SOURCE in the environment");
1738         source_env = concat("SOURCE=", source, (const char *) 0);
1739         if (putenv(source_env) != 0)
1740             sysdie("cannot set SOURCE in the environment");
1741     }
1742     if (build != NULL) {
1743         c_tap_build_env = concat("C_TAP_BUILD=", build, (const char *) 0);
1744         if (putenv(c_tap_build_env) != 0)
1745             sysdie("cannot set C_TAP_BUILD in the environment");
1746         build_env = concat("BUILD=", build, (const char *) 0);
1747         if (putenv(build_env) != 0)
1748             sysdie("cannot set BUILD in the environment");
1749     }
1750 
1751     /* Run the tests as instructed. */
1752     if (single)
1753         test_single(argv[0], source, build);
1754     else if (list != NULL) {
1755         shortlist = strrchr(list, '/');
1756         if (shortlist == NULL)
1757             shortlist = list;
1758         else
1759             shortlist++;
1760         printf(banner, shortlist);
1761         tests = read_test_list(list, source, build);
1762         status = test_batch(tests, verbose) ? 0 : 1;
1763     } else {
1764         tests = build_test_list(argv, argc, source, build);
1765         status = test_batch(tests, verbose) ? 0 : 1;
1766     }
1767 
1768     /* For valgrind cleanliness, free all our memory. */
1769     if (source_env != NULL) {
1770         putenv((char *) "C_TAP_SOURCE=");
1771         putenv((char *) "SOURCE=");
1772         free(c_tap_source_env);
1773         free(source_env);
1774     }
1775     if (build_env != NULL) {
1776         putenv((char *) "C_TAP_BUILD=");
1777         putenv((char *) "BUILD=");
1778         free(c_tap_build_env);
1779         free(build_env);
1780     }
1781     exit(status);
1782 }
1783