• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

test-main.h

Go to the documentation of this file.
00001 // -*- C++ -*-
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                 // todo dump possible suites?
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                             // todo dump possible suites?
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         /* std::cerr << "test died: " << test << "/"
00082            << suites[suite].testCount << std::endl; */
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         // re-announce the suite
00096         announced_suite --;
00097         ++ test; // continue with next test
00098         test_ok = 0;
00099         suite_failed ++;
00100     }
00101 
00102     void processStatus( std::string line ) {
00103         // std::cerr << line << std::endl;
00104         if ( line == "done" ) { // finished
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             /* std::cerr << "test ok: " << test << "/"
00119                << suites[suite].testCount << std::endl; */
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         // std::cerr << "status: " << line << std::endl;
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 ) { // child
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

Generated on Tue May 10 2011 16:51:50 for wibble by  doxygen 1.7.1