1*657871a7Schristos /* $NetBSD: tinytest.c,v 1.1.1.3 2021/04/07 02:43:15 christos Exp $ */
26ecf6635Schristos /* tinytest.c -- Copyright 2009-2012 Nick Mathewson
36ecf6635Schristos *
46ecf6635Schristos * Redistribution and use in source and binary forms, with or without
56ecf6635Schristos * modification, are permitted provided that the following conditions
66ecf6635Schristos * are met:
76ecf6635Schristos * 1. Redistributions of source code must retain the above copyright
86ecf6635Schristos * notice, this list of conditions and the following disclaimer.
96ecf6635Schristos * 2. Redistributions in binary form must reproduce the above copyright
106ecf6635Schristos * notice, this list of conditions and the following disclaimer in the
116ecf6635Schristos * documentation and/or other materials provided with the distribution.
126ecf6635Schristos * 3. The name of the author may not be used to endorse or promote products
136ecf6635Schristos * derived from this software without specific prior written permission.
146ecf6635Schristos *
156ecf6635Schristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
166ecf6635Schristos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
176ecf6635Schristos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
186ecf6635Schristos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
196ecf6635Schristos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
206ecf6635Schristos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
216ecf6635Schristos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
226ecf6635Schristos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
236ecf6635Schristos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
246ecf6635Schristos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
256ecf6635Schristos */
26805a1ce9Schristos #ifdef TINYTEST_LOCAL
27805a1ce9Schristos #include "tinytest_local.h"
28805a1ce9Schristos #endif
296ecf6635Schristos
306ecf6635Schristos #include <stdio.h>
316ecf6635Schristos #include <stdlib.h>
326ecf6635Schristos #include <string.h>
336ecf6635Schristos #include <assert.h>
346ecf6635Schristos
35805a1ce9Schristos #ifndef NO_FORKING
366ecf6635Schristos
37805a1ce9Schristos #ifdef _WIN32
386ecf6635Schristos #include <windows.h>
396ecf6635Schristos #else
406ecf6635Schristos #include <sys/types.h>
416ecf6635Schristos #include <sys/wait.h>
426ecf6635Schristos #include <unistd.h>
436ecf6635Schristos #endif
446ecf6635Schristos
456ecf6635Schristos #if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
466ecf6635Schristos #if (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060 && \
476ecf6635Schristos __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070)
486ecf6635Schristos /* Workaround for a stupid bug in OSX 10.6 */
496ecf6635Schristos #define FORK_BREAKS_GCOV
506ecf6635Schristos #include <vproc.h>
516ecf6635Schristos #endif
526ecf6635Schristos #endif
536ecf6635Schristos
54805a1ce9Schristos #endif /* !NO_FORKING */
55805a1ce9Schristos
566ecf6635Schristos #ifndef __GNUC__
576ecf6635Schristos #define __attribute__(x)
586ecf6635Schristos #endif
596ecf6635Schristos
606ecf6635Schristos #include "tinytest.h"
616ecf6635Schristos #include "tinytest_macros.h"
626ecf6635Schristos
636ecf6635Schristos #define LONGEST_TEST_NAME 16384
64*657871a7Schristos #define DEFAULT_TESTCASE_TIMEOUT 30U
65*657871a7Schristos #define MAGIC_EXITCODE 42
666ecf6635Schristos
676ecf6635Schristos static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/
686ecf6635Schristos static int n_ok = 0; /**< Number of tests that have passed */
696ecf6635Schristos static int n_bad = 0; /**< Number of tests that have failed. */
706ecf6635Schristos static int n_skipped = 0; /**< Number of tests that have been skipped. */
716ecf6635Schristos
726ecf6635Schristos static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/
736ecf6635Schristos static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */
746ecf6635Schristos static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */
75*657871a7Schristos static unsigned int opt_timeout = DEFAULT_TESTCASE_TIMEOUT; /**< Timeout for every test (using alarm()) */
766ecf6635Schristos const char *verbosity_flag = "";
776ecf6635Schristos
78805a1ce9Schristos const struct testlist_alias_t *cfg_aliases=NULL;
79805a1ce9Schristos
806ecf6635Schristos enum outcome { SKIP=2, OK=1, FAIL=0 };
816ecf6635Schristos static enum outcome cur_test_outcome = 0;
826ecf6635Schristos const char *cur_test_prefix = NULL; /**< prefix of the current test group */
836ecf6635Schristos /** Name of the current test, if we haven't logged is yet. Used for --quiet */
846ecf6635Schristos const char *cur_test_name = NULL;
856ecf6635Schristos
866ecf6635Schristos static void usage(struct testgroup_t *groups, int list_groups)
876ecf6635Schristos __attribute__((noreturn));
88805a1ce9Schristos static int process_test_option(struct testgroup_t *groups, const char *test);
896ecf6635Schristos
90*657871a7Schristos #ifdef _WIN32
91*657871a7Schristos /* Copy of argv[0] for win32. */
92*657871a7Schristos static char commandname[MAX_PATH+1];
93*657871a7Schristos
94*657871a7Schristos struct timeout_thread_args {
95*657871a7Schristos const testcase_fn *fn;
96*657871a7Schristos void *env;
97*657871a7Schristos };
98*657871a7Schristos
99*657871a7Schristos static DWORD WINAPI
timeout_thread_proc_(LPVOID arg)100*657871a7Schristos timeout_thread_proc_(LPVOID arg)
101*657871a7Schristos {
102*657871a7Schristos struct timeout_thread_args *args = arg;
103*657871a7Schristos (*(args->fn))(args->env);
104*657871a7Schristos ExitThread(cur_test_outcome == FAIL ? 1 : 0);
105*657871a7Schristos }
106*657871a7Schristos
107*657871a7Schristos static enum outcome
testcase_run_in_thread_(const struct testcase_t * testcase,void * env)108*657871a7Schristos testcase_run_in_thread_(const struct testcase_t *testcase, void *env)
109*657871a7Schristos {
110*657871a7Schristos /* We will never run testcase in a new thread when the
111*657871a7Schristos timeout is set to zero */
112*657871a7Schristos assert(opt_timeout);
113*657871a7Schristos DWORD ret, tid;
114*657871a7Schristos HANDLE handle;
115*657871a7Schristos struct timeout_thread_args args = {
116*657871a7Schristos &(testcase->fn),
117*657871a7Schristos env
118*657871a7Schristos };
119*657871a7Schristos
120*657871a7Schristos handle =CreateThread(NULL, 0, timeout_thread_proc_,
121*657871a7Schristos (LPVOID)&args, 0, &tid);
122*657871a7Schristos ret = WaitForSingleObject(handle, opt_timeout * 1000U);
123*657871a7Schristos if (ret == WAIT_OBJECT_0) {
124*657871a7Schristos ret = 0;
125*657871a7Schristos if (!GetExitCodeThread(handle, &ret)) {
126*657871a7Schristos printf("GetExitCodeThread failed\n");
127*657871a7Schristos ret = 1;
128*657871a7Schristos }
129*657871a7Schristos } else if (ret == WAIT_TIMEOUT) {
130*657871a7Schristos printf("timeout\n");
131*657871a7Schristos } else {
132*657871a7Schristos printf("Wait failed\n");
133*657871a7Schristos }
134*657871a7Schristos CloseHandle(handle);
135*657871a7Schristos if (ret == 0)
136*657871a7Schristos return OK;
137*657871a7Schristos else if (ret == MAGIC_EXITCODE)
138*657871a7Schristos return SKIP;
139*657871a7Schristos else
140*657871a7Schristos return FAIL;
141*657871a7Schristos }
142*657871a7Schristos #else
testcase_set_timeout_(void)143*657871a7Schristos static unsigned int testcase_set_timeout_(void)
144*657871a7Schristos {
145*657871a7Schristos return alarm(opt_timeout);
146*657871a7Schristos }
147*657871a7Schristos
testcase_reset_timeout_(void)148*657871a7Schristos static unsigned int testcase_reset_timeout_(void)
149*657871a7Schristos {
150*657871a7Schristos return alarm(0);
151*657871a7Schristos }
152*657871a7Schristos #endif
153*657871a7Schristos
1546ecf6635Schristos static enum outcome
testcase_run_bare_(const struct testcase_t * testcase)155805a1ce9Schristos testcase_run_bare_(const struct testcase_t *testcase)
1566ecf6635Schristos {
1576ecf6635Schristos void *env = NULL;
1586ecf6635Schristos int outcome;
1596ecf6635Schristos if (testcase->setup) {
1606ecf6635Schristos env = testcase->setup->setup_fn(testcase);
1616ecf6635Schristos if (!env)
1626ecf6635Schristos return FAIL;
1636ecf6635Schristos else if (env == (void*)TT_SKIP)
1646ecf6635Schristos return SKIP;
1656ecf6635Schristos }
1666ecf6635Schristos
1676ecf6635Schristos cur_test_outcome = OK;
168*657871a7Schristos {
169*657871a7Schristos if (opt_timeout) {
170*657871a7Schristos #ifdef _WIN32
171*657871a7Schristos cur_test_outcome = testcase_run_in_thread_(testcase, env);
172*657871a7Schristos #else
173*657871a7Schristos testcase_set_timeout_();
1746ecf6635Schristos testcase->fn(env);
175*657871a7Schristos testcase_reset_timeout_();
176*657871a7Schristos #endif
177*657871a7Schristos } else {
178*657871a7Schristos testcase->fn(env);
179*657871a7Schristos }
180*657871a7Schristos }
1816ecf6635Schristos outcome = cur_test_outcome;
1826ecf6635Schristos
1836ecf6635Schristos if (testcase->setup) {
1846ecf6635Schristos if (testcase->setup->cleanup_fn(testcase, env) == 0)
1856ecf6635Schristos outcome = FAIL;
1866ecf6635Schristos }
1876ecf6635Schristos
1886ecf6635Schristos return outcome;
1896ecf6635Schristos }
1906ecf6635Schristos
1916ecf6635Schristos
192805a1ce9Schristos #ifndef NO_FORKING
193805a1ce9Schristos
1946ecf6635Schristos static enum outcome
testcase_run_forked_(const struct testgroup_t * group,const struct testcase_t * testcase)195805a1ce9Schristos testcase_run_forked_(const struct testgroup_t *group,
1966ecf6635Schristos const struct testcase_t *testcase)
1976ecf6635Schristos {
198805a1ce9Schristos #ifdef _WIN32
1996ecf6635Schristos /* Fork? On Win32? How primitive! We'll do what the smart kids do:
2006ecf6635Schristos we'll invoke our own exe (whose name we recall from the command
2016ecf6635Schristos line) with a command line that tells it to run just the test we
2026ecf6635Schristos want, and this time without forking.
2036ecf6635Schristos
2046ecf6635Schristos (No, threads aren't an option. The whole point of forking is to
2056ecf6635Schristos share no state between tests.)
2066ecf6635Schristos */
2076ecf6635Schristos int ok;
2086ecf6635Schristos char buffer[LONGEST_TEST_NAME+256];
2096ecf6635Schristos STARTUPINFOA si;
2106ecf6635Schristos PROCESS_INFORMATION info;
211*657871a7Schristos DWORD ret;
2126ecf6635Schristos
2136ecf6635Schristos if (!in_tinytest_main) {
214805a1ce9Schristos printf("\nERROR. On Windows, testcase_run_forked_ must be"
2156ecf6635Schristos " called from within tinytest_main.\n");
2166ecf6635Schristos abort();
2176ecf6635Schristos }
2186ecf6635Schristos if (opt_verbosity>0)
2196ecf6635Schristos printf("[forking] ");
2206ecf6635Schristos
221*657871a7Schristos snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s --timeout 0 %s%s",
2226ecf6635Schristos commandname, verbosity_flag, group->prefix, testcase->name);
2236ecf6635Schristos
2246ecf6635Schristos memset(&si, 0, sizeof(si));
2256ecf6635Schristos memset(&info, 0, sizeof(info));
2266ecf6635Schristos si.cb = sizeof(si);
2276ecf6635Schristos
2286ecf6635Schristos ok = CreateProcessA(commandname, buffer, NULL, NULL, 0,
2296ecf6635Schristos 0, NULL, NULL, &si, &info);
2306ecf6635Schristos if (!ok) {
2316ecf6635Schristos printf("CreateProcess failed!\n");
232*657871a7Schristos return FAIL;
2336ecf6635Schristos }
234*657871a7Schristos ret = WaitForSingleObject(info.hProcess,
235*657871a7Schristos (opt_timeout ? opt_timeout * 1000U : INFINITE));
236*657871a7Schristos
237*657871a7Schristos if (ret == WAIT_OBJECT_0) {
238*657871a7Schristos GetExitCodeProcess(info.hProcess, &ret);
239*657871a7Schristos } else if (ret == WAIT_TIMEOUT) {
240*657871a7Schristos printf("timeout\n");
241*657871a7Schristos } else {
242*657871a7Schristos printf("Wait failed\n");
243*657871a7Schristos }
2446ecf6635Schristos CloseHandle(info.hProcess);
2456ecf6635Schristos CloseHandle(info.hThread);
246*657871a7Schristos if (ret == 0)
2476ecf6635Schristos return OK;
248*657871a7Schristos else if (ret == MAGIC_EXITCODE)
2496ecf6635Schristos return SKIP;
2506ecf6635Schristos else
2516ecf6635Schristos return FAIL;
2526ecf6635Schristos #else
2536ecf6635Schristos int outcome_pipe[2];
2546ecf6635Schristos pid_t pid;
2556ecf6635Schristos (void)group;
2566ecf6635Schristos
2576ecf6635Schristos if (pipe(outcome_pipe))
2586ecf6635Schristos perror("opening pipe");
2596ecf6635Schristos
2606ecf6635Schristos if (opt_verbosity>0)
2616ecf6635Schristos printf("[forking] ");
2626ecf6635Schristos pid = fork();
2636ecf6635Schristos #ifdef FORK_BREAKS_GCOV
2646ecf6635Schristos vproc_transaction_begin(0);
2656ecf6635Schristos #endif
2666ecf6635Schristos if (!pid) {
2676ecf6635Schristos /* child. */
2686ecf6635Schristos int test_r, write_r;
2696ecf6635Schristos char b[1];
2706ecf6635Schristos close(outcome_pipe[0]);
271805a1ce9Schristos test_r = testcase_run_bare_(testcase);
2726ecf6635Schristos assert(0<=(int)test_r && (int)test_r<=2);
2736ecf6635Schristos b[0] = "NYS"[test_r];
2746ecf6635Schristos write_r = (int)write(outcome_pipe[1], b, 1);
2756ecf6635Schristos if (write_r != 1) {
2766ecf6635Schristos perror("write outcome to pipe");
2776ecf6635Schristos exit(1);
2786ecf6635Schristos }
2796ecf6635Schristos exit(0);
2806ecf6635Schristos return FAIL; /* unreachable */
2816ecf6635Schristos } else {
2826ecf6635Schristos /* parent */
283*657871a7Schristos int status, r, exitcode;
2846ecf6635Schristos char b[1];
2856ecf6635Schristos /* Close this now, so that if the other side closes it,
2866ecf6635Schristos * our read fails. */
2876ecf6635Schristos close(outcome_pipe[1]);
2886ecf6635Schristos r = (int)read(outcome_pipe[0], b, 1);
2896ecf6635Schristos if (r == 0) {
2906ecf6635Schristos printf("[Lost connection!] ");
291*657871a7Schristos return FAIL;
2926ecf6635Schristos } else if (r != 1) {
2936ecf6635Schristos perror("read outcome from pipe");
2946ecf6635Schristos }
2956ecf6635Schristos waitpid(pid, &status, 0);
296*657871a7Schristos exitcode = WEXITSTATUS(status);
2976ecf6635Schristos close(outcome_pipe[0]);
298*657871a7Schristos if (opt_verbosity>1)
299*657871a7Schristos printf("%s%s: exited with %i (%i)\n", group->prefix, testcase->name, exitcode, status);
300*657871a7Schristos if (exitcode != 0)
301*657871a7Schristos {
302*657871a7Schristos printf("[atexit failure!] ");
303*657871a7Schristos return FAIL;
304*657871a7Schristos }
3056ecf6635Schristos return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL);
3066ecf6635Schristos }
3076ecf6635Schristos #endif
3086ecf6635Schristos }
3096ecf6635Schristos
310805a1ce9Schristos #endif /* !NO_FORKING */
311805a1ce9Schristos
3126ecf6635Schristos int
testcase_run_one(const struct testgroup_t * group,const struct testcase_t * testcase)3136ecf6635Schristos testcase_run_one(const struct testgroup_t *group,
3146ecf6635Schristos const struct testcase_t *testcase)
3156ecf6635Schristos {
3166ecf6635Schristos enum outcome outcome;
3176ecf6635Schristos
318805a1ce9Schristos if (testcase->flags & (TT_SKIP|TT_OFF_BY_DEFAULT)) {
3196ecf6635Schristos if (opt_verbosity>0)
320805a1ce9Schristos printf("%s%s: %s\n",
321805a1ce9Schristos group->prefix, testcase->name,
322805a1ce9Schristos (testcase->flags & TT_SKIP) ? "SKIPPED" : "DISABLED");
3236ecf6635Schristos ++n_skipped;
3246ecf6635Schristos return SKIP;
3256ecf6635Schristos }
3266ecf6635Schristos
3276ecf6635Schristos if (opt_verbosity>0 && !opt_forked) {
3286ecf6635Schristos printf("%s%s: ", group->prefix, testcase->name);
3296ecf6635Schristos } else {
3306ecf6635Schristos if (opt_verbosity==0) printf(".");
3316ecf6635Schristos cur_test_prefix = group->prefix;
3326ecf6635Schristos cur_test_name = testcase->name;
3336ecf6635Schristos }
3346ecf6635Schristos
335805a1ce9Schristos #ifndef NO_FORKING
3366ecf6635Schristos if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) {
337805a1ce9Schristos outcome = testcase_run_forked_(group, testcase);
3386ecf6635Schristos } else {
339805a1ce9Schristos #else
340805a1ce9Schristos {
341805a1ce9Schristos #endif
342805a1ce9Schristos outcome = testcase_run_bare_(testcase);
3436ecf6635Schristos }
3446ecf6635Schristos
3456ecf6635Schristos if (outcome == OK) {
3466ecf6635Schristos if (opt_verbosity>0 && !opt_forked)
3476ecf6635Schristos puts(opt_verbosity==1?"OK":"");
3486ecf6635Schristos } else if (outcome == SKIP) {
3496ecf6635Schristos if (opt_verbosity>0 && !opt_forked)
3506ecf6635Schristos puts("SKIPPED");
3516ecf6635Schristos } else {
3526ecf6635Schristos if (!opt_forked)
3536ecf6635Schristos printf("\n [%s FAILED]\n", testcase->name);
3546ecf6635Schristos }
3556ecf6635Schristos
3566ecf6635Schristos if (opt_forked) {
3576ecf6635Schristos exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1));
3586ecf6635Schristos return 1; /* unreachable */
3596ecf6635Schristos } else {
3606ecf6635Schristos return (int)outcome;
3616ecf6635Schristos }
3626ecf6635Schristos }
3636ecf6635Schristos
3646ecf6635Schristos int
365805a1ce9Schristos tinytest_set_flag_(struct testgroup_t *groups, const char *arg, int set, unsigned long flag)
3666ecf6635Schristos {
3676ecf6635Schristos int i, j;
3686ecf6635Schristos size_t length = LONGEST_TEST_NAME;
3696ecf6635Schristos char fullname[LONGEST_TEST_NAME];
3706ecf6635Schristos int found=0;
3716ecf6635Schristos if (strstr(arg, ".."))
3726ecf6635Schristos length = strstr(arg,"..")-arg;
3736ecf6635Schristos for (i=0; groups[i].prefix; ++i) {
3746ecf6635Schristos for (j=0; groups[i].cases[j].name; ++j) {
375805a1ce9Schristos struct testcase_t *testcase = &groups[i].cases[j];
3766ecf6635Schristos snprintf(fullname, sizeof(fullname), "%s%s",
377805a1ce9Schristos groups[i].prefix, testcase->name);
378805a1ce9Schristos if (!flag) { /* Hack! */
379805a1ce9Schristos printf(" %s", fullname);
380805a1ce9Schristos if (testcase->flags & TT_OFF_BY_DEFAULT)
381805a1ce9Schristos puts(" (Off by default)");
382805a1ce9Schristos else if (testcase->flags & TT_SKIP)
383805a1ce9Schristos puts(" (DISABLED)");
384805a1ce9Schristos else
385805a1ce9Schristos puts("");
386805a1ce9Schristos }
3876ecf6635Schristos if (!strncmp(fullname, arg, length)) {
388805a1ce9Schristos if (set)
389805a1ce9Schristos testcase->flags |= flag;
390805a1ce9Schristos else
391805a1ce9Schristos testcase->flags &= ~flag;
3926ecf6635Schristos ++found;
3936ecf6635Schristos }
3946ecf6635Schristos }
3956ecf6635Schristos }
3966ecf6635Schristos return found;
3976ecf6635Schristos }
3986ecf6635Schristos
3996ecf6635Schristos static void
4006ecf6635Schristos usage(struct testgroup_t *groups, int list_groups)
4016ecf6635Schristos {
402*657871a7Schristos puts("Options are: [--verbose|--quiet|--terse] [--no-fork] [--timeout <sec>]");
4036ecf6635Schristos puts(" Specify tests by name, or using a prefix ending with '..'");
404805a1ce9Schristos puts(" To skip a test, prefix its name with a colon.");
405805a1ce9Schristos puts(" To enable a disabled test, prefix its name with a plus.");
4066ecf6635Schristos puts(" Use --list-tests for a list of tests.");
4076ecf6635Schristos if (list_groups) {
4086ecf6635Schristos puts("Known tests are:");
409805a1ce9Schristos tinytest_set_flag_(groups, "..", 1, 0);
4106ecf6635Schristos }
4116ecf6635Schristos exit(0);
4126ecf6635Schristos }
4136ecf6635Schristos
414805a1ce9Schristos static int
415805a1ce9Schristos process_test_alias(struct testgroup_t *groups, const char *test)
416805a1ce9Schristos {
417805a1ce9Schristos int i, j, n, r;
418805a1ce9Schristos for (i=0; cfg_aliases && cfg_aliases[i].name; ++i) {
419805a1ce9Schristos if (!strcmp(cfg_aliases[i].name, test)) {
420805a1ce9Schristos n = 0;
421805a1ce9Schristos for (j = 0; cfg_aliases[i].tests[j]; ++j) {
422805a1ce9Schristos r = process_test_option(groups, cfg_aliases[i].tests[j]);
423805a1ce9Schristos if (r<0)
424805a1ce9Schristos return -1;
425805a1ce9Schristos n += r;
426805a1ce9Schristos }
427805a1ce9Schristos return n;
428805a1ce9Schristos }
429805a1ce9Schristos }
430805a1ce9Schristos printf("No such test alias as @%s!",test);
431805a1ce9Schristos return -1;
432805a1ce9Schristos }
433805a1ce9Schristos
434805a1ce9Schristos static int
435805a1ce9Schristos process_test_option(struct testgroup_t *groups, const char *test)
436805a1ce9Schristos {
437805a1ce9Schristos int flag = TT_ENABLED_;
438805a1ce9Schristos int n = 0;
439805a1ce9Schristos if (test[0] == '@') {
440805a1ce9Schristos return process_test_alias(groups, test + 1);
441805a1ce9Schristos } else if (test[0] == ':') {
442805a1ce9Schristos ++test;
443805a1ce9Schristos flag = TT_SKIP;
444805a1ce9Schristos } else if (test[0] == '+') {
445805a1ce9Schristos ++test;
446805a1ce9Schristos ++n;
447805a1ce9Schristos if (!tinytest_set_flag_(groups, test, 0, TT_OFF_BY_DEFAULT)) {
448805a1ce9Schristos printf("No such test as %s!\n", test);
449805a1ce9Schristos return -1;
450805a1ce9Schristos }
451805a1ce9Schristos } else {
452805a1ce9Schristos ++n;
453805a1ce9Schristos }
454805a1ce9Schristos if (!tinytest_set_flag_(groups, test, 1, flag)) {
455805a1ce9Schristos printf("No such test as %s!\n", test);
456805a1ce9Schristos return -1;
457805a1ce9Schristos }
458805a1ce9Schristos return n;
459805a1ce9Schristos }
460805a1ce9Schristos
461805a1ce9Schristos void
462805a1ce9Schristos tinytest_set_aliases(const struct testlist_alias_t *aliases)
463805a1ce9Schristos {
464805a1ce9Schristos cfg_aliases = aliases;
465805a1ce9Schristos }
466805a1ce9Schristos
4676ecf6635Schristos int
4686ecf6635Schristos tinytest_main(int c, const char **v, struct testgroup_t *groups)
4696ecf6635Schristos {
4706ecf6635Schristos int i, j, n=0;
4716ecf6635Schristos
472805a1ce9Schristos #ifdef _WIN32
4736ecf6635Schristos const char *sp = strrchr(v[0], '.');
4746ecf6635Schristos const char *extension = "";
4756ecf6635Schristos if (!sp || stricmp(sp, ".exe"))
4766ecf6635Schristos extension = ".exe"; /* Add an exe so CreateProcess will work */
4776ecf6635Schristos snprintf(commandname, sizeof(commandname), "%s%s", v[0], extension);
4786ecf6635Schristos commandname[MAX_PATH]='\0';
4796ecf6635Schristos #endif
4806ecf6635Schristos for (i=1; i<c; ++i) {
4816ecf6635Schristos if (v[i][0] == '-') {
4826ecf6635Schristos if (!strcmp(v[i], "--RUNNING-FORKED")) {
4836ecf6635Schristos opt_forked = 1;
4846ecf6635Schristos } else if (!strcmp(v[i], "--no-fork")) {
4856ecf6635Schristos opt_nofork = 1;
4866ecf6635Schristos } else if (!strcmp(v[i], "--quiet")) {
4876ecf6635Schristos opt_verbosity = -1;
4886ecf6635Schristos verbosity_flag = "--quiet";
4896ecf6635Schristos } else if (!strcmp(v[i], "--verbose")) {
4906ecf6635Schristos opt_verbosity = 2;
4916ecf6635Schristos verbosity_flag = "--verbose";
4926ecf6635Schristos } else if (!strcmp(v[i], "--terse")) {
4936ecf6635Schristos opt_verbosity = 0;
4946ecf6635Schristos verbosity_flag = "--terse";
4956ecf6635Schristos } else if (!strcmp(v[i], "--help")) {
4966ecf6635Schristos usage(groups, 0);
4976ecf6635Schristos } else if (!strcmp(v[i], "--list-tests")) {
4986ecf6635Schristos usage(groups, 1);
499*657871a7Schristos } else if (!strcmp(v[i], "--timeout")) {
500*657871a7Schristos ++i;
501*657871a7Schristos if (i >= c) {
502*657871a7Schristos fprintf(stderr, "--timeout requires argument\n");
503*657871a7Schristos return -1;
504*657871a7Schristos }
505*657871a7Schristos opt_timeout = (unsigned)atoi(v[i]);
5066ecf6635Schristos } else {
507*657871a7Schristos fprintf(stderr, "Unknown option %s. Try --help\n", v[i]);
5086ecf6635Schristos return -1;
5096ecf6635Schristos }
5106ecf6635Schristos } else {
511805a1ce9Schristos int r = process_test_option(groups, v[i]);
512805a1ce9Schristos if (r<0)
5136ecf6635Schristos return -1;
514805a1ce9Schristos n += r;
5156ecf6635Schristos }
5166ecf6635Schristos }
5176ecf6635Schristos if (!n)
518805a1ce9Schristos tinytest_set_flag_(groups, "..", 1, TT_ENABLED_);
5196ecf6635Schristos
520805a1ce9Schristos #ifdef _IONBF
5216ecf6635Schristos setvbuf(stdout, NULL, _IONBF, 0);
522805a1ce9Schristos #endif
5236ecf6635Schristos
5246ecf6635Schristos ++in_tinytest_main;
525*657871a7Schristos for (i = 0; groups[i].prefix; ++i) {
526*657871a7Schristos struct testgroup_t *group = &groups[i];
527*657871a7Schristos for (j = 0; group->cases[j].name; ++j) {
528*657871a7Schristos struct testcase_t *testcase = &group->cases[j];
529*657871a7Schristos int test_attempts = 3;
530*657871a7Schristos int test_ret_err;
531*657871a7Schristos
532*657871a7Schristos if (!(testcase->flags & TT_ENABLED_))
533*657871a7Schristos continue;
534*657871a7Schristos
535*657871a7Schristos for (;;) {
536*657871a7Schristos test_ret_err = testcase_run_one(group, testcase);
537*657871a7Schristos
538*657871a7Schristos if (test_ret_err == OK)
539*657871a7Schristos break;
540*657871a7Schristos if (!(testcase->flags & TT_RETRIABLE))
541*657871a7Schristos break;
542*657871a7Schristos printf("\n [RETRYING %s (%i)]\n", testcase->name, test_attempts);
543*657871a7Schristos if (!test_attempts--)
544*657871a7Schristos break;
545*657871a7Schristos }
546*657871a7Schristos
547*657871a7Schristos switch (test_ret_err) {
548*657871a7Schristos case OK: ++n_ok; break;
549*657871a7Schristos case SKIP: ++n_skipped; break;
550*657871a7Schristos default: ++n_bad; break;
551*657871a7Schristos }
552*657871a7Schristos }
553*657871a7Schristos }
5546ecf6635Schristos
5556ecf6635Schristos --in_tinytest_main;
5566ecf6635Schristos
5576ecf6635Schristos if (opt_verbosity==0)
5586ecf6635Schristos puts("");
5596ecf6635Schristos
5606ecf6635Schristos if (n_bad)
5616ecf6635Schristos printf("%d/%d TESTS FAILED. (%d skipped)\n", n_bad,
5626ecf6635Schristos n_bad+n_ok,n_skipped);
5636ecf6635Schristos else if (opt_verbosity >= 1)
5646ecf6635Schristos printf("%d tests ok. (%d skipped)\n", n_ok, n_skipped);
5656ecf6635Schristos
5666ecf6635Schristos return (n_bad == 0) ? 0 : 1;
5676ecf6635Schristos }
5686ecf6635Schristos
5696ecf6635Schristos int
570805a1ce9Schristos tinytest_get_verbosity_(void)
5716ecf6635Schristos {
5726ecf6635Schristos return opt_verbosity;
5736ecf6635Schristos }
5746ecf6635Schristos
5756ecf6635Schristos void
576805a1ce9Schristos tinytest_set_test_failed_(void)
5776ecf6635Schristos {
5786ecf6635Schristos if (opt_verbosity <= 0 && cur_test_name) {
5796ecf6635Schristos if (opt_verbosity==0) puts("");
5806ecf6635Schristos printf("%s%s: ", cur_test_prefix, cur_test_name);
5816ecf6635Schristos cur_test_name = NULL;
5826ecf6635Schristos }
583*657871a7Schristos cur_test_outcome = FAIL;
5846ecf6635Schristos }
5856ecf6635Schristos
5866ecf6635Schristos void
587805a1ce9Schristos tinytest_set_test_skipped_(void)
5886ecf6635Schristos {
5896ecf6635Schristos if (cur_test_outcome==OK)
5906ecf6635Schristos cur_test_outcome = SKIP;
5916ecf6635Schristos }
5926ecf6635Schristos
593805a1ce9Schristos char *
594805a1ce9Schristos tinytest_format_hex_(const void *val_, unsigned long len)
595805a1ce9Schristos {
596805a1ce9Schristos const unsigned char *val = val_;
597805a1ce9Schristos char *result, *cp;
598805a1ce9Schristos size_t i;
599805a1ce9Schristos
600805a1ce9Schristos if (!val)
601805a1ce9Schristos return strdup("null");
602805a1ce9Schristos if (!(result = malloc(len*2+1)))
603805a1ce9Schristos return strdup("<allocation failure>");
604805a1ce9Schristos cp = result;
605805a1ce9Schristos for (i=0;i<len;++i) {
606805a1ce9Schristos *cp++ = "0123456789ABCDEF"[val[i] >> 4];
607805a1ce9Schristos *cp++ = "0123456789ABCDEF"[val[i] & 0x0f];
608805a1ce9Schristos }
609805a1ce9Schristos *cp = 0;
610805a1ce9Schristos return result;
611805a1ce9Schristos }
612