Go to the documentation of this file.00001
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
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
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
00083
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
00097 announced_suite --;
00098 ++ test;
00099 test_ok = 0;
00100 suite_failed ++;
00101 }
00102
00103 void processStatus( std::string line ) {
00104
00105 if ( line == "done" ) {
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
00120
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
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 ) {
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