1*e985b929SDavid van Moolenbroek /* $NetBSD: tinytest.c,v 1.1.1.1 2013/04/11 16:43:32 christos Exp $ */
2*e985b929SDavid van Moolenbroek /* tinytest.c -- Copyright 2009-2012 Nick Mathewson
3*e985b929SDavid van Moolenbroek *
4*e985b929SDavid van Moolenbroek * Redistribution and use in source and binary forms, with or without
5*e985b929SDavid van Moolenbroek * modification, are permitted provided that the following conditions
6*e985b929SDavid van Moolenbroek * are met:
7*e985b929SDavid van Moolenbroek * 1. Redistributions of source code must retain the above copyright
8*e985b929SDavid van Moolenbroek * notice, this list of conditions and the following disclaimer.
9*e985b929SDavid van Moolenbroek * 2. Redistributions in binary form must reproduce the above copyright
10*e985b929SDavid van Moolenbroek * notice, this list of conditions and the following disclaimer in the
11*e985b929SDavid van Moolenbroek * documentation and/or other materials provided with the distribution.
12*e985b929SDavid van Moolenbroek * 3. The name of the author may not be used to endorse or promote products
13*e985b929SDavid van Moolenbroek * derived from this software without specific prior written permission.
14*e985b929SDavid van Moolenbroek *
15*e985b929SDavid van Moolenbroek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16*e985b929SDavid van Moolenbroek * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17*e985b929SDavid van Moolenbroek * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18*e985b929SDavid van Moolenbroek * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19*e985b929SDavid van Moolenbroek * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20*e985b929SDavid van Moolenbroek * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21*e985b929SDavid van Moolenbroek * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22*e985b929SDavid van Moolenbroek * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23*e985b929SDavid van Moolenbroek * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24*e985b929SDavid van Moolenbroek * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*e985b929SDavid van Moolenbroek */
26*e985b929SDavid van Moolenbroek
27*e985b929SDavid van Moolenbroek #include <stdio.h>
28*e985b929SDavid van Moolenbroek #include <stdlib.h>
29*e985b929SDavid van Moolenbroek #include <string.h>
30*e985b929SDavid van Moolenbroek #include <assert.h>
31*e985b929SDavid van Moolenbroek
32*e985b929SDavid van Moolenbroek #ifdef TINYTEST_LOCAL
33*e985b929SDavid van Moolenbroek #include "tinytest_local.h"
34*e985b929SDavid van Moolenbroek #endif
35*e985b929SDavid van Moolenbroek
36*e985b929SDavid van Moolenbroek #ifdef WIN32
37*e985b929SDavid van Moolenbroek #include <windows.h>
38*e985b929SDavid van Moolenbroek #else
39*e985b929SDavid van Moolenbroek #include <sys/types.h>
40*e985b929SDavid van Moolenbroek #include <sys/wait.h>
41*e985b929SDavid van Moolenbroek #include <unistd.h>
42*e985b929SDavid van Moolenbroek #endif
43*e985b929SDavid van Moolenbroek
44*e985b929SDavid van Moolenbroek #if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
45*e985b929SDavid van Moolenbroek #if (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060 && \
46*e985b929SDavid van Moolenbroek __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070)
47*e985b929SDavid van Moolenbroek /* Workaround for a stupid bug in OSX 10.6 */
48*e985b929SDavid van Moolenbroek #define FORK_BREAKS_GCOV
49*e985b929SDavid van Moolenbroek #include <vproc.h>
50*e985b929SDavid van Moolenbroek #endif
51*e985b929SDavid van Moolenbroek #endif
52*e985b929SDavid van Moolenbroek
53*e985b929SDavid van Moolenbroek #ifndef __GNUC__
54*e985b929SDavid van Moolenbroek #define __attribute__(x)
55*e985b929SDavid van Moolenbroek #endif
56*e985b929SDavid van Moolenbroek
57*e985b929SDavid van Moolenbroek #include "tinytest.h"
58*e985b929SDavid van Moolenbroek #include "tinytest_macros.h"
59*e985b929SDavid van Moolenbroek
60*e985b929SDavid van Moolenbroek #define LONGEST_TEST_NAME 16384
61*e985b929SDavid van Moolenbroek
62*e985b929SDavid van Moolenbroek static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/
63*e985b929SDavid van Moolenbroek static int n_ok = 0; /**< Number of tests that have passed */
64*e985b929SDavid van Moolenbroek static int n_bad = 0; /**< Number of tests that have failed. */
65*e985b929SDavid van Moolenbroek static int n_skipped = 0; /**< Number of tests that have been skipped. */
66*e985b929SDavid van Moolenbroek
67*e985b929SDavid van Moolenbroek static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/
68*e985b929SDavid van Moolenbroek static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */
69*e985b929SDavid van Moolenbroek static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */
70*e985b929SDavid van Moolenbroek const char *verbosity_flag = "";
71*e985b929SDavid van Moolenbroek
72*e985b929SDavid van Moolenbroek enum outcome { SKIP=2, OK=1, FAIL=0 };
73*e985b929SDavid van Moolenbroek static enum outcome cur_test_outcome = 0;
74*e985b929SDavid van Moolenbroek const char *cur_test_prefix = NULL; /**< prefix of the current test group */
75*e985b929SDavid van Moolenbroek /** Name of the current test, if we haven't logged is yet. Used for --quiet */
76*e985b929SDavid van Moolenbroek const char *cur_test_name = NULL;
77*e985b929SDavid van Moolenbroek
78*e985b929SDavid van Moolenbroek #ifdef WIN32
79*e985b929SDavid van Moolenbroek /* Copy of argv[0] for win32. */
80*e985b929SDavid van Moolenbroek static char commandname[MAX_PATH+1];
81*e985b929SDavid van Moolenbroek #endif
82*e985b929SDavid van Moolenbroek
83*e985b929SDavid van Moolenbroek static void usage(struct testgroup_t *groups, int list_groups)
84*e985b929SDavid van Moolenbroek __attribute__((noreturn));
85*e985b929SDavid van Moolenbroek
86*e985b929SDavid van Moolenbroek static enum outcome
_testcase_run_bare(const struct testcase_t * testcase)87*e985b929SDavid van Moolenbroek _testcase_run_bare(const struct testcase_t *testcase)
88*e985b929SDavid van Moolenbroek {
89*e985b929SDavid van Moolenbroek void *env = NULL;
90*e985b929SDavid van Moolenbroek int outcome;
91*e985b929SDavid van Moolenbroek if (testcase->setup) {
92*e985b929SDavid van Moolenbroek env = testcase->setup->setup_fn(testcase);
93*e985b929SDavid van Moolenbroek if (!env)
94*e985b929SDavid van Moolenbroek return FAIL;
95*e985b929SDavid van Moolenbroek else if (env == (void*)TT_SKIP)
96*e985b929SDavid van Moolenbroek return SKIP;
97*e985b929SDavid van Moolenbroek }
98*e985b929SDavid van Moolenbroek
99*e985b929SDavid van Moolenbroek cur_test_outcome = OK;
100*e985b929SDavid van Moolenbroek testcase->fn(env);
101*e985b929SDavid van Moolenbroek outcome = cur_test_outcome;
102*e985b929SDavid van Moolenbroek
103*e985b929SDavid van Moolenbroek if (testcase->setup) {
104*e985b929SDavid van Moolenbroek if (testcase->setup->cleanup_fn(testcase, env) == 0)
105*e985b929SDavid van Moolenbroek outcome = FAIL;
106*e985b929SDavid van Moolenbroek }
107*e985b929SDavid van Moolenbroek
108*e985b929SDavid van Moolenbroek return outcome;
109*e985b929SDavid van Moolenbroek }
110*e985b929SDavid van Moolenbroek
111*e985b929SDavid van Moolenbroek #define MAGIC_EXITCODE 42
112*e985b929SDavid van Moolenbroek
113*e985b929SDavid van Moolenbroek static enum outcome
_testcase_run_forked(const struct testgroup_t * group,const struct testcase_t * testcase)114*e985b929SDavid van Moolenbroek _testcase_run_forked(const struct testgroup_t *group,
115*e985b929SDavid van Moolenbroek const struct testcase_t *testcase)
116*e985b929SDavid van Moolenbroek {
117*e985b929SDavid van Moolenbroek #ifdef WIN32
118*e985b929SDavid van Moolenbroek /* Fork? On Win32? How primitive! We'll do what the smart kids do:
119*e985b929SDavid van Moolenbroek we'll invoke our own exe (whose name we recall from the command
120*e985b929SDavid van Moolenbroek line) with a command line that tells it to run just the test we
121*e985b929SDavid van Moolenbroek want, and this time without forking.
122*e985b929SDavid van Moolenbroek
123*e985b929SDavid van Moolenbroek (No, threads aren't an option. The whole point of forking is to
124*e985b929SDavid van Moolenbroek share no state between tests.)
125*e985b929SDavid van Moolenbroek */
126*e985b929SDavid van Moolenbroek int ok;
127*e985b929SDavid van Moolenbroek char buffer[LONGEST_TEST_NAME+256];
128*e985b929SDavid van Moolenbroek STARTUPINFOA si;
129*e985b929SDavid van Moolenbroek PROCESS_INFORMATION info;
130*e985b929SDavid van Moolenbroek DWORD exitcode;
131*e985b929SDavid van Moolenbroek
132*e985b929SDavid van Moolenbroek if (!in_tinytest_main) {
133*e985b929SDavid van Moolenbroek printf("\nERROR. On Windows, _testcase_run_forked must be"
134*e985b929SDavid van Moolenbroek " called from within tinytest_main.\n");
135*e985b929SDavid van Moolenbroek abort();
136*e985b929SDavid van Moolenbroek }
137*e985b929SDavid van Moolenbroek if (opt_verbosity>0)
138*e985b929SDavid van Moolenbroek printf("[forking] ");
139*e985b929SDavid van Moolenbroek
140*e985b929SDavid van Moolenbroek snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s %s%s",
141*e985b929SDavid van Moolenbroek commandname, verbosity_flag, group->prefix, testcase->name);
142*e985b929SDavid van Moolenbroek
143*e985b929SDavid van Moolenbroek memset(&si, 0, sizeof(si));
144*e985b929SDavid van Moolenbroek memset(&info, 0, sizeof(info));
145*e985b929SDavid van Moolenbroek si.cb = sizeof(si);
146*e985b929SDavid van Moolenbroek
147*e985b929SDavid van Moolenbroek ok = CreateProcessA(commandname, buffer, NULL, NULL, 0,
148*e985b929SDavid van Moolenbroek 0, NULL, NULL, &si, &info);
149*e985b929SDavid van Moolenbroek if (!ok) {
150*e985b929SDavid van Moolenbroek printf("CreateProcess failed!\n");
151*e985b929SDavid van Moolenbroek return 0;
152*e985b929SDavid van Moolenbroek }
153*e985b929SDavid van Moolenbroek WaitForSingleObject(info.hProcess, INFINITE);
154*e985b929SDavid van Moolenbroek GetExitCodeProcess(info.hProcess, &exitcode);
155*e985b929SDavid van Moolenbroek CloseHandle(info.hProcess);
156*e985b929SDavid van Moolenbroek CloseHandle(info.hThread);
157*e985b929SDavid van Moolenbroek if (exitcode == 0)
158*e985b929SDavid van Moolenbroek return OK;
159*e985b929SDavid van Moolenbroek else if (exitcode == MAGIC_EXITCODE)
160*e985b929SDavid van Moolenbroek return SKIP;
161*e985b929SDavid van Moolenbroek else
162*e985b929SDavid van Moolenbroek return FAIL;
163*e985b929SDavid van Moolenbroek #else
164*e985b929SDavid van Moolenbroek int outcome_pipe[2];
165*e985b929SDavid van Moolenbroek pid_t pid;
166*e985b929SDavid van Moolenbroek (void)group;
167*e985b929SDavid van Moolenbroek
168*e985b929SDavid van Moolenbroek if (pipe(outcome_pipe))
169*e985b929SDavid van Moolenbroek perror("opening pipe");
170*e985b929SDavid van Moolenbroek
171*e985b929SDavid van Moolenbroek if (opt_verbosity>0)
172*e985b929SDavid van Moolenbroek printf("[forking] ");
173*e985b929SDavid van Moolenbroek pid = fork();
174*e985b929SDavid van Moolenbroek #ifdef FORK_BREAKS_GCOV
175*e985b929SDavid van Moolenbroek vproc_transaction_begin(0);
176*e985b929SDavid van Moolenbroek #endif
177*e985b929SDavid van Moolenbroek if (!pid) {
178*e985b929SDavid van Moolenbroek /* child. */
179*e985b929SDavid van Moolenbroek int test_r, write_r;
180*e985b929SDavid van Moolenbroek char b[1];
181*e985b929SDavid van Moolenbroek close(outcome_pipe[0]);
182*e985b929SDavid van Moolenbroek test_r = _testcase_run_bare(testcase);
183*e985b929SDavid van Moolenbroek assert(0<=(int)test_r && (int)test_r<=2);
184*e985b929SDavid van Moolenbroek b[0] = "NYS"[test_r];
185*e985b929SDavid van Moolenbroek write_r = (int)write(outcome_pipe[1], b, 1);
186*e985b929SDavid van Moolenbroek if (write_r != 1) {
187*e985b929SDavid van Moolenbroek perror("write outcome to pipe");
188*e985b929SDavid van Moolenbroek exit(1);
189*e985b929SDavid van Moolenbroek }
190*e985b929SDavid van Moolenbroek exit(0);
191*e985b929SDavid van Moolenbroek return FAIL; /* unreachable */
192*e985b929SDavid van Moolenbroek } else {
193*e985b929SDavid van Moolenbroek /* parent */
194*e985b929SDavid van Moolenbroek int status, r;
195*e985b929SDavid van Moolenbroek char b[1];
196*e985b929SDavid van Moolenbroek /* Close this now, so that if the other side closes it,
197*e985b929SDavid van Moolenbroek * our read fails. */
198*e985b929SDavid van Moolenbroek close(outcome_pipe[1]);
199*e985b929SDavid van Moolenbroek r = (int)read(outcome_pipe[0], b, 1);
200*e985b929SDavid van Moolenbroek if (r == 0) {
201*e985b929SDavid van Moolenbroek printf("[Lost connection!] ");
202*e985b929SDavid van Moolenbroek return 0;
203*e985b929SDavid van Moolenbroek } else if (r != 1) {
204*e985b929SDavid van Moolenbroek perror("read outcome from pipe");
205*e985b929SDavid van Moolenbroek }
206*e985b929SDavid van Moolenbroek waitpid(pid, &status, 0);
207*e985b929SDavid van Moolenbroek close(outcome_pipe[0]);
208*e985b929SDavid van Moolenbroek return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL);
209*e985b929SDavid van Moolenbroek }
210*e985b929SDavid van Moolenbroek #endif
211*e985b929SDavid van Moolenbroek }
212*e985b929SDavid van Moolenbroek
213*e985b929SDavid van Moolenbroek int
testcase_run_one(const struct testgroup_t * group,const struct testcase_t * testcase)214*e985b929SDavid van Moolenbroek testcase_run_one(const struct testgroup_t *group,
215*e985b929SDavid van Moolenbroek const struct testcase_t *testcase)
216*e985b929SDavid van Moolenbroek {
217*e985b929SDavid van Moolenbroek enum outcome outcome;
218*e985b929SDavid van Moolenbroek
219*e985b929SDavid van Moolenbroek if (testcase->flags & TT_SKIP) {
220*e985b929SDavid van Moolenbroek if (opt_verbosity>0)
221*e985b929SDavid van Moolenbroek printf("%s%s: SKIPPED\n",
222*e985b929SDavid van Moolenbroek group->prefix, testcase->name);
223*e985b929SDavid van Moolenbroek ++n_skipped;
224*e985b929SDavid van Moolenbroek return SKIP;
225*e985b929SDavid van Moolenbroek }
226*e985b929SDavid van Moolenbroek
227*e985b929SDavid van Moolenbroek if (opt_verbosity>0 && !opt_forked) {
228*e985b929SDavid van Moolenbroek printf("%s%s: ", group->prefix, testcase->name);
229*e985b929SDavid van Moolenbroek } else {
230*e985b929SDavid van Moolenbroek if (opt_verbosity==0) printf(".");
231*e985b929SDavid van Moolenbroek cur_test_prefix = group->prefix;
232*e985b929SDavid van Moolenbroek cur_test_name = testcase->name;
233*e985b929SDavid van Moolenbroek }
234*e985b929SDavid van Moolenbroek
235*e985b929SDavid van Moolenbroek if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) {
236*e985b929SDavid van Moolenbroek outcome = _testcase_run_forked(group, testcase);
237*e985b929SDavid van Moolenbroek } else {
238*e985b929SDavid van Moolenbroek outcome = _testcase_run_bare(testcase);
239*e985b929SDavid van Moolenbroek }
240*e985b929SDavid van Moolenbroek
241*e985b929SDavid van Moolenbroek if (outcome == OK) {
242*e985b929SDavid van Moolenbroek ++n_ok;
243*e985b929SDavid van Moolenbroek if (opt_verbosity>0 && !opt_forked)
244*e985b929SDavid van Moolenbroek puts(opt_verbosity==1?"OK":"");
245*e985b929SDavid van Moolenbroek } else if (outcome == SKIP) {
246*e985b929SDavid van Moolenbroek ++n_skipped;
247*e985b929SDavid van Moolenbroek if (opt_verbosity>0 && !opt_forked)
248*e985b929SDavid van Moolenbroek puts("SKIPPED");
249*e985b929SDavid van Moolenbroek } else {
250*e985b929SDavid van Moolenbroek ++n_bad;
251*e985b929SDavid van Moolenbroek if (!opt_forked)
252*e985b929SDavid van Moolenbroek printf("\n [%s FAILED]\n", testcase->name);
253*e985b929SDavid van Moolenbroek }
254*e985b929SDavid van Moolenbroek
255*e985b929SDavid van Moolenbroek if (opt_forked) {
256*e985b929SDavid van Moolenbroek exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1));
257*e985b929SDavid van Moolenbroek return 1; /* unreachable */
258*e985b929SDavid van Moolenbroek } else {
259*e985b929SDavid van Moolenbroek return (int)outcome;
260*e985b929SDavid van Moolenbroek }
261*e985b929SDavid van Moolenbroek }
262*e985b929SDavid van Moolenbroek
263*e985b929SDavid van Moolenbroek int
_tinytest_set_flag(struct testgroup_t * groups,const char * arg,unsigned long flag)264*e985b929SDavid van Moolenbroek _tinytest_set_flag(struct testgroup_t *groups, const char *arg, unsigned long flag)
265*e985b929SDavid van Moolenbroek {
266*e985b929SDavid van Moolenbroek int i, j;
267*e985b929SDavid van Moolenbroek size_t length = LONGEST_TEST_NAME;
268*e985b929SDavid van Moolenbroek char fullname[LONGEST_TEST_NAME];
269*e985b929SDavid van Moolenbroek int found=0;
270*e985b929SDavid van Moolenbroek if (strstr(arg, ".."))
271*e985b929SDavid van Moolenbroek length = strstr(arg,"..")-arg;
272*e985b929SDavid van Moolenbroek for (i=0; groups[i].prefix; ++i) {
273*e985b929SDavid van Moolenbroek for (j=0; groups[i].cases[j].name; ++j) {
274*e985b929SDavid van Moolenbroek snprintf(fullname, sizeof(fullname), "%s%s",
275*e985b929SDavid van Moolenbroek groups[i].prefix, groups[i].cases[j].name);
276*e985b929SDavid van Moolenbroek if (!flag) /* Hack! */
277*e985b929SDavid van Moolenbroek printf(" %s\n", fullname);
278*e985b929SDavid van Moolenbroek if (!strncmp(fullname, arg, length)) {
279*e985b929SDavid van Moolenbroek groups[i].cases[j].flags |= flag;
280*e985b929SDavid van Moolenbroek ++found;
281*e985b929SDavid van Moolenbroek }
282*e985b929SDavid van Moolenbroek }
283*e985b929SDavid van Moolenbroek }
284*e985b929SDavid van Moolenbroek return found;
285*e985b929SDavid van Moolenbroek }
286*e985b929SDavid van Moolenbroek
287*e985b929SDavid van Moolenbroek static void
usage(struct testgroup_t * groups,int list_groups)288*e985b929SDavid van Moolenbroek usage(struct testgroup_t *groups, int list_groups)
289*e985b929SDavid van Moolenbroek {
290*e985b929SDavid van Moolenbroek puts("Options are: [--verbose|--quiet|--terse] [--no-fork]");
291*e985b929SDavid van Moolenbroek puts(" Specify tests by name, or using a prefix ending with '..'");
292*e985b929SDavid van Moolenbroek puts(" To skip a test, list give its name prefixed with a colon.");
293*e985b929SDavid van Moolenbroek puts(" Use --list-tests for a list of tests.");
294*e985b929SDavid van Moolenbroek if (list_groups) {
295*e985b929SDavid van Moolenbroek puts("Known tests are:");
296*e985b929SDavid van Moolenbroek _tinytest_set_flag(groups, "..", 0);
297*e985b929SDavid van Moolenbroek }
298*e985b929SDavid van Moolenbroek exit(0);
299*e985b929SDavid van Moolenbroek }
300*e985b929SDavid van Moolenbroek
301*e985b929SDavid van Moolenbroek int
tinytest_main(int c,const char ** v,struct testgroup_t * groups)302*e985b929SDavid van Moolenbroek tinytest_main(int c, const char **v, struct testgroup_t *groups)
303*e985b929SDavid van Moolenbroek {
304*e985b929SDavid van Moolenbroek int i, j, n=0;
305*e985b929SDavid van Moolenbroek
306*e985b929SDavid van Moolenbroek #ifdef WIN32
307*e985b929SDavid van Moolenbroek const char *sp = strrchr(v[0], '.');
308*e985b929SDavid van Moolenbroek const char *extension = "";
309*e985b929SDavid van Moolenbroek if (!sp || stricmp(sp, ".exe"))
310*e985b929SDavid van Moolenbroek extension = ".exe"; /* Add an exe so CreateProcess will work */
311*e985b929SDavid van Moolenbroek snprintf(commandname, sizeof(commandname), "%s%s", v[0], extension);
312*e985b929SDavid van Moolenbroek commandname[MAX_PATH]='\0';
313*e985b929SDavid van Moolenbroek #endif
314*e985b929SDavid van Moolenbroek for (i=1; i<c; ++i) {
315*e985b929SDavid van Moolenbroek if (v[i][0] == '-') {
316*e985b929SDavid van Moolenbroek if (!strcmp(v[i], "--RUNNING-FORKED")) {
317*e985b929SDavid van Moolenbroek opt_forked = 1;
318*e985b929SDavid van Moolenbroek } else if (!strcmp(v[i], "--no-fork")) {
319*e985b929SDavid van Moolenbroek opt_nofork = 1;
320*e985b929SDavid van Moolenbroek } else if (!strcmp(v[i], "--quiet")) {
321*e985b929SDavid van Moolenbroek opt_verbosity = -1;
322*e985b929SDavid van Moolenbroek verbosity_flag = "--quiet";
323*e985b929SDavid van Moolenbroek } else if (!strcmp(v[i], "--verbose")) {
324*e985b929SDavid van Moolenbroek opt_verbosity = 2;
325*e985b929SDavid van Moolenbroek verbosity_flag = "--verbose";
326*e985b929SDavid van Moolenbroek } else if (!strcmp(v[i], "--terse")) {
327*e985b929SDavid van Moolenbroek opt_verbosity = 0;
328*e985b929SDavid van Moolenbroek verbosity_flag = "--terse";
329*e985b929SDavid van Moolenbroek } else if (!strcmp(v[i], "--help")) {
330*e985b929SDavid van Moolenbroek usage(groups, 0);
331*e985b929SDavid van Moolenbroek } else if (!strcmp(v[i], "--list-tests")) {
332*e985b929SDavid van Moolenbroek usage(groups, 1);
333*e985b929SDavid van Moolenbroek } else {
334*e985b929SDavid van Moolenbroek printf("Unknown option %s. Try --help\n",v[i]);
335*e985b929SDavid van Moolenbroek return -1;
336*e985b929SDavid van Moolenbroek }
337*e985b929SDavid van Moolenbroek } else {
338*e985b929SDavid van Moolenbroek const char *test = v[i];
339*e985b929SDavid van Moolenbroek int flag = _TT_ENABLED;
340*e985b929SDavid van Moolenbroek if (test[0] == ':') {
341*e985b929SDavid van Moolenbroek ++test;
342*e985b929SDavid van Moolenbroek flag = TT_SKIP;
343*e985b929SDavid van Moolenbroek } else {
344*e985b929SDavid van Moolenbroek ++n;
345*e985b929SDavid van Moolenbroek }
346*e985b929SDavid van Moolenbroek if (!_tinytest_set_flag(groups, test, flag)) {
347*e985b929SDavid van Moolenbroek printf("No such test as %s!\n", v[i]);
348*e985b929SDavid van Moolenbroek return -1;
349*e985b929SDavid van Moolenbroek }
350*e985b929SDavid van Moolenbroek }
351*e985b929SDavid van Moolenbroek }
352*e985b929SDavid van Moolenbroek if (!n)
353*e985b929SDavid van Moolenbroek _tinytest_set_flag(groups, "..", _TT_ENABLED);
354*e985b929SDavid van Moolenbroek
355*e985b929SDavid van Moolenbroek setvbuf(stdout, NULL, _IONBF, 0);
356*e985b929SDavid van Moolenbroek
357*e985b929SDavid van Moolenbroek ++in_tinytest_main;
358*e985b929SDavid van Moolenbroek for (i=0; groups[i].prefix; ++i)
359*e985b929SDavid van Moolenbroek for (j=0; groups[i].cases[j].name; ++j)
360*e985b929SDavid van Moolenbroek if (groups[i].cases[j].flags & _TT_ENABLED)
361*e985b929SDavid van Moolenbroek testcase_run_one(&groups[i],
362*e985b929SDavid van Moolenbroek &groups[i].cases[j]);
363*e985b929SDavid van Moolenbroek
364*e985b929SDavid van Moolenbroek --in_tinytest_main;
365*e985b929SDavid van Moolenbroek
366*e985b929SDavid van Moolenbroek if (opt_verbosity==0)
367*e985b929SDavid van Moolenbroek puts("");
368*e985b929SDavid van Moolenbroek
369*e985b929SDavid van Moolenbroek if (n_bad)
370*e985b929SDavid van Moolenbroek printf("%d/%d TESTS FAILED. (%d skipped)\n", n_bad,
371*e985b929SDavid van Moolenbroek n_bad+n_ok,n_skipped);
372*e985b929SDavid van Moolenbroek else if (opt_verbosity >= 1)
373*e985b929SDavid van Moolenbroek printf("%d tests ok. (%d skipped)\n", n_ok, n_skipped);
374*e985b929SDavid van Moolenbroek
375*e985b929SDavid van Moolenbroek return (n_bad == 0) ? 0 : 1;
376*e985b929SDavid van Moolenbroek }
377*e985b929SDavid van Moolenbroek
378*e985b929SDavid van Moolenbroek int
_tinytest_get_verbosity(void)379*e985b929SDavid van Moolenbroek _tinytest_get_verbosity(void)
380*e985b929SDavid van Moolenbroek {
381*e985b929SDavid van Moolenbroek return opt_verbosity;
382*e985b929SDavid van Moolenbroek }
383*e985b929SDavid van Moolenbroek
384*e985b929SDavid van Moolenbroek void
_tinytest_set_test_failed(void)385*e985b929SDavid van Moolenbroek _tinytest_set_test_failed(void)
386*e985b929SDavid van Moolenbroek {
387*e985b929SDavid van Moolenbroek if (opt_verbosity <= 0 && cur_test_name) {
388*e985b929SDavid van Moolenbroek if (opt_verbosity==0) puts("");
389*e985b929SDavid van Moolenbroek printf("%s%s: ", cur_test_prefix, cur_test_name);
390*e985b929SDavid van Moolenbroek cur_test_name = NULL;
391*e985b929SDavid van Moolenbroek }
392*e985b929SDavid van Moolenbroek cur_test_outcome = 0;
393*e985b929SDavid van Moolenbroek }
394*e985b929SDavid van Moolenbroek
395*e985b929SDavid van Moolenbroek void
_tinytest_set_test_skipped(void)396*e985b929SDavid van Moolenbroek _tinytest_set_test_skipped(void)
397*e985b929SDavid van Moolenbroek {
398*e985b929SDavid van Moolenbroek if (cur_test_outcome==OK)
399*e985b929SDavid van Moolenbroek cur_test_outcome = SKIP;
400*e985b929SDavid van Moolenbroek }
401*e985b929SDavid van Moolenbroek
402