Fix typo.
[beanstalkd.git] / cut.c
blob39df543ffab8fbe67fd4ff1d1e2c431b4e49820c
1 /*
2 * libcut.inc
3 * CUT 2.1
5 * Copyright (c) 2001-2002 Samuel A. Falvo II, William D. Tanksley
6 * See CUT-LICENSE.TXT for details.
8 * Based on WDT's 'TestAssert' package.
10 * $log$
13 #include <string.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <stdarg.h>
17 #include <sys/wait.h>
18 #include <errno.h>
19 #include "cut.h"
22 #define BUF_SIZE 1024
24 #ifndef BOOL /* Just in case -- helps in portability */
25 #define BOOL int
26 #endif
28 #ifndef FALSE
29 #define FALSE (0)
30 #endif
32 #ifndef TRUE
33 #define TRUE 1
34 #endif
36 typedef struct test_output *test_output;
38 struct test_output {
39 test_output next;
40 int status;
41 const char *desc;
42 const char *group_name;
43 const char *test_name;
44 FILE *file;
47 static int breakpoint = 0;
48 static int count = 0, count_failures = 0, count_errors = 0;
49 static cut_fn cur_takedown = 0;
50 static test_output problem_reports = 0;
51 static const char *program;
53 static void
54 die(int code, const char *fmt, ...)
56 va_list v;
58 putc('\n', stderr);
60 va_start(v, fmt);
61 vfprintf(stderr, fmt, v);
62 va_end(v);
64 if (fmt && *fmt) fputs(": ", stderr);
65 fprintf(stderr, "%s\n", strerror(errno));
66 exit(code);
69 /* I/O Functions */
71 static void print_string( char *string )
73 printf( "%s", string );
74 fflush( stdout );
77 static void print_string_as_error( char *filename, int lineNumber, char *string )
79 printf( " %s:%d: %s", filename, lineNumber, string );
80 fflush( stdout );
83 static void print_integer( int i )
85 printf( "%d", i );
86 fflush( stdout );
89 static void print_integer_in_field( int i, int width )
91 printf( "%*d", width, i );
92 fflush( stdout );
95 static void new_line( void )
97 printf( "\n" );
98 fflush( stdout );
101 static void print_character( char ch )
103 printf( "%c", ch );
104 fflush( stdout );
107 static void dot( void )
109 print_character( '.' );
112 static void space( void )
114 print_character( ' ' );
117 /* CUT Initialization and Takedown Functions */
119 void cut_init(const char *prog_name, int brkpoint )
121 breakpoint = brkpoint;
122 count = 0;
123 program = prog_name;
125 if( brkpoint >= 0 )
127 print_string( "Breakpoint at test " );
128 print_integer( brkpoint );
129 new_line();
133 void cut_exit( void )
135 int r, s;
136 char buf[BUF_SIZE];
137 test_output to;
139 printf("\n");
140 for (to = problem_reports; to; to = to->next) {
141 printf("\n%s in %s/%s", to->desc, to->group_name, to->test_name);
142 if (!WIFEXITED(to->status) || (WEXITSTATUS(to->status) != 255)) {
143 if (WIFEXITED(to->status)) {
144 printf(" (Exit Status %d)", WEXITSTATUS(to->status));
146 if (WIFSIGNALED(to->status)) {
147 printf(" (Signal %d)", WTERMSIG(to->status));
150 printf("\n");
151 rewind(to->file);
152 while (r = fread(buf, 1, BUF_SIZE, to->file)) {
153 s = fwrite(buf, 1, r, stdout);
154 if (r != s) die(3, "fwrite");
158 printf("\n%d tests; %d failures; %d errors.\n", count, count_failures,
159 count_errors);
160 exit(!!(count_failures + count_errors));
163 /* Test Progress Accounting functions */
165 static void
166 cut_mark_point(char out, char *filename, int lineNumber )
168 if ((count % 10) == 0) {
169 if ((count % 50) == 0) new_line();
170 print_integer_in_field( count, 5 );
173 print_character(out);
174 count++;
176 if( count == breakpoint )
178 print_string_as_error( filename, lineNumber, "Breakpoint hit" );
179 new_line();
180 cut_exit();
185 void __cut_assert(
186 char *filename,
187 int lineNumber,
188 char *message,
189 char *expression,
190 BOOL success
193 if (success) return;
195 print_string_as_error( filename, lineNumber, "(" );
196 print_string( expression );
197 print_string(") ");
198 print_string( message );
199 new_line();
201 if (cur_takedown) cur_takedown();
202 fflush(stdout);
203 fflush(stderr);
204 exit(-1);
207 typedef void(*collect_fn)(void *);
209 static FILE *
210 collect(pid_t *pid, collect_fn fn, void *data)
212 int r;
213 FILE *out;
215 out = tmpfile();
216 if (!out) return 0;
218 fflush(stdout);
219 fflush(stderr);
221 if (*pid = fork()) {
222 if (*pid < 0) return 0;
223 return out;
224 } else {
225 r = dup2(fileno(out), fileno(stdout));
226 if (r < 0) die(3, "dup2");
227 r = fclose(out);
228 if (r) die(3, "fclose");
229 out = 0;
231 fn(data);
232 exit(0);
236 static void
237 exec(void *data)
239 int r;
241 char **info = (char **) data;
242 r = execvp(info[0], info);
243 die(5, "Wrong execvp");
246 /* Read the full symbol table (not just the dynamic symbols) and return the
247 * value of the specified symbol. If an error occurs, print an error message
248 * and exit.
250 * We cheat by using "nm" to parse the symbol table of the file on disk.
252 void *
253 __cut_debug_addr(const char *sym, const char *file, int line)
255 void *val;
256 FILE *out;
257 pid_t pid;
258 int status, r;
259 char cmd[BUF_SIZE], s[BUF_SIZE];
260 char *args[] = { "sh", "-c", cmd, 0 };
262 sprintf(cmd, "nm %s | grep ' %s$'", program, sym);
264 out = collect(&pid, exec, args);
265 if (!out) die(1, " %s:%d: collect", file, line);
267 pid = waitpid(pid, &status, 0);
268 if (pid < 1) die(1, " %s:%d: wait", file, line);
270 rewind(out);
271 r = fread(s, 1, BUF_SIZE - 1, out);
272 if (!r) printf(" %s:%d: no symbol: %s\n", file, line, sym), exit(1);
274 s[r] = 0;
276 errno = 0;
277 val = (void *) strtoul(s, 0, 16);
278 if (errno) die(1, " %s:%d: strtoul on ``%s''", file, line, s);
279 if (((size_t) val) < 100) {
280 die(1, " %s:%d: strtoul on ``%s''", file, line, s);
283 return val;
286 static void
287 run_in_child(void *data)
289 int r;
290 cut_fn *fns = data, bringup = fns[0], test = fns[1], takedown = fns[2];
292 r = dup2(fileno(stdout), fileno(stderr));
293 if (r < 0) die(3, "dup2");
294 bringup();
295 cur_takedown = takedown;
296 test();
297 takedown();
298 fflush(stdout);
299 fflush(stderr);
302 void
303 __cut_run(char *group_name, cut_fn bringup, cut_fn takedown, char *test_name,
304 cut_fn test, char *filename, int lineno)
306 pid_t pid;
307 int status, r;
308 FILE *out;
309 test_output to;
310 char *problem_desc = 0;
311 cut_fn fns[3] = { bringup, test, takedown };
313 out = collect(&pid, run_in_child, fns);
314 if (!out) die(1, " %s:%d: collect", filename, lineno);
315 if (pid < 0) die(3, "fork");
317 r = waitpid(pid, &status, 0);
318 if (r != pid) die(3, "wait");
320 if (!status) {
321 cut_mark_point('.', filename, lineno );
322 } else if (WIFEXITED(status) && (WEXITSTATUS(status) == 255)) {
323 cut_mark_point('F', filename, lineno );
324 count_failures++;
325 problem_desc = "Failure";
326 } else {
327 cut_mark_point('E', filename, lineno );
328 count_errors++;
329 problem_desc = "Error";
332 if (!problem_desc) {
333 fclose(out);
334 return;
337 /* collect the output */
338 to = malloc(sizeof(struct test_output));
339 if (!to) die(3, "malloc");
341 to->desc = problem_desc;
342 to->status = status;
343 to->group_name = group_name;
344 to->test_name = test_name;
345 to->file = out;
346 to->next = problem_reports;
347 problem_reports = to;