2009-02-12 22:54:45 +03:00
# include <fcntl.h>
# include <string.h>
# include <stdio.h>
# include <sys/socket.h>
# include <sys/wait.h>
# include <unistd.h>
# include <stdlib.h>
pid_t pid ;
int fds [ 2 ] ;
int * status ;
int nfailed = 0 ;
int nskipped = 0 ;
int npassed = 0 ;
char * readbuf = NULL ;
int readbuf_sz = 0 , readbuf_used = 0 ;
int die = 0 ;
# define PASSED 0
# define SKIPPED 1
# define FAILED 2
void handler ( int s ) {
signal ( s , SIG_DFL ) ;
kill ( pid , s ) ;
die = s ;
}
void dump ( ) {
write ( 1 , readbuf , readbuf_used ) ;
}
void clear ( ) {
readbuf_used = 0 ;
}
void drain ( ) {
int sz ;
char buf [ 2048 ] ;
while ( 1 ) {
sz = read ( fds [ 1 ] , buf , 2048 ) ;
if ( sz < = 0 )
return ;
if ( readbuf_used + sz > = readbuf_sz ) {
readbuf_sz = readbuf_sz ? 2 * readbuf_sz : 4096 ;
readbuf = realloc ( readbuf , readbuf_sz ) ;
}
if ( ! readbuf )
exit ( 205 ) ;
memcpy ( readbuf + readbuf_used , buf , sz ) ;
readbuf_used + = sz ;
}
}
void passed ( int i , char * f ) {
+ + npassed ;
status [ i ] = PASSED ;
printf ( " passed. \n " ) ;
}
void skipped ( int i , char * f ) {
+ + nskipped ;
status [ i ] = SKIPPED ;
printf ( " skipped. \n " ) ;
}
void failed ( int i , char * f , int st ) {
+ + nfailed ;
status [ i ] = FAILED ;
if ( die = = 2 ) {
printf ( " interrupted. \n " ) ;
return ;
}
printf ( " FAILED. \n " ) ;
printf ( " -- FAILED %s ------------------------------------ \n " , f ) ;
dump ( ) ;
printf ( " -- FAILED %s (end) ------------------------------ \n " , f ) ;
}
void run ( int i , char * f ) {
pid = fork ( ) ;
if ( pid < 0 ) {
perror ( " Fork failed. " ) ;
exit ( 201 ) ;
} else if ( pid = = 0 ) {
close ( 0 ) ;
dup2 ( fds [ 0 ] , 1 ) ;
dup2 ( fds [ 0 ] , 2 ) ;
execlp ( " bash " , " bash " , f , NULL ) ;
perror ( " execlp " ) ;
exit ( 202 ) ;
} else {
char buf [ 128 ] ;
snprintf ( buf , 128 , " %s ... " , f ) ;
buf [ 127 ] = 0 ;
printf ( " Running %-40s " , buf ) ;
fflush ( stdout ) ;
int st , w ;
while ( ( w = waitpid ( pid , & st , WNOHANG ) ) = = 0 ) {
drain ( ) ;
usleep ( 20000 ) ;
}
if ( w ! = pid ) {
perror ( " waitpid " ) ;
exit ( 206 ) ;
}
if ( WIFEXITED ( st ) ) {
if ( WEXITSTATUS ( st ) = = 0 ) {
passed ( i , f ) ;
} else if ( WEXITSTATUS ( st ) = = 200 ) {
skipped ( i , f ) ;
} else {
failed ( i , f , st ) ;
}
} else {
failed ( i , f , st ) ;
}
clear ( ) ;
}
}
int main ( int argc , char * * argv ) {
int i ;
status = alloca ( sizeof ( int ) * argc ) ;
if ( socketpair ( PF_UNIX , SOCK_STREAM , 0 , fds ) ) {
perror ( " socketpair " ) ;
return 201 ;
}
if ( fcntl ( fds [ 1 ] , F_SETFL , O_NONBLOCK ) = = - 1 ) {
perror ( " fcntl on socket " ) ;
return 202 ;
}
/* set up signal handlers */
for ( i = 0 ; i < = 32 ; + + i ) {
if ( i = = SIGCHLD | | i = = SIGWINCH | | i = = SIGURG )
continue ;
signal ( i , handler ) ;
}
/* run the tests */
for ( i = 1 ; i < argc ; + + i ) {
run ( i , argv [ i ] ) ;
if ( die )
break ;
}
printf ( " \n ## %d tests: %d OK, %d failed, %d skipped \n " ,
npassed + nfailed + nskipped , npassed , nfailed , nskipped ) ;
/* print out a summary */
2009-02-16 19:49:21 +03:00
if ( nfailed | | nskipped ) {
2009-02-12 22:54:45 +03:00
for ( i = 1 ; i < argc ; + + i ) {
switch ( status [ i ] ) {
case FAILED :
printf ( " FAILED: %s \n " , argv [ i ] ) ;
break ;
case SKIPPED :
printf ( " skipped: %s \n " , argv [ i ] ) ;
break ;
}
}
printf ( " \n " ) ;
2009-02-16 19:49:21 +03:00
return nfailed > 0 | | die ;
2009-02-12 22:54:45 +03:00
}
return ! die ;
}