/* tinytest.c -- Copyright 2009-2012 Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ #ifdef TINYTEST_LOCAL #include"tinytest_local.h" #endif
staticint in_tinytest_main = 0; /**< true if we're in tinytest_main().*/ staticint n_ok = 0; /**< Number of tests that have passed */ staticint n_bad = 0; /**< Number of tests that have failed. */ staticint n_skipped = 0; /**< Number of tests that have been skipped. */
staticint opt_forked = 0; /**< True iff we're called from inside a win32 fork*/ staticint opt_nofork = 0; /**< Suppress calls to fork() for debugging. */ staticint opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */ staticunsignedint opt_timeout = DEFAULT_TESTCASE_TIMEOUT; /**< Timeout for every test (using alarm()) */ constchar *verbosity_flag = "";
conststruct testlist_alias_t *cfg_aliases=NULL;
enum outcome { SKIP=2, OK=1, FAIL=0 }; staticenum outcome cur_test_outcome = 0; constchar *cur_test_prefix = NULL; /**< prefix of the current test group */ /** Name of the current test, if we haven't logged is yet. Used for --quiet */ constchar *cur_test_name = NULL;
staticenum outcome
testcase_run_in_thread_(conststruct testcase_t *testcase, void *env)
{ /* We will never run testcase in a new thread when the
timeout is set to zero */
assert(opt_timeout);
DWORD ret, tid;
HANDLE handle; struct timeout_thread_args args = {
&(testcase->fn),
env
};
if (testcase->setup) { if (testcase->setup->cleanup_fn(testcase, env) == 0)
outcome = FAIL;
}
return outcome;
}
#ifndef NO_FORKING
staticenum outcome
testcase_run_forked_(conststruct testgroup_t *group, conststruct testcase_t *testcase)
{ #ifdef _WIN32 /* Fork? On Win32? How primitive! We'll do what the smart kids do: we'll invoke our own exe (whose name we recall from the command line) with a command line that tells it to run just the test we want, and this time without forking.
(No, threads aren't an option. The whole point of forking is to share no state between tests.)
*/ int ok; char buffer[LONGEST_TEST_NAME+256];
STARTUPINFOA si;
PROCESS_INFORMATION info;
DWORD ret;
if (!in_tinytest_main) {
printf("\nERROR. On Windows, testcase_run_forked_ must be" " called from within tinytest_main.\n");
abort();
} if (opt_verbosity>0)
printf("[forking] ");
int
tinytest_set_flag_(struct testgroup_t *groups, constchar *arg, int set, unsignedlong flag)
{ int i, j;
size_t length = LONGEST_TEST_NAME; char fullname[LONGEST_TEST_NAME]; int found=0; if (strstr(arg, ".."))
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, testcase->name); if (!flag) { /* Hack! */
printf(" %s", fullname); if (testcase->flags & TT_OFF_BY_DEFAULT)
puts(" (Off by default)"); elseif (testcase->flags & TT_SKIP)
puts(" (DISABLED)"); else
puts("");
} if (!strncmp(fullname, arg, length)) { if (set)
testcase->flags |= flag; else
testcase->flags &= ~flag;
++found;
}
}
} return found;
}
staticvoid
usage(struct testgroup_t *groups, int list_groups)
{
puts("Options are: [--verbose|--quiet|--terse] [--no-fork] [--timeout ]");
puts(" Specify tests by name, or using a prefix ending with '..'");
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, "..", 1, 0);
} exit(0);
}
staticint
process_test_alias(struct testgroup_t *groups, constchar *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;
}
staticint
process_test_option(struct testgroup_t *groups, constchar *test)
{ int flag = TT_ENABLED_; int n = 0; if (test[0] == '@') { return process_test_alias(groups, test + 1);
} elseif (test[0] == ':') {
++test;
flag = TT_SKIP;
} elseif (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;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.