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.
24 #ifndef BOOL /* Just in case -- helps in portability */
36 typedef struct test_output
*test_output
;
42 const char *group_name
;
43 const char *test_name
;
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
;
54 die(int code
, const char *fmt
, ...)
61 vfprintf(stderr
, fmt
, v
);
64 if (fmt
&& *fmt
) fputs(": ", stderr
);
65 fprintf(stderr
, "%s\n", strerror(errno
));
71 static void print_string( char *string
)
73 printf( "%s", string
);
77 static void print_string_as_error( char *filename
, int lineNumber
, char *string
)
79 printf( " %s:%d: %s", filename
, lineNumber
, string
);
83 static void print_integer( int i
)
89 static void print_integer_in_field( int i
, int width
)
91 printf( "%*d", width
, i
);
95 static void new_line( void )
101 static void print_character( char ch
)
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
;
127 print_string( "Breakpoint at test " );
128 print_integer( brkpoint
);
133 void cut_exit( void )
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
));
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
,
160 exit(!!(count_failures
+ count_errors
));
163 /* Test Progress Accounting functions */
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
);
176 if( count
== breakpoint
)
178 print_string_as_error( filename
, lineNumber
, "Breakpoint hit" );
195 print_string_as_error( filename
, lineNumber
, "(" );
196 print_string( expression
);
198 print_string( message
);
201 if (cur_takedown
) cur_takedown();
207 typedef void(*collect_fn
)(void *);
210 collect(pid_t
*pid
, collect_fn fn
, void *data
)
222 if (*pid
< 0) return 0;
225 r
= dup2(fileno(out
), fileno(stdout
));
226 if (r
< 0) die(3, "dup2");
228 if (r
) die(3, "fclose");
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
250 * We cheat by using "nm" to parse the symbol table of the file on disk.
253 __cut_debug_addr(const char *sym
, const char *file
, int line
)
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
);
271 r
= fread(s
, 1, BUF_SIZE
- 1, out
);
272 if (!r
) printf(" %s:%d: no symbol: %s\n", file
, line
, sym
), exit(1);
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
);
287 run_in_child(void *data
)
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");
295 cur_takedown
= takedown
;
303 __cut_run(char *group_name
, cut_fn bringup
, cut_fn takedown
, char *test_name
,
304 cut_fn test
, char *filename
, int lineno
)
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");
321 cut_mark_point('.', filename
, lineno
);
322 } else if (WIFEXITED(status
) && (WEXITSTATUS(status
) == 255)) {
323 cut_mark_point('F', filename
, lineno
);
325 problem_desc
= "Failure";
327 cut_mark_point('E', filename
, lineno
);
329 problem_desc
= "Error";
337 /* collect the output */
338 to
= malloc(sizeof(struct test_output
));
339 if (!to
) die(3, "malloc");
341 to
->desc
= problem_desc
;
343 to
->group_name
= group_name
;
344 to
->test_name
= test_name
;
346 to
->next
= problem_reports
;
347 problem_reports
= to
;