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.
32 #include "tinytest_local.h"
38 #include <sys/types.h>
43 #if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
44 #if (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060 && \
45 __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070)
46 /* Workaround for a stupid bug in OSX 10.6 */
47 #define FORK_BREAKS_GCOV
53 #define __attribute__(x)
57 #include "tinytest_macros.h"
59 #define LONGEST_TEST_NAME 16384
61 static int in_tinytest_main
= 0; /**< true if we're in tinytest_main().*/
62 static int n_ok
= 0; /**< Number of tests that have passed */
63 static int n_bad
= 0; /**< Number of tests that have failed. */
64 static int n_skipped
= 0; /**< Number of tests that have been skipped. */
66 static int opt_forked
= 0; /**< True iff we're called from inside a win32 fork*/
67 static int opt_nofork
= 0; /**< Suppress calls to fork() for debugging. */
68 static int opt_verbosity
= 1; /**< -==quiet,0==terse,1==normal,2==verbose */
69 const char *verbosity_flag
= "";
71 enum outcome
{ SKIP
=2, OK
=1, FAIL
=0 };
72 static enum outcome cur_test_outcome
= 0;
73 const char *cur_test_prefix
= NULL
; /**< prefix of the current test group */
74 /** Name of the current test, if we haven't logged is yet. Used for --quiet */
75 const char *cur_test_name
= NULL
;
78 /* Copy of argv[0] for win32. */
79 static char commandname
[MAX_PATH
+1];
82 static void usage(struct testgroup_t
*groups
, int list_groups
)
83 __attribute__((noreturn
));
86 _testcase_run_bare(const struct testcase_t
*testcase
)
90 if (testcase
->setup
) {
91 env
= testcase
->setup
->setup_fn(testcase
);
94 else if (env
== (void*)TT_SKIP
)
98 cur_test_outcome
= OK
;
100 outcome
= cur_test_outcome
;
102 if (testcase
->setup
) {
103 if (testcase
->setup
->cleanup_fn(testcase
, env
) == 0)
110 #define MAGIC_EXITCODE 42
113 _testcase_run_forked(const struct testgroup_t
*group
,
114 const struct testcase_t
*testcase
)
117 /* Fork? On Win32? How primitive! We'll do what the smart kids do:
118 we'll invoke our own exe (whose name we recall from the command
119 line) with a command line that tells it to run just the test we
120 want, and this time without forking.
122 (No, threads aren't an option. The whole point of forking is to
123 share no state between tests.)
126 char buffer
[LONGEST_TEST_NAME
+256];
128 PROCESS_INFORMATION info
;
131 if (!in_tinytest_main
) {
132 printf("\nERROR. On Windows, _testcase_run_forked must be"
133 " called from within tinytest_main.\n");
137 printf("[forking] ");
139 snprintf(buffer
, sizeof(buffer
), "%s --RUNNING-FORKED %s %s%s",
140 commandname
, verbosity_flag
, group
->prefix
, testcase
->name
);
142 memset(&si
, 0, sizeof(si
));
143 memset(&info
, 0, sizeof(info
));
146 ok
= CreateProcessA(commandname
, buffer
, NULL
, NULL
, 0,
147 0, NULL
, NULL
, &si
, &info
);
149 printf("CreateProcess failed!\n");
152 WaitForSingleObject(info
.hProcess
, INFINITE
);
153 GetExitCodeProcess(info
.hProcess
, &exitcode
);
154 CloseHandle(info
.hProcess
);
155 CloseHandle(info
.hThread
);
158 else if (exitcode
== MAGIC_EXITCODE
)
167 if (pipe(outcome_pipe
))
168 perror("opening pipe");
171 printf("[forking] ");
173 #ifdef FORK_BREAKS_GCOV
174 vproc_transaction_begin(0);
180 close(outcome_pipe
[0]);
181 test_r
= _testcase_run_bare(testcase
);
182 assert(0<=(int)test_r
&& (int)test_r
<=2);
183 b
[0] = "NYS"[test_r
];
184 write_r
= (int)write(outcome_pipe
[1], b
, 1);
186 perror("write outcome to pipe");
190 return FAIL
; /* unreachable */
195 /* Close this now, so that if the other side closes it,
197 close(outcome_pipe
[1]);
198 r
= (int)read(outcome_pipe
[0], b
, 1);
200 printf("[Lost connection!] ");
203 perror("read outcome from pipe");
205 waitpid(pid
, &status
, 0);
206 close(outcome_pipe
[0]);
207 return b
[0]=='Y' ? OK
: (b
[0]=='S' ? SKIP
: FAIL
);
213 testcase_run_one(const struct testgroup_t
*group
,
214 const struct testcase_t
*testcase
)
216 enum outcome outcome
;
218 if (testcase
->flags
& TT_SKIP
) {
220 printf("%s%s: SKIPPED\n",
221 group
->prefix
, testcase
->name
);
226 if (opt_verbosity
>0 && !opt_forked
) {
227 printf("%s%s: ", group
->prefix
, testcase
->name
);
229 if (opt_verbosity
==0) printf(".");
230 cur_test_prefix
= group
->prefix
;
231 cur_test_name
= testcase
->name
;
234 if ((testcase
->flags
& TT_FORK
) && !(opt_forked
||opt_nofork
)) {
235 outcome
= _testcase_run_forked(group
, testcase
);
237 outcome
= _testcase_run_bare(testcase
);
242 if (opt_verbosity
>0 && !opt_forked
)
243 puts(opt_verbosity
==1?"OK":"");
244 } else if (outcome
== SKIP
) {
246 if (opt_verbosity
>0 && !opt_forked
)
251 printf("\n [%s FAILED]\n", testcase
->name
);
255 exit(outcome
==OK
? 0 : (outcome
==SKIP
?MAGIC_EXITCODE
: 1));
256 return 1; /* unreachable */
263 _tinytest_set_flag(struct testgroup_t
*groups
, const char *arg
, unsigned long flag
)
266 size_t length
= LONGEST_TEST_NAME
;
267 char fullname
[LONGEST_TEST_NAME
];
269 if (strstr(arg
, ".."))
270 length
= strstr(arg
,"..")-arg
;
271 for (i
=0; groups
[i
].prefix
; ++i
) {
272 for (j
=0; groups
[i
].cases
[j
].name
; ++j
) {
273 snprintf(fullname
, sizeof(fullname
), "%s%s",
274 groups
[i
].prefix
, groups
[i
].cases
[j
].name
);
275 if (!flag
) /* Hack! */
276 printf(" %s\n", fullname
);
277 if (!strncmp(fullname
, arg
, length
)) {
278 groups
[i
].cases
[j
].flags
|= flag
;
287 usage(struct testgroup_t
*groups
, int list_groups
)
289 puts("Options are: [--verbose|--quiet|--terse] [--no-fork]");
290 puts(" Specify tests by name, or using a prefix ending with '..'");
291 puts(" To skip a test, list give its name prefixed with a colon.");
292 puts(" Use --list-tests for a list of tests.");
294 puts("Known tests are:");
295 _tinytest_set_flag(groups
, "..", 0);
301 tinytest_main(int c
, const char **v
, struct testgroup_t
*groups
)
306 const char *sp
= strrchr(v
[0], '.');
307 const char *extension
= "";
308 if (!sp
|| stricmp(sp
, ".exe"))
309 extension
= ".exe"; /* Add an exe so CreateProcess will work */
310 snprintf(commandname
, sizeof(commandname
), "%s%s", v
[0], extension
);
311 commandname
[MAX_PATH
]='\0';
313 for (i
=1; i
<c
; ++i
) {
314 if (v
[i
][0] == '-') {
315 if (!strcmp(v
[i
], "--RUNNING-FORKED")) {
317 } else if (!strcmp(v
[i
], "--no-fork")) {
319 } else if (!strcmp(v
[i
], "--quiet")) {
321 verbosity_flag
= "--quiet";
322 } else if (!strcmp(v
[i
], "--verbose")) {
324 verbosity_flag
= "--verbose";
325 } else if (!strcmp(v
[i
], "--terse")) {
327 verbosity_flag
= "--terse";
328 } else if (!strcmp(v
[i
], "--help")) {
330 } else if (!strcmp(v
[i
], "--list-tests")) {
333 printf("Unknown option %s. Try --help\n",v
[i
]);
337 const char *test
= v
[i
];
338 int flag
= _TT_ENABLED
;
339 if (test
[0] == ':') {
345 if (!_tinytest_set_flag(groups
, test
, flag
)) {
346 printf("No such test as %s!\n", v
[i
]);
352 _tinytest_set_flag(groups
, "..", _TT_ENABLED
);
354 setvbuf(stdout
, NULL
, _IONBF
, 0);
357 for (i
=0; groups
[i
].prefix
; ++i
)
358 for (j
=0; groups
[i
].cases
[j
].name
; ++j
)
359 if (groups
[i
].cases
[j
].flags
& _TT_ENABLED
)
360 testcase_run_one(&groups
[i
],
361 &groups
[i
].cases
[j
]);
365 if (opt_verbosity
==0)
369 printf("%d/%d TESTS FAILED. (%d skipped)\n", n_bad
,
370 n_bad
+n_ok
,n_skipped
);
371 else if (opt_verbosity
>= 1)
372 printf("%d tests ok. (%d skipped)\n", n_ok
, n_skipped
);
374 return (n_bad
== 0) ? 0 : 1;
378 _tinytest_get_verbosity(void)
380 return opt_verbosity
;
384 _tinytest_set_test_failed(void)
386 if (opt_verbosity
<= 0 && cur_test_name
) {
387 if (opt_verbosity
==0) puts("");
388 printf("%s%s: ", cur_test_prefix
, cur_test_name
);
389 cur_test_name
= NULL
;
391 cur_test_outcome
= 0;
395 _tinytest_set_test_skipped(void)
397 if (cur_test_outcome
==OK
)
398 cur_test_outcome
= SKIP
;