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>
44 #define __attribute__(x)
48 #include "tinytest_macros.h"
50 #define LONGEST_TEST_NAME 16384
52 static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/
53 static int n_ok = 0; /**< Number of tests that have passed */
54 static int n_bad = 0; /**< Number of tests that have failed. */
55 static int n_skipped = 0; /**< Number of tests that have been skipped. */
57 static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/
58 static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */
59 static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */
60 const char *verbosity_flag = "";
62 enum outcome { SKIP=2, OK=1, FAIL=0 };
63 static enum outcome cur_test_outcome = 0;
64 const char *cur_test_prefix = NULL; /**< prefix of the current test group */
65 /** Name of the current test, if we haven't logged is yet. Used for --quiet */
66 const char *cur_test_name = NULL;
69 /* Copy of argv[0] for win32. */
70 static char commandname[MAX_PATH+1];
73 static void usage(struct testgroup_t *groups, int list_groups)
74 __attribute__((noreturn));
77 _testcase_run_bare(const struct testcase_t *testcase)
81 if (testcase->setup) {
82 env = testcase->setup->setup_fn(testcase);
85 else if (env == (void*)TT_SKIP)
89 cur_test_outcome = OK;
91 outcome = cur_test_outcome;
93 if (testcase->setup) {
94 if (testcase->setup->cleanup_fn(testcase, env) == 0)
101 #define MAGIC_EXITCODE 42
104 _testcase_run_forked(const struct testgroup_t *group,
105 const struct testcase_t *testcase)
108 /* Fork? On Win32? How primitive! We'll do what the smart kids do:
109 we'll invoke our own exe (whose name we recall from the command
110 line) with a command line that tells it to run just the test we
111 want, and this time without forking.
113 (No, threads aren't an option. The whole point of forking is to
114 share no state between tests.)
117 char buffer[LONGEST_TEST_NAME+256];
119 PROCESS_INFORMATION info;
122 if (!in_tinytest_main) {
123 printf("\nERROR. On Windows, _testcase_run_forked must be"
124 " called from within tinytest_main.\n");
128 printf("[forking] ");
130 snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s %s%s",
131 commandname, verbosity_flag, group->prefix, testcase->name);
133 memset(&si, 0, sizeof(si));
134 memset(&info, 0, sizeof(info));
137 ok = CreateProcessA(commandname, buffer, NULL, NULL, 0,
138 0, NULL, NULL, &si, &info);
140 printf("CreateProcess failed!\n");
143 WaitForSingleObject(info.hProcess, INFINITE);
144 GetExitCodeProcess(info.hProcess, &exitcode);
145 CloseHandle(info.hProcess);
146 CloseHandle(info.hThread);
149 else if (exitcode == MAGIC_EXITCODE)
158 if (pipe(outcome_pipe))
159 perror("opening pipe");
162 printf("[forking] ");
168 close(outcome_pipe[0]);
169 test_r = _testcase_run_bare(testcase);
170 assert(0<=(int)test_r && (int)test_r<=2);
171 b[0] = "NYS"[test_r];
172 write_r = (int)write(outcome_pipe[1], b, 1);
174 perror("write outcome to pipe");
178 return FAIL; /* unreachable */
183 /* Close this now, so that if the other side closes it,
185 close(outcome_pipe[1]);
186 r = (int)read(outcome_pipe[0], b, 1);
188 printf("[Lost connection!] ");
191 perror("read outcome from pipe");
193 waitpid(pid, &status, 0);
194 close(outcome_pipe[0]);
195 return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL);
201 testcase_run_one(const struct testgroup_t *group,
202 const struct testcase_t *testcase)
204 enum outcome outcome;
206 if (testcase->flags & TT_SKIP) {
208 printf("%s%s: SKIPPED\n",
209 group->prefix, testcase->name);
214 if (opt_verbosity>0 && !opt_forked) {
215 printf("%s%s: ", group->prefix, testcase->name);
217 if (opt_verbosity==0) printf(".");
218 cur_test_prefix = group->prefix;
219 cur_test_name = testcase->name;
222 if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) {
223 outcome = _testcase_run_forked(group, testcase);
225 outcome = _testcase_run_bare(testcase);
230 if (opt_verbosity>0 && !opt_forked)
231 puts(opt_verbosity==1?"OK":"");
232 } else if (outcome == SKIP) {
234 if (opt_verbosity>0 && !opt_forked)
239 printf("\n [%s FAILED]\n", testcase->name);
243 exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1));
244 return 1; /* unreachable */
251 _tinytest_set_flag(struct testgroup_t *groups, const char *arg, unsigned long flag)
254 size_t length = LONGEST_TEST_NAME;
255 char fullname[LONGEST_TEST_NAME];
257 if (strstr(arg, ".."))
258 length = strstr(arg,"..")-arg;
259 for (i=0; groups[i].prefix; ++i) {
260 for (j=0; groups[i].cases[j].name; ++j) {
261 snprintf(fullname, sizeof(fullname), "%s%s",
262 groups[i].prefix, groups[i].cases[j].name);
263 if (!flag) /* Hack! */
264 printf(" %s\n", fullname);
265 if (!strncmp(fullname, arg, length)) {
266 groups[i].cases[j].flags |= flag;
275 usage(struct testgroup_t *groups, int list_groups)
277 puts("Options are: [--verbose|--quiet|--terse] [--no-fork]");
278 puts(" Specify tests by name, or using a prefix ending with '..'");
279 puts(" To skip a test, list give its name prefixed with a colon.");
280 puts(" Use --list-tests for a list of tests.");
282 puts("Known tests are:");
283 _tinytest_set_flag(groups, "..", 0);
289 tinytest_main(int c, const char **v, struct testgroup_t *groups)
294 const char *sp = strrchr(v[0], '.');
295 const char *extension = "";
296 if (!sp || stricmp(sp, ".exe"))
297 extension = ".exe"; /* Add an exe so CreateProcess will work */
298 snprintf(commandname, sizeof(commandname), "%s%s", v[0], extension);
299 commandname[MAX_PATH]='\0';
301 for (i=1; i<c; ++i) {
302 if (v[i][0] == '-') {
303 if (!strcmp(v[i], "--RUNNING-FORKED")) {
305 } else if (!strcmp(v[i], "--no-fork")) {
307 } else if (!strcmp(v[i], "--quiet")) {
309 verbosity_flag = "--quiet";
310 } else if (!strcmp(v[i], "--verbose")) {
312 verbosity_flag = "--verbose";
313 } else if (!strcmp(v[i], "--terse")) {
315 verbosity_flag = "--terse";
316 } else if (!strcmp(v[i], "--help")) {
318 } else if (!strcmp(v[i], "--list-tests")) {
321 printf("Unknown option %s. Try --help\n",v[i]);
325 const char *test = v[i];
326 int flag = _TT_ENABLED;
327 if (test[0] == ':') {
333 if (!_tinytest_set_flag(groups, test, flag)) {
334 printf("No such test as %s!\n", v[i]);
340 _tinytest_set_flag(groups, "..", _TT_ENABLED);
342 setvbuf(stdout, NULL, _IONBF, 0);
345 for (i=0; groups[i].prefix; ++i)
346 for (j=0; groups[i].cases[j].name; ++j)
347 if (groups[i].cases[j].flags & _TT_ENABLED)
348 testcase_run_one(&groups[i],
349 &groups[i].cases[j]);
353 if (opt_verbosity==0)
357 printf("%d/%d TESTS FAILED. (%d skipped)\n", n_bad,
358 n_bad+n_ok,n_skipped);
359 else if (opt_verbosity >= 1)
360 printf("%d tests ok. (%d skipped)\n", n_ok, n_skipped);
362 return (n_bad == 0) ? 0 : 1;
366 _tinytest_get_verbosity(void)
368 return opt_verbosity;
372 _tinytest_set_test_failed(void)
374 if (opt_verbosity <= 0 && cur_test_name) {
375 if (opt_verbosity==0) puts("");
376 printf("%s%s: ", cur_test_prefix, cur_test_name);
377 cur_test_name = NULL;
379 cur_test_outcome = 0;
383 _tinytest_set_test_skipped(void)
385 if (cur_test_outcome==OK)
386 cur_test_outcome = SKIP;