TPIE

v1.1rc1-6-g0c97303
unittest.h
1 // -*- mode: c++; tab-width: 4; indent-tabs-mode: t; c-file-style: "stroustrup"; -*-
2 // vi:set ts=4 sts=4 sw=4 noet :
3 // Copyright 2012, The TPIE development team
4 //
5 // This file is part of TPIE.
6 //
7 // TPIE is free software: you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License as published by the
9 // Free Software Foundation, either version 3 of the License, or (at your
10 // option) any later version.
11 //
12 // TPIE is distributed in the hope that it will be useful, but WITHOUT ANY
13 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 // License for more details.
16 //
17 // You should have received a copy of the GNU Lesser General Public License
18 // along with TPIE. If not, see <http://www.gnu.org/licenses/>
19 
20 #ifndef __TPIE_UNITTEST_H__
21 #define __TPIE_UNITTEST_H__
22 
23 #include <iostream>
24 #include <tpie/types.h>
25 #include <tpie/logstream.h>
26 #include <map>
27 #include <vector>
28 #include <boost/lexical_cast.hpp>
29 #include <algorithm>
30 
31 namespace tpie {
32 
33 class teststream_buf: public std::basic_streambuf<char, std::char_traits<char> > {
34 private:
35  const static size_t line_size = 2048;
36  char m_line[line_size];
37  bool m_new_line;
38 public:
40  virtual int overflow(int c = traits_type::eof());
41  void stateAlign();
42  virtual int sync();
43 };
44 
45 class teststream: public std::ostream {
46 private:
47  teststream_buf m_buff;
48  size_t failed;
49  size_t total;
50 public:
51  teststream();
52  bool success();
53  friend void result_manip(teststream & s, bool success);
54 };
55 
56 template <class TP>
57 class testmanip {
58  void (*_f)(teststream&, TP);
59  TP _a;
60 public:
61  inline testmanip(void (*f)(teststream&, TP), TP a) : _f(f), _a(a) {}
62  inline friend std::ostream& operator<<(std::ostream& o, const testmanip<TP>& m) {
63  (*m._f)(static_cast<teststream&>(o), m._a);
64  return o;
65  }
66 };
67 
68 
69 testmanip<bool> result(bool success);
70 testmanip<bool> success();
71 testmanip<bool> failure();
72 
73 #define TEST_ENSURE(cond, message) { \
74  if (! (cond) ) { \
75  tpie::log_error() << message \
76  << " (line " << __LINE__ << ")" << std::endl; \
77  return false; \
78  } \
79  }
80 
81 #define TEST_ENSURE_EQUALITY(v1, v2, message) { \
82  if ( !((v1) == (v2)) ) { \
83  tpie::log_error() << message \
84  << " (" << v1 << " != " << v2 \
85  << " line " << __LINE__ << ")" << std::endl; \
86  } \
87  }
88 
89 
90 class tests;
91 
92 namespace bits {
93  class test_runner {
94  tests * t;
95  bool result;
96 
97  public:
98  test_runner(tests * t, const std::string & name);
99 
100  void set_result(bool result);
101  void exception();
102 
103  ~test_runner();
104  };
105 } // namespace bits
106 
107 class tests {
108 public:
109  static const size_t lineLength = 79;
110 
111  tests(int argc, char ** argv, memory_size_type memory_limit=50);
112  virtual ~tests();
113 
114  template <typename T>
115  tests & setup(T t);
116 
117  template <typename T>
118  tests & finish(T t);
119 
120  template <typename T>
121  tests & test(T fct, const std::string & name);
122 
123  template <typename T, typename T1>
124  tests & test(T fct, const std::string & name,
125  const std::string & p1_name, T1 p1_default);
126 
127  template <typename T, typename T1, typename T2>
128  tests & test(T fct, const std::string & name,
129  const std::string & p1_name, T1 p1_default,
130  const std::string & p2_name, T2 p2_default);
131 
132  template <typename T, typename T1, typename T2, typename T3>
133  tests & test(T fct, const std::string & name,
134  const std::string & p1_name, T1 p1_default,
135  const std::string & p2_name, T2 p2_default,
136  const std::string & p3_name, T3 p3_default);
137 
138  template <typename T, typename T1, typename T2, typename T3, typename T4>
139  tests & test(T fct, const std::string & name,
140  const std::string & p1_name, T1 p1_default,
141  const std::string & p2_name, T2 p2_default,
142  const std::string & p3_name, T3 p3_default,
143  const std::string & p4_name, T4 p4_default);
144 
145  template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5>
146  tests & test(T fct, const std::string & name,
147  const std::string & p1_name, T1 p1_default,
148  const std::string & p2_name, T2 p2_default,
149  const std::string & p3_name, T3 p3_default,
150  const std::string & p4_name, T4 p4_default,
151  const std::string & p5_name, T5 p5_default);
152 
153  template <typename T>
154  tests & multi_test(T fct, const std::string & name);
155 
156  template <typename T, typename T1>
157  tests & multi_test(T fct, const std::string & name, const std::string & p1_name, T1 p1_default);
158 
159  template <typename T, typename T1, typename T2>
160  tests & multi_test(T fct, const std::string & name,
161  const std::string & p1_name, T1 p1_default,
162  const std::string & p2_name, T2 p2_default);
163 
164  template <typename T, typename T1, typename T2, typename T3>
165  tests & multi_test(T fct, const std::string & name,
166  const std::string & p1_name, T1 p1_default,
167  const std::string & p2_name, T2 p2_default,
168  const std::string & p3_name, T3 p3_default);
169 
170  template <typename T, typename T1, typename T2, typename T3, typename T4>
171  tests & multi_test(T fct, const std::string & name,
172  const std::string & p1_name, T1 p1_default,
173  const std::string & p2_name, T2 p2_default,
174  const std::string & p3_name, T3 p3_default,
175  const std::string & p4_name, T4 p4_default);
176 
177  operator int();
178 protected:
179  virtual void build_information(std::ostream & o);
180 private:
181  void show_usage(std::ostream & o);
182 
183  struct func {
184  virtual void operator()() = 0;
185  virtual ~func() {}
186  };
187 
188  template <typename T>
189  struct func_impl: func {
190  T t;
191  func_impl(T t): t(t) {}
192  virtual void operator()() {t();}
193  };
194 
195 
196  struct test_log_target: public log_target {
197  test_log_target(std::ostream & os = std::cout)
198  : os(os)
199  , threshold(LOG_FATAL)
200  , bufferThreshold(LOG_FATAL)
201  , m_onNameLine(false)
202  , m_onBOL(true)
203  {
204  }
205 
206  ~test_log_target() {
207  if (!m_onBOL) os << std::endl;
208  }
209 
210  void set_test(const std::string & name) {
211  buffer.str("");
212  m_onNameLine = false;
213  m_name = name;
214  set_status(" ");
215  }
216 
217  void set_status(const std::string & status) {
218  if (m_onNameLine) {
219  os << '\r';
220  } else if (!m_onBOL) {
221  os << '\n';
222  }
223 
224  os << m_name << ' ';
225  const size_t maxNameSize = lineLength
226  - 2 // spaces before and after dots
227  - 6; // status message: "[STAT]"
228  if (maxNameSize > m_name.size()) os << std::string(maxNameSize-m_name.size(), '.');
229  os << ' ';
230 
231  os << '[' << status << ']' << std::flush;
232  m_onNameLine = true;
233  m_onBOL = false;
234  }
235 
236  void log(log_level level, const char * buf, size_t n) {
237  if (!n) return;
238  if (level <= bufferThreshold) buffer << std::string(buf, n);
239  if (level > threshold) return;
240  if (m_onNameLine) os << '\n';
241  std::string msg(buf, n);
242  os << msg;
243  m_onNameLine = false;
244  m_onBOL = msg[msg.size()-1] == '\n' || msg[msg.size()-1] == '\r';
245  os << std::flush;
246  }
247 
248  void set_threshold(log_level level) {
249  threshold = level;
250  }
251 
252  void set_buffer_threshold(log_level level) {
253  bufferThreshold = level;
254  }
255 
256  std::stringstream buffer;
257  private:
258  std::ostream & os;
259  log_level threshold;
260  log_level bufferThreshold;
261  bool m_onNameLine;
262  std::string m_name;
263  bool m_onBOL;
264  };
265 
266 
267  void start_test(const std::string & name);
268  void end_test(bool result);
269 
270  template <typename T>
271  T get_arg(const std::string & name, T def) const;
272 
273  template <typename T>
274  std::string arg_str(const std::string & name, T def) const;
275 
276  bool bad, usage, version;
277  size_t tests_runned;
278  std::string exe_name;
279  std::string test_name;
280  bool testAll;
281  std::map<std::string, std::string> args;
282  memory_size_type memory_limit;
283  std::string current_name;
284  std::vector<func *> setups;
285  std::vector<func *> finishs;
286  test_log_target log;
287  std::vector<std::string> m_tests;
288 
289  friend class bits::test_runner;
290 };
291 
292 template <typename src, typename dst>
294  dst operator()(const src & s) {
295  return boost::lexical_cast<dst>(s);
296  }
297 };
298 
299 template <>
300 struct magic_cast_help<bool, std::string> {
301  std::string operator()(bool b) {
302  return b?"true":"false";
303  }
304 };
305 
306 template <>
307 struct magic_cast_help<std::string, bool> {
308  bool operator()(std::string v) {
309  std::transform(v.begin(), v.end(), v.begin(), tolower);
310  return v == "true" || v == "1" || v == "on" || v == "yes";
311  }
312 };
313 
314 template <typename dst, typename src>
315 dst magic_cast(const src & s) {
316  return magic_cast_help<src, dst>()(s);
317 }
318 
319 template <typename T>
320 struct get_arg_help {
321  T operator()(const std::map<std::string, std::string> & args, const std::string & name, T def) {
322  T arg=def;
323  try {
324  std::map<std::string, std::string>::const_iterator i=args.find(name);
325  if (i != args.end()) arg=magic_cast<T>(i->second);
326  } catch (std::bad_cast) {
327  std::cerr << "The argument " << name << " has the wrong type" << std::endl;
328  }
329  return arg;
330  }
331 };
332 
333 template <>
334 struct get_arg_help<bool> {
335  bool operator()(const std::map<std::string, std::string> & args, const std::string & name, bool) {
336  return args.count(name) != 0;
337  }
338 };
339 
340 template <typename T>
341 T tests::get_arg(const std::string & name, T def) const {
342  return get_arg_help<T>()(args, name, def);
343 }
344 
345 template <typename T>
346 std::string tests::arg_str(const std::string & name, T def) const {
347  std::string dashes((name.size() == 1) ? 1 : 2, '-');
348  return std::string(" [")+dashes+name+" ARG (= "+magic_cast<std::string>(def)+")]";
349 }
350 
351 template <typename T>
352 tests & tests::test(T fct, const std::string & name) {
353  m_tests.push_back(name);
354  if (testAll || name == test_name) {
355  bits::test_runner t(this, name);
356  try {
357  t.set_result(fct());
358  } catch (...) {
359  t.exception();
360  }
361  }
362  return *this;
363 }
364 
365 template <typename T, typename T1>
366 tests & tests::test(T fct, const std::string & name, const std::string & p1_name, T1 p1_default) {
367  m_tests.push_back(name
368  + arg_str(p1_name, p1_default));
369  if (testAll || name == test_name) {
370  bits::test_runner t(this, name);
371  try {
372  t.set_result(fct(get_arg(p1_name, p1_default)));
373  } catch (...) {
374  t.exception();
375  }
376  }
377  return *this;
378 }
379 
380 
381 template <typename T, typename T1, typename T2>
382 tests & tests::test(T fct, const std::string & name, const std::string & p1_name, T1 p1_default, const std::string & p2_name, T2 p2_default) {
383  m_tests.push_back(name
384  + arg_str(p1_name, p1_default)
385  + arg_str(p2_name, p2_default));
386  if (testAll || name == test_name) {
387  bits::test_runner t(this, name);
388  try {
389  t.set_result(fct(get_arg(p1_name, p1_default),
390  get_arg(p2_name, p2_default)));
391  } catch (...) {
392  t.exception();
393  }
394  }
395  return *this;
396 }
397 
398 template <typename T, typename T1, typename T2, typename T3>
399 tests & tests::test(T fct, const std::string & name,
400  const std::string & p1_name, T1 p1_default,
401  const std::string & p2_name, T2 p2_default,
402  const std::string & p3_name, T3 p3_default) {
403  m_tests.push_back(name
404  + arg_str(p1_name, p1_default)
405  + arg_str(p2_name, p2_default)
406  + arg_str(p3_name, p3_default));
407  if (testAll || name == test_name) {
408  bits::test_runner t(this, name);
409  try {
410  t.set_result(fct(get_arg(p1_name, p1_default),
411  get_arg(p2_name, p2_default),
412  get_arg(p3_name, p3_default)));
413  } catch (...) {
414  t.exception();
415  }
416  }
417  return *this;
418 
419 }
420 
421 template <typename T, typename T1, typename T2, typename T3, typename T4>
422 tests & tests::test(T fct, const std::string & name,
423  const std::string & p1_name, T1 p1_default,
424  const std::string & p2_name, T2 p2_default,
425  const std::string & p3_name, T3 p3_default,
426  const std::string & p4_name, T4 p4_default) {
427  m_tests.push_back(name
428  + arg_str(p1_name, p1_default)
429  + arg_str(p2_name, p2_default)
430  + arg_str(p3_name, p3_default)
431  + arg_str(p4_name, p4_default));
432  if (testAll || name == test_name) {
433  bits::test_runner t(this, name);
434  try {
435  t.set_result(fct(get_arg(p1_name, p1_default),
436  get_arg(p2_name, p2_default),
437  get_arg(p3_name, p3_default),
438  get_arg(p4_name, p4_default)));
439  } catch (...) {
440  t.exception();
441  }
442  }
443  return *this;
444 }
445 
446 template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5>
447 tests & tests::test(T fct, const std::string & name,
448  const std::string & p1_name, T1 p1_default,
449  const std::string & p2_name, T2 p2_default,
450  const std::string & p3_name, T3 p3_default,
451  const std::string & p4_name, T4 p4_default,
452  const std::string & p5_name, T5 p5_default) {
453  m_tests.push_back(name
454  + arg_str(p1_name, p1_default)
455  + arg_str(p2_name, p2_default)
456  + arg_str(p3_name, p3_default)
457  + arg_str(p4_name, p4_default)
458  + arg_str(p5_name, p5_default));
459  if (testAll || name == test_name) {
460  bits::test_runner t(this, name);
461  try {
462  t.set_result(fct(get_arg(p1_name, p1_default),
463  get_arg(p2_name, p2_default),
464  get_arg(p3_name, p3_default),
465  get_arg(p4_name, p4_default),
466  get_arg(p5_name, p5_default)));
467  } catch (...) {
468  t.exception();
469  }
470  }
471  return *this;
472 }
473 
474 
475 template <typename T>
476 tests & tests::multi_test(T fct, const std::string & name) {
477  m_tests.push_back(name);
478  if (testAll || name == test_name) {
479  bits::test_runner t(this, name);
480  try {
481  teststream ts;
482  fct(ts);
483  t.set_result(ts.success());
484  } catch (...) {
485  t.exception();
486  }
487  }
488  return *this;
489 }
490 
491 template <typename T, typename T1>
492 tests & tests::multi_test(T fct, const std::string & name, const std::string & p1_name, T1 p1_default) {
493  m_tests.push_back(name+ arg_str(p1_name, p1_default));
494  if (testAll || name == test_name) {
495  bits::test_runner t(this, name);
496  try {
497  teststream ts;
498  fct(ts, get_arg(p1_name, p1_default));
499  t.set_result(ts.success());
500  } catch (...) {
501  t.exception();
502  }
503  }
504  return *this;
505 }
506 
507 template <typename T, typename T1, typename T2>
508 tests & tests::multi_test(T fct, const std::string & name,
509  const std::string & p1_name, T1 p1_default,
510  const std::string & p2_name, T2 p2_default) {
511  m_tests.push_back(name+
512  arg_str(p1_name, p1_default) +
513  arg_str(p2_name, p2_default));
514 
515  if (testAll || name == test_name) {
516  bits::test_runner t(this, name);
517  try {
518  teststream ts;
519  fct(ts,
520  get_arg(p1_name, p1_default),
521  get_arg(p2_name, p2_default));
522  t.set_result(ts.success());
523  } catch (...) {
524  t.exception();
525  }
526  }
527  return *this;
528 }
529 
530 template <typename T, typename T1, typename T2, typename T3>
531 tests & tests::multi_test(T fct, const std::string & name,
532  const std::string & p1_name, T1 p1_default,
533  const std::string & p2_name, T2 p2_default,
534  const std::string & p3_name, T3 p3_default) {
535  m_tests.push_back(name+
536  arg_str(p1_name, p1_default) +
537  arg_str(p2_name, p2_default) +
538  arg_str(p3_name, p3_default));
539 
540  if (testAll || name == test_name) {
541  bits::test_runner t(this, name);
542  try {
543  teststream ts;
544  fct(ts,
545  get_arg(p1_name, p1_default),
546  get_arg(p2_name, p2_default),
547  get_arg(p3_name, p3_default));
548  t.set_result(ts.success());
549  } catch (...) {
550  t.exception();
551  }
552  }
553  return *this;
554 }
555 
556 template <typename T, typename T1, typename T2, typename T3, typename T4>
557 tests & tests::multi_test(T fct, const std::string & name,
558  const std::string & p1_name, T1 p1_default,
559  const std::string & p2_name, T2 p2_default,
560  const std::string & p3_name, T3 p3_default,
561  const std::string & p4_name, T4 p4_default) {
562  m_tests.push_back(name+
563  arg_str(p1_name, p1_default) +
564  arg_str(p2_name, p2_default) +
565  arg_str(p3_name, p3_default) +
566  arg_str(p4_name, p4_default));
567 
568  if (testAll || name == test_name) {
569  bits::test_runner t(this, name);
570  try {
571  teststream ts;
572  fct(ts,
573  get_arg(p1_name, p1_default),
574  get_arg(p2_name, p2_default),
575  get_arg(p3_name, p3_default),
576  get_arg(p4_name, p4_default));
577  t.set_result(ts.success());
578  } catch (...) {
579  t.exception();
580  }
581  }
582  return *this;
583 }
584 
585 template <typename T>
586 tests & tests::setup(T t) {
587  setups.push_back(new func_impl<T>(t));
588  return *this;
589 }
590 
591 template <typename T>
592 tests & tests::finish(T t) {
593  finishs.push_back(new func_impl<T>(t));
594  return *this;
595 }
596 
597 } //namespace tpie
598 
599 #endif // __TPIE_UNITTEST_H__
LOG_FATAL is the highest error level and is used for all kinds of errors that would normally impair s...
Definition: loglevel.h:37
Standard types.
logstream class used by definitions in tpie_log.h.
log_level
TPIE logging levels, from higest priority to lowest.
Definition: loglevel.h:33