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