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