00001
00002 #include <unistd.h>
00003 #include <sys/wait.h>
00004 #include <cstring>
00005 #include <sys/socket.h>
00006
00007 #include <wibble/sys/pipe.h>
00008
00009 struct Main {
00010
00011 int suite, test;
00012 wibble::sys::Pipe f_status;
00013 int status[2];
00014 int confirm[2];
00015 FILE *f_confirm;
00016 pid_t pid;
00017 int argc;
00018 char **argv;
00019 pid_t finished;
00020 int status_code;
00021 int test_ok;
00022
00023 int suite_ok, suite_failed;
00024 int total_ok, total_failed;
00025
00026 int announced_suite;
00027 std::string current;
00028
00029 RunAll all;
00030
00031 Main() : suite(0), test(0) {
00032 suite_ok = suite_failed = 0;
00033 total_ok = total_failed = 0;
00034 test_ok = 0;
00035 announced_suite = -1;
00036 }
00037
00038 void child() {
00039 close( status[0] );
00040 close( confirm[1] );
00041 all.status = fdopen( status[1], "w" );
00042 all.confirm = wibble::sys::Pipe( confirm[0] );
00043 if ( argc > 1 ) {
00044 RunSuite *s = all.findSuite( argv[1] );
00045 if (!s) {
00046 std::cerr << "No such suite " << argv[1] << std::endl;
00047
00048 exit(250);
00049 }
00050 if ( argc > 2 ) {
00051 if ( !test )
00052 all.runTest( *s, atoi( argv[2] ) );
00053 } else
00054 all.runSuite( *s, test, 0, 1 );
00055 }
00056 if ( argc == 1 ) {
00057 all.runFrom( suite, test );
00058 }
00059 fprintf( all.status, "done\n" );
00060 exit( 0 );
00061 }
00062
00063 void testDied()
00064 {
00065
00066
00067 if ( WIFEXITED( status_code ) ) {
00068 if ( WEXITSTATUS( status_code ) == 250 )
00069 exit( 3 );
00070 if ( WEXITSTATUS( status_code ) == 0 )
00071 return;
00072 }
00073 std::cout << "--> FAILED: "<< current;
00074 if ( WIFEXITED( status_code ) )
00075 std::cout << " (exit status " << WEXITSTATUS( status_code ) << ")";
00076 if ( WIFSIGNALED( status_code ) )
00077 std::cout << " (caught signal " << WTERMSIG( status_code ) << ")";
00078 std::cout << std::endl;
00079
00080 announced_suite --;
00081 ++ test;
00082 test_ok = 0;
00083 suite_failed ++;
00084 }
00085
00086 void processStatus( std::string line ) {
00087 if ( line == "done" ) {
00088 finished = waitpid( pid, &status_code, 0 );
00089 assert_eq( pid, finished );
00090 assert( WIFEXITED( status_code ) );
00091 assert_eq( WEXITSTATUS( status_code ), 0 );
00092 std::cout << "overall " << total_ok << "/"
00093 << total_ok + total_failed
00094 << " ok" << std::endl;
00095 exit( total_failed == 0 ? 0 : 1 );
00096 }
00097
00098 if ( test_ok ) {
00099
00100
00101 std::cout << "." << std::flush;
00102 suite_ok ++;
00103 ++ test;
00104 test_ok = 0;
00105 }
00106
00107 if ( line[0] == 's' ) {
00108 if ( line[2] == 'd' ) {
00109 std::cout << " " << suite_ok << "/" << suite_ok + suite_failed
00110 << " ok" << std::endl;
00111 ++ suite; test = 0;
00112 assert( !test_ok );
00113 total_ok += suite_ok;
00114 total_failed += suite_failed;
00115 suite_ok = suite_failed = 0;
00116 }
00117 if ( line[2] == 's' ) {
00118 if ( announced_suite < suite ) {
00119 std::cout << std::string( line.begin() + 5, line.end() )
00120 << ": " << std::flush;
00121 announced_suite = suite;
00122 }
00123 }
00124 }
00125 if ( line[0] == 't' ) {
00126 if ( line[2] == 'd' ) {
00127 fprintf( f_confirm, "ack\n" );
00128 fflush( f_confirm );
00129 test_ok = 1;
00130 }
00131 if ( line[2] == 's' ) {
00132 fprintf( f_confirm, "ack\n" );
00133 fflush( f_confirm );
00134 current = std::string( line.begin() + 5, line.end() );
00135 }
00136 }
00137 }
00138
00139 void parent() {
00140 close( status[1] );
00141 close( confirm[0] );
00142 f_status = wibble::sys::Pipe( status[ 0 ]);
00143 f_confirm = fdopen( confirm[1], "w" );
00144 std::string line;
00145 size_t n;
00146
00147 while ( true ) {
00148 if ( f_status.eof() ) {
00149 finished = waitpid( pid, &status_code, 0 );
00150 if ( finished < 0 ) {
00151 perror( "waitpid failed" );
00152 exit( 5 );
00153 }
00154 assert_eq( pid, finished );
00155 testDied();
00156 return;
00157 }
00158
00159 line = f_status.nextLineBlocking();
00160 processStatus( line );
00161 }
00162 }
00163
00164 int main( int _argc, char **_argv )
00165 {
00166 argc = _argc;
00167 argv = _argv;
00168
00169 all.suiteCount = sizeof(suites)/sizeof(RunSuite);
00170 all.suites = suites;
00171
00172 while (true) {
00173 if ( socketpair( PF_UNIX,SOCK_STREAM, 0, status ) )
00174 return 1;
00175 if ( socketpair( PF_UNIX,SOCK_STREAM, 0, confirm ) )
00176 return 1;
00177 pid = fork();
00178 if ( pid < 0 )
00179 return 2;
00180 if ( pid == 0 ) {
00181 child();
00182 } else {
00183 parent();
00184 }
00185 }
00186 }
00187 };
00188
00189 int main( int argc, char **argv ) {
00190 return Main().main( argc, argv );
00191 }