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