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