tut logo

tut_restartable.hpp Source File


tut_restartable.hpp
1 #ifndef TUT_RESTARTABLE_H_GUARD
2 #define TUT_RESTARTABLE_H_GUARD
3 
4 #include <tut/tut.hpp>
5 #include <fstream>
6 #include <iostream>
7 #include <stdexcept>
8 #include <cassert>
9 
20 namespace tut
21 {
22 
23 namespace util
24 {
25 
29 std::string escape(const std::string& orig)
30 {
31  std::string rc;
32  std::string::const_iterator i,e;
33  i = orig.begin();
34  e = orig.end();
35 
36  while (i != e)
37  {
38  if ((*i >= 'a' && *i <= 'z') ||
39  (*i >= 'A' && *i <= 'Z') ||
40  (*i >= '0' && *i <= '9') )
41  {
42  rc += *i;
43  }
44  else
45  {
46  rc += '\\';
47  rc += ('a'+(((unsigned int)*i) >> 4));
48  rc += ('a'+(((unsigned int)*i) & 0xF));
49  }
50 
51  ++i;
52  }
53  return rc;
54 }
55 
59 std::string unescape(const std::string& orig)
60 {
61  std::string rc;
62  std::string::const_iterator i,e;
63  i = orig.begin();
64  e = orig.end();
65 
66  while (i != e)
67  {
68  if (*i != '\\')
69  {
70  rc += *i;
71  }
72  else
73  {
74  ++i;
75  if (i == e)
76  {
77  throw std::invalid_argument("unexpected end of string");
78  }
79  unsigned int c1 = *i;
80  ++i;
81  if (i == e)
82  {
83  throw std::invalid_argument("unexpected end of string");
84  }
85  unsigned int c2 = *i;
86  rc += (((c1 - 'a') << 4) + (c2 - 'a'));
87  }
88 
89  ++i;
90  }
91  return rc;
92 }
93 
97 void serialize(std::ostream& os, const tut::test_result& tr)
98 {
99  os << escape(tr.group) << std::endl;
100  os << tr.test << ' ';
101  switch(tr.result)
102  {
103  case test_result::ok:
104  os << 0;
105  break;
106  case test_result::fail:
107  os << 1;
108  break;
109  case test_result::ex:
110  os << 2;
111  break;
112  case test_result::warn:
113  os << 3;
114  break;
115  case test_result::term:
116  os << 4;
117  break;
118  case test_result::rethrown:
119  os << 5;
120  break;
121  case test_result::ex_ctor:
122  os << 6;
123  break;
124  case test_result::dummy:
125  assert(!"Should never be called");
126  default:
127  throw std::logic_error("operator << : bad result_type");
128  }
129  os << ' ' << escape(tr.message) << std::endl;
130 }
131 
135 bool deserialize(std::istream& is, tut::test_result& tr)
136 {
137  std::getline(is,tr.group);
138  if (is.eof())
139  {
140  return false;
141  }
142  tr.group = unescape(tr.group);
143 
144  tr.test = -1;
145  is >> tr.test;
146  if (tr.test < 0)
147  {
148  throw std::logic_error("operator >> : bad test number");
149  }
150 
151  int n = -1;
152  is >> n;
153  switch(n)
154  {
155  case 0:
156  tr.result = test_result::ok;
157  break;
158  case 1:
159  tr.result = test_result::fail;
160  break;
161  case 2:
162  tr.result = test_result::ex;
163  break;
164  case 3:
165  tr.result = test_result::warn;
166  break;
167  case 4:
168  tr.result = test_result::term;
169  break;
170  case 5:
171  tr.result = test_result::rethrown;
172  break;
173  case 6:
174  tr.result = test_result::ex_ctor;
175  break;
176  default:
177  throw std::logic_error("operator >> : bad result_type");
178  }
179 
180  is.ignore(1); // space
181  std::getline(is,tr.message);
182  tr.message = unescape(tr.message);
183  if (!is.good())
184  {
185  throw std::logic_error("malformed test result");
186  }
187  return true;
188 }
189 }
190 
195 {
196  test_runner& runner_;
197  callbacks callbacks_;
198 
199  std::string dir_;
200  std::string log_; // log file: last test being executed
201  std::string jrn_; // journal file: results of all executed tests
202 
203 public:
208  restartable_wrapper(const std::string& dir = ".")
209  : runner_(runner.get()),
210  callbacks_(),
211  dir_(dir),
212  log_( dir + '/' + "log.tut" ),
213  jrn_( dir + '/' + "journal.tut" )
214  {
215  // dozen: it works, but it would be better to use system path separator
216  }
217 
221  void register_group(const std::string& name, group_base* gr)
222  {
223  runner_.register_group(name,gr);
224  }
225 
230  {
231  callbacks_.clear();
232  callbacks_.insert(cb);
233  }
234 
235  void insert_callback(callback* cb)
236  {
237  callbacks_.insert(cb);
238  }
239 
240  void erase_callback(callback* cb)
241  {
242  callbacks_.erase(cb);
243  }
244 
245  void set_callbacks(const callbacks& cb)
246  {
247  callbacks_ = cb;
248  }
249 
250  const callbacks& get_callbacks() const
251  {
252  return runner_.get_callbacks();
253  }
254 
259  {
260  return runner_.list_groups();
261  }
262 
266  void run_tests() const
267  {
268  // where last run was failed
269  std::string fail_group;
270  int fail_test;
271  read_log_(fail_group,fail_test);
272  bool fail_group_reached = (fail_group == "");
273 
274  // iterate over groups
276  tut::groupnames::const_iterator gni,gne;
277  gni = gn.begin();
278  gne = gn.end();
279  while (gni != gne)
280  {
281  // skip all groups before one that failed
282  if (!fail_group_reached)
283  {
284  if (*gni != fail_group)
285  {
286  ++gni;
287  continue;
288  }
289  fail_group_reached = true;
290  }
291 
292  // first or restarted run
293  int test = (*gni == fail_group && fail_test >= 0) ? fail_test + 1 : 1;
294  while(true)
295  {
296  // last executed test pos
297  register_execution_(*gni,test);
298 
299  tut::test_result tr;
300  if( !runner_.run_test(*gni,test, tr) || tr.result == test_result::dummy )
301  {
302  break;
303  }
304  register_test_(tr);
305 
306  ++test;
307  }
308 
309  ++gni;
310  }
311 
312  // show final results to user
313  invoke_callback_();
314 
315  // truncate files as mark of successful finish
316  truncate_();
317  }
318 
319 private:
323  void invoke_callback_() const
324  {
325  runner_.set_callbacks(callbacks_);
326  runner_.cb_run_started_();
327 
328  std::string current_group;
329  std::ifstream ijournal(jrn_.c_str());
330  while (ijournal.good())
331  {
332  tut::test_result tr;
333  if( !util::deserialize(ijournal,tr) )
334  {
335  break;
336  }
337  runner_.cb_test_completed_(tr);
338  }
339 
340  runner_.cb_run_completed_();
341  }
342 
346  void register_test_(const test_result& tr) const
347  {
348  std::ofstream ojournal(jrn_.c_str(), std::ios::app);
349  util::serialize(ojournal, tr);
350  ojournal << std::flush;
351  if (!ojournal.good())
352  {
353  throw std::runtime_error("unable to register test result in file "
354  + jrn_);
355  }
356  }
357 
361  void register_execution_(const std::string& grp, int test) const
362  {
363  // last executed test pos
364  std::ofstream olog(log_.c_str());
365  olog << util::escape(grp) << std::endl << test << std::endl << std::flush;
366  if (!olog.good())
367  {
368  throw std::runtime_error("unable to register execution in file "
369  + log_);
370  }
371  }
372 
376  void truncate_() const
377  {
378  std::ofstream olog(log_.c_str());
379  std::ofstream ojournal(jrn_.c_str());
380  }
381 
385  void read_log_(std::string& fail_group, int& fail_test) const
386  {
387  // read failure point, if any
388  std::ifstream ilog(log_.c_str());
389  std::getline(ilog,fail_group);
390  fail_group = util::unescape(fail_group);
391  ilog >> fail_test;
392  if (!ilog.good())
393  {
394  fail_group = "";
395  fail_test = -1;
396  truncate_();
397  }
398  else
399  {
400  // test was terminated...
401  tut::test_result tr(fail_group, fail_test, "", tut::test_result::term);
402  register_test_(tr);
403  }
404  }
405 };
406 
407 }
408 
409 #endif
410 
Definition: tut_runner.hpp:113
std::string group
Definition: tut_result.hpp:74
groupnames list_groups() const
Definition: tut_restartable.hpp:258
bool run_test(const std::string &group_name, int n, test_result &tr) const
Definition: tut_runner.hpp:268
test finished successfully
Definition: tut_result.hpp:91
void set_callbacks(const callbacks &cb)
Definition: tut_runner.hpp:200
int test
Definition: tut_result.hpp:79
void register_group(const std::string &name, group_base *gr)
Definition: tut_restartable.hpp:221
test finished successfully, but test destructor throwed
Definition: tut_result.hpp:94
std::vector< std::string > groupnames
Definition: tut_runner.hpp:107
void register_group(const std::string &name, group_base *gr)
Definition: tut_runner.hpp:132
Definition: tut_runner.hpp:16
Definition: tut_restartable.hpp:194
void run_tests() const
Definition: tut_restartable.hpp:266
test failed with ensure() or fail() methods
Definition: tut_result.hpp:92
const groupnames list_groups() const
Definition: tut_runner.hpp:209
std::string message
Definition: tut_result.hpp:107
Definition: tut_result.hpp:69
test forced test application to terminate abnormally
Definition: tut_result.hpp:95
test throwed an exceptions
Definition: tut_result.hpp:93
const callbacks & get_callbacks() const
Definition: tut_runner.hpp:191
restartable_wrapper(const std::string &dir=".")
Definition: tut_restartable.hpp:208
void set_callback(callback *cb)
Definition: tut_restartable.hpp:229
Definition: tut_runner.hpp:38

All Rights Reserved. Generated on Wed Dec 18 2013 11:19:52 for TUT by doxygen 1.8.5