diff options
Diffstat (limited to 'src/ext/tinytest.c')
-rw-r--r-- | src/ext/tinytest.c | 157 |
1 files changed, 135 insertions, 22 deletions
diff --git a/src/ext/tinytest.c b/src/ext/tinytest.c index 4d9afacce..cc054ad34 100644 --- a/src/ext/tinytest.c +++ b/src/ext/tinytest.c @@ -31,6 +31,8 @@ #include <string.h> #include <assert.h> +#ifndef NO_FORKING + #ifdef _WIN32 #include <windows.h> #else @@ -39,6 +41,17 @@ #include <unistd.h> #endif +#if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) +#if (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060 && \ + __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070) +/* Workaround for a stupid bug in OSX 10.6 */ +#define FORK_BREAKS_GCOV +#include <vproc.h> +#endif +#endif + +#endif /* !NO_FORKING */ + #ifndef __GNUC__ #define __attribute__(x) #endif @@ -58,6 +71,8 @@ static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */ static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */ const char *verbosity_flag = ""; +const struct testlist_alias_t *cfg_aliases=NULL; + enum outcome { SKIP=2, OK=1, FAIL=0 }; static enum outcome cur_test_outcome = 0; const char *cur_test_prefix = NULL; /**< prefix of the current test group */ @@ -71,6 +86,7 @@ static char commandname[MAX_PATH+1]; static void usage(struct testgroup_t *groups, int list_groups) __attribute__((noreturn)); +static int process_test_option(struct testgroup_t *groups, const char *test); static enum outcome testcase_run_bare_(const struct testcase_t *testcase) @@ -99,6 +115,8 @@ testcase_run_bare_(const struct testcase_t *testcase) #define MAGIC_EXITCODE 42 +#ifndef NO_FORKING + static enum outcome testcase_run_forked_(const struct testgroup_t *group, const struct testcase_t *testcase) @@ -160,6 +178,9 @@ testcase_run_forked_(const struct testgroup_t *group, if (opt_verbosity>0) printf("[forking] "); pid = fork(); +#ifdef FORK_BREAKS_GCOV + vproc_transaction_begin(0); +#endif if (!pid) { /* child. */ int test_r, write_r; @@ -196,16 +217,19 @@ testcase_run_forked_(const struct testgroup_t *group, #endif } +#endif /* !NO_FORKING */ + int testcase_run_one(const struct testgroup_t *group, const struct testcase_t *testcase) { enum outcome outcome; - if (testcase->flags & TT_SKIP) { + if (testcase->flags & (TT_SKIP|TT_OFF_BY_DEFAULT)) { if (opt_verbosity>0) - printf("%s%s: SKIPPED\n", - group->prefix, testcase->name); + printf("%s%s: %s\n", + group->prefix, testcase->name, + (testcase->flags & TT_SKIP) ? "SKIPPED" : "DISABLED"); ++n_skipped; return SKIP; } @@ -218,9 +242,13 @@ testcase_run_one(const struct testgroup_t *group, cur_test_name = testcase->name; } +#ifndef NO_FORKING if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) { outcome = testcase_run_forked_(group, testcase); } else { +#else + { +#endif outcome = testcase_run_bare_(testcase); } @@ -247,7 +275,7 @@ testcase_run_one(const struct testgroup_t *group, } int -tinytest_set_flag_(struct testgroup_t *groups, const char *arg, unsigned long flag) +tinytest_set_flag_(struct testgroup_t *groups, const char *arg, int set, unsigned long flag) { int i, j; size_t length = LONGEST_TEST_NAME; @@ -257,12 +285,23 @@ tinytest_set_flag_(struct testgroup_t *groups, const char *arg, unsigned long fl length = strstr(arg,"..")-arg; for (i=0; groups[i].prefix; ++i) { for (j=0; groups[i].cases[j].name; ++j) { + struct testcase_t *testcase = &groups[i].cases[j]; snprintf(fullname, sizeof(fullname), "%s%s", - groups[i].prefix, groups[i].cases[j].name); - if (!flag) /* Hack! */ - printf(" %s\n", fullname); + groups[i].prefix, testcase->name); + if (!flag) { /* Hack! */ + printf(" %s", fullname); + if (testcase->flags & TT_OFF_BY_DEFAULT) + puts(" (Off by default)"); + else if (testcase->flags & TT_SKIP) + puts(" (DISABLED)"); + else + puts(""); + } if (!strncmp(fullname, arg, length)) { - groups[i].cases[j].flags |= flag; + if (set) + testcase->flags |= flag; + else + testcase->flags &= ~flag; ++found; } } @@ -275,15 +314,69 @@ usage(struct testgroup_t *groups, int list_groups) { puts("Options are: [--verbose|--quiet|--terse] [--no-fork]"); puts(" Specify tests by name, or using a prefix ending with '..'"); - puts(" To skip a test, list give its name prefixed with a colon."); + puts(" To skip a test, prefix its name with a colon."); + puts(" To enable a disabled test, prefix its name with a plus."); puts(" Use --list-tests for a list of tests."); if (list_groups) { puts("Known tests are:"); - tinytest_set_flag_(groups, "..", 0); + tinytest_set_flag_(groups, "..", 1, 0); } exit(0); } +static int +process_test_alias(struct testgroup_t *groups, const char *test) +{ + int i, j, n, r; + for (i=0; cfg_aliases && cfg_aliases[i].name; ++i) { + if (!strcmp(cfg_aliases[i].name, test)) { + n = 0; + for (j = 0; cfg_aliases[i].tests[j]; ++j) { + r = process_test_option(groups, cfg_aliases[i].tests[j]); + if (r<0) + return -1; + n += r; + } + return n; + } + } + printf("No such test alias as @%s!",test); + return -1; +} + +static int +process_test_option(struct testgroup_t *groups, const char *test) +{ + int flag = TT_ENABLED_; + int n = 0; + if (test[0] == '@') { + return process_test_alias(groups, test + 1); + } else if (test[0] == ':') { + ++test; + flag = TT_SKIP; + } else if (test[0] == '+') { + ++test; + ++n; + if (!tinytest_set_flag_(groups, test, 0, TT_OFF_BY_DEFAULT)) { + printf("No such test as %s!\n", test); + return -1; + } + } else { + ++n; + } + if (!tinytest_set_flag_(groups, test, 1, flag)) { + printf("No such test as %s!\n", test); + return -1; + } + return n; +} + +void +tinytest_set_aliases(const struct testlist_alias_t *aliases) +{ + cfg_aliases = aliases; +} + int tinytest_main(int c, const char **v, struct testgroup_t *groups) { @@ -321,24 +414,18 @@ tinytest_main(int c, const char **v, struct testgroup_t *groups) return -1; } } else { - const char *test = v[i]; - int flag = TT_ENABLED_; - if (test[0] == ':') { - ++test; - flag = TT_SKIP; - } else { - ++n; - } - if (!tinytest_set_flag_(groups, test, flag)) { - printf("No such test as %s!\n", v[i]); + int r = process_test_option(groups, v[i]); + if (r<0) return -1; - } + n += r; } } if (!n) - tinytest_set_flag_(groups, "..", TT_ENABLED_); + tinytest_set_flag_(groups, "..", 1, TT_ENABLED_); +#ifdef _IONBF setvbuf(stdout, NULL, _IONBF, 0); +#endif ++in_tinytest_main; for (i=0; groups[i].prefix; ++i) @@ -385,3 +472,29 @@ tinytest_set_test_skipped_(void) cur_test_outcome = SKIP; } +char * +tinytest_format_hex_(const void *val_, unsigned long len) +{ + const unsigned char *val = val_; + char *result, *cp; + size_t i; + int ellipses = 0; + + if (!val) + return strdup("null"); + if (len > 1024) { + ellipses = 3; + len = 1024; + } + if (!(result = malloc(len*2+4))) + return strdup("<allocation failure>"); + cp = result; + for (i=0;i<len;++i) { + *cp++ = "0123456789ABCDEF"[val[i] >> 4]; + *cp++ = "0123456789ABCDEF"[val[i] & 0x0f]; + } + while (ellipses--) + *cp++ = '.'; + *cp = 0; + return result; +} |