Merge remote branch 'origin/maint-0.2.1' into maint-0.2.2
[tor/rransom.git] / src / test / tinytest.c
blob11ffc2fe564e86f8e583160165605ce0e648ac90
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
5 * are met:
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 <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <assert.h>
31 #ifdef WIN32
32 #include <windows.h>
33 #else
34 #include <sys/types.h>
35 #include <sys/wait.h>
36 #include <unistd.h>
37 #endif
39 #ifndef __GNUC__
40 #define __attribute__(x)
41 #endif
43 #ifdef TINYTEST_LOCAL
44 #include "tinytest_local.h"
45 #endif
46 #include "tinytest.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;
67 #ifdef WIN32
68 /** Pointer to argv[0] for win32. */
69 static const char *commandname = NULL;
70 #endif
72 static void usage(struct testgroup_t *groups, int list_groups)
73 __attribute__((noreturn));
75 static enum outcome
76 _testcase_run_bare(const struct testcase_t *testcase)
78 void *env = NULL;
79 int outcome;
80 if (testcase->setup) {
81 env = testcase->setup->setup_fn(testcase);
82 if (!env)
83 return FAIL;
84 else if (env == (void*)TT_SKIP)
85 return SKIP;
88 cur_test_outcome = OK;
89 testcase->fn(env);
90 outcome = cur_test_outcome;
92 if (testcase->setup) {
93 if (testcase->setup->cleanup_fn(testcase, env) == 0)
94 outcome = FAIL;
97 return outcome;
100 #define MAGIC_EXITCODE 42
102 static enum outcome
103 _testcase_run_forked(const struct testgroup_t *group,
104 const struct testcase_t *testcase)
106 #ifdef WIN32
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.)
115 int ok;
116 char buffer[LONGEST_TEST_NAME+256];
117 STARTUPINFOA si;
118 PROCESS_INFORMATION info;
119 DWORD exitcode;
121 if (!in_tinytest_main) {
122 printf("\nERROR. On Windows, _testcase_run_forked must be"
123 " called from within tinytest_main.\n");
124 abort();
126 if (opt_verbosity>0)
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));
134 si.cb = sizeof(si);
136 ok = CreateProcessA(commandname, buffer, NULL, NULL, 0,
137 0, NULL, NULL, &si, &info);
138 if (!ok) {
139 printf("CreateProcess failed!\n");
140 return 0;
142 WaitForSingleObject(info.hProcess, INFINITE);
143 GetExitCodeProcess(info.hProcess, &exitcode);
144 CloseHandle(info.hProcess);
145 CloseHandle(info.hThread);
146 if (exitcode == 0)
147 return OK;
148 else if (exitcode == MAGIC_EXITCODE)
149 return SKIP;
150 else
151 return FAIL;
152 #else
153 int outcome_pipe[2];
154 pid_t pid;
155 (void)group;
157 if (pipe(outcome_pipe))
158 perror("opening pipe");
160 if (opt_verbosity>0)
161 printf("[forking] ");
162 pid = fork();
163 if (!pid) {
164 /* child. */
165 int test_r, write_r;
166 char b[1];
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);
172 if (write_r != 1) {
173 perror("write outcome to pipe");
174 exit(1);
176 exit(0);
177 } else {
178 /* parent */
179 int status, r;
180 char b[1];
181 /* Close this now, so that if the other side closes it,
182 * our read fails. */
183 close(outcome_pipe[1]);
184 r = (int)read(outcome_pipe[0], b, 1);
185 if (r == 0) {
186 printf("[Lost connection!] ");
187 return 0;
188 } else if (r != 1) {
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);
195 #endif
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) {
205 if (opt_verbosity>0)
206 printf("%s%s: SKIPPED\n",
207 group->prefix, testcase->name);
208 ++n_skipped;
209 return SKIP;
212 if (opt_verbosity>0 && !opt_forked) {
213 printf("%s%s: ", group->prefix, testcase->name);
214 } else {
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);
222 } else {
223 outcome = _testcase_run_bare(testcase);
226 if (outcome == OK) {
227 ++n_ok;
228 if (opt_verbosity>0 && !opt_forked)
229 puts(opt_verbosity==1?"OK":"");
230 } else if (outcome == SKIP) {
231 ++n_skipped;
232 if (opt_verbosity>0 && !opt_forked)
233 puts("SKIPPED");
234 } else {
235 ++n_bad;
236 if (!opt_forked)
237 printf("\n [%s FAILED]\n", testcase->name);
240 if (opt_forked) {
241 exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1));
242 } else {
243 return (int)outcome;
248 _tinytest_set_flag(struct testgroup_t *groups, const char *arg, unsigned long flag)
250 int i, j;
251 size_t length = LONGEST_TEST_NAME;
252 char fullname[LONGEST_TEST_NAME];
253 int found=0;
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;
264 ++found;
268 return found;
271 static void
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.");
278 if (list_groups) {
279 puts("Known tests are:");
280 _tinytest_set_flag(groups, "..", 0);
282 exit(0);
286 tinytest_main(int c, const char **v, struct testgroup_t *groups)
288 int i, j, n=0;
290 #ifdef WIN32
291 commandname = v[0];
292 #endif
293 for (i=1; i<c; ++i) {
294 if (v[i][0] == '-') {
295 if (!strcmp(v[i], "--RUNNING-FORKED")) {
296 opt_forked = 1;
297 } else if (!strcmp(v[i], "--no-fork")) {
298 opt_nofork = 1;
299 } else if (!strcmp(v[i], "--quiet")) {
300 opt_verbosity = -1;
301 verbosity_flag = "--quiet";
302 } else if (!strcmp(v[i], "--verbose")) {
303 opt_verbosity = 2;
304 verbosity_flag = "--verbose";
305 } else if (!strcmp(v[i], "--terse")) {
306 opt_verbosity = 0;
307 verbosity_flag = "--terse";
308 } else if (!strcmp(v[i], "--help")) {
309 usage(groups, 0);
310 } else if (!strcmp(v[i], "--list-tests")) {
311 usage(groups, 1);
312 } else {
313 printf("Unknown option %s. Try --help\n",v[i]);
314 return -1;
316 } else {
317 const char *test = v[i];
318 int flag = _TT_ENABLED;
319 if (test[0] == ':') {
320 ++test;
321 flag = TT_SKIP;
322 } else {
323 ++n;
325 if (!_tinytest_set_flag(groups, test, flag)) {
326 printf("No such test as %s!\n", v[i]);
327 return -1;
331 if (!n)
332 _tinytest_set_flag(groups, "..", _TT_ENABLED);
334 setvbuf(stdout, NULL, _IONBF, 0);
336 ++in_tinytest_main;
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]);
343 --in_tinytest_main;
345 if (opt_verbosity==0)
346 puts("");
348 if (n_bad)
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;
363 void
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;
374 void
375 _tinytest_set_test_skipped(void)
377 if (cur_test_outcome==OK)
378 cur_test_outcome = SKIP;