26 #include "tinytest_local.h"
28 #define TINYTEST_POSTFORK
40 #include <sys/types.h>
45 #if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
46 #if (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060 && \
47 __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070)
49 #define FORK_BREAKS_GCOV
57 #define __attribute__(x)
61 #include "tinytest_macros.h"
63 #define LONGEST_TEST_NAME 16384
65 static int in_tinytest_main = 0;
68 static int n_skipped = 0;
70 static int opt_forked = 0;
71 static int opt_nofork = 0;
72 static int opt_verbosity = 1;
73 static const char *verbosity_flag =
"";
77 enum outcome { SKIP=2, OK=1, FAIL=0 };
78 static enum outcome cur_test_outcome = 0;
80 static const char *cur_test_prefix = NULL;
82 static const char *cur_test_name = NULL;
86 static char commandname[MAX_PATH+1];
89 static void usage(
struct testgroup_t *groups,
int list_groups)
90 __attribute__((noreturn));
91 static int process_test_option(
struct testgroup_t *groups,
const char *test);
94 testcase_run_bare_(
const struct testcase_t *testcase)
98 if (testcase->
setup) {
102 else if (env == (
void*)TT_SKIP)
106 cur_test_outcome = OK;
108 outcome = cur_test_outcome;
110 if (testcase->
setup) {
118 #define MAGIC_EXITCODE 42
122 #ifdef TINYTEST_POSTFORK
123 void tinytest_prefork(
void);
124 void tinytest_postfork(
void);
126 static void tinytest_prefork(
void) { }
127 static void tinytest_postfork(
void) { }
131 testcase_run_forked_(
const struct testgroup_t *group,
144 char buffer[LONGEST_TEST_NAME+256];
146 PROCESS_INFORMATION info;
149 if (!in_tinytest_main) {
150 printf(
"\nERROR. On Windows, testcase_run_forked_ must be"
151 " called from within tinytest_main.\n");
155 printf(
"[forking] ");
157 snprintf(buffer,
sizeof(buffer),
"\"%s\" --RUNNING-FORKED %s %s%s",
158 commandname, verbosity_flag, group->
prefix, testcase->
name);
160 memset(&si, 0,
sizeof(si));
161 memset(&info, 0,
sizeof(info));
164 ok = CreateProcessA(commandname, buffer, NULL, NULL, 0,
165 0, NULL, NULL, &si, &info);
167 printf(
"CreateProcess failed!\n");
170 WaitForSingleObject(info.hProcess, INFINITE);
171 GetExitCodeProcess(info.hProcess, &exitcode);
172 CloseHandle(info.hProcess);
173 CloseHandle(info.hThread);
176 else if (exitcode == MAGIC_EXITCODE)
185 if (pipe(outcome_pipe))
186 perror(
"opening pipe");
189 printf(
"[forking] ");
192 #ifdef FORK_BREAKS_GCOV
193 vproc_transaction_begin(0);
200 close(outcome_pipe[0]);
201 test_r = testcase_run_bare_(testcase);
202 assert(0<=(
int)test_r && (
int)test_r<=2);
203 b[0] =
"NYS"[test_r];
204 write_r = (int)write(outcome_pipe[1], b, 1);
206 perror(
"write outcome to pipe");
217 close(outcome_pipe[1]);
218 r = (int)read(outcome_pipe[0], b, 1);
220 printf(
"[Lost connection!] ");
223 perror(
"read outcome from pipe");
225 r = waitpid(pid, &status, 0);
226 close(outcome_pipe[0]);
231 if (! WIFEXITED(status) || WEXITSTATUS(status) != 0) {
232 printf(
"[did not exit cleanly.]");
235 return b[0]==
'Y' ? OK : (b[0]==
'S' ? SKIP : FAIL);
246 enum outcome outcome;
248 if (testcase->
flags & (TT_SKIP|TT_OFF_BY_DEFAULT)) {
252 (testcase->
flags & TT_SKIP) ?
"SKIPPED" :
"DISABLED");
257 if (opt_verbosity>0 && !opt_forked) {
258 printf(
"%s%s: ", group->
prefix, testcase->
name);
260 if (opt_verbosity==0) printf(
".");
261 cur_test_prefix = group->
prefix;
262 cur_test_name = testcase->
name;
266 if ((testcase->
flags & TT_FORK) && !(opt_forked||opt_nofork)) {
267 outcome = testcase_run_forked_(group, testcase);
272 outcome = testcase_run_bare_(testcase);
277 if (opt_verbosity>0 && !opt_forked)
278 puts(opt_verbosity==1?
"OK":
"");
279 }
else if (outcome == SKIP) {
281 if (opt_verbosity>0 && !opt_forked)
286 printf(
"\n [%s FAILED]\n", testcase->
name);
290 exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1));
298 tinytest_set_flag_(
struct testgroup_t *groups,
const char *arg,
int set,
unsigned long flag)
301 size_t length = LONGEST_TEST_NAME;
302 char fullname[LONGEST_TEST_NAME];
304 if (strstr(arg,
".."))
305 length = strstr(arg,
"..")-arg;
306 for (i=0; groups[i].
prefix; ++i) {
307 for (j=0; groups[i].cases[j].
name; ++j) {
308 struct testcase_t *testcase = &groups[i].cases[j];
309 snprintf(fullname,
sizeof(fullname),
"%s%s",
310 groups[i].prefix, testcase->
name);
312 printf(
" %s", fullname);
313 if (testcase->
flags & TT_OFF_BY_DEFAULT)
314 puts(
" (Off by default)");
315 else if (testcase->
flags & TT_SKIP)
320 if (!strncmp(fullname, arg, length)) {
322 testcase->
flags |= flag;
324 testcase->
flags &= ~flag;
335 puts(
"Options are: [--verbose|--quiet|--terse] [--no-fork]");
336 puts(
" Specify tests by name, or using a prefix ending with '..'");
337 puts(
" To skip a test, prefix its name with a colon.");
338 puts(
" To enable a disabled test, prefix its name with a plus.");
339 puts(
" Use --list-tests for a list of tests.");
341 puts(
"Known tests are:");
342 tinytest_set_flag_(groups,
"..", 1, 0);
348 process_test_alias(
struct testgroup_t *groups,
const char *test)
351 for (i=0; cfg_aliases && cfg_aliases[i].name; ++i) {
352 if (!strcmp(cfg_aliases[i].
name, test)) {
354 for (j = 0; cfg_aliases[i].tests[j]; ++j) {
355 r = process_test_option(groups, cfg_aliases[i].tests[j]);
363 printf(
"No such test alias as @%s!",test);
368 process_test_option(
struct testgroup_t *groups,
const char *test)
370 int flag = TT_ENABLED_;
372 if (test[0] ==
'@') {
373 return process_test_alias(groups, test + 1);
374 }
else if (test[0] ==
':') {
377 }
else if (test[0] ==
'+') {
380 if (!tinytest_set_flag_(groups, test, 0, TT_OFF_BY_DEFAULT)) {
381 printf(
"No such test as %s!\n", test);
387 if (!tinytest_set_flag_(groups, test, 1, flag)) {
388 printf(
"No such test as %s!\n", test);
397 cfg_aliases = aliases;
401 tinytest_main(
int c,
const char **v,
struct testgroup_t *groups)
406 const char *sp = strrchr(v[0],
'.');
407 const char *extension =
"";
408 if (!sp || stricmp(sp,
".exe"))
410 snprintf(commandname,
sizeof(commandname),
"%s%s", v[0], extension);
411 commandname[MAX_PATH]=
'\0';
413 for (i=1; i<c; ++i) {
414 if (v[i][0] ==
'-') {
415 if (!strcmp(v[i],
"--RUNNING-FORKED")) {
417 }
else if (!strcmp(v[i],
"--no-fork")) {
419 }
else if (!strcmp(v[i],
"--quiet")) {
421 verbosity_flag =
"--quiet";
422 }
else if (!strcmp(v[i],
"--verbose")) {
424 verbosity_flag =
"--verbose";
425 }
else if (!strcmp(v[i],
"--terse")) {
427 verbosity_flag =
"--terse";
428 }
else if (!strcmp(v[i],
"--help")) {
430 }
else if (!strcmp(v[i],
"--list-tests")) {
433 printf(
"Unknown option %s. Try --help\n",v[i]);
437 int r = process_test_option(groups, v[i]);
444 tinytest_set_flag_(groups,
"..", 1, TT_ENABLED_);
447 setvbuf(stdout, NULL, _IONBF, 0);
451 for (i=0; groups[i].
prefix; ++i)
452 for (j=0; groups[i].cases[j].
name; ++j)
453 if (groups[i].cases[j].
flags & TT_ENABLED_)
454 testcase_run_one(&groups[i],
455 &groups[i].cases[j]);
459 if (opt_verbosity==0)
463 printf(
"%d/%d TESTS FAILED. (%d skipped)\n", n_bad,
464 n_bad+n_ok,n_skipped);
465 else if (opt_verbosity >= 1)
466 printf(
"%d tests ok. (%d skipped)\n", n_ok, n_skipped);
468 return (n_bad == 0) ? 0 : 1;
472 tinytest_get_verbosity_(
void)
474 return opt_verbosity;
478 tinytest_set_test_failed_(
void)
480 if (opt_verbosity <= 0 && cur_test_name) {
481 if (opt_verbosity==0) puts(
"");
482 printf(
"%s%s: ", cur_test_prefix, cur_test_name);
483 cur_test_name = NULL;
485 cur_test_outcome = 0;
489 tinytest_set_test_skipped_(
void)
491 if (cur_test_outcome==OK)
492 cur_test_outcome = SKIP;
496 tinytest_cur_test_has_failed(
void)
498 return (cur_test_outcome == FAIL);
502 tinytest_format_hex_(
const void *val_,
unsigned long len)
504 const unsigned char *val = val_;
510 return strdup(
"null");
515 if (!(result = malloc(len*2+4)))
516 return strdup(
"<allocation failure>");
518 for (i=0;i<len;++i) {
519 *cp++ =
"0123456789ABCDEF"[(val[i] >> 4)&0x0f];
520 *cp++ =
"0123456789ABCDEF"[val[i] & 0x0f];
void *(* setup_fn)(const struct testcase_t *)
int(* cleanup_fn)(const struct testcase_t *, void *)
const struct testcase_setup_t * setup