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
64 static int in_tinytest_main
= 0; /**< true if we're in tinytest_main().*/
65 static int n_ok
= 0; /**< Number of tests that have passed */
66 static int n_bad
= 0; /**< Number of tests that have failed. */
67 static int n_skipped
= 0; /**< Number of tests that have been skipped. */
69 static int opt_forked
= 0; /**< True iff we're called from inside a win32 fork*/
70 static int opt_nofork
= 0; /**< Suppress calls to fork() for debugging. */
71 static int opt_verbosity
= 1; /**< -==quiet,0==terse,1==normal,2==verbose */
72 const char *verbosity_flag
= "";
74 const struct testlist_alias_t
*cfg_aliases
=NULL
;
76 enum outcome
{ SKIP
=2, OK
=1, FAIL
=0 };
77 static enum outcome cur_test_outcome
= 0;
78 const char *cur_test_prefix
= NULL
; /**< prefix of the current test group */
79 /** Name of the current test, if we haven't logged is yet. Used for --quiet */
80 const char *cur_test_name
= NULL
;
83 /* Copy of argv[0] for win32. */
84 static char commandname
[MAX_PATH
+1];
87 static void usage(struct testgroup_t
*groups
, int list_groups
)
88 __attribute__((noreturn
));
89 static int process_test_option(struct testgroup_t
*groups
, const char *test
);
92 testcase_run_bare_(const struct testcase_t
*testcase
)
96 if (testcase
->setup
) {
97 env
= testcase
->setup
->setup_fn(testcase
);
100 else if (env
== (void*)TT_SKIP
)
104 cur_test_outcome
= OK
;
106 outcome
= cur_test_outcome
;
108 if (testcase
->setup
) {
109 if (testcase
->setup
->cleanup_fn(testcase
, env
) == 0)
116 #define MAGIC_EXITCODE 42
121 testcase_run_forked_(const struct testgroup_t
*group
,
122 const struct testcase_t
*testcase
)
125 /* Fork? On Win32? How primitive! We'll do what the smart kids do:
126 we'll invoke our own exe (whose name we recall from the command
127 line) with a command line that tells it to run just the test we
128 want, and this time without forking.
130 (No, threads aren't an option. The whole point of forking is to
131 share no state between tests.)
134 char buffer
[LONGEST_TEST_NAME
+256];
136 PROCESS_INFORMATION info
;
139 if (!in_tinytest_main
) {
140 printf("\nERROR. On Windows, testcase_run_forked_ must be"
141 " called from within tinytest_main.\n");
145 printf("[forking] ");
147 snprintf(buffer
, sizeof(buffer
), "%s --RUNNING-FORKED %s %s%s",
148 commandname
, verbosity_flag
, group
->prefix
, testcase
->name
);
150 memset(&si
, 0, sizeof(si
));
151 memset(&info
, 0, sizeof(info
));
154 ok
= CreateProcessA(commandname
, buffer
, NULL
, NULL
, 0,
155 0, NULL
, NULL
, &si
, &info
);
157 printf("CreateProcess failed!\n");
160 WaitForSingleObject(info
.hProcess
, INFINITE
);
161 GetExitCodeProcess(info
.hProcess
, &exitcode
);
162 CloseHandle(info
.hProcess
);
163 CloseHandle(info
.hThread
);
166 else if (exitcode
== MAGIC_EXITCODE
)
175 if (pipe(outcome_pipe
))
176 perror("opening pipe");
179 printf("[forking] ");
181 #ifdef FORK_BREAKS_GCOV
182 vproc_transaction_begin(0);
188 close(outcome_pipe
[0]);
189 test_r
= testcase_run_bare_(testcase
);
190 assert(0<=(int)test_r
&& (int)test_r
<=2);
191 b
[0] = "NYS"[test_r
];
192 write_r
= (int)write(outcome_pipe
[1], b
, 1);
194 perror("write outcome to pipe");
198 return FAIL
; /* unreachable */
203 /* Close this now, so that if the other side closes it,
205 close(outcome_pipe
[1]);
206 r
= (int)read(outcome_pipe
[0], b
, 1);
208 printf("[Lost connection!] ");
211 perror("read outcome from pipe");
213 waitpid(pid
, &status
, 0);
214 close(outcome_pipe
[0]);
215 return b
[0]=='Y' ? OK
: (b
[0]=='S' ? SKIP
: FAIL
);
220 #endif /* !NO_FORKING */
223 testcase_run_one(const struct testgroup_t
*group
,
224 const struct testcase_t
*testcase
)
226 enum outcome outcome
;
228 if (testcase
->flags
& (TT_SKIP
|TT_OFF_BY_DEFAULT
)) {
231 group
->prefix
, testcase
->name
,
232 (testcase
->flags
& TT_SKIP
) ? "SKIPPED" : "DISABLED");
237 if (opt_verbosity
>0 && !opt_forked
) {
238 printf("%s%s: ", group
->prefix
, testcase
->name
);
240 if (opt_verbosity
==0) printf(".");
241 cur_test_prefix
= group
->prefix
;
242 cur_test_name
= testcase
->name
;
246 if ((testcase
->flags
& TT_FORK
) && !(opt_forked
||opt_nofork
)) {
247 outcome
= testcase_run_forked_(group
, testcase
);
252 outcome
= testcase_run_bare_(testcase
);
257 if (opt_verbosity
>0 && !opt_forked
)
258 puts(opt_verbosity
==1?"OK":"");
259 } else if (outcome
== SKIP
) {
261 if (opt_verbosity
>0 && !opt_forked
)
266 printf("\n [%s FAILED]\n", testcase
->name
);
270 exit(outcome
==OK
? 0 : (outcome
==SKIP
?MAGIC_EXITCODE
: 1));
271 return 1; /* unreachable */
278 tinytest_set_flag_(struct testgroup_t
*groups
, const char *arg
, int set
, unsigned long flag
)
281 size_t length
= LONGEST_TEST_NAME
;
282 char fullname
[LONGEST_TEST_NAME
];
284 if (strstr(arg
, ".."))
285 length
= strstr(arg
,"..")-arg
;
286 for (i
=0; groups
[i
].prefix
; ++i
) {
287 for (j
=0; groups
[i
].cases
[j
].name
; ++j
) {
288 struct testcase_t
*testcase
= &groups
[i
].cases
[j
];
289 snprintf(fullname
, sizeof(fullname
), "%s%s",
290 groups
[i
].prefix
, testcase
->name
);
291 if (!flag
) { /* Hack! */
292 printf(" %s", fullname
);
293 if (testcase
->flags
& TT_OFF_BY_DEFAULT
)
294 puts(" (Off by default)");
295 else if (testcase
->flags
& TT_SKIP
)
300 if (!strncmp(fullname
, arg
, length
)) {
302 testcase
->flags
|= flag
;
304 testcase
->flags
&= ~flag
;
313 usage(struct testgroup_t
*groups
, int list_groups
)
315 puts("Options are: [--verbose|--quiet|--terse] [--no-fork]");
316 puts(" Specify tests by name, or using a prefix ending with '..'");
317 puts(" To skip a test, prefix its name with a colon.");
318 puts(" To enable a disabled test, prefix its name with a plus.");
319 puts(" Use --list-tests for a list of tests.");
321 puts("Known tests are:");
322 tinytest_set_flag_(groups
, "..", 1, 0);
328 process_test_alias(struct testgroup_t
*groups
, const char *test
)
331 for (i
=0; cfg_aliases
&& cfg_aliases
[i
].name
; ++i
) {
332 if (!strcmp(cfg_aliases
[i
].name
, test
)) {
334 for (j
= 0; cfg_aliases
[i
].tests
[j
]; ++j
) {
335 r
= process_test_option(groups
, cfg_aliases
[i
].tests
[j
]);
343 printf("No such test alias as @%s!",test
);
348 process_test_option(struct testgroup_t
*groups
, const char *test
)
350 int flag
= TT_ENABLED_
;
352 if (test
[0] == '@') {
353 return process_test_alias(groups
, test
+ 1);
354 } else if (test
[0] == ':') {
357 } else if (test
[0] == '+') {
360 if (!tinytest_set_flag_(groups
, test
, 0, TT_OFF_BY_DEFAULT
)) {
361 printf("No such test as %s!\n", test
);
367 if (!tinytest_set_flag_(groups
, test
, 1, flag
)) {
368 printf("No such test as %s!\n", test
);
375 tinytest_set_aliases(const struct testlist_alias_t
*aliases
)
377 cfg_aliases
= aliases
;
381 tinytest_main(int c
, const char **v
, struct testgroup_t
*groups
)
386 const char *sp
= strrchr(v
[0], '.');
387 const char *extension
= "";
388 if (!sp
|| stricmp(sp
, ".exe"))
389 extension
= ".exe"; /* Add an exe so CreateProcess will work */
390 snprintf(commandname
, sizeof(commandname
), "%s%s", v
[0], extension
);
391 commandname
[MAX_PATH
]='\0';
393 for (i
=1; i
<c
; ++i
) {
394 if (v
[i
][0] == '-') {
395 if (!strcmp(v
[i
], "--RUNNING-FORKED")) {
397 } else if (!strcmp(v
[i
], "--no-fork")) {
399 } else if (!strcmp(v
[i
], "--quiet")) {
401 verbosity_flag
= "--quiet";
402 } else if (!strcmp(v
[i
], "--verbose")) {
404 verbosity_flag
= "--verbose";
405 } else if (!strcmp(v
[i
], "--terse")) {
407 verbosity_flag
= "--terse";
408 } else if (!strcmp(v
[i
], "--help")) {
410 } else if (!strcmp(v
[i
], "--list-tests")) {
413 printf("Unknown option %s. Try --help\n",v
[i
]);
417 int r
= process_test_option(groups
, v
[i
]);
424 tinytest_set_flag_(groups
, "..", 1, TT_ENABLED_
);
427 setvbuf(stdout
, NULL
, _IONBF
, 0);
431 for (i
=0; groups
[i
].prefix
; ++i
)
432 for (j
=0; groups
[i
].cases
[j
].name
; ++j
)
433 if (groups
[i
].cases
[j
].flags
& TT_ENABLED_
)
434 testcase_run_one(&groups
[i
],
435 &groups
[i
].cases
[j
]);
439 if (opt_verbosity
==0)
443 printf("%d/%d TESTS FAILED. (%d skipped)\n", n_bad
,
444 n_bad
+n_ok
,n_skipped
);
445 else if (opt_verbosity
>= 1)
446 printf("%d tests ok. (%d skipped)\n", n_ok
, n_skipped
);
448 return (n_bad
== 0) ? 0 : 1;
452 tinytest_get_verbosity_(void)
454 return opt_verbosity
;
458 tinytest_set_test_failed_(void)
460 if (opt_verbosity
<= 0 && cur_test_name
) {
461 if (opt_verbosity
==0) puts("");
462 printf("%s%s: ", cur_test_prefix
, cur_test_name
);
463 cur_test_name
= NULL
;
465 cur_test_outcome
= 0;
469 tinytest_set_test_skipped_(void)
471 if (cur_test_outcome
==OK
)
472 cur_test_outcome
= SKIP
;
476 tinytest_format_hex_(const void *val_
, unsigned long len
)
478 const unsigned char *val
= val_
;
484 return strdup("null");
489 if (!(result
= malloc(len
*2+4)))
490 return strdup("<allocation failure>");
492 for (i
=0;i
<len
;++i
) {
493 *cp
++ = "0123456789ABCDEF"[(val
[i
] >> 4)&0x0f];
494 *cp
++ = "0123456789ABCDEF"[val
[i
] & 0x0f];