Add a basic binlog test.
[beanstalkd.git] / cut.c
blob1af3f4955e5d3362fac80e945d863343fd9166a1
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 <unistd.h>
18 #include <sys/wait.h>
19 #include <errno.h>
20 #include "cut.h"
23 #define BUF_SIZE 1024
25 #ifndef BOOL /* Just in case -- helps in portability */
26 #define BOOL int
27 #endif
29 #ifndef FALSE
30 #define FALSE (0)
31 #endif
33 #ifndef TRUE
34 #define TRUE 1
35 #endif
37 typedef struct test_output *test_output;
39 struct test_output {
40 test_output next;
41 int status;
42 const char *desc;
43 const char *group_name;
44 const char *test_name;
45 FILE *file;
48 static int breakpoint = 0;
49 static int count = 0, count_failures = 0, count_errors = 0;
50 static cut_fn cur_takedown = 0;
51 static test_output problem_reports = 0;
52 static const char *program;
54 static void
55 die(int code, const char *fmt, ...)
57 va_list v;
59 putc('\n', stderr);
61 va_start(v, fmt);
62 vfprintf(stderr, fmt, v);
63 va_end(v);
65 if (fmt && *fmt) fputs(": ", stderr);
66 fprintf(stderr, "%s\n", strerror(errno));
67 exit(code);
70 /* I/O Functions */
72 static void print_string( char *string )
74 printf( "%s", string );
75 fflush( stdout );
78 static void print_string_as_error( char *filename, int lineNumber, char *string )
80 printf( " %s:%d: %s", filename, lineNumber, string );
81 fflush( stdout );
84 static void print_integer( int i )
86 printf( "%d", i );
87 fflush( stdout );
90 static void print_integer_in_field( int i, int width )
92 printf( "%*d", width, i );
93 fflush( stdout );
96 static void new_line( void )
98 printf( "\n" );
99 fflush( stdout );
102 static void print_character( char ch )
104 printf( "%c", ch );
105 fflush( stdout );
108 /* CUT Initialization and Takedown Functions */
110 void cut_init(const char *prog_name, int brkpoint )
112 breakpoint = brkpoint;
113 count = 0;
114 program = prog_name;
116 if( brkpoint >= 0 )
118 print_string( "Breakpoint at test " );
119 print_integer( brkpoint );
120 new_line();
124 void cut_exit( void )
126 int r, s;
127 char buf[BUF_SIZE];
128 test_output to;
130 printf("\n");
131 for (to = problem_reports; to; to = to->next) {
132 printf("\n%s in %s/%s", to->desc, to->group_name, to->test_name);
133 if (!WIFEXITED(to->status) || (WEXITSTATUS(to->status) != 255)) {
134 if (WIFEXITED(to->status)) {
135 printf(" (Exit Status %d)", WEXITSTATUS(to->status));
137 if (WIFSIGNALED(to->status)) {
138 printf(" (Signal %d)", WTERMSIG(to->status));
141 printf("\n");
142 rewind(to->file);
143 while ((r = fread(buf, 1, BUF_SIZE, to->file))) {
144 s = fwrite(buf, 1, r, stdout);
145 if (r != s) die(3, "fwrite");
149 printf("\n%d tests; %d failures; %d errors.\n", count, count_failures,
150 count_errors);
151 exit(!!(count_failures + count_errors));
154 /* Test Progress Accounting functions */
156 static void
157 cut_mark_point(char out, char *filename, int lineNumber )
159 if ((count % 10) == 0) {
160 if ((count % 50) == 0) new_line();
161 print_integer_in_field( count, 5 );
164 print_character(out);
165 count++;
167 if( count == breakpoint )
169 print_string_as_error( filename, lineNumber, "Breakpoint hit" );
170 new_line();
171 cut_exit();
176 void __cut_assert(
177 char *filename,
178 int lineNumber,
179 char *message,
180 char *expression,
181 BOOL success
184 if (success) return;
186 print_string_as_error( filename, lineNumber, "(" );
187 print_string( expression );
188 print_string(") ");
189 print_string( message );
190 new_line();
192 if (cur_takedown) cur_takedown();
193 fflush(stdout);
194 fflush(stderr);
195 exit(-1);
198 typedef void(*collect_fn)(void *);
200 static FILE *
201 collect(pid_t *pid, collect_fn fn, void *data)
203 int r;
204 FILE *out;
206 out = tmpfile();
207 if (!out) return 0;
209 fflush(stdout);
210 fflush(stderr);
212 if ((*pid = fork())) {
213 if (*pid < 0) return 0;
214 return out;
215 } else {
216 r = dup2(fileno(out), fileno(stdout));
217 if (r < 0) die(3, "dup2");
218 r = fclose(out);
219 if (r) die(3, "fclose");
220 out = 0;
222 fn(data);
223 exit(0);
227 static void
228 exec(void *data)
230 int r;
232 char **info = (char **) data;
233 r = execvp(info[0], info);
234 die(5, "Wrong execvp");
237 /* Read the full symbol table (not just the dynamic symbols) and return the
238 * value of the specified symbol. If an error occurs, print an error message
239 * and exit.
241 * We cheat by using "nm" to parse the symbol table of the file on disk.
243 void *
244 __cut_debug_addr(const char *sym, const char *file, int line)
246 void *val;
247 FILE *out;
248 pid_t pid;
249 int status, r;
250 char cmd[BUF_SIZE], s[BUF_SIZE];
251 char *args[] = { "sh", "-c", cmd, 0 };
253 sprintf(cmd, "nm %s | grep ' %s$'", program, sym);
255 out = collect(&pid, exec, args);
256 if (!out) die(1, " %s:%d: collect", file, line);
258 pid = waitpid(pid, &status, 0);
259 if (pid < 1) die(1, " %s:%d: wait", file, line);
261 rewind(out);
262 r = fread(s, 1, BUF_SIZE - 1, out);
263 if (!r) printf(" %s:%d: no symbol: %s\n", file, line, sym), exit(1);
265 s[r] = 0;
267 errno = 0;
268 val = (void *) strtoul(s, 0, 16);
269 if (errno) die(1, " %s:%d: strtoul on ``%s''", file, line, s);
270 if (((size_t) val) < 100) {
271 die(1, " %s:%d: strtoul on ``%s''", file, line, s);
274 return val;
277 static void
278 run_in_child(void *data)
280 int r;
281 cut_fn *fns = data, bringup = fns[0], test = fns[1], takedown = fns[2];
283 r = dup2(fileno(stdout), fileno(stderr));
284 if (r < 0) die(3, "dup2");
285 bringup();
286 cur_takedown = takedown;
287 test();
288 takedown();
289 fflush(stdout);
290 fflush(stderr);
293 void
294 __cut_run(char *group_name, cut_fn bringup, cut_fn takedown, char *test_name,
295 cut_fn test, char *filename, int lineno)
297 pid_t pid;
298 int status, r;
299 FILE *out;
300 test_output to;
301 char *problem_desc = 0;
302 cut_fn fns[3] = { bringup, test, takedown };
304 out = collect(&pid, run_in_child, fns);
305 if (!out) die(1, " %s:%d: collect", filename, lineno);
306 if (pid < 0) die(3, "fork");
308 r = waitpid(pid, &status, 0);
309 if (r != pid) die(3, "wait");
311 if (!status) {
312 cut_mark_point('.', filename, lineno );
313 } else if (WIFEXITED(status) && (WEXITSTATUS(status) == 255)) {
314 cut_mark_point('F', filename, lineno );
315 count_failures++;
316 problem_desc = "Failure";
317 } else {
318 cut_mark_point('E', filename, lineno );
319 count_errors++;
320 problem_desc = "Error";
323 if (!problem_desc) {
324 fclose(out);
325 return;
328 /* collect the output */
329 to = malloc(sizeof(struct test_output));
330 if (!to) die(3, "malloc");
332 to->desc = problem_desc;
333 to->status = status;
334 to->group_name = group_name;
335 to->test_name = test_name;
336 to->file = out;
337 to->next = problem_reports;
338 problem_reports = to;