wibble  1.1
test-main.h
Go to the documentation of this file.
1 // -*- C++ -*-
2 #include <wibble/sys/macros.h>
3 
4 #include <unistd.h>
5 
6 #ifdef POSIX
7 #include <sys/wait.h>
8 #include <sys/socket.h>
9 #endif
10 
11 #include <cstring>
12 #include <cstdio>
13 
14 #include <wibble/sys/pipe.h>
15 
16 struct Main : RunFeedback {
17 
18  int suite, test;
21  int status_fds[2];
22  int confirm_fds[2];
23  pid_t pid;
24  int argc;
25  char **argv;
26  pid_t finished;
28  int test_ok;
29 
32 
34  std::string current;
35  bool want_fork;
36 
38 
39  Main() : suite(0), test(0) {
40  suite_ok = suite_failed = 0;
41  total_ok = total_failed = 0;
42  test_ok = 0;
43  announced_suite = -1;
44  }
45 
46  void child() {
47 #ifdef POSIX
48  close( status_fds[0] );
49  close( confirm_fds[1] );
50 #endif
51  p_confirm = wibble::sys::Pipe( confirm_fds[0] );
52  if ( argc > 1 ) {
53  RunSuite *s = all.findSuite( argv[1] );
54  if (!s) {
55  std::cerr << "No such suite " << argv[1] << std::endl;
56  // todo dump possible suites?
57  exit(250);
58  }
59  if ( argc > 2 ) {
60  if ( !test ) {
61  char *end;
62  int t = strtol( argv[2], &end, 0 );
63  if ( end == argv[2] && t == 0 ) {
64  t = s->findTest( argv[2] );
65  if ( t < 0 ) {
66  std::cerr << "No such test " << argv[2]
67  << " in suite " << argv[1] << std::endl;
68  // todo dump possible suites?
69  exit(250);
70  }
71  }
72  all.runTest( *s, t );
73  }
74  } else
75  all.runSuite( *s, test, 0, 1 );
76  }
77  if ( argc == 1 ) {
78  all.runFrom( suite, test );
79  }
80  status( "done" );
81  exit( 0 );
82  }
83 
84 #ifdef POSIX
85  void testDied()
86  {
87 #pragma GCC diagnostic push
88 #pragma GCC diagnostic ignored "-Wold-style-cast"
89  /* std::cerr << "test died: " << test << "/"
90  << suites[suite].testCount << std::endl; */
91  if ( WIFEXITED( status_code ) ) {
92  if ( WEXITSTATUS( status_code ) == 250 )
93  exit( 3 );
94  if ( WEXITSTATUS( status_code ) == 0 )
95  return;
96  }
97  std::cout << "--> FAILED: "<< current;
98  if ( WIFEXITED( status_code ) )
99  std::cout << " (exit status " << WEXITSTATUS( status_code ) << ")";
100  if ( WIFSIGNALED( status_code ) )
101  std::cout << " (caught signal " << WTERMSIG( status_code ) << ")";
102  std::cout << std::endl;
103  // re-announce the suite
104  announced_suite --;
105  ++ test; // continue with next test
106  test_ok = 0;
107  suite_failed ++;
108 #pragma GCC diagnostic pop
109  }
110 #endif
111 
112  void processStatus( std::string line ) {
113  // std::cerr << line << std::endl;
114  if ( line == "done" ) { // finished
115 #ifdef POSIX
116 #pragma GCC diagnostic push
117 #pragma GCC diagnostic ignored "-Wold-style-cast"
118  if ( want_fork ) {
119  finished = waitpid( pid, &status_code, 0 );
120  assert_eq( pid, finished );
121  assert( WIFEXITED( status_code ) );
122  assert_eq( WEXITSTATUS( status_code ), 0 );
123  }
124 #pragma GCC diagnostic pop
125 #endif
126  std::cout << "overall " << total_ok << "/"
127  << total_ok + total_failed
128  << " ok" << std::endl;
129  exit( total_failed == 0 ? 0 : 1 );
130  }
131 
132  if ( test_ok ) {
133  /* std::cerr << "test ok: " << test << "/"
134  << suites[suite].testCount << std::endl; */
135  std::cout << "." << std::flush;
136  suite_ok ++;
137  ++ test;
138  test_ok = 0;
139  }
140 
141  if ( line[0] == 's' ) {
142  if ( line[2] == 'd' ) {
143  std::cout << " " << suite_ok << "/" << suite_ok + suite_failed
144  << " ok" << std::endl;
145  ++ suite; test = 0;
146  assert( !test_ok );
147  total_ok += suite_ok;
148  total_failed += suite_failed;
149  suite_ok = suite_failed = 0;
150  }
151  if ( line[2] == 's' ) {
152  if ( announced_suite < suite ) {
153  std::cout << std::string( line.begin() + 5, line.end() )
154  << ": " << std::flush;
155  announced_suite = suite;
156  }
157  }
158  }
159  if ( line[0] == 't' ) {
160  if ( line[2] == 'd' ) {
161  confirm();
162  test_ok = 1;
163  }
164  if ( line[2] == 's' ) {
165  confirm();
166  current = std::string( line.begin() + 5, line.end() );
167  }
168  }
169  }
170 
171 #ifdef POSIX
172  void parent() {
173  close( status_fds[1] );
174  close( confirm_fds[0] );
175  p_status = wibble::sys::Pipe( status_fds[ 0 ]);
176  std::string line;
177 
178  while ( true ) {
179  if ( p_status.eof() ) {
180  finished = waitpid( pid, &status_code, 0 );
181  if ( finished < 0 ) {
182  perror( "waitpid failed" );
183  exit( 5 );
184  }
185  assert_eq( pid, finished );
186  testDied();
187  return;
188  }
189 
190  line = p_status.nextLineBlocking();
191  processStatus( line );
192  }
193  }
194 #endif
195 
196  void status( std::string line ) {
197  // std::cerr << "status: " << line << std::endl;
198 #ifdef POSIX
199  if ( want_fork ) {
200  line += "\n";
201  ::write( status_fds[ 1 ], line.c_str(), line.length() );
202  } else
203 #endif
204  processStatus( line );
205  }
206 
207  void confirm() {
208  std::string line( "ack\n" );
209  if ( want_fork )
210  ::write( confirm_fds[ 1 ], line.c_str(), line.length() );
211  }
212 
213  void waitForAck() {
214  if ( want_fork ) {
215  std::string line = p_confirm.nextLineBlocking();
216  assert_eq( std::string( "ack" ), line );
217  }
218  }
219 
220  int main( int _argc, char **_argv )
221  {
222  argc = _argc;
223  argv = _argv;
224 
225  all.suiteCount = sizeof(suites)/sizeof(RunSuite);
226  all.suites = suites;
227  all.feedback = this;
228 #ifdef POSIX
229  want_fork = argc <= 2;
230 #else
231  want_fork = false;
232 #endif
233 
234  while (true) {
235 #ifdef POSIX
236  if ( socketpair( PF_UNIX,SOCK_STREAM, 0, status_fds ) )
237  return 1;
238  if ( socketpair( PF_UNIX,SOCK_STREAM, 0, confirm_fds ) )
239  return 1;
240  if ( want_fork ) {
241  pid = fork();
242  if ( pid < 0 )
243  return 2;
244  if ( pid == 0 ) { // child
245  child();
246  } else {
247  parent();
248  }
249  } else
250 #endif
251  child();
252  }
253  return 0;
254  }
255 };
256 
257 int main( int argc, char **argv ) {
258  return Main().main( argc, argv );
259 }
260 
int confirm_fds[2]
Definition: test-main.h:22
int suiteCount
Definition: test-runner.h:38
void status(std::string line)
Definition: test-main.h:196
RunSuite * findSuite(std::string name)
Definition: test-runner.h:41
void processStatus(std::string line)
Definition: test-main.h:112
void waitForAck()
Definition: test-main.h:213
wibble::sys::Pipe p_status
Definition: test-main.h:19
void child()
Definition: test-main.h:46
wibble::sys::Pipe p_confirm
Definition: test-main.h:20
int suite_ok
Definition: test-main.h:30
RunAll all
Definition: test-main.h:37
void runTest(RunSuite &s, int test)
Definition: test-runner.h:65
bool want_fork
Definition: test-main.h:35
std::string current
Definition: test-main.h:34
Definition: test-runner.h:31
int suite
Definition: test-main.h:18
#define assert_eq(x, y)
Definition: test.h:33
#define assert(x)
Definition: test.h:30
Main()
Definition: test-main.h:39
Definition: pipe.h:27
char ** argv
Definition: test-main.h:25
int main(int _argc, char **_argv)
Definition: test-main.h:220
int findTest(std::string name)
Definition: test-runner.h:22
int status_code
Definition: test-main.h:27
Definition: test-runner.h:17
int test_ok
Definition: test-main.h:28
std::string nextLineBlocking()
Definition: pipe.h:204
Definition: test-runner.h:36
void confirm()
Definition: test-main.h:207
int total_ok
Definition: test-main.h:31
int total_failed
Definition: test-main.h:31
int test
Definition: test-main.h:18
int suite_failed
Definition: test-main.h:30
int argc
Definition: test-main.h:24
pid_t pid
Definition: test-main.h:23
pid_t finished
Definition: test-main.h:26
int announced_suite
Definition: test-main.h:33
void runSuite(RunSuite &s, int fromTest, int suite, int suiteCount)
Definition: test-runner.h:48
Definition: test-main.h:16
RunSuite * suites
Definition: test-runner.h:37
int status_fds[2]
Definition: test-main.h:21
bool eof()
Definition: pipe.h:130
ListIterator< List > end(List)
Definition: list.h:425
void runFrom(int suite, int test)
Definition: test-runner.h:76
RunFeedback * feedback
Definition: test-runner.h:39