xref: /minix3/external/bsd/libevent/dist/test/tinytest.c (revision e985b929927b5932e3b68f4b50587d458900107a)
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