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
63 #define DEFAULT_TESTCASE_TIMEOUT 30U
64 #define MAGIC_EXITCODE 42
66 static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/
67 static int n_ok = 0; /**< Number of tests that have passed */
68 static int n_bad = 0; /**< Number of tests that have failed. */
69 static int n_skipped = 0; /**< Number of tests that have been skipped. */
71 static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/
72 static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */
73 static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */
74 static unsigned int opt_timeout = DEFAULT_TESTCASE_TIMEOUT; /**< Timeout for every test (using alarm()) */
75 const char *verbosity_flag = "";
77 const struct testlist_alias_t *cfg_aliases=NULL;
79 enum outcome { SKIP=2, OK=1, FAIL=0 };
80 static enum outcome cur_test_outcome = 0;
81 const char *cur_test_prefix = NULL; /**< prefix of the current test group */
82 /** Name of the current test, if we haven't logged is yet. Used for --quiet */
83 const char *cur_test_name = NULL;
85 static void usage(struct testgroup_t *groups, int list_groups)
86 __attribute__((noreturn));
87 static int process_test_option(struct testgroup_t *groups, const char *test);
90 /* Copy of argv[0] for win32. */
91 static char commandname[MAX_PATH+1];
93 struct timeout_thread_args {
94 const testcase_fn *fn;
99 timeout_thread_proc_(LPVOID arg)
101 struct timeout_thread_args *args = arg;
102 (*(args->fn))(args->env);
103 ExitThread(cur_test_outcome == FAIL ? 1 : 0);
107 testcase_run_in_thread_(const struct testcase_t *testcase, void *env)
109 /* We will never run testcase in a new thread when the
110 timeout is set to zero */
114 struct timeout_thread_args args = {
119 handle =CreateThread(NULL, 0, timeout_thread_proc_,
120 (LPVOID)&args, 0, &tid);
121 ret = WaitForSingleObject(handle, opt_timeout * 1000U);
122 if (ret == WAIT_OBJECT_0) {
124 if (!GetExitCodeThread(handle, &ret)) {
125 printf("GetExitCodeThread failed\n");
128 } else if (ret == WAIT_TIMEOUT) {
131 printf("Wait failed\n");
136 else if (ret == MAGIC_EXITCODE)
142 static unsigned int testcase_set_timeout_(void)
144 return alarm(opt_timeout);
147 static unsigned int testcase_reset_timeout_(void)
154 testcase_run_bare_(const struct testcase_t *testcase)
158 if (testcase->setup) {
159 env = testcase->setup->setup_fn(testcase);
162 else if (env == (void*)TT_SKIP)
166 cur_test_outcome = OK;
170 cur_test_outcome = testcase_run_in_thread_(testcase, env);
172 testcase_set_timeout_();
174 testcase_reset_timeout_();
180 outcome = cur_test_outcome;
182 if (testcase->setup) {
183 if (testcase->setup->cleanup_fn(testcase, env) == 0)
194 testcase_run_forked_(const struct testgroup_t *group,
195 const struct testcase_t *testcase)
198 /* Fork? On Win32? How primitive! We'll do what the smart kids do:
199 we'll invoke our own exe (whose name we recall from the command
200 line) with a command line that tells it to run just the test we
201 want, and this time without forking.
203 (No, threads aren't an option. The whole point of forking is to
204 share no state between tests.)
207 char buffer[LONGEST_TEST_NAME+256];
209 PROCESS_INFORMATION info;
212 if (!in_tinytest_main) {
213 printf("\nERROR. On Windows, testcase_run_forked_ must be"
214 " called from within tinytest_main.\n");
218 printf("[forking] ");
220 snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s --timeout 0 %s%s",
221 commandname, verbosity_flag, group->prefix, testcase->name);
223 memset(&si, 0, sizeof(si));
224 memset(&info, 0, sizeof(info));
227 ok = CreateProcessA(commandname, buffer, NULL, NULL, 0,
228 0, NULL, NULL, &si, &info);
230 printf("CreateProcess failed!\n");
233 ret = WaitForSingleObject(info.hProcess,
234 (opt_timeout ? opt_timeout * 1000U : INFINITE));
236 if (ret == WAIT_OBJECT_0) {
237 GetExitCodeProcess(info.hProcess, &ret);
238 } else if (ret == WAIT_TIMEOUT) {
241 printf("Wait failed\n");
243 CloseHandle(info.hProcess);
244 CloseHandle(info.hThread);
247 else if (ret == MAGIC_EXITCODE)
256 if (pipe(outcome_pipe))
257 perror("opening pipe");
260 printf("[forking] ");
262 #ifdef FORK_BREAKS_GCOV
263 vproc_transaction_begin(0);
269 close(outcome_pipe[0]);
270 test_r = testcase_run_bare_(testcase);
271 assert(0<=(int)test_r && (int)test_r<=2);
272 b[0] = "NYS"[test_r];
273 write_r = (int)write(outcome_pipe[1], b, 1);
275 perror("write outcome to pipe");
279 return FAIL; /* unreachable */
282 int status, r, exitcode;
284 /* Close this now, so that if the other side closes it,
286 close(outcome_pipe[1]);
287 r = (int)read(outcome_pipe[0], b, 1);
289 printf("[Lost connection!] ");
292 perror("read outcome from pipe");
294 waitpid(pid, &status, 0);
295 exitcode = WEXITSTATUS(status);
296 close(outcome_pipe[0]);
298 printf("%s%s: exited with %i (%i)\n", group->prefix, testcase->name, exitcode, status);
301 printf("[atexit failure!] ");
304 return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL);
309 #endif /* !NO_FORKING */
312 testcase_run_one(const struct testgroup_t *group,
313 const struct testcase_t *testcase)
315 enum outcome outcome;
317 if (testcase->flags & (TT_SKIP|TT_OFF_BY_DEFAULT)) {
320 group->prefix, testcase->name,
321 (testcase->flags & TT_SKIP) ? "SKIPPED" : "DISABLED");
326 if (opt_verbosity>0 && !opt_forked) {
327 printf("%s%s: ", group->prefix, testcase->name);
329 if (opt_verbosity==0) printf(".");
330 cur_test_prefix = group->prefix;
331 cur_test_name = testcase->name;
335 if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) {
336 outcome = testcase_run_forked_(group, testcase);
341 outcome = testcase_run_bare_(testcase);
345 if (opt_verbosity>0 && !opt_forked)
346 puts(opt_verbosity==1?"OK":"");
347 } else if (outcome == SKIP) {
348 if (opt_verbosity>0 && !opt_forked)
352 printf("\n [%s FAILED]\n", testcase->name);
356 exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1));
357 return 1; /* unreachable */
364 tinytest_set_flag_(struct testgroup_t *groups, const char *arg, int set, unsigned long flag)
367 size_t length = LONGEST_TEST_NAME;
368 char fullname[LONGEST_TEST_NAME];
370 if (strstr(arg, ".."))
371 length = strstr(arg,"..")-arg;
372 for (i=0; groups[i].prefix; ++i) {
373 for (j=0; groups[i].cases[j].name; ++j) {
374 struct testcase_t *testcase = &groups[i].cases[j];
375 snprintf(fullname, sizeof(fullname), "%s%s",
376 groups[i].prefix, testcase->name);
377 if (!flag) { /* Hack! */
378 printf(" %s", fullname);
379 if (testcase->flags & TT_OFF_BY_DEFAULT)
380 puts(" (Off by default)");
381 else if (testcase->flags & TT_SKIP)
386 if (!strncmp(fullname, arg, length)) {
388 testcase->flags |= flag;
390 testcase->flags &= ~flag;
399 usage(struct testgroup_t *groups, int list_groups)
401 puts("Options are: [--verbose|--quiet|--terse] [--no-fork] [--timeout <sec>]");
402 puts(" Specify tests by name, or using a prefix ending with '..'");
403 puts(" To skip a test, prefix its name with a colon.");
404 puts(" To enable a disabled test, prefix its name with a plus.");
405 puts(" Use --list-tests for a list of tests.");
407 puts("Known tests are:");
408 tinytest_set_flag_(groups, "..", 1, 0);
414 process_test_alias(struct testgroup_t *groups, const char *test)
417 for (i=0; cfg_aliases && cfg_aliases[i].name; ++i) {
418 if (!strcmp(cfg_aliases[i].name, test)) {
420 for (j = 0; cfg_aliases[i].tests[j]; ++j) {
421 r = process_test_option(groups, cfg_aliases[i].tests[j]);
429 printf("No such test alias as @%s!",test);
434 process_test_option(struct testgroup_t *groups, const char *test)
436 int flag = TT_ENABLED_;
438 if (test[0] == '@') {
439 return process_test_alias(groups, test + 1);
440 } else if (test[0] == ':') {
443 } else if (test[0] == '+') {
446 if (!tinytest_set_flag_(groups, test, 0, TT_OFF_BY_DEFAULT)) {
447 printf("No such test as %s!\n", test);
453 if (!tinytest_set_flag_(groups, test, 1, flag)) {
454 printf("No such test as %s!\n", test);
461 tinytest_set_aliases(const struct testlist_alias_t *aliases)
463 cfg_aliases = aliases;
467 tinytest_main(int c, const char **v, struct testgroup_t *groups)
472 const char *sp = strrchr(v[0], '.');
473 const char *extension = "";
474 if (!sp || stricmp(sp, ".exe"))
475 extension = ".exe"; /* Add an exe so CreateProcess will work */
476 snprintf(commandname, sizeof(commandname), "%s%s", v[0], extension);
477 commandname[MAX_PATH]='\0';
479 for (i=1; i<c; ++i) {
480 if (v[i][0] == '-') {
481 if (!strcmp(v[i], "--RUNNING-FORKED")) {
483 } else if (!strcmp(v[i], "--no-fork")) {
485 } else if (!strcmp(v[i], "--quiet")) {
487 verbosity_flag = "--quiet";
488 } else if (!strcmp(v[i], "--verbose")) {
490 verbosity_flag = "--verbose";
491 } else if (!strcmp(v[i], "--terse")) {
493 verbosity_flag = "--terse";
494 } else if (!strcmp(v[i], "--help")) {
496 } else if (!strcmp(v[i], "--list-tests")) {
498 } else if (!strcmp(v[i], "--timeout")) {
501 fprintf(stderr, "--timeout requires argument\n");
504 opt_timeout = (unsigned)atoi(v[i]);
506 fprintf(stderr, "Unknown option %s. Try --help\n", v[i]);
510 int r = process_test_option(groups, v[i]);
517 tinytest_set_flag_(groups, "..", 1, TT_ENABLED_);
520 setvbuf(stdout, NULL, _IONBF, 0);
524 for (i = 0; groups[i].prefix; ++i) {
525 struct testgroup_t *group = &groups[i];
526 for (j = 0; group->cases[j].name; ++j) {
527 struct testcase_t *testcase = &group->cases[j];
528 int test_attempts = 3;
531 if (!(testcase->flags & TT_ENABLED_))
535 test_ret_err = testcase_run_one(group, testcase);
537 if (test_ret_err == OK)
539 if (!(testcase->flags & TT_RETRIABLE))
541 printf("\n [RETRYING %s (%i)]\n", testcase->name, test_attempts);
542 if (!test_attempts--)
546 switch (test_ret_err) {
547 case OK: ++n_ok; break;
548 case SKIP: ++n_skipped; break;
549 default: ++n_bad; break;
556 if (opt_verbosity==0)
560 printf("%d/%d TESTS FAILED. (%d skipped)\n", n_bad,
561 n_bad+n_ok,n_skipped);
562 else if (opt_verbosity >= 1)
563 printf("%d tests ok. (%d skipped)\n", n_ok, n_skipped);
565 return (n_bad == 0) ? 0 : 1;
569 tinytest_get_verbosity_(void)
571 return opt_verbosity;
575 tinytest_set_test_failed_(void)
577 if (opt_verbosity <= 0 && cur_test_name) {
578 if (opt_verbosity==0) puts("");
579 printf("%s%s: ", cur_test_prefix, cur_test_name);
580 cur_test_name = NULL;
582 cur_test_outcome = FAIL;
586 tinytest_set_test_skipped_(void)
588 if (cur_test_outcome==OK)
589 cur_test_outcome = SKIP;
593 tinytest_format_hex_(const void *val_, unsigned long len)
595 const unsigned char *val = val_;
600 return strdup("null");
601 if (!(result = malloc(len*2+1)))
602 return strdup("<allocation failure>");
604 for (i=0;i<len;++i) {
605 *cp++ = "0123456789ABCDEF"[val[i] >> 4];
606 *cp++ = "0123456789ABCDEF"[val[i] & 0x0f];