xref: /freebsd/contrib/ntp/sntp/libevent/test/tinytest.c (revision a466cc55373fc3cf86837f09da729535b57e69a1)
12b15cb3dSCy Schubert /* tinytest.c -- Copyright 2009-2012 Nick Mathewson
22b15cb3dSCy Schubert  *
32b15cb3dSCy Schubert  * Redistribution and use in source and binary forms, with or without
42b15cb3dSCy Schubert  * modification, are permitted provided that the following conditions
52b15cb3dSCy Schubert  * are met:
62b15cb3dSCy Schubert  * 1. Redistributions of source code must retain the above copyright
72b15cb3dSCy Schubert  *    notice, this list of conditions and the following disclaimer.
82b15cb3dSCy Schubert  * 2. Redistributions in binary form must reproduce the above copyright
92b15cb3dSCy Schubert  *    notice, this list of conditions and the following disclaimer in the
102b15cb3dSCy Schubert  *    documentation and/or other materials provided with the distribution.
112b15cb3dSCy Schubert  * 3. The name of the author may not be used to endorse or promote products
122b15cb3dSCy Schubert  *    derived from this software without specific prior written permission.
132b15cb3dSCy Schubert  *
142b15cb3dSCy Schubert  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
152b15cb3dSCy Schubert  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
162b15cb3dSCy Schubert  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
172b15cb3dSCy Schubert  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
182b15cb3dSCy Schubert  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
192b15cb3dSCy Schubert  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
202b15cb3dSCy Schubert  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
212b15cb3dSCy Schubert  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
222b15cb3dSCy Schubert  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
232b15cb3dSCy Schubert  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
242b15cb3dSCy Schubert  */
252b15cb3dSCy Schubert #ifdef TINYTEST_LOCAL
262b15cb3dSCy Schubert #include "tinytest_local.h"
272b15cb3dSCy Schubert #endif
282b15cb3dSCy Schubert 
292b15cb3dSCy Schubert #include <stdio.h>
302b15cb3dSCy Schubert #include <stdlib.h>
312b15cb3dSCy Schubert #include <string.h>
322b15cb3dSCy Schubert #include <assert.h>
332b15cb3dSCy Schubert 
34a25439b6SCy Schubert #ifndef NO_FORKING
35a25439b6SCy Schubert 
362b15cb3dSCy Schubert #ifdef _WIN32
372b15cb3dSCy Schubert #include <windows.h>
382b15cb3dSCy Schubert #else
392b15cb3dSCy Schubert #include <sys/types.h>
402b15cb3dSCy Schubert #include <sys/wait.h>
412b15cb3dSCy Schubert #include <unistd.h>
422b15cb3dSCy Schubert #endif
432b15cb3dSCy Schubert 
442b15cb3dSCy Schubert #if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
452b15cb3dSCy Schubert #if (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060 && \
462b15cb3dSCy Schubert     __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070)
472b15cb3dSCy Schubert /* Workaround for a stupid bug in OSX 10.6 */
482b15cb3dSCy Schubert #define FORK_BREAKS_GCOV
492b15cb3dSCy Schubert #include <vproc.h>
502b15cb3dSCy Schubert #endif
512b15cb3dSCy Schubert #endif
522b15cb3dSCy Schubert 
53a25439b6SCy Schubert #endif /* !NO_FORKING */
54a25439b6SCy Schubert 
552b15cb3dSCy Schubert #ifndef __GNUC__
562b15cb3dSCy Schubert #define __attribute__(x)
572b15cb3dSCy Schubert #endif
582b15cb3dSCy Schubert 
592b15cb3dSCy Schubert #include "tinytest.h"
602b15cb3dSCy Schubert #include "tinytest_macros.h"
612b15cb3dSCy Schubert 
622b15cb3dSCy Schubert #define LONGEST_TEST_NAME 16384
63*a466cc55SCy Schubert #define DEFAULT_TESTCASE_TIMEOUT 30U
64*a466cc55SCy Schubert #define MAGIC_EXITCODE 42
652b15cb3dSCy Schubert 
662b15cb3dSCy Schubert static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/
672b15cb3dSCy Schubert static int n_ok = 0; /**< Number of tests that have passed */
682b15cb3dSCy Schubert static int n_bad = 0; /**< Number of tests that have failed. */
692b15cb3dSCy Schubert static int n_skipped = 0; /**< Number of tests that have been skipped. */
702b15cb3dSCy Schubert 
712b15cb3dSCy Schubert static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/
722b15cb3dSCy Schubert static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */
732b15cb3dSCy Schubert static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */
74*a466cc55SCy Schubert static unsigned int opt_timeout = DEFAULT_TESTCASE_TIMEOUT; /**< Timeout for every test (using alarm()) */
752b15cb3dSCy Schubert const char *verbosity_flag = "";
762b15cb3dSCy Schubert 
772b15cb3dSCy Schubert const struct testlist_alias_t *cfg_aliases=NULL;
782b15cb3dSCy Schubert 
792b15cb3dSCy Schubert enum outcome { SKIP=2, OK=1, FAIL=0 };
802b15cb3dSCy Schubert static enum outcome cur_test_outcome = 0;
812b15cb3dSCy Schubert const char *cur_test_prefix = NULL; /**< prefix of the current test group */
822b15cb3dSCy Schubert /** Name of the current test, if we haven't logged is yet. Used for --quiet */
832b15cb3dSCy Schubert const char *cur_test_name = NULL;
842b15cb3dSCy Schubert 
852b15cb3dSCy Schubert static void usage(struct testgroup_t *groups, int list_groups)
862b15cb3dSCy Schubert 	__attribute__((noreturn));
872b15cb3dSCy Schubert static int process_test_option(struct testgroup_t *groups, const char *test);
882b15cb3dSCy Schubert 
89*a466cc55SCy Schubert #ifdef _WIN32
90*a466cc55SCy Schubert /* Copy of argv[0] for win32. */
91*a466cc55SCy Schubert static char commandname[MAX_PATH+1];
92*a466cc55SCy Schubert 
93*a466cc55SCy Schubert struct timeout_thread_args {
94*a466cc55SCy Schubert 	const testcase_fn *fn;
95*a466cc55SCy Schubert 	void *env;
96*a466cc55SCy Schubert };
97*a466cc55SCy Schubert 
98*a466cc55SCy Schubert static DWORD WINAPI
timeout_thread_proc_(LPVOID arg)99*a466cc55SCy Schubert timeout_thread_proc_(LPVOID arg)
100*a466cc55SCy Schubert {
101*a466cc55SCy Schubert 	struct timeout_thread_args *args = arg;
102*a466cc55SCy Schubert 	(*(args->fn))(args->env);
103*a466cc55SCy Schubert 	ExitThread(cur_test_outcome == FAIL ? 1 : 0);
104*a466cc55SCy Schubert }
105*a466cc55SCy Schubert 
106*a466cc55SCy Schubert static enum outcome
testcase_run_in_thread_(const struct testcase_t * testcase,void * env)107*a466cc55SCy Schubert testcase_run_in_thread_(const struct testcase_t *testcase, void *env)
108*a466cc55SCy Schubert {
109*a466cc55SCy Schubert 	/* We will never run testcase in a new thread when the
110*a466cc55SCy Schubert 	timeout is set to zero */
111*a466cc55SCy Schubert 	assert(opt_timeout);
112*a466cc55SCy Schubert 	DWORD ret, tid;
113*a466cc55SCy Schubert 	HANDLE handle;
114*a466cc55SCy Schubert 	struct timeout_thread_args args = {
115*a466cc55SCy Schubert 		&(testcase->fn),
116*a466cc55SCy Schubert 		env
117*a466cc55SCy Schubert 	};
118*a466cc55SCy Schubert 
119*a466cc55SCy Schubert 	handle =CreateThread(NULL, 0, timeout_thread_proc_,
120*a466cc55SCy Schubert 		(LPVOID)&args, 0, &tid);
121*a466cc55SCy Schubert 	ret = WaitForSingleObject(handle, opt_timeout * 1000U);
122*a466cc55SCy Schubert 	if (ret == WAIT_OBJECT_0) {
123*a466cc55SCy Schubert 		ret = 0;
124*a466cc55SCy Schubert 		if (!GetExitCodeThread(handle, &ret)) {
125*a466cc55SCy Schubert 			printf("GetExitCodeThread failed\n");
126*a466cc55SCy Schubert 			ret = 1;
127*a466cc55SCy Schubert 		}
128*a466cc55SCy Schubert 	} else if (ret == WAIT_TIMEOUT)	{
129*a466cc55SCy Schubert 		printf("timeout\n");
130*a466cc55SCy Schubert 	} else {
131*a466cc55SCy Schubert 		printf("Wait failed\n");
132*a466cc55SCy Schubert 	}
133*a466cc55SCy Schubert 	CloseHandle(handle);
134*a466cc55SCy Schubert 	if (ret == 0)
135*a466cc55SCy Schubert 		return OK;
136*a466cc55SCy Schubert 	else if (ret == MAGIC_EXITCODE)
137*a466cc55SCy Schubert 		return SKIP;
138*a466cc55SCy Schubert 	else
139*a466cc55SCy Schubert 		return FAIL;
140*a466cc55SCy Schubert }
141*a466cc55SCy Schubert #else
testcase_set_timeout_(void)142*a466cc55SCy Schubert static unsigned int testcase_set_timeout_(void)
143*a466cc55SCy Schubert {
144*a466cc55SCy Schubert 	return alarm(opt_timeout);
145*a466cc55SCy Schubert }
146*a466cc55SCy Schubert 
testcase_reset_timeout_(void)147*a466cc55SCy Schubert static unsigned int testcase_reset_timeout_(void)
148*a466cc55SCy Schubert {
149*a466cc55SCy Schubert 	return alarm(0);
150*a466cc55SCy Schubert }
151*a466cc55SCy Schubert #endif
152*a466cc55SCy Schubert 
1532b15cb3dSCy Schubert static enum outcome
testcase_run_bare_(const struct testcase_t * testcase)1542b15cb3dSCy Schubert testcase_run_bare_(const struct testcase_t *testcase)
1552b15cb3dSCy Schubert {
1562b15cb3dSCy Schubert 	void *env = NULL;
1572b15cb3dSCy Schubert 	int outcome;
1582b15cb3dSCy Schubert 	if (testcase->setup) {
1592b15cb3dSCy Schubert 		env = testcase->setup->setup_fn(testcase);
1602b15cb3dSCy Schubert 		if (!env)
1612b15cb3dSCy Schubert 			return FAIL;
1622b15cb3dSCy Schubert 		else if (env == (void*)TT_SKIP)
1632b15cb3dSCy Schubert 			return SKIP;
1642b15cb3dSCy Schubert 	}
1652b15cb3dSCy Schubert 
1662b15cb3dSCy Schubert 	cur_test_outcome = OK;
167*a466cc55SCy Schubert 	{
168*a466cc55SCy Schubert 		if (opt_timeout) {
169*a466cc55SCy Schubert #ifdef _WIN32
170*a466cc55SCy Schubert 			cur_test_outcome = testcase_run_in_thread_(testcase, env);
171*a466cc55SCy Schubert #else
172*a466cc55SCy Schubert 			testcase_set_timeout_();
1732b15cb3dSCy Schubert 			testcase->fn(env);
174*a466cc55SCy Schubert 			testcase_reset_timeout_();
175*a466cc55SCy Schubert #endif
176*a466cc55SCy Schubert 		} else {
177*a466cc55SCy Schubert 			testcase->fn(env);
178*a466cc55SCy Schubert 		}
179*a466cc55SCy Schubert 	}
1802b15cb3dSCy Schubert 	outcome = cur_test_outcome;
1812b15cb3dSCy Schubert 
1822b15cb3dSCy Schubert 	if (testcase->setup) {
1832b15cb3dSCy Schubert 		if (testcase->setup->cleanup_fn(testcase, env) == 0)
1842b15cb3dSCy Schubert 			outcome = FAIL;
1852b15cb3dSCy Schubert 	}
1862b15cb3dSCy Schubert 
1872b15cb3dSCy Schubert 	return outcome;
1882b15cb3dSCy Schubert }
1892b15cb3dSCy Schubert 
1902b15cb3dSCy Schubert 
191a25439b6SCy Schubert #ifndef NO_FORKING
192a25439b6SCy Schubert 
1932b15cb3dSCy Schubert static enum outcome
testcase_run_forked_(const struct testgroup_t * group,const struct testcase_t * testcase)1942b15cb3dSCy Schubert testcase_run_forked_(const struct testgroup_t *group,
1952b15cb3dSCy Schubert 		     const struct testcase_t *testcase)
1962b15cb3dSCy Schubert {
1972b15cb3dSCy Schubert #ifdef _WIN32
1982b15cb3dSCy Schubert 	/* Fork? On Win32?  How primitive!  We'll do what the smart kids do:
1992b15cb3dSCy Schubert 	   we'll invoke our own exe (whose name we recall from the command
2002b15cb3dSCy Schubert 	   line) with a command line that tells it to run just the test we
2012b15cb3dSCy Schubert 	   want, and this time without forking.
2022b15cb3dSCy Schubert 
2032b15cb3dSCy Schubert 	   (No, threads aren't an option.  The whole point of forking is to
2042b15cb3dSCy Schubert 	   share no state between tests.)
2052b15cb3dSCy Schubert 	 */
2062b15cb3dSCy Schubert 	int ok;
2072b15cb3dSCy Schubert 	char buffer[LONGEST_TEST_NAME+256];
2082b15cb3dSCy Schubert 	STARTUPINFOA si;
2092b15cb3dSCy Schubert 	PROCESS_INFORMATION info;
210*a466cc55SCy Schubert 	DWORD ret;
2112b15cb3dSCy Schubert 
2122b15cb3dSCy Schubert 	if (!in_tinytest_main) {
2132b15cb3dSCy Schubert 		printf("\nERROR.  On Windows, testcase_run_forked_ must be"
2142b15cb3dSCy Schubert 		       " called from within tinytest_main.\n");
2152b15cb3dSCy Schubert 		abort();
2162b15cb3dSCy Schubert 	}
2172b15cb3dSCy Schubert 	if (opt_verbosity>0)
2182b15cb3dSCy Schubert 		printf("[forking] ");
2192b15cb3dSCy Schubert 
220*a466cc55SCy Schubert 	snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s --timeout 0 %s%s",
2212b15cb3dSCy Schubert 		 commandname, verbosity_flag, group->prefix, testcase->name);
2222b15cb3dSCy Schubert 
2232b15cb3dSCy Schubert 	memset(&si, 0, sizeof(si));
2242b15cb3dSCy Schubert 	memset(&info, 0, sizeof(info));
2252b15cb3dSCy Schubert 	si.cb = sizeof(si);
2262b15cb3dSCy Schubert 
2272b15cb3dSCy Schubert 	ok = CreateProcessA(commandname, buffer, NULL, NULL, 0,
2282b15cb3dSCy Schubert 			   0, NULL, NULL, &si, &info);
2292b15cb3dSCy Schubert 	if (!ok) {
2302b15cb3dSCy Schubert 		printf("CreateProcess failed!\n");
231*a466cc55SCy Schubert 		return FAIL;
2322b15cb3dSCy Schubert 	}
233*a466cc55SCy Schubert 	ret = WaitForSingleObject(info.hProcess,
234*a466cc55SCy Schubert 		(opt_timeout ? opt_timeout * 1000U : INFINITE));
235*a466cc55SCy Schubert 
236*a466cc55SCy Schubert 	if (ret == WAIT_OBJECT_0) {
237*a466cc55SCy Schubert 		GetExitCodeProcess(info.hProcess, &ret);
238*a466cc55SCy Schubert 	} else if (ret == WAIT_TIMEOUT) {
239*a466cc55SCy Schubert 		printf("timeout\n");
240*a466cc55SCy Schubert 	} else {
241*a466cc55SCy Schubert 		printf("Wait failed\n");
242*a466cc55SCy Schubert 	}
2432b15cb3dSCy Schubert 	CloseHandle(info.hProcess);
2442b15cb3dSCy Schubert 	CloseHandle(info.hThread);
245*a466cc55SCy Schubert 	if (ret == 0)
2462b15cb3dSCy Schubert 		return OK;
247*a466cc55SCy Schubert 	else if (ret == MAGIC_EXITCODE)
2482b15cb3dSCy Schubert 		return SKIP;
2492b15cb3dSCy Schubert 	else
2502b15cb3dSCy Schubert 		return FAIL;
2512b15cb3dSCy Schubert #else
2522b15cb3dSCy Schubert 	int outcome_pipe[2];
2532b15cb3dSCy Schubert 	pid_t pid;
2542b15cb3dSCy Schubert 	(void)group;
2552b15cb3dSCy Schubert 
2562b15cb3dSCy Schubert 	if (pipe(outcome_pipe))
2572b15cb3dSCy Schubert 		perror("opening pipe");
2582b15cb3dSCy Schubert 
2592b15cb3dSCy Schubert 	if (opt_verbosity>0)
2602b15cb3dSCy Schubert 		printf("[forking] ");
2612b15cb3dSCy Schubert 	pid = fork();
2622b15cb3dSCy Schubert #ifdef FORK_BREAKS_GCOV
2632b15cb3dSCy Schubert 	vproc_transaction_begin(0);
2642b15cb3dSCy Schubert #endif
2652b15cb3dSCy Schubert 	if (!pid) {
2662b15cb3dSCy Schubert 		/* child. */
2672b15cb3dSCy Schubert 		int test_r, write_r;
2682b15cb3dSCy Schubert 		char b[1];
2692b15cb3dSCy Schubert 		close(outcome_pipe[0]);
2702b15cb3dSCy Schubert 		test_r = testcase_run_bare_(testcase);
2712b15cb3dSCy Schubert 		assert(0<=(int)test_r && (int)test_r<=2);
2722b15cb3dSCy Schubert 		b[0] = "NYS"[test_r];
2732b15cb3dSCy Schubert 		write_r = (int)write(outcome_pipe[1], b, 1);
2742b15cb3dSCy Schubert 		if (write_r != 1) {
2752b15cb3dSCy Schubert 			perror("write outcome to pipe");
2762b15cb3dSCy Schubert 			exit(1);
2772b15cb3dSCy Schubert 		}
2782b15cb3dSCy Schubert 		exit(0);
2792b15cb3dSCy Schubert 		return FAIL; /* unreachable */
2802b15cb3dSCy Schubert 	} else {
2812b15cb3dSCy Schubert 		/* parent */
282*a466cc55SCy Schubert 		int status, r, exitcode;
2832b15cb3dSCy Schubert 		char b[1];
2842b15cb3dSCy Schubert 		/* Close this now, so that if the other side closes it,
2852b15cb3dSCy Schubert 		 * our read fails. */
2862b15cb3dSCy Schubert 		close(outcome_pipe[1]);
2872b15cb3dSCy Schubert 		r = (int)read(outcome_pipe[0], b, 1);
2882b15cb3dSCy Schubert 		if (r == 0) {
2892b15cb3dSCy Schubert 			printf("[Lost connection!] ");
290*a466cc55SCy Schubert 			return FAIL;
2912b15cb3dSCy Schubert 		} else if (r != 1) {
2922b15cb3dSCy Schubert 			perror("read outcome from pipe");
2932b15cb3dSCy Schubert 		}
2942b15cb3dSCy Schubert 		waitpid(pid, &status, 0);
295*a466cc55SCy Schubert 		exitcode = WEXITSTATUS(status);
2962b15cb3dSCy Schubert 		close(outcome_pipe[0]);
297*a466cc55SCy Schubert 		if (opt_verbosity>1)
298*a466cc55SCy Schubert 			printf("%s%s: exited with %i (%i)\n", group->prefix, testcase->name, exitcode, status);
299*a466cc55SCy Schubert 		if (exitcode != 0)
300*a466cc55SCy Schubert 		{
301*a466cc55SCy Schubert 			printf("[atexit failure!] ");
302*a466cc55SCy Schubert 			return FAIL;
303*a466cc55SCy Schubert 		}
3042b15cb3dSCy Schubert 		return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL);
3052b15cb3dSCy Schubert 	}
3062b15cb3dSCy Schubert #endif
3072b15cb3dSCy Schubert }
3082b15cb3dSCy Schubert 
309a25439b6SCy Schubert #endif /* !NO_FORKING */
310a25439b6SCy Schubert 
3112b15cb3dSCy Schubert int
testcase_run_one(const struct testgroup_t * group,const struct testcase_t * testcase)3122b15cb3dSCy Schubert testcase_run_one(const struct testgroup_t *group,
3132b15cb3dSCy Schubert 		 const struct testcase_t *testcase)
3142b15cb3dSCy Schubert {
3152b15cb3dSCy Schubert 	enum outcome outcome;
3162b15cb3dSCy Schubert 
3172b15cb3dSCy Schubert 	if (testcase->flags & (TT_SKIP|TT_OFF_BY_DEFAULT)) {
3182b15cb3dSCy Schubert 		if (opt_verbosity>0)
3192b15cb3dSCy Schubert 			printf("%s%s: %s\n",
3202b15cb3dSCy Schubert 			   group->prefix, testcase->name,
3212b15cb3dSCy Schubert 			   (testcase->flags & TT_SKIP) ? "SKIPPED" : "DISABLED");
3222b15cb3dSCy Schubert 		++n_skipped;
3232b15cb3dSCy Schubert 		return SKIP;
3242b15cb3dSCy Schubert 	}
3252b15cb3dSCy Schubert 
3262b15cb3dSCy Schubert 	if (opt_verbosity>0 && !opt_forked) {
3272b15cb3dSCy Schubert 		printf("%s%s: ", group->prefix, testcase->name);
3282b15cb3dSCy Schubert 	} else {
3292b15cb3dSCy Schubert 		if (opt_verbosity==0) printf(".");
3302b15cb3dSCy Schubert 		cur_test_prefix = group->prefix;
3312b15cb3dSCy Schubert 		cur_test_name = testcase->name;
3322b15cb3dSCy Schubert 	}
3332b15cb3dSCy Schubert 
334a25439b6SCy Schubert #ifndef NO_FORKING
3352b15cb3dSCy Schubert 	if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) {
3362b15cb3dSCy Schubert 		outcome = testcase_run_forked_(group, testcase);
3372b15cb3dSCy Schubert 	} else {
338a25439b6SCy Schubert #else
339a25439b6SCy Schubert 	{
340a25439b6SCy Schubert #endif
3412b15cb3dSCy Schubert 		outcome = testcase_run_bare_(testcase);
3422b15cb3dSCy Schubert 	}
3432b15cb3dSCy Schubert 
3442b15cb3dSCy Schubert 	if (outcome == OK) {
3452b15cb3dSCy Schubert 		if (opt_verbosity>0 && !opt_forked)
3462b15cb3dSCy Schubert 			puts(opt_verbosity==1?"OK":"");
3472b15cb3dSCy Schubert 	} else if (outcome == SKIP) {
3482b15cb3dSCy Schubert 		if (opt_verbosity>0 && !opt_forked)
3492b15cb3dSCy Schubert 			puts("SKIPPED");
3502b15cb3dSCy Schubert 	} else {
3512b15cb3dSCy Schubert 		if (!opt_forked)
3522b15cb3dSCy Schubert 			printf("\n  [%s FAILED]\n", testcase->name);
3532b15cb3dSCy Schubert 	}
3542b15cb3dSCy Schubert 
3552b15cb3dSCy Schubert 	if (opt_forked) {
3562b15cb3dSCy Schubert 		exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1));
3572b15cb3dSCy Schubert 		return 1; /* unreachable */
3582b15cb3dSCy Schubert 	} else {
3592b15cb3dSCy Schubert 		return (int)outcome;
3602b15cb3dSCy Schubert 	}
3612b15cb3dSCy Schubert }
3622b15cb3dSCy Schubert 
3632b15cb3dSCy Schubert int
3642b15cb3dSCy Schubert tinytest_set_flag_(struct testgroup_t *groups, const char *arg, int set, unsigned long flag)
3652b15cb3dSCy Schubert {
3662b15cb3dSCy Schubert 	int i, j;
3672b15cb3dSCy Schubert 	size_t length = LONGEST_TEST_NAME;
3682b15cb3dSCy Schubert 	char fullname[LONGEST_TEST_NAME];
3692b15cb3dSCy Schubert 	int found=0;
3702b15cb3dSCy Schubert 	if (strstr(arg, ".."))
3712b15cb3dSCy Schubert 		length = strstr(arg,"..")-arg;
3722b15cb3dSCy Schubert 	for (i=0; groups[i].prefix; ++i) {
3732b15cb3dSCy Schubert 		for (j=0; groups[i].cases[j].name; ++j) {
3742b15cb3dSCy Schubert 			struct testcase_t *testcase = &groups[i].cases[j];
3752b15cb3dSCy Schubert 			snprintf(fullname, sizeof(fullname), "%s%s",
3762b15cb3dSCy Schubert 				 groups[i].prefix, testcase->name);
3772b15cb3dSCy Schubert 			if (!flag) { /* Hack! */
3782b15cb3dSCy Schubert 				printf("    %s", fullname);
3792b15cb3dSCy Schubert 				if (testcase->flags & TT_OFF_BY_DEFAULT)
3802b15cb3dSCy Schubert 					puts("   (Off by default)");
3812b15cb3dSCy Schubert 				else if (testcase->flags & TT_SKIP)
3822b15cb3dSCy Schubert 					puts("  (DISABLED)");
3832b15cb3dSCy Schubert 				else
3842b15cb3dSCy Schubert 					puts("");
3852b15cb3dSCy Schubert 			}
3862b15cb3dSCy Schubert 			if (!strncmp(fullname, arg, length)) {
3872b15cb3dSCy Schubert 				if (set)
3882b15cb3dSCy Schubert 					testcase->flags |= flag;
3892b15cb3dSCy Schubert 				else
3902b15cb3dSCy Schubert 					testcase->flags &= ~flag;
3912b15cb3dSCy Schubert 				++found;
3922b15cb3dSCy Schubert 			}
3932b15cb3dSCy Schubert 		}
3942b15cb3dSCy Schubert 	}
3952b15cb3dSCy Schubert 	return found;
3962b15cb3dSCy Schubert }
3972b15cb3dSCy Schubert 
3982b15cb3dSCy Schubert static void
3992b15cb3dSCy Schubert usage(struct testgroup_t *groups, int list_groups)
4002b15cb3dSCy Schubert {
401*a466cc55SCy Schubert 	puts("Options are: [--verbose|--quiet|--terse] [--no-fork] [--timeout <sec>]");
4022b15cb3dSCy Schubert 	puts("  Specify tests by name, or using a prefix ending with '..'");
4032b15cb3dSCy Schubert 	puts("  To skip a test, prefix its name with a colon.");
4042b15cb3dSCy Schubert 	puts("  To enable a disabled test, prefix its name with a plus.");
4052b15cb3dSCy Schubert 	puts("  Use --list-tests for a list of tests.");
4062b15cb3dSCy Schubert 	if (list_groups) {
4072b15cb3dSCy Schubert 		puts("Known tests are:");
4082b15cb3dSCy Schubert 		tinytest_set_flag_(groups, "..", 1, 0);
4092b15cb3dSCy Schubert 	}
4102b15cb3dSCy Schubert 	exit(0);
4112b15cb3dSCy Schubert }
4122b15cb3dSCy Schubert 
4132b15cb3dSCy Schubert static int
4142b15cb3dSCy Schubert process_test_alias(struct testgroup_t *groups, const char *test)
4152b15cb3dSCy Schubert {
4162b15cb3dSCy Schubert 	int i, j, n, r;
4172b15cb3dSCy Schubert 	for (i=0; cfg_aliases && cfg_aliases[i].name; ++i) {
4182b15cb3dSCy Schubert 		if (!strcmp(cfg_aliases[i].name, test)) {
4192b15cb3dSCy Schubert 			n = 0;
4202b15cb3dSCy Schubert 			for (j = 0; cfg_aliases[i].tests[j]; ++j) {
4212b15cb3dSCy Schubert 				r = process_test_option(groups, cfg_aliases[i].tests[j]);
4222b15cb3dSCy Schubert 				if (r<0)
4232b15cb3dSCy Schubert 					return -1;
4242b15cb3dSCy Schubert 				n += r;
4252b15cb3dSCy Schubert 			}
4262b15cb3dSCy Schubert 			return n;
4272b15cb3dSCy Schubert 		}
4282b15cb3dSCy Schubert 	}
4292b15cb3dSCy Schubert 	printf("No such test alias as @%s!",test);
4302b15cb3dSCy Schubert 	return -1;
4312b15cb3dSCy Schubert }
4322b15cb3dSCy Schubert 
4332b15cb3dSCy Schubert static int
4342b15cb3dSCy Schubert process_test_option(struct testgroup_t *groups, const char *test)
4352b15cb3dSCy Schubert {
4362b15cb3dSCy Schubert 	int flag = TT_ENABLED_;
4372b15cb3dSCy Schubert 	int n = 0;
4382b15cb3dSCy Schubert 	if (test[0] == '@') {
4392b15cb3dSCy Schubert 		return process_test_alias(groups, test + 1);
4402b15cb3dSCy Schubert 	} else if (test[0] == ':') {
4412b15cb3dSCy Schubert 		++test;
4422b15cb3dSCy Schubert 		flag = TT_SKIP;
4432b15cb3dSCy Schubert 	} else if (test[0] == '+') {
4442b15cb3dSCy Schubert 		++test;
4452b15cb3dSCy Schubert 		++n;
4462b15cb3dSCy Schubert 		if (!tinytest_set_flag_(groups, test, 0, TT_OFF_BY_DEFAULT)) {
4472b15cb3dSCy Schubert 			printf("No such test as %s!\n", test);
4482b15cb3dSCy Schubert 			return -1;
4492b15cb3dSCy Schubert 		}
4502b15cb3dSCy Schubert 	} else {
4512b15cb3dSCy Schubert 		++n;
4522b15cb3dSCy Schubert 	}
4532b15cb3dSCy Schubert 	if (!tinytest_set_flag_(groups, test, 1, flag)) {
4542b15cb3dSCy Schubert 		printf("No such test as %s!\n", test);
4552b15cb3dSCy Schubert 		return -1;
4562b15cb3dSCy Schubert 	}
4572b15cb3dSCy Schubert 	return n;
4582b15cb3dSCy Schubert }
4592b15cb3dSCy Schubert 
4602b15cb3dSCy Schubert void
4612b15cb3dSCy Schubert tinytest_set_aliases(const struct testlist_alias_t *aliases)
4622b15cb3dSCy Schubert {
4632b15cb3dSCy Schubert 	cfg_aliases = aliases;
4642b15cb3dSCy Schubert }
4652b15cb3dSCy Schubert 
4662b15cb3dSCy Schubert int
4672b15cb3dSCy Schubert tinytest_main(int c, const char **v, struct testgroup_t *groups)
4682b15cb3dSCy Schubert {
4692b15cb3dSCy Schubert 	int i, j, n=0;
4702b15cb3dSCy Schubert 
4712b15cb3dSCy Schubert #ifdef _WIN32
4722b15cb3dSCy Schubert 	const char *sp = strrchr(v[0], '.');
4732b15cb3dSCy Schubert 	const char *extension = "";
4742b15cb3dSCy Schubert 	if (!sp || stricmp(sp, ".exe"))
4752b15cb3dSCy Schubert 		extension = ".exe"; /* Add an exe so CreateProcess will work */
4762b15cb3dSCy Schubert 	snprintf(commandname, sizeof(commandname), "%s%s", v[0], extension);
4772b15cb3dSCy Schubert 	commandname[MAX_PATH]='\0';
4782b15cb3dSCy Schubert #endif
4792b15cb3dSCy Schubert 	for (i=1; i<c; ++i) {
4802b15cb3dSCy Schubert 		if (v[i][0] == '-') {
4812b15cb3dSCy Schubert 			if (!strcmp(v[i], "--RUNNING-FORKED")) {
4822b15cb3dSCy Schubert 				opt_forked = 1;
4832b15cb3dSCy Schubert 			} else if (!strcmp(v[i], "--no-fork")) {
4842b15cb3dSCy Schubert 				opt_nofork = 1;
4852b15cb3dSCy Schubert 			} else if (!strcmp(v[i], "--quiet")) {
4862b15cb3dSCy Schubert 				opt_verbosity = -1;
4872b15cb3dSCy Schubert 				verbosity_flag = "--quiet";
4882b15cb3dSCy Schubert 			} else if (!strcmp(v[i], "--verbose")) {
4892b15cb3dSCy Schubert 				opt_verbosity = 2;
4902b15cb3dSCy Schubert 				verbosity_flag = "--verbose";
4912b15cb3dSCy Schubert 			} else if (!strcmp(v[i], "--terse")) {
4922b15cb3dSCy Schubert 				opt_verbosity = 0;
4932b15cb3dSCy Schubert 				verbosity_flag = "--terse";
4942b15cb3dSCy Schubert 			} else if (!strcmp(v[i], "--help")) {
4952b15cb3dSCy Schubert 				usage(groups, 0);
4962b15cb3dSCy Schubert 			} else if (!strcmp(v[i], "--list-tests")) {
4972b15cb3dSCy Schubert 				usage(groups, 1);
498*a466cc55SCy Schubert 			} else if (!strcmp(v[i], "--timeout")) {
499*a466cc55SCy Schubert 				++i;
500*a466cc55SCy Schubert 				if (i >= c) {
501*a466cc55SCy Schubert 					fprintf(stderr, "--timeout requires argument\n");
502*a466cc55SCy Schubert 					return -1;
503*a466cc55SCy Schubert 				}
504*a466cc55SCy Schubert 				opt_timeout = (unsigned)atoi(v[i]);
5052b15cb3dSCy Schubert 			} else {
506*a466cc55SCy Schubert 				fprintf(stderr, "Unknown option %s. Try --help\n", v[i]);
5072b15cb3dSCy Schubert 				return -1;
5082b15cb3dSCy Schubert 			}
5092b15cb3dSCy Schubert 		} else {
5102b15cb3dSCy Schubert 			int r = process_test_option(groups, v[i]);
5112b15cb3dSCy Schubert 			if (r<0)
5122b15cb3dSCy Schubert 				return -1;
5132b15cb3dSCy Schubert 			n += r;
5142b15cb3dSCy Schubert 		}
5152b15cb3dSCy Schubert 	}
5162b15cb3dSCy Schubert 	if (!n)
5172b15cb3dSCy Schubert 		tinytest_set_flag_(groups, "..", 1, TT_ENABLED_);
5182b15cb3dSCy Schubert 
519a25439b6SCy Schubert #ifdef _IONBF
5202b15cb3dSCy Schubert 	setvbuf(stdout, NULL, _IONBF, 0);
521a25439b6SCy Schubert #endif
5222b15cb3dSCy Schubert 
5232b15cb3dSCy Schubert 	++in_tinytest_main;
524*a466cc55SCy Schubert 	for (i = 0; groups[i].prefix; ++i) {
525*a466cc55SCy Schubert 		struct testgroup_t *group = &groups[i];
526*a466cc55SCy Schubert 		for (j = 0; group->cases[j].name; ++j) {
527*a466cc55SCy Schubert 			struct testcase_t *testcase = &group->cases[j];
528*a466cc55SCy Schubert 			int test_attempts = 3;
529*a466cc55SCy Schubert 			int test_ret_err;
530*a466cc55SCy Schubert 
531*a466cc55SCy Schubert 			if (!(testcase->flags & TT_ENABLED_))
532*a466cc55SCy Schubert 				continue;
533*a466cc55SCy Schubert 
534*a466cc55SCy Schubert 			for (;;) {
535*a466cc55SCy Schubert 				test_ret_err = testcase_run_one(group, testcase);
536*a466cc55SCy Schubert 
537*a466cc55SCy Schubert 				if (test_ret_err == OK)
538*a466cc55SCy Schubert 					break;
539*a466cc55SCy Schubert 				if (!(testcase->flags & TT_RETRIABLE))
540*a466cc55SCy Schubert 					break;
541*a466cc55SCy Schubert 				printf("\n  [RETRYING %s (%i)]\n", testcase->name, test_attempts);
542*a466cc55SCy Schubert 				if (!test_attempts--)
543*a466cc55SCy Schubert 					break;
544*a466cc55SCy Schubert 			}
545*a466cc55SCy Schubert 
546*a466cc55SCy Schubert 			switch (test_ret_err) {
547*a466cc55SCy Schubert 				case OK:   ++n_ok;      break;
548*a466cc55SCy Schubert 				case SKIP: ++n_skipped; break;
549*a466cc55SCy Schubert 				default:   ++n_bad;     break;
550*a466cc55SCy Schubert 			}
551*a466cc55SCy Schubert 		}
552*a466cc55SCy Schubert 	}
5532b15cb3dSCy Schubert 
5542b15cb3dSCy Schubert 	--in_tinytest_main;
5552b15cb3dSCy Schubert 
5562b15cb3dSCy Schubert 	if (opt_verbosity==0)
5572b15cb3dSCy Schubert 		puts("");
5582b15cb3dSCy Schubert 
5592b15cb3dSCy Schubert 	if (n_bad)
5602b15cb3dSCy Schubert 		printf("%d/%d TESTS FAILED. (%d skipped)\n", n_bad,
5612b15cb3dSCy Schubert 		       n_bad+n_ok,n_skipped);
5622b15cb3dSCy Schubert 	else if (opt_verbosity >= 1)
5632b15cb3dSCy Schubert 		printf("%d tests ok.  (%d skipped)\n", n_ok, n_skipped);
5642b15cb3dSCy Schubert 
5652b15cb3dSCy Schubert 	return (n_bad == 0) ? 0 : 1;
5662b15cb3dSCy Schubert }
5672b15cb3dSCy Schubert 
5682b15cb3dSCy Schubert int
5692b15cb3dSCy Schubert tinytest_get_verbosity_(void)
5702b15cb3dSCy Schubert {
5712b15cb3dSCy Schubert 	return opt_verbosity;
5722b15cb3dSCy Schubert }
5732b15cb3dSCy Schubert 
5742b15cb3dSCy Schubert void
5752b15cb3dSCy Schubert tinytest_set_test_failed_(void)
5762b15cb3dSCy Schubert {
5772b15cb3dSCy Schubert 	if (opt_verbosity <= 0 && cur_test_name) {
5782b15cb3dSCy Schubert 		if (opt_verbosity==0) puts("");
5792b15cb3dSCy Schubert 		printf("%s%s: ", cur_test_prefix, cur_test_name);
5802b15cb3dSCy Schubert 		cur_test_name = NULL;
5812b15cb3dSCy Schubert 	}
582*a466cc55SCy Schubert 	cur_test_outcome = FAIL;
5832b15cb3dSCy Schubert }
5842b15cb3dSCy Schubert 
5852b15cb3dSCy Schubert void
5862b15cb3dSCy Schubert tinytest_set_test_skipped_(void)
5872b15cb3dSCy Schubert {
5882b15cb3dSCy Schubert 	if (cur_test_outcome==OK)
5892b15cb3dSCy Schubert 		cur_test_outcome = SKIP;
5902b15cb3dSCy Schubert }
5912b15cb3dSCy Schubert 
592a25439b6SCy Schubert char *
593a25439b6SCy Schubert tinytest_format_hex_(const void *val_, unsigned long len)
594a25439b6SCy Schubert {
595a25439b6SCy Schubert 	const unsigned char *val = val_;
596a25439b6SCy Schubert 	char *result, *cp;
597a25439b6SCy Schubert 	size_t i;
598a25439b6SCy Schubert 
599a25439b6SCy Schubert 	if (!val)
600a25439b6SCy Schubert 		return strdup("null");
601a25439b6SCy Schubert 	if (!(result = malloc(len*2+1)))
602a25439b6SCy Schubert 		return strdup("<allocation failure>");
603a25439b6SCy Schubert 	cp = result;
604a25439b6SCy Schubert 	for (i=0;i<len;++i) {
605a25439b6SCy Schubert 		*cp++ = "0123456789ABCDEF"[val[i] >> 4];
606a25439b6SCy Schubert 		*cp++ = "0123456789ABCDEF"[val[i] & 0x0f];
607a25439b6SCy Schubert 	}
608a25439b6SCy Schubert 	*cp = 0;
609a25439b6SCy Schubert 	return result;
610a25439b6SCy Schubert }
611