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.
25 #ifndef BOOL /* Just in case -- helps in portability */
37 typedef struct test_output
*test_output
;
43 const char *group_name
;
44 const char *test_name
;
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
;
55 die(int code
, const char *fmt
, ...)
62 vfprintf(stderr
, fmt
, v
);
65 if (fmt
&& *fmt
) fputs(": ", stderr
);
66 fprintf(stderr
, "%s\n", strerror(errno
));
72 static void print_string( char *string
)
74 printf( "%s", string
);
78 static void print_string_as_error( char *filename
, int lineNumber
, char *string
)
80 printf( " %s:%d: %s", filename
, lineNumber
, string
);
84 static void print_integer( int i
)
90 static void print_integer_in_field( int i
, int width
)
92 printf( "%*d", width
, i
);
96 static void new_line( void )
102 static void print_character( char ch
)
108 /* CUT Initialization and Takedown Functions */
110 void cut_init(const char *prog_name
, int brkpoint
)
112 breakpoint
= brkpoint
;
118 print_string( "Breakpoint at test " );
119 print_integer( brkpoint
);
124 void cut_exit( void )
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
));
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
,
151 exit(!!(count_failures
+ count_errors
));
154 /* Test Progress Accounting functions */
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
);
167 if( count
== breakpoint
)
169 print_string_as_error( filename
, lineNumber
, "Breakpoint hit" );
186 print_string_as_error( filename
, lineNumber
, "(" );
187 print_string( expression
);
189 print_string( message
);
192 if (cur_takedown
) cur_takedown();
198 typedef void(*collect_fn
)(void *);
201 collect(pid_t
*pid
, collect_fn fn
, void *data
)
212 if ((*pid
= fork())) {
213 if (*pid
< 0) return 0;
216 r
= dup2(fileno(out
), fileno(stdout
));
217 if (r
< 0) die(3, "dup2");
219 if (r
) die(3, "fclose");
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
241 * We cheat by using "nm" to parse the symbol table of the file on disk.
244 __cut_debug_addr(const char *sym
, const char *file
, int line
)
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
);
262 r
= fread(s
, 1, BUF_SIZE
- 1, out
);
263 if (!r
) printf(" %s:%d: no symbol: %s\n", file
, line
, sym
), exit(1);
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
);
278 run_in_child(void *data
)
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");
286 cur_takedown
= takedown
;
294 __cut_run(char *group_name
, cut_fn bringup
, cut_fn takedown
, char *test_name
,
295 cut_fn test
, char *filename
, int lineno
)
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");
312 cut_mark_point('.', filename
, lineno
);
313 } else if (WIFEXITED(status
) && (WEXITSTATUS(status
) == 255)) {
314 cut_mark_point('F', filename
, lineno
);
316 problem_desc
= "Failure";
318 cut_mark_point('E', filename
, lineno
);
320 problem_desc
= "Error";
328 /* collect the output */
329 to
= malloc(sizeof(struct test_output
));
330 if (!to
) die(3, "malloc");
332 to
->desc
= problem_desc
;
334 to
->group_name
= group_name
;
335 to
->test_name
= test_name
;
337 to
->next
= problem_reports
;
338 problem_reports
= to
;