1 /* tinytest.c -- Copyright 2009-2012 Nick Mathewson
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions
6 * 1. Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * 2. Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
11 * 3. The name of the author may not be used to endorse or promote products
12 * derived from this software without specific prior written permission.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #include "tinytest_local.h"
39 #include <sys/types.h>
44 #if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
45 #if (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060 && \
46 __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070)
47 /* Workaround for a stupid bug in OSX 10.6 */
48 #define FORK_BREAKS_GCOV
53 #endif /* !NO_FORKING */
56 #define __attribute__(x)
60 #include "tinytest_macros.h"
62 #define LONGEST_TEST_NAME 16384
65 #define DEFAULT_TESTCASE_TIMEOUT 30U
67 #define DEFAULT_TESTCASE_TIMEOUT 0U
70 static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/
71 static int n_ok = 0; /**< Number of tests that have passed */
72 static int n_bad = 0; /**< Number of tests that have failed. */
73 static int n_skipped = 0; /**< Number of tests that have been skipped. */
75 static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/
76 static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */
77 static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */
78 static unsigned int opt_timeout = DEFAULT_TESTCASE_TIMEOUT; /**< Timeout for every test (using alarm()) */
79 const char *verbosity_flag = "";
81 const struct testlist_alias_t *cfg_aliases=NULL;
83 enum outcome { SKIP=2, OK=1, FAIL=0 };
84 static enum outcome cur_test_outcome = 0;
85 const char *cur_test_prefix = NULL; /**< prefix of the current test group */
86 /** Name of the current test, if we haven't logged is yet. Used for --quiet */
87 const char *cur_test_name = NULL;
90 /* Copy of argv[0] for win32. */
91 static char commandname[MAX_PATH+1];
94 static void usage(struct testgroup_t *groups, int list_groups)
95 __attribute__((noreturn));
96 static int process_test_option(struct testgroup_t *groups, const char *test);
98 static unsigned int testcase_set_timeout_(void)
103 return alarm(opt_timeout);
105 /** TODO: win32 support */
106 fprintf(stderr, "You cannot set alarm on windows\n");
110 static unsigned int testcase_reset_timeout_(void)
118 testcase_run_bare_(const struct testcase_t *testcase)
122 if (testcase->setup) {
123 env = testcase->setup->setup_fn(testcase);
126 else if (env == (void*)TT_SKIP)
130 cur_test_outcome = OK;
132 testcase_set_timeout_();
134 testcase_reset_timeout_();
136 outcome = cur_test_outcome;
138 if (testcase->setup) {
139 if (testcase->setup->cleanup_fn(testcase, env) == 0)
146 #define MAGIC_EXITCODE 42
151 testcase_run_forked_(const struct testgroup_t *group,
152 const struct testcase_t *testcase)
155 /* Fork? On Win32? How primitive! We'll do what the smart kids do:
156 we'll invoke our own exe (whose name we recall from the command
157 line) with a command line that tells it to run just the test we
158 want, and this time without forking.
160 (No, threads aren't an option. The whole point of forking is to
161 share no state between tests.)
164 char buffer[LONGEST_TEST_NAME+256];
166 PROCESS_INFORMATION info;
169 if (!in_tinytest_main) {
170 printf("\nERROR. On Windows, testcase_run_forked_ must be"
171 " called from within tinytest_main.\n");
175 printf("[forking] ");
177 snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s %s%s",
178 commandname, verbosity_flag, group->prefix, testcase->name);
180 memset(&si, 0, sizeof(si));
181 memset(&info, 0, sizeof(info));
184 ok = CreateProcessA(commandname, buffer, NULL, NULL, 0,
185 0, NULL, NULL, &si, &info);
187 printf("CreateProcess failed!\n");
190 WaitForSingleObject(info.hProcess, INFINITE);
191 GetExitCodeProcess(info.hProcess, &exitcode);
192 CloseHandle(info.hProcess);
193 CloseHandle(info.hThread);
196 else if (exitcode == MAGIC_EXITCODE)
205 if (pipe(outcome_pipe))
206 perror("opening pipe");
209 printf("[forking] ");
211 #ifdef FORK_BREAKS_GCOV
212 vproc_transaction_begin(0);
218 close(outcome_pipe[0]);
219 test_r = testcase_run_bare_(testcase);
220 assert(0<=(int)test_r && (int)test_r<=2);
221 b[0] = "NYS"[test_r];
222 write_r = (int)write(outcome_pipe[1], b, 1);
224 perror("write outcome to pipe");
228 return FAIL; /* unreachable */
233 /* Close this now, so that if the other side closes it,
235 close(outcome_pipe[1]);
236 r = (int)read(outcome_pipe[0], b, 1);
238 printf("[Lost connection!] ");
241 perror("read outcome from pipe");
243 waitpid(pid, &status, 0);
244 close(outcome_pipe[0]);
245 return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL);
250 #endif /* !NO_FORKING */
253 testcase_run_one(const struct testgroup_t *group,
254 const struct testcase_t *testcase)
256 enum outcome outcome;
258 if (testcase->flags & (TT_SKIP|TT_OFF_BY_DEFAULT)) {
261 group->prefix, testcase->name,
262 (testcase->flags & TT_SKIP) ? "SKIPPED" : "DISABLED");
267 if (opt_verbosity>0 && !opt_forked) {
268 printf("%s%s: ", group->prefix, testcase->name);
270 if (opt_verbosity==0) printf(".");
271 cur_test_prefix = group->prefix;
272 cur_test_name = testcase->name;
276 if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) {
277 outcome = testcase_run_forked_(group, testcase);
282 outcome = testcase_run_bare_(testcase);
286 if (opt_verbosity>0 && !opt_forked)
287 puts(opt_verbosity==1?"OK":"");
288 } else if (outcome == SKIP) {
289 if (opt_verbosity>0 && !opt_forked)
293 printf("\n [%s FAILED]\n", testcase->name);
297 exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1));
298 return 1; /* unreachable */
305 tinytest_set_flag_(struct testgroup_t *groups, const char *arg, int set, unsigned long flag)
308 size_t length = LONGEST_TEST_NAME;
309 char fullname[LONGEST_TEST_NAME];
311 if (strstr(arg, ".."))
312 length = strstr(arg,"..")-arg;
313 for (i=0; groups[i].prefix; ++i) {
314 for (j=0; groups[i].cases[j].name; ++j) {
315 struct testcase_t *testcase = &groups[i].cases[j];
316 snprintf(fullname, sizeof(fullname), "%s%s",
317 groups[i].prefix, testcase->name);
318 if (!flag) { /* Hack! */
319 printf(" %s", fullname);
320 if (testcase->flags & TT_OFF_BY_DEFAULT)
321 puts(" (Off by default)");
322 else if (testcase->flags & TT_SKIP)
327 if (!strncmp(fullname, arg, length)) {
329 testcase->flags |= flag;
331 testcase->flags &= ~flag;
340 usage(struct testgroup_t *groups, int list_groups)
342 puts("Options are: [--verbose|--quiet|--terse] [--no-fork] [--timeout <sec>]");
343 puts(" Specify tests by name, or using a prefix ending with '..'");
344 puts(" To skip a test, prefix its name with a colon.");
345 puts(" To enable a disabled test, prefix its name with a plus.");
346 puts(" Use --list-tests for a list of tests.");
348 puts("Known tests are:");
349 tinytest_set_flag_(groups, "..", 1, 0);
355 process_test_alias(struct testgroup_t *groups, const char *test)
358 for (i=0; cfg_aliases && cfg_aliases[i].name; ++i) {
359 if (!strcmp(cfg_aliases[i].name, test)) {
361 for (j = 0; cfg_aliases[i].tests[j]; ++j) {
362 r = process_test_option(groups, cfg_aliases[i].tests[j]);
370 printf("No such test alias as @%s!",test);
375 process_test_option(struct testgroup_t *groups, const char *test)
377 int flag = TT_ENABLED_;
379 if (test[0] == '@') {
380 return process_test_alias(groups, test + 1);
381 } else if (test[0] == ':') {
384 } else if (test[0] == '+') {
387 if (!tinytest_set_flag_(groups, test, 0, TT_OFF_BY_DEFAULT)) {
388 printf("No such test as %s!\n", test);
394 if (!tinytest_set_flag_(groups, test, 1, flag)) {
395 printf("No such test as %s!\n", test);
402 tinytest_set_aliases(const struct testlist_alias_t *aliases)
404 cfg_aliases = aliases;
408 tinytest_main(int c, const char **v, struct testgroup_t *groups)
413 const char *sp = strrchr(v[0], '.');
414 const char *extension = "";
415 if (!sp || stricmp(sp, ".exe"))
416 extension = ".exe"; /* Add an exe so CreateProcess will work */
417 snprintf(commandname, sizeof(commandname), "%s%s", v[0], extension);
418 commandname[MAX_PATH]='\0';
420 for (i=1; i<c; ++i) {
421 if (v[i][0] == '-') {
422 if (!strcmp(v[i], "--RUNNING-FORKED")) {
424 } else if (!strcmp(v[i], "--no-fork")) {
426 } else if (!strcmp(v[i], "--quiet")) {
428 verbosity_flag = "--quiet";
429 } else if (!strcmp(v[i], "--verbose")) {
431 verbosity_flag = "--verbose";
432 } else if (!strcmp(v[i], "--terse")) {
434 verbosity_flag = "--terse";
435 } else if (!strcmp(v[i], "--help")) {
437 } else if (!strcmp(v[i], "--list-tests")) {
439 } else if (!strcmp(v[i], "--timeout")) {
442 fprintf(stderr, "--timeout requires argument\n");
445 opt_timeout = (unsigned)atoi(v[i]);
447 fprintf(stderr, "Unknown option %s. Try --help\n", v[i]);
451 int r = process_test_option(groups, v[i]);
458 tinytest_set_flag_(groups, "..", 1, TT_ENABLED_);
461 setvbuf(stdout, NULL, _IONBF, 0);
465 for (i = 0; groups[i].prefix; ++i) {
466 struct testgroup_t *group = &groups[i];
467 for (j = 0; group->cases[j].name; ++j) {
468 struct testcase_t *testcase = &group->cases[j];
469 int test_attempts = 3;
472 if (!(testcase->flags & TT_ENABLED_))
476 test_ret_err = testcase_run_one(group, testcase);
478 if (test_ret_err == OK)
480 if (!(testcase->flags & TT_RETRIABLE))
482 printf("\n [RETRYING %s (%i)]\n", testcase->name, test_attempts);
483 if (!test_attempts--)
487 switch (test_ret_err) {
488 case OK: ++n_ok; break;
489 case SKIP: ++n_skipped; break;
490 default: ++n_bad; break;
497 if (opt_verbosity==0)
501 printf("%d/%d TESTS FAILED. (%d skipped)\n", n_bad,
502 n_bad+n_ok,n_skipped);
503 else if (opt_verbosity >= 1)
504 printf("%d tests ok. (%d skipped)\n", n_ok, n_skipped);
506 return (n_bad == 0) ? 0 : 1;
510 tinytest_get_verbosity_(void)
512 return opt_verbosity;
516 tinytest_set_test_failed_(void)
518 if (opt_verbosity <= 0 && cur_test_name) {
519 if (opt_verbosity==0) puts("");
520 printf("%s%s: ", cur_test_prefix, cur_test_name);
521 cur_test_name = NULL;
523 cur_test_outcome = 0;
527 tinytest_set_test_skipped_(void)
529 if (cur_test_outcome==OK)
530 cur_test_outcome = SKIP;
534 tinytest_format_hex_(const void *val_, unsigned long len)
536 const unsigned char *val = val_;
541 return strdup("null");
542 if (!(result = malloc(len*2+1)))
543 return strdup("<allocation failure>");
545 for (i=0;i<len;++i) {
546 *cp++ = "0123456789ABCDEF"[val[i] >> 4];
547 *cp++ = "0123456789ABCDEF"[val[i] & 0x0f];