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 34*a25439b6SCy Schubert #ifndef NO_FORKING 35*a25439b6SCy 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 53*a25439b6SCy Schubert #endif /* !NO_FORKING */ 54*a25439b6SCy 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 632b15cb3dSCy Schubert 642b15cb3dSCy Schubert static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/ 652b15cb3dSCy Schubert static int n_ok = 0; /**< Number of tests that have passed */ 662b15cb3dSCy Schubert static int n_bad = 0; /**< Number of tests that have failed. */ 672b15cb3dSCy Schubert static int n_skipped = 0; /**< Number of tests that have been skipped. */ 682b15cb3dSCy Schubert 692b15cb3dSCy Schubert static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/ 702b15cb3dSCy Schubert static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */ 712b15cb3dSCy Schubert static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */ 722b15cb3dSCy Schubert const char *verbosity_flag = ""; 732b15cb3dSCy Schubert 742b15cb3dSCy Schubert const struct testlist_alias_t *cfg_aliases=NULL; 752b15cb3dSCy Schubert 762b15cb3dSCy Schubert enum outcome { SKIP=2, OK=1, FAIL=0 }; 772b15cb3dSCy Schubert static enum outcome cur_test_outcome = 0; 782b15cb3dSCy Schubert const char *cur_test_prefix = NULL; /**< prefix of the current test group */ 792b15cb3dSCy Schubert /** Name of the current test, if we haven't logged is yet. Used for --quiet */ 802b15cb3dSCy Schubert const char *cur_test_name = NULL; 812b15cb3dSCy Schubert 822b15cb3dSCy Schubert #ifdef _WIN32 832b15cb3dSCy Schubert /* Copy of argv[0] for win32. */ 842b15cb3dSCy Schubert static char commandname[MAX_PATH+1]; 852b15cb3dSCy Schubert #endif 862b15cb3dSCy Schubert 872b15cb3dSCy Schubert static void usage(struct testgroup_t *groups, int list_groups) 882b15cb3dSCy Schubert __attribute__((noreturn)); 892b15cb3dSCy Schubert static int process_test_option(struct testgroup_t *groups, const char *test); 902b15cb3dSCy Schubert 912b15cb3dSCy Schubert static enum outcome 922b15cb3dSCy Schubert testcase_run_bare_(const struct testcase_t *testcase) 932b15cb3dSCy Schubert { 942b15cb3dSCy Schubert void *env = NULL; 952b15cb3dSCy Schubert int outcome; 962b15cb3dSCy Schubert if (testcase->setup) { 972b15cb3dSCy Schubert env = testcase->setup->setup_fn(testcase); 982b15cb3dSCy Schubert if (!env) 992b15cb3dSCy Schubert return FAIL; 1002b15cb3dSCy Schubert else if (env == (void*)TT_SKIP) 1012b15cb3dSCy Schubert return SKIP; 1022b15cb3dSCy Schubert } 1032b15cb3dSCy Schubert 1042b15cb3dSCy Schubert cur_test_outcome = OK; 1052b15cb3dSCy Schubert testcase->fn(env); 1062b15cb3dSCy Schubert outcome = cur_test_outcome; 1072b15cb3dSCy Schubert 1082b15cb3dSCy Schubert if (testcase->setup) { 1092b15cb3dSCy Schubert if (testcase->setup->cleanup_fn(testcase, env) == 0) 1102b15cb3dSCy Schubert outcome = FAIL; 1112b15cb3dSCy Schubert } 1122b15cb3dSCy Schubert 1132b15cb3dSCy Schubert return outcome; 1142b15cb3dSCy Schubert } 1152b15cb3dSCy Schubert 1162b15cb3dSCy Schubert #define MAGIC_EXITCODE 42 1172b15cb3dSCy Schubert 118*a25439b6SCy Schubert #ifndef NO_FORKING 119*a25439b6SCy Schubert 1202b15cb3dSCy Schubert static enum outcome 1212b15cb3dSCy Schubert testcase_run_forked_(const struct testgroup_t *group, 1222b15cb3dSCy Schubert const struct testcase_t *testcase) 1232b15cb3dSCy Schubert { 1242b15cb3dSCy Schubert #ifdef _WIN32 1252b15cb3dSCy Schubert /* Fork? On Win32? How primitive! We'll do what the smart kids do: 1262b15cb3dSCy Schubert we'll invoke our own exe (whose name we recall from the command 1272b15cb3dSCy Schubert line) with a command line that tells it to run just the test we 1282b15cb3dSCy Schubert want, and this time without forking. 1292b15cb3dSCy Schubert 1302b15cb3dSCy Schubert (No, threads aren't an option. The whole point of forking is to 1312b15cb3dSCy Schubert share no state between tests.) 1322b15cb3dSCy Schubert */ 1332b15cb3dSCy Schubert int ok; 1342b15cb3dSCy Schubert char buffer[LONGEST_TEST_NAME+256]; 1352b15cb3dSCy Schubert STARTUPINFOA si; 1362b15cb3dSCy Schubert PROCESS_INFORMATION info; 1372b15cb3dSCy Schubert DWORD exitcode; 1382b15cb3dSCy Schubert 1392b15cb3dSCy Schubert if (!in_tinytest_main) { 1402b15cb3dSCy Schubert printf("\nERROR. On Windows, testcase_run_forked_ must be" 1412b15cb3dSCy Schubert " called from within tinytest_main.\n"); 1422b15cb3dSCy Schubert abort(); 1432b15cb3dSCy Schubert } 1442b15cb3dSCy Schubert if (opt_verbosity>0) 1452b15cb3dSCy Schubert printf("[forking] "); 1462b15cb3dSCy Schubert 1472b15cb3dSCy Schubert snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s %s%s", 1482b15cb3dSCy Schubert commandname, verbosity_flag, group->prefix, testcase->name); 1492b15cb3dSCy Schubert 1502b15cb3dSCy Schubert memset(&si, 0, sizeof(si)); 1512b15cb3dSCy Schubert memset(&info, 0, sizeof(info)); 1522b15cb3dSCy Schubert si.cb = sizeof(si); 1532b15cb3dSCy Schubert 1542b15cb3dSCy Schubert ok = CreateProcessA(commandname, buffer, NULL, NULL, 0, 1552b15cb3dSCy Schubert 0, NULL, NULL, &si, &info); 1562b15cb3dSCy Schubert if (!ok) { 1572b15cb3dSCy Schubert printf("CreateProcess failed!\n"); 1582b15cb3dSCy Schubert return 0; 1592b15cb3dSCy Schubert } 1602b15cb3dSCy Schubert WaitForSingleObject(info.hProcess, INFINITE); 1612b15cb3dSCy Schubert GetExitCodeProcess(info.hProcess, &exitcode); 1622b15cb3dSCy Schubert CloseHandle(info.hProcess); 1632b15cb3dSCy Schubert CloseHandle(info.hThread); 1642b15cb3dSCy Schubert if (exitcode == 0) 1652b15cb3dSCy Schubert return OK; 1662b15cb3dSCy Schubert else if (exitcode == MAGIC_EXITCODE) 1672b15cb3dSCy Schubert return SKIP; 1682b15cb3dSCy Schubert else 1692b15cb3dSCy Schubert return FAIL; 1702b15cb3dSCy Schubert #else 1712b15cb3dSCy Schubert int outcome_pipe[2]; 1722b15cb3dSCy Schubert pid_t pid; 1732b15cb3dSCy Schubert (void)group; 1742b15cb3dSCy Schubert 1752b15cb3dSCy Schubert if (pipe(outcome_pipe)) 1762b15cb3dSCy Schubert perror("opening pipe"); 1772b15cb3dSCy Schubert 1782b15cb3dSCy Schubert if (opt_verbosity>0) 1792b15cb3dSCy Schubert printf("[forking] "); 1802b15cb3dSCy Schubert pid = fork(); 1812b15cb3dSCy Schubert #ifdef FORK_BREAKS_GCOV 1822b15cb3dSCy Schubert vproc_transaction_begin(0); 1832b15cb3dSCy Schubert #endif 1842b15cb3dSCy Schubert if (!pid) { 1852b15cb3dSCy Schubert /* child. */ 1862b15cb3dSCy Schubert int test_r, write_r; 1872b15cb3dSCy Schubert char b[1]; 1882b15cb3dSCy Schubert close(outcome_pipe[0]); 1892b15cb3dSCy Schubert test_r = testcase_run_bare_(testcase); 1902b15cb3dSCy Schubert assert(0<=(int)test_r && (int)test_r<=2); 1912b15cb3dSCy Schubert b[0] = "NYS"[test_r]; 1922b15cb3dSCy Schubert write_r = (int)write(outcome_pipe[1], b, 1); 1932b15cb3dSCy Schubert if (write_r != 1) { 1942b15cb3dSCy Schubert perror("write outcome to pipe"); 1952b15cb3dSCy Schubert exit(1); 1962b15cb3dSCy Schubert } 1972b15cb3dSCy Schubert exit(0); 1982b15cb3dSCy Schubert return FAIL; /* unreachable */ 1992b15cb3dSCy Schubert } else { 2002b15cb3dSCy Schubert /* parent */ 2012b15cb3dSCy Schubert int status, r; 2022b15cb3dSCy Schubert char b[1]; 2032b15cb3dSCy Schubert /* Close this now, so that if the other side closes it, 2042b15cb3dSCy Schubert * our read fails. */ 2052b15cb3dSCy Schubert close(outcome_pipe[1]); 2062b15cb3dSCy Schubert r = (int)read(outcome_pipe[0], b, 1); 2072b15cb3dSCy Schubert if (r == 0) { 2082b15cb3dSCy Schubert printf("[Lost connection!] "); 2092b15cb3dSCy Schubert return 0; 2102b15cb3dSCy Schubert } else if (r != 1) { 2112b15cb3dSCy Schubert perror("read outcome from pipe"); 2122b15cb3dSCy Schubert } 2132b15cb3dSCy Schubert waitpid(pid, &status, 0); 2142b15cb3dSCy Schubert close(outcome_pipe[0]); 2152b15cb3dSCy Schubert return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL); 2162b15cb3dSCy Schubert } 2172b15cb3dSCy Schubert #endif 2182b15cb3dSCy Schubert } 2192b15cb3dSCy Schubert 220*a25439b6SCy Schubert #endif /* !NO_FORKING */ 221*a25439b6SCy Schubert 2222b15cb3dSCy Schubert int 2232b15cb3dSCy Schubert testcase_run_one(const struct testgroup_t *group, 2242b15cb3dSCy Schubert const struct testcase_t *testcase) 2252b15cb3dSCy Schubert { 2262b15cb3dSCy Schubert enum outcome outcome; 2272b15cb3dSCy Schubert 2282b15cb3dSCy Schubert if (testcase->flags & (TT_SKIP|TT_OFF_BY_DEFAULT)) { 2292b15cb3dSCy Schubert if (opt_verbosity>0) 2302b15cb3dSCy Schubert printf("%s%s: %s\n", 2312b15cb3dSCy Schubert group->prefix, testcase->name, 2322b15cb3dSCy Schubert (testcase->flags & TT_SKIP) ? "SKIPPED" : "DISABLED"); 2332b15cb3dSCy Schubert ++n_skipped; 2342b15cb3dSCy Schubert return SKIP; 2352b15cb3dSCy Schubert } 2362b15cb3dSCy Schubert 2372b15cb3dSCy Schubert if (opt_verbosity>0 && !opt_forked) { 2382b15cb3dSCy Schubert printf("%s%s: ", group->prefix, testcase->name); 2392b15cb3dSCy Schubert } else { 2402b15cb3dSCy Schubert if (opt_verbosity==0) printf("."); 2412b15cb3dSCy Schubert cur_test_prefix = group->prefix; 2422b15cb3dSCy Schubert cur_test_name = testcase->name; 2432b15cb3dSCy Schubert } 2442b15cb3dSCy Schubert 245*a25439b6SCy Schubert #ifndef NO_FORKING 2462b15cb3dSCy Schubert if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) { 2472b15cb3dSCy Schubert outcome = testcase_run_forked_(group, testcase); 2482b15cb3dSCy Schubert } else { 249*a25439b6SCy Schubert #else 250*a25439b6SCy Schubert { 251*a25439b6SCy Schubert #endif 2522b15cb3dSCy Schubert outcome = testcase_run_bare_(testcase); 2532b15cb3dSCy Schubert } 2542b15cb3dSCy Schubert 2552b15cb3dSCy Schubert if (outcome == OK) { 2562b15cb3dSCy Schubert ++n_ok; 2572b15cb3dSCy Schubert if (opt_verbosity>0 && !opt_forked) 2582b15cb3dSCy Schubert puts(opt_verbosity==1?"OK":""); 2592b15cb3dSCy Schubert } else if (outcome == SKIP) { 2602b15cb3dSCy Schubert ++n_skipped; 2612b15cb3dSCy Schubert if (opt_verbosity>0 && !opt_forked) 2622b15cb3dSCy Schubert puts("SKIPPED"); 2632b15cb3dSCy Schubert } else { 2642b15cb3dSCy Schubert ++n_bad; 2652b15cb3dSCy Schubert if (!opt_forked) 2662b15cb3dSCy Schubert printf("\n [%s FAILED]\n", testcase->name); 2672b15cb3dSCy Schubert } 2682b15cb3dSCy Schubert 2692b15cb3dSCy Schubert if (opt_forked) { 2702b15cb3dSCy Schubert exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1)); 2712b15cb3dSCy Schubert return 1; /* unreachable */ 2722b15cb3dSCy Schubert } else { 2732b15cb3dSCy Schubert return (int)outcome; 2742b15cb3dSCy Schubert } 2752b15cb3dSCy Schubert } 2762b15cb3dSCy Schubert 2772b15cb3dSCy Schubert int 2782b15cb3dSCy Schubert tinytest_set_flag_(struct testgroup_t *groups, const char *arg, int set, unsigned long flag) 2792b15cb3dSCy Schubert { 2802b15cb3dSCy Schubert int i, j; 2812b15cb3dSCy Schubert size_t length = LONGEST_TEST_NAME; 2822b15cb3dSCy Schubert char fullname[LONGEST_TEST_NAME]; 2832b15cb3dSCy Schubert int found=0; 2842b15cb3dSCy Schubert if (strstr(arg, "..")) 2852b15cb3dSCy Schubert length = strstr(arg,"..")-arg; 2862b15cb3dSCy Schubert for (i=0; groups[i].prefix; ++i) { 2872b15cb3dSCy Schubert for (j=0; groups[i].cases[j].name; ++j) { 2882b15cb3dSCy Schubert struct testcase_t *testcase = &groups[i].cases[j]; 2892b15cb3dSCy Schubert snprintf(fullname, sizeof(fullname), "%s%s", 2902b15cb3dSCy Schubert groups[i].prefix, testcase->name); 2912b15cb3dSCy Schubert if (!flag) { /* Hack! */ 2922b15cb3dSCy Schubert printf(" %s", fullname); 2932b15cb3dSCy Schubert if (testcase->flags & TT_OFF_BY_DEFAULT) 2942b15cb3dSCy Schubert puts(" (Off by default)"); 2952b15cb3dSCy Schubert else if (testcase->flags & TT_SKIP) 2962b15cb3dSCy Schubert puts(" (DISABLED)"); 2972b15cb3dSCy Schubert else 2982b15cb3dSCy Schubert puts(""); 2992b15cb3dSCy Schubert } 3002b15cb3dSCy Schubert if (!strncmp(fullname, arg, length)) { 3012b15cb3dSCy Schubert if (set) 3022b15cb3dSCy Schubert testcase->flags |= flag; 3032b15cb3dSCy Schubert else 3042b15cb3dSCy Schubert testcase->flags &= ~flag; 3052b15cb3dSCy Schubert ++found; 3062b15cb3dSCy Schubert } 3072b15cb3dSCy Schubert } 3082b15cb3dSCy Schubert } 3092b15cb3dSCy Schubert return found; 3102b15cb3dSCy Schubert } 3112b15cb3dSCy Schubert 3122b15cb3dSCy Schubert static void 3132b15cb3dSCy Schubert usage(struct testgroup_t *groups, int list_groups) 3142b15cb3dSCy Schubert { 3152b15cb3dSCy Schubert puts("Options are: [--verbose|--quiet|--terse] [--no-fork]"); 3162b15cb3dSCy Schubert puts(" Specify tests by name, or using a prefix ending with '..'"); 3172b15cb3dSCy Schubert puts(" To skip a test, prefix its name with a colon."); 3182b15cb3dSCy Schubert puts(" To enable a disabled test, prefix its name with a plus."); 3192b15cb3dSCy Schubert puts(" Use --list-tests for a list of tests."); 3202b15cb3dSCy Schubert if (list_groups) { 3212b15cb3dSCy Schubert puts("Known tests are:"); 3222b15cb3dSCy Schubert tinytest_set_flag_(groups, "..", 1, 0); 3232b15cb3dSCy Schubert } 3242b15cb3dSCy Schubert exit(0); 3252b15cb3dSCy Schubert } 3262b15cb3dSCy Schubert 3272b15cb3dSCy Schubert static int 3282b15cb3dSCy Schubert process_test_alias(struct testgroup_t *groups, const char *test) 3292b15cb3dSCy Schubert { 3302b15cb3dSCy Schubert int i, j, n, r; 3312b15cb3dSCy Schubert for (i=0; cfg_aliases && cfg_aliases[i].name; ++i) { 3322b15cb3dSCy Schubert if (!strcmp(cfg_aliases[i].name, test)) { 3332b15cb3dSCy Schubert n = 0; 3342b15cb3dSCy Schubert for (j = 0; cfg_aliases[i].tests[j]; ++j) { 3352b15cb3dSCy Schubert r = process_test_option(groups, cfg_aliases[i].tests[j]); 3362b15cb3dSCy Schubert if (r<0) 3372b15cb3dSCy Schubert return -1; 3382b15cb3dSCy Schubert n += r; 3392b15cb3dSCy Schubert } 3402b15cb3dSCy Schubert return n; 3412b15cb3dSCy Schubert } 3422b15cb3dSCy Schubert } 3432b15cb3dSCy Schubert printf("No such test alias as @%s!",test); 3442b15cb3dSCy Schubert return -1; 3452b15cb3dSCy Schubert } 3462b15cb3dSCy Schubert 3472b15cb3dSCy Schubert static int 3482b15cb3dSCy Schubert process_test_option(struct testgroup_t *groups, const char *test) 3492b15cb3dSCy Schubert { 3502b15cb3dSCy Schubert int flag = TT_ENABLED_; 3512b15cb3dSCy Schubert int n = 0; 3522b15cb3dSCy Schubert if (test[0] == '@') { 3532b15cb3dSCy Schubert return process_test_alias(groups, test + 1); 3542b15cb3dSCy Schubert } else if (test[0] == ':') { 3552b15cb3dSCy Schubert ++test; 3562b15cb3dSCy Schubert flag = TT_SKIP; 3572b15cb3dSCy Schubert } else if (test[0] == '+') { 3582b15cb3dSCy Schubert ++test; 3592b15cb3dSCy Schubert ++n; 3602b15cb3dSCy Schubert if (!tinytest_set_flag_(groups, test, 0, TT_OFF_BY_DEFAULT)) { 3612b15cb3dSCy Schubert printf("No such test as %s!\n", test); 3622b15cb3dSCy Schubert return -1; 3632b15cb3dSCy Schubert } 3642b15cb3dSCy Schubert } else { 3652b15cb3dSCy Schubert ++n; 3662b15cb3dSCy Schubert } 3672b15cb3dSCy Schubert if (!tinytest_set_flag_(groups, test, 1, flag)) { 3682b15cb3dSCy Schubert printf("No such test as %s!\n", test); 3692b15cb3dSCy Schubert return -1; 3702b15cb3dSCy Schubert } 3712b15cb3dSCy Schubert return n; 3722b15cb3dSCy Schubert } 3732b15cb3dSCy Schubert 3742b15cb3dSCy Schubert void 3752b15cb3dSCy Schubert tinytest_set_aliases(const struct testlist_alias_t *aliases) 3762b15cb3dSCy Schubert { 3772b15cb3dSCy Schubert cfg_aliases = aliases; 3782b15cb3dSCy Schubert } 3792b15cb3dSCy Schubert 3802b15cb3dSCy Schubert int 3812b15cb3dSCy Schubert tinytest_main(int c, const char **v, struct testgroup_t *groups) 3822b15cb3dSCy Schubert { 3832b15cb3dSCy Schubert int i, j, n=0; 3842b15cb3dSCy Schubert 3852b15cb3dSCy Schubert #ifdef _WIN32 3862b15cb3dSCy Schubert const char *sp = strrchr(v[0], '.'); 3872b15cb3dSCy Schubert const char *extension = ""; 3882b15cb3dSCy Schubert if (!sp || stricmp(sp, ".exe")) 3892b15cb3dSCy Schubert extension = ".exe"; /* Add an exe so CreateProcess will work */ 3902b15cb3dSCy Schubert snprintf(commandname, sizeof(commandname), "%s%s", v[0], extension); 3912b15cb3dSCy Schubert commandname[MAX_PATH]='\0'; 3922b15cb3dSCy Schubert #endif 3932b15cb3dSCy Schubert for (i=1; i<c; ++i) { 3942b15cb3dSCy Schubert if (v[i][0] == '-') { 3952b15cb3dSCy Schubert if (!strcmp(v[i], "--RUNNING-FORKED")) { 3962b15cb3dSCy Schubert opt_forked = 1; 3972b15cb3dSCy Schubert } else if (!strcmp(v[i], "--no-fork")) { 3982b15cb3dSCy Schubert opt_nofork = 1; 3992b15cb3dSCy Schubert } else if (!strcmp(v[i], "--quiet")) { 4002b15cb3dSCy Schubert opt_verbosity = -1; 4012b15cb3dSCy Schubert verbosity_flag = "--quiet"; 4022b15cb3dSCy Schubert } else if (!strcmp(v[i], "--verbose")) { 4032b15cb3dSCy Schubert opt_verbosity = 2; 4042b15cb3dSCy Schubert verbosity_flag = "--verbose"; 4052b15cb3dSCy Schubert } else if (!strcmp(v[i], "--terse")) { 4062b15cb3dSCy Schubert opt_verbosity = 0; 4072b15cb3dSCy Schubert verbosity_flag = "--terse"; 4082b15cb3dSCy Schubert } else if (!strcmp(v[i], "--help")) { 4092b15cb3dSCy Schubert usage(groups, 0); 4102b15cb3dSCy Schubert } else if (!strcmp(v[i], "--list-tests")) { 4112b15cb3dSCy Schubert usage(groups, 1); 4122b15cb3dSCy Schubert } else { 4132b15cb3dSCy Schubert printf("Unknown option %s. Try --help\n",v[i]); 4142b15cb3dSCy Schubert return -1; 4152b15cb3dSCy Schubert } 4162b15cb3dSCy Schubert } else { 4172b15cb3dSCy Schubert int r = process_test_option(groups, v[i]); 4182b15cb3dSCy Schubert if (r<0) 4192b15cb3dSCy Schubert return -1; 4202b15cb3dSCy Schubert n += r; 4212b15cb3dSCy Schubert } 4222b15cb3dSCy Schubert } 4232b15cb3dSCy Schubert if (!n) 4242b15cb3dSCy Schubert tinytest_set_flag_(groups, "..", 1, TT_ENABLED_); 4252b15cb3dSCy Schubert 426*a25439b6SCy Schubert #ifdef _IONBF 4272b15cb3dSCy Schubert setvbuf(stdout, NULL, _IONBF, 0); 428*a25439b6SCy Schubert #endif 4292b15cb3dSCy Schubert 4302b15cb3dSCy Schubert ++in_tinytest_main; 4312b15cb3dSCy Schubert for (i=0; groups[i].prefix; ++i) 4322b15cb3dSCy Schubert for (j=0; groups[i].cases[j].name; ++j) 4332b15cb3dSCy Schubert if (groups[i].cases[j].flags & TT_ENABLED_) 4342b15cb3dSCy Schubert testcase_run_one(&groups[i], 4352b15cb3dSCy Schubert &groups[i].cases[j]); 4362b15cb3dSCy Schubert 4372b15cb3dSCy Schubert --in_tinytest_main; 4382b15cb3dSCy Schubert 4392b15cb3dSCy Schubert if (opt_verbosity==0) 4402b15cb3dSCy Schubert puts(""); 4412b15cb3dSCy Schubert 4422b15cb3dSCy Schubert if (n_bad) 4432b15cb3dSCy Schubert printf("%d/%d TESTS FAILED. (%d skipped)\n", n_bad, 4442b15cb3dSCy Schubert n_bad+n_ok,n_skipped); 4452b15cb3dSCy Schubert else if (opt_verbosity >= 1) 4462b15cb3dSCy Schubert printf("%d tests ok. (%d skipped)\n", n_ok, n_skipped); 4472b15cb3dSCy Schubert 4482b15cb3dSCy Schubert return (n_bad == 0) ? 0 : 1; 4492b15cb3dSCy Schubert } 4502b15cb3dSCy Schubert 4512b15cb3dSCy Schubert int 4522b15cb3dSCy Schubert tinytest_get_verbosity_(void) 4532b15cb3dSCy Schubert { 4542b15cb3dSCy Schubert return opt_verbosity; 4552b15cb3dSCy Schubert } 4562b15cb3dSCy Schubert 4572b15cb3dSCy Schubert void 4582b15cb3dSCy Schubert tinytest_set_test_failed_(void) 4592b15cb3dSCy Schubert { 4602b15cb3dSCy Schubert if (opt_verbosity <= 0 && cur_test_name) { 4612b15cb3dSCy Schubert if (opt_verbosity==0) puts(""); 4622b15cb3dSCy Schubert printf("%s%s: ", cur_test_prefix, cur_test_name); 4632b15cb3dSCy Schubert cur_test_name = NULL; 4642b15cb3dSCy Schubert } 4652b15cb3dSCy Schubert cur_test_outcome = 0; 4662b15cb3dSCy Schubert } 4672b15cb3dSCy Schubert 4682b15cb3dSCy Schubert void 4692b15cb3dSCy Schubert tinytest_set_test_skipped_(void) 4702b15cb3dSCy Schubert { 4712b15cb3dSCy Schubert if (cur_test_outcome==OK) 4722b15cb3dSCy Schubert cur_test_outcome = SKIP; 4732b15cb3dSCy Schubert } 4742b15cb3dSCy Schubert 475*a25439b6SCy Schubert char * 476*a25439b6SCy Schubert tinytest_format_hex_(const void *val_, unsigned long len) 477*a25439b6SCy Schubert { 478*a25439b6SCy Schubert const unsigned char *val = val_; 479*a25439b6SCy Schubert char *result, *cp; 480*a25439b6SCy Schubert size_t i; 481*a25439b6SCy Schubert 482*a25439b6SCy Schubert if (!val) 483*a25439b6SCy Schubert return strdup("null"); 484*a25439b6SCy Schubert if (!(result = malloc(len*2+1))) 485*a25439b6SCy Schubert return strdup("<allocation failure>"); 486*a25439b6SCy Schubert cp = result; 487*a25439b6SCy Schubert for (i=0;i<len;++i) { 488*a25439b6SCy Schubert *cp++ = "0123456789ABCDEF"[val[i] >> 4]; 489*a25439b6SCy Schubert *cp++ = "0123456789ABCDEF"[val[i] & 0x0f]; 490*a25439b6SCy Schubert } 491*a25439b6SCy Schubert *cp = 0; 492*a25439b6SCy Schubert return result; 493*a25439b6SCy Schubert } 494