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"
37 #include <sys/types.h>
43 #define __attribute__(x)
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 /* Copy of argv[0] for win32. */
69 static char commandname
[MAX_PATH
+1];
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");
177 return FAIL
; /* unreachable */
182 /* Close this now, so that if the other side closes it,
184 close(outcome_pipe
[1]);
185 r
= (int)read(outcome_pipe
[0], b
, 1);
187 printf("[Lost connection!] ");
190 perror("read outcome from pipe");
192 waitpid(pid
, &status
, 0);
193 close(outcome_pipe
[0]);
194 return b
[0]=='Y' ? OK
: (b
[0]=='S' ? SKIP
: FAIL
);
200 testcase_run_one(const struct testgroup_t
*group
,
201 const struct testcase_t
*testcase
)
203 enum outcome outcome
;
205 if (testcase
->flags
& TT_SKIP
) {
207 printf("%s%s: SKIPPED\n",
208 group
->prefix
, testcase
->name
);
213 if (opt_verbosity
>0 && !opt_forked
) {
214 printf("%s%s: ", group
->prefix
, testcase
->name
);
216 if (opt_verbosity
==0) printf(".");
217 cur_test_prefix
= group
->prefix
;
218 cur_test_name
= testcase
->name
;
221 if ((testcase
->flags
& TT_FORK
) && !(opt_forked
||opt_nofork
)) {
222 outcome
= testcase_run_forked_(group
, testcase
);
224 outcome
= testcase_run_bare_(testcase
);
229 if (opt_verbosity
>0 && !opt_forked
)
230 puts(opt_verbosity
==1?"OK":"");
231 } else if (outcome
== SKIP
) {
233 if (opt_verbosity
>0 && !opt_forked
)
238 printf("\n [%s FAILED]\n", testcase
->name
);
242 exit(outcome
==OK
? 0 : (outcome
==SKIP
?MAGIC_EXITCODE
: 1));
243 return 1; /* unreachable */
250 tinytest_set_flag_(struct testgroup_t
*groups
, const char *arg
, unsigned long flag
)
253 size_t length
= LONGEST_TEST_NAME
;
254 char fullname
[LONGEST_TEST_NAME
];
256 if (strstr(arg
, ".."))
257 length
= strstr(arg
,"..")-arg
;
258 for (i
=0; groups
[i
].prefix
; ++i
) {
259 for (j
=0; groups
[i
].cases
[j
].name
; ++j
) {
260 snprintf(fullname
, sizeof(fullname
), "%s%s",
261 groups
[i
].prefix
, groups
[i
].cases
[j
].name
);
262 if (!flag
) /* Hack! */
263 printf(" %s\n", fullname
);
264 if (!strncmp(fullname
, arg
, length
)) {
265 groups
[i
].cases
[j
].flags
|= flag
;
274 usage(struct testgroup_t
*groups
, int list_groups
)
276 puts("Options are: [--verbose|--quiet|--terse] [--no-fork]");
277 puts(" Specify tests by name, or using a prefix ending with '..'");
278 puts(" To skip a test, list give its name prefixed with a colon.");
279 puts(" Use --list-tests for a list of tests.");
281 puts("Known tests are:");
282 tinytest_set_flag_(groups
, "..", 0);
288 tinytest_main(int c
, const char **v
, struct testgroup_t
*groups
)
293 const char *sp
= strrchr(v
[0], '.');
294 const char *extension
= "";
295 if (!sp
|| stricmp(sp
, ".exe"))
296 extension
= ".exe"; /* Add an exe so CreateProcess will work */
297 snprintf(commandname
, sizeof(commandname
), "%s%s", v
[0], extension
);
298 commandname
[MAX_PATH
]='\0';
300 for (i
=1; i
<c
; ++i
) {
301 if (v
[i
][0] == '-') {
302 if (!strcmp(v
[i
], "--RUNNING-FORKED")) {
304 } else if (!strcmp(v
[i
], "--no-fork")) {
306 } else if (!strcmp(v
[i
], "--quiet")) {
308 verbosity_flag
= "--quiet";
309 } else if (!strcmp(v
[i
], "--verbose")) {
311 verbosity_flag
= "--verbose";
312 } else if (!strcmp(v
[i
], "--terse")) {
314 verbosity_flag
= "--terse";
315 } else if (!strcmp(v
[i
], "--help")) {
317 } else if (!strcmp(v
[i
], "--list-tests")) {
320 printf("Unknown option %s. Try --help\n",v
[i
]);
324 const char *test
= v
[i
];
325 int flag
= TT_ENABLED_
;
326 if (test
[0] == ':') {
332 if (!tinytest_set_flag_(groups
, test
, flag
)) {
333 printf("No such test as %s!\n", v
[i
]);
339 tinytest_set_flag_(groups
, "..", TT_ENABLED_
);
341 setvbuf(stdout
, NULL
, _IONBF
, 0);
344 for (i
=0; groups
[i
].prefix
; ++i
)
345 for (j
=0; groups
[i
].cases
[j
].name
; ++j
)
346 if (groups
[i
].cases
[j
].flags
& TT_ENABLED_
)
347 testcase_run_one(&groups
[i
],
348 &groups
[i
].cases
[j
]);
352 if (opt_verbosity
==0)
356 printf("%d/%d TESTS FAILED. (%d skipped)\n", n_bad
,
357 n_bad
+n_ok
,n_skipped
);
358 else if (opt_verbosity
>= 1)
359 printf("%d tests ok. (%d skipped)\n", n_ok
, n_skipped
);
361 return (n_bad
== 0) ? 0 : 1;
365 tinytest_get_verbosity_(void)
367 return opt_verbosity
;
371 tinytest_set_test_failed_(void)
373 if (opt_verbosity
<= 0 && cur_test_name
) {
374 if (opt_verbosity
==0) puts("");
375 printf("%s%s: ", cur_test_prefix
, cur_test_name
);
376 cur_test_name
= NULL
;
378 cur_test_outcome
= 0;
382 tinytest_set_test_skipped_(void)
384 if (cur_test_outcome
==OK
)
385 cur_test_outcome
= SKIP
;