Portability fixes.
[beanstalkd.git] / cut.c
blob8ddc7451a0514eae760d17f5f1b2fa6b6fc97bf1
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 run_in_child(void *data)
230 int r;
231 cut_fn *fns = data, bringup = fns[0], test = fns[1], takedown = fns[2];
233 r = dup2(fileno(stdout), fileno(stderr));
234 if (r < 0) die(3, "dup2");
235 bringup();
236 cur_takedown = takedown;
237 test();
238 takedown();
239 fflush(stdout);
240 fflush(stderr);
243 void
244 __cut_run(char *group_name, cut_fn bringup, cut_fn takedown, char *test_name,
245 cut_fn test, char *filename, int lineno)
247 pid_t pid = -1;
248 int status, r;
249 FILE *out;
250 test_output to;
251 char *problem_desc = 0;
252 cut_fn fns[3] = { bringup, test, takedown };
254 out = collect(&pid, run_in_child, fns);
255 if (!out) die(1, " %s:%d: collect", filename, lineno);
256 if (pid < 0) die(3, "fork");
258 r = waitpid(pid, &status, 0);
259 if (r != pid) die(3, "wait");
261 if (!status) {
262 cut_mark_point('.', filename, lineno );
263 } else if (WIFEXITED(status) && (WEXITSTATUS(status) == 255)) {
264 cut_mark_point('F', filename, lineno );
265 count_failures++;
266 problem_desc = "Failure";
267 } else {
268 cut_mark_point('E', filename, lineno );
269 count_errors++;
270 problem_desc = "Error";
273 if (!problem_desc) {
274 fclose(out);
275 return;
278 /* collect the output */
279 to = malloc(sizeof(struct test_output));
280 if (!to) die(3, "malloc");
282 to->desc = problem_desc;
283 to->status = status;
284 to->group_name = group_name;
285 to->test_name = test_name;
286 to->file = out;
287 to->next = problem_reports;
288 problem_reports = to;