Fix several warnings that appear in gcc 4.3.2.
[wvstreams.git] / utils / wvtest.cc
blob809d1ec31a48850874e1711185b30749b6b9704c
1 /*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2003 Net Integration Technologies, Inc.
5 * Part of an automated testing framework. See wvtest.h.
6 */
7 #include "wvtest.h"
8 #include "wvautoconf.h"
9 #include <stdio.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include <ctype.h>
13 #ifdef _WIN32
14 #include <direct.h>
15 #else
16 #include <unistd.h>
17 #include <sys/wait.h>
18 #endif
19 #include <errno.h>
20 #include <signal.h>
22 #include <cstdlib>
24 #ifdef HAVE_VALGRIND_MEMCHECK_H
25 # include <valgrind/memcheck.h>
26 # include <valgrind/valgrind.h>
27 #else
28 # define VALGRIND_COUNT_ERRORS 0
29 # define VALGRIND_DO_LEAK_CHECK
30 # define VALGRIND_COUNT_LEAKS(a,b,c,d) (a=b=c=d=0)
31 #endif
33 #define MAX_TEST_TIME 40 // max seconds for a single test to run
34 #define MAX_TOTAL_TIME 120*60 // max seconds for the entire suite to run
36 #define TEST_START_FORMAT "! %s:%-5d %-40s "
38 static int memerrs()
40 return (int)VALGRIND_COUNT_ERRORS;
43 static int memleaks()
45 int leaked = 0, dubious = 0, reachable = 0, suppressed = 0;
46 VALGRIND_DO_LEAK_CHECK;
47 VALGRIND_COUNT_LEAKS(leaked, dubious, reachable, suppressed);
48 printf("memleaks: sure:%d dubious:%d reachable:%d suppress:%d\n",
49 leaked, dubious, reachable, suppressed);
50 fflush(stdout);
52 // dubious+reachable are normally non-zero because of globals...
53 // return leaked+dubious+reachable;
54 return leaked;
57 // Return 1 if no children are running or zombies, 0 if there are any running
58 // or zombie children.
59 // Will wait for any already-terminated children first.
60 // Passes if no rogue children were running, fails otherwise.
61 // If your test gets a failure in here, either you're not killing all your
62 // children, or you're not calling waitpid(2) on all of them.
63 static bool no_running_children()
65 #ifndef _WIN32
66 pid_t wait_result;
68 // Acknowledge and complain about any zombie children
69 do
71 int status = 0;
72 wait_result = waitpid(-1, &status, WNOHANG);
74 if (wait_result > 0)
76 char buf[256];
77 snprintf(buf, sizeof(buf) - 1, "%d", wait_result);
78 buf[sizeof(buf)-1] = '\0';
79 WVFAILEQ("Unclaimed dead child process", buf);
81 } while (wait_result > 0);
83 // There should not be any running children, so waitpid should return -1
84 WVPASSEQ(errno, ECHILD);
85 WVPASSEQ(wait_result, -1);
86 return (wait_result == -1 && errno == ECHILD);
87 #endif
88 return true;
92 WvTest *WvTest::first, *WvTest::last;
93 int WvTest::fails, WvTest::runs;
94 time_t WvTest::start_time;
95 bool WvTest::run_twice = false;
97 void WvTest::alarm_handler(int)
99 printf("\n! WvTest Current test took longer than %d seconds! FAILED\n",
100 MAX_TEST_TIME);
101 fflush(stdout);
102 abort();
106 static const char *pathstrip(const char *filename)
108 const char *cptr;
109 cptr = strrchr(filename, '/');
110 if (cptr) filename = cptr + 1;
111 cptr = strrchr(filename, '\\');
112 if (cptr) filename = cptr + 1;
113 return filename;
117 WvTest::WvTest(const char *_descr, const char *_idstr, MainFunc *_main,
118 int _slowness) :
119 descr(_descr),
120 idstr(pathstrip(_idstr)),
121 main(_main),
122 slowness(_slowness),
123 next(NULL)
125 if (first)
126 last->next = this;
127 else
128 first = this;
129 last = this;
133 static bool prefix_match(const char *s, const char * const *prefixes)
135 for (const char * const *prefix = prefixes; prefix && *prefix; prefix++)
137 if (!strncasecmp(s, *prefix, strlen(*prefix)))
138 return true;
140 return false;
144 int WvTest::run_all(const char * const *prefixes)
146 int old_valgrind_errs = 0, new_valgrind_errs;
147 int old_valgrind_leaks = 0, new_valgrind_leaks;
149 #ifdef _WIN32
150 /* I should be doing something to do with SetTimer here,
151 * not sure exactly what just yet */
152 #else
153 char *disable(getenv("WVTEST_DISABLE_TIMEOUT"));
154 if (disable != NULL && disable[0] != '\0' && disable[0] != '0')
155 signal(SIGALRM, SIG_IGN);
156 else
157 signal(SIGALRM, alarm_handler);
158 alarm(MAX_TEST_TIME);
159 #endif
160 start_time = time(NULL);
162 // make sure we can always start out in the same directory, so tests have
163 // access to their files. If a test uses chdir(), we want to be able to
164 // reverse it.
165 char wd[1024];
166 if (!getcwd(wd, sizeof(wd)))
167 strcpy(wd, ".");
169 const char *slowstr1 = getenv("WVTEST_MIN_SLOWNESS");
170 const char *slowstr2 = getenv("WVTEST_MAX_SLOWNESS");
171 int min_slowness = 0, max_slowness = 65535;
172 if (slowstr1) min_slowness = atoi(slowstr1);
173 if (slowstr2) max_slowness = atoi(slowstr2);
175 #ifdef _WIN32
176 run_twice = false;
177 #else
178 char *parallel_str = getenv("WVTEST_PARALLEL");
179 if (parallel_str)
180 run_twice = atoi(parallel_str) > 0;
181 #endif
183 // there are lots of fflush() calls in here because stupid win32 doesn't
184 // flush very often by itself.
185 fails = runs = 0;
186 for (WvTest *cur = first; cur; cur = cur->next)
188 if (cur->slowness <= max_slowness
189 && cur->slowness >= min_slowness
190 && (!prefixes
191 || prefix_match(cur->idstr, prefixes)
192 || prefix_match(cur->descr, prefixes)))
194 #ifndef _WIN32
195 // set SIGPIPE back to default, helps catch tests which don't set
196 // this signal to SIG_IGN (which is almost always what you want)
197 // on startup
198 signal(SIGPIPE, SIG_DFL);
200 pid_t child = 0;
201 if (run_twice)
203 // I see everything twice!
204 printf("Running test in parallel.\n");
205 child = fork();
207 #endif
209 printf("\nTesting \"%s\" in %s:\n", cur->descr, cur->idstr);
210 fflush(stdout);
212 cur->main();
213 chdir(wd);
215 new_valgrind_errs = memerrs();
216 WVPASS(new_valgrind_errs == old_valgrind_errs);
217 old_valgrind_errs = new_valgrind_errs;
219 new_valgrind_leaks = memleaks();
220 WVPASS(new_valgrind_leaks == old_valgrind_leaks);
221 old_valgrind_leaks = new_valgrind_leaks;
223 fflush(stderr);
224 printf("\n");
225 fflush(stdout);
227 #ifndef _WIN32
228 if (run_twice)
230 if (!child)
232 // I see everything once!
233 printf("Child exiting.\n");
234 _exit(0);
236 else
238 printf("Waiting for child to exit.\n");
239 int result;
240 while ((result = waitpid(child, NULL, 0)) == -1 &&
241 errno == EINTR)
242 printf("Waitpid interrupted, retrying.\n");
245 #endif
247 WVPASS(no_running_children());
251 WVPASS(runs > 0);
253 if (prefixes && *prefixes && **prefixes)
254 printf("WvTest: WARNING: only ran tests starting with "
255 "specifed prefix(es).\n");
256 else
257 printf("WvTest: ran all tests.\n");
258 printf("WvTest: %d test%s, %d failure%s.\n",
259 runs, runs==1 ? "" : "s",
260 fails, fails==1 ? "": "s");
261 fflush(stdout);
263 return fails != 0;
267 // If we aren't running in parallel, we want to output the name of the test
268 // before we run it, so we know what happened if it crashes. If we are
269 // running in parallel, outputting this information in multiple printf()s
270 // can confuse parsers, so we want to output everything in one printf().
272 // This function gets called by both start() and check(). If we're not
273 // running in parallel, just print the data. If we're running in parallel,
274 // and we're starting a test, save a copy of the file/line/description until
275 // the test is done and we can output it all at once.
277 // Yes, this is probably the worst API of all time.
278 void WvTest::print_result(bool start, const char *_file, int _line,
279 const char *_condstr, bool result)
281 static char *file;
282 static char *condstr;
283 static int line;
285 if (start)
287 if (file)
288 free(file);
289 if (condstr)
290 free(condstr);
291 file = strdup(pathstrip(_file));
292 condstr = strdup(_condstr);
293 line = _line;
295 for (char *cptr = condstr; *cptr; cptr++)
297 if (!isprint((unsigned char)*cptr))
298 *cptr = '!';
302 const char *result_str = result ? "ok\n" : "FAILED\n";
303 if (run_twice)
305 if (!start)
306 printf(TEST_START_FORMAT "%s", file, line, condstr, result_str);
308 else
310 if (start)
311 printf(TEST_START_FORMAT, file, line, condstr);
312 else
313 printf("%s", result_str);
315 fflush(stdout);
317 if (!start)
319 if (file)
320 free(file);
321 if (condstr)
322 free(condstr);
323 file = condstr = NULL;
328 void WvTest::start(const char *file, int line, const char *condstr)
330 // Either print the file, line, and condstr, or save them for later.
331 print_result(true, file, line, condstr, 0);
335 void WvTest::check(bool cond)
337 #ifndef _WIN32
338 alarm(MAX_TEST_TIME); // restart per-test timeout
339 #endif
340 if (!start_time) start_time = time(NULL);
342 if (time(NULL) - start_time > MAX_TOTAL_TIME)
344 printf("\n! WvTest Total run time exceeded %d seconds! FAILED\n",
345 MAX_TOTAL_TIME);
346 fflush(stdout);
347 abort();
350 runs++;
352 print_result(false, NULL, 0, NULL, cond);
354 if (!cond)
356 fails++;
358 if (getenv("WVTEST_DIE_FAST"))
359 abort();
364 bool WvTest::start_check_eq(const char *file, int line,
365 const char *a, const char *b, bool expect_pass)
367 if (!a) a = "";
368 if (!b) b = "";
370 size_t len = strlen(a) + strlen(b) + 8 + 1;
371 char *str = new char[len];
372 sprintf(str, "[%s] %s [%s]", a, expect_pass ? "==" : "!=", b);
374 start(file, line, str);
375 delete[] str;
377 bool cond = !strcmp(a, b);
378 if (!expect_pass)
379 cond = !cond;
381 check(cond);
382 return cond;
386 bool WvTest::start_check_eq(const char *file, int line,
387 int a, int b, bool expect_pass)
389 size_t len = 128 + 128 + 8 + 1;
390 char *str = new char[len];
391 sprintf(str, "%d %s %d", a, expect_pass ? "==" : "!=", b);
393 start(file, line, str);
394 delete[] str;
396 bool cond = (a == b);
397 if (!expect_pass)
398 cond = !cond;
400 check(cond);
401 return cond;
405 bool WvTest::start_check_lt(const char *file, int line,
406 const char *a, const char *b)
408 if (!a) a = "";
409 if (!b) b = "";
411 size_t len = strlen(a) + strlen(b) + 8 + 1;
412 char *str = new char[len];
413 sprintf(str, "[%s] < [%s]", a, b);
415 start(file, line, str);
416 delete[] str;
418 bool cond = strcmp(a, b) < 0;
419 check(cond);
420 return cond;
424 bool WvTest::start_check_lt(const char *file, int line, int a, int b)
426 size_t len = 128 + 128 + 8 + 1;
427 char *str = new char[len];
428 sprintf(str, "%d < %d", a, b);
430 start(file, line, str);
431 delete[] str;
433 bool cond = a < b;
434 check(cond);
435 return cond;