1 /* tinytest.c -- Copyright 2009-2010 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.
34 #include <sys/types.h>
40 #define __attribute__(x)
44 #include "tinytest_local.h"
47 #include "tinytest_macros.h"
49 #define LONGEST_TEST_NAME 16384
51 static int in_tinytest_main
= 0; /**< true if we're in tinytest_main().*/
52 static int n_ok
= 0; /**< Number of tests that have passed */
53 static int n_bad
= 0; /**< Number of tests that have failed. */
54 static int n_skipped
= 0; /**< Number of tests that have been skipped. */
56 static int opt_forked
= 0; /**< True iff we're called from inside a win32 fork*/
57 static int opt_nofork
= 0; /**< Suppress calls to fork() for debugging. */
58 static int opt_verbosity
= 1; /**< -==quiet,0==terse,1==normal,2==verbose */
59 const char *verbosity_flag
= "";
61 enum outcome
{ SKIP
=2, OK
=1, FAIL
=0 };
62 static enum outcome cur_test_outcome
= 0;
63 const char *cur_test_prefix
= NULL
; /**< prefix of the current test group */
64 /** Name of the current test, if we haven't logged is yet. Used for --quiet */
65 const char *cur_test_name
= NULL
;
68 /** Pointer to argv[0] for win32. */
69 static const char *commandname
= NULL
;
72 static void usage(struct testgroup_t
*groups
, int list_groups
)
73 __attribute__((noreturn
));
76 _testcase_run_bare(const struct testcase_t
*testcase
)
80 if (testcase
->setup
) {
81 env
= testcase
->setup
->setup_fn(testcase
);
84 else if (env
== (void*)TT_SKIP
)
88 cur_test_outcome
= OK
;
90 outcome
= cur_test_outcome
;
92 if (testcase
->setup
) {
93 if (testcase
->setup
->cleanup_fn(testcase
, env
) == 0)
100 #define MAGIC_EXITCODE 42
103 _testcase_run_forked(const struct testgroup_t
*group
,
104 const struct testcase_t
*testcase
)
107 /* Fork? On Win32? How primitive! We'll do what the smart kids do:
108 we'll invoke our own exe (whose name we recall from the command
109 line) with a command line that tells it to run just the test we
110 want, and this time without forking.
112 (No, threads aren't an option. The whole point of forking is to
113 share no state between tests.)
116 char buffer
[LONGEST_TEST_NAME
+256];
118 PROCESS_INFORMATION info
;
121 if (!in_tinytest_main
) {
122 printf("\nERROR. On Windows, _testcase_run_forked must be"
123 " called from within tinytest_main.\n");
127 printf("[forking] ");
129 snprintf(buffer
, sizeof(buffer
), "%s --RUNNING-FORKED %s %s%s",
130 commandname
, verbosity_flag
, group
->prefix
, testcase
->name
);
132 memset(&si
, 0, sizeof(si
));
133 memset(&info
, 0, sizeof(info
));
136 ok
= CreateProcessA(commandname
, buffer
, NULL
, NULL
, 0,
137 0, NULL
, NULL
, &si
, &info
);
139 printf("CreateProcess failed!\n");
142 WaitForSingleObject(info
.hProcess
, INFINITE
);
143 GetExitCodeProcess(info
.hProcess
, &exitcode
);
144 CloseHandle(info
.hProcess
);
145 CloseHandle(info
.hThread
);
148 else if (exitcode
== MAGIC_EXITCODE
)
157 if (pipe(outcome_pipe
))
158 perror("opening pipe");
161 printf("[forking] ");
167 close(outcome_pipe
[0]);
168 test_r
= _testcase_run_bare(testcase
);
169 assert(0<=(int)test_r
&& (int)test_r
<=2);
170 b
[0] = "NYS"[test_r
];
171 write_r
= (int)write(outcome_pipe
[1], b
, 1);
173 perror("write outcome to pipe");
181 /* Close this now, so that if the other side closes it,
183 close(outcome_pipe
[1]);
184 r
= (int)read(outcome_pipe
[0], b
, 1);
186 printf("[Lost connection!] ");
189 perror("read outcome from pipe");
191 waitpid(pid
, &status
, 0);
192 close(outcome_pipe
[0]);
193 return b
[0]=='Y' ? OK
: (b
[0]=='S' ? SKIP
: FAIL
);
199 testcase_run_one(const struct testgroup_t
*group
,
200 const struct testcase_t
*testcase
)
202 enum outcome outcome
;
204 if (testcase
->flags
& TT_SKIP
) {
206 printf("%s%s: SKIPPED\n",
207 group
->prefix
, testcase
->name
);
212 if (opt_verbosity
>0 && !opt_forked
) {
213 printf("%s%s: ", group
->prefix
, testcase
->name
);
215 if (opt_verbosity
==0) printf(".");
216 cur_test_prefix
= group
->prefix
;
217 cur_test_name
= testcase
->name
;
220 if ((testcase
->flags
& TT_FORK
) && !(opt_forked
||opt_nofork
)) {
221 outcome
= _testcase_run_forked(group
, testcase
);
223 outcome
= _testcase_run_bare(testcase
);
228 if (opt_verbosity
>0 && !opt_forked
)
229 puts(opt_verbosity
==1?"OK":"");
230 } else if (outcome
== SKIP
) {
232 if (opt_verbosity
>0 && !opt_forked
)
237 printf("\n [%s FAILED]\n", testcase
->name
);
241 exit(outcome
==OK
? 0 : (outcome
==SKIP
?MAGIC_EXITCODE
: 1));
248 _tinytest_set_flag(struct testgroup_t
*groups
, const char *arg
, unsigned long flag
)
251 size_t length
= LONGEST_TEST_NAME
;
252 char fullname
[LONGEST_TEST_NAME
];
254 if (strstr(arg
, ".."))
255 length
= strstr(arg
,"..")-arg
;
256 for (i
=0; groups
[i
].prefix
; ++i
) {
257 for (j
=0; groups
[i
].cases
[j
].name
; ++j
) {
258 snprintf(fullname
, sizeof(fullname
), "%s%s",
259 groups
[i
].prefix
, groups
[i
].cases
[j
].name
);
260 if (!flag
) /* Hack! */
261 printf(" %s\n", fullname
);
262 if (!strncmp(fullname
, arg
, length
)) {
263 groups
[i
].cases
[j
].flags
|= flag
;
272 usage(struct testgroup_t
*groups
, int list_groups
)
274 puts("Options are: [--verbose|--quiet|--terse] [--no-fork]");
275 puts(" Specify tests by name, or using a prefix ending with '..'");
276 puts(" To skip a test, list give its name prefixed with a colon.");
277 puts(" Use --list-tests for a list of tests.");
279 puts("Known tests are:");
280 _tinytest_set_flag(groups
, "..", 0);
286 tinytest_main(int c
, const char **v
, struct testgroup_t
*groups
)
293 for (i
=1; i
<c
; ++i
) {
294 if (v
[i
][0] == '-') {
295 if (!strcmp(v
[i
], "--RUNNING-FORKED")) {
297 } else if (!strcmp(v
[i
], "--no-fork")) {
299 } else if (!strcmp(v
[i
], "--quiet")) {
301 verbosity_flag
= "--quiet";
302 } else if (!strcmp(v
[i
], "--verbose")) {
304 verbosity_flag
= "--verbose";
305 } else if (!strcmp(v
[i
], "--terse")) {
307 verbosity_flag
= "--terse";
308 } else if (!strcmp(v
[i
], "--help")) {
310 } else if (!strcmp(v
[i
], "--list-tests")) {
313 printf("Unknown option %s. Try --help\n",v
[i
]);
317 const char *test
= v
[i
];
318 int flag
= _TT_ENABLED
;
319 if (test
[0] == ':') {
325 if (!_tinytest_set_flag(groups
, test
, flag
)) {
326 printf("No such test as %s!\n", v
[i
]);
332 _tinytest_set_flag(groups
, "..", _TT_ENABLED
);
334 setvbuf(stdout
, NULL
, _IONBF
, 0);
337 for (i
=0; groups
[i
].prefix
; ++i
)
338 for (j
=0; groups
[i
].cases
[j
].name
; ++j
)
339 if (groups
[i
].cases
[j
].flags
& _TT_ENABLED
)
340 testcase_run_one(&groups
[i
],
341 &groups
[i
].cases
[j
]);
345 if (opt_verbosity
==0)
349 printf("%d/%d TESTS FAILED. (%d skipped)\n", n_bad
,
350 n_bad
+n_ok
,n_skipped
);
351 else if (opt_verbosity
>= 1)
352 printf("%d tests ok. (%d skipped)\n", n_ok
, n_skipped
);
354 return (n_bad
== 0) ? 0 : 1;
358 _tinytest_get_verbosity(void)
360 return opt_verbosity
;
364 _tinytest_set_test_failed(void)
366 if (opt_verbosity
<= 0 && cur_test_name
) {
367 if (opt_verbosity
==0) puts("");
368 printf("%s%s: ", cur_test_prefix
, cur_test_name
);
369 cur_test_name
= NULL
;
371 cur_test_outcome
= 0;
375 _tinytest_set_test_skipped(void)
377 if (cur_test_outcome
==OK
)
378 cur_test_outcome
= SKIP
;