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