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