BALL  1.5.0
classTest.h
Go to the documentation of this file.
1 #ifndef BALL_CONCEPT_CLASSTEST_H
2 #define BALL_CONCEPT_CLASSTEST_H
3 
5 #include <BALL/SYSTEM/file.h>
7 
8 #include <chrono>
9 #include <cmath>
10 #include <list>
11 #include <string>
12 #include <thread>
13 
14 /* define a special namespace for all internal variables */\
15 /* to avoid potential collisions */\
16 namespace TEST
17 {
18  int verbose = 0;
19  bool all_tests = true;
20  bool test = true;
21  bool this_test;
22  int exception = 0;
23  string exception_name = "";
24  const char* version_string = BALL_RELEASE_STRING;
25  bool newline = false;
26  list<string> tmp_file_list;
27  std::ifstream infile;
28  std::ifstream templatefile;
30  double precision = 1e-6;
31 
32  template<class T>
33  void printErrorMessage(T &, bool subtest)
34  {
35  std::cout << std::endl
36  << " (caught unidentified and unexpected exception"
37  << (subtest ? "" : " outside a subtest") << "!)"
38  << std::endl;
39  }
40 
41  template<>
42  void printErrorMessage(std::exception& e, bool subtest)
43  {
44  std::cout << std::endl
45  << " (caught expected STL exception"
46  << (subtest ? "" : " outside a subtest")
47  << ": " << e.what() << ")"
48  << std::endl;
49  }
50 
51  template<>
53  {
54  std::cout << std::endl
55  << " (caught exception of type "
56  << e.getName();
57  if ((e.getLine() > 0) && e.getFile()[0] != '\0')
58  {
59  std::cout << (subtest ? "" : " outside a subtest")
60  << ", which was thrown in line "
61  << e.getLine() << " of file " << e.getFile();
62  }
63  std::cout << " - unexpected!) "
64  << std::endl
65  << " (message is: " << e.getMessage() << ")"
66  << std::endl;
67  }
68 
69  template<>
71  {
72  std::cout << std::endl
73  << " (caught exception of type "
74  << e.getName();
75  if ((e.getLine() > 0) && e.getFile()[0] != '\0')
76  {
77  std::cout << (subtest ? "" : " outside a subtest")
78  << ", which was thrown in line "
79  << e.getLine() << " of file " << e.getFile();
80  }
81  std::cout << " while looking for file " << e.getFilename()
82  << " - unexpected!) "
83  << std::endl;
84  }
85 
86  template<class T>
87  void printException(T e, bool subtest)
88  {
89  TEST::this_test = false;
90  TEST::test = false;
91  TEST::all_tests = false;
92  if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))
93  {
94  if(!TEST::newline)
95  {
96  TEST::newline = true;
97  std::cout << std::endl;
98  }
99  printErrorMessage(e, subtest);
100  }
101  }
102 }
103 
112 #define PRECISION(a) \
113  TEST::precision = (a);
114 
128 #define START_TEST(class_name)\
129 \
130 int main(int argc, char **argv)\
131 {\
132 \
133  if (argc == 2) {\
134  if (!strcmp(argv[1], "-v"))\
135  TEST::verbose = 1;\
136  if (!strcmp(argv[1], "-V"))\
137  TEST::verbose = 2;\
138  };\
139 \
140  if ((argc > 2) || ((argc == 2) && (TEST::verbose == 0))) {\
141  std::cerr << "Checks " #class_name " class" << std::endl;\
142 \
143  std::cerr << "On successful operation it simply returns OK," << std::endl;\
144  std::cerr << "otherwise FAILURE is printed." << std::endl;\
145  std::cerr << "If called with an argument of -v, " << argv[0] << " prints detailed" << std::endl;\
146  std::cerr << "information about individual tests." << std::endl;\
147  std::cerr << "Option -V provides verbose information on" << std::endl;\
148  std::cerr << "every subtest." << std::endl;\
149  return 1;\
150  }\
151 \
152  if (TEST::verbose > 0)\
153  std::cout << "Version: " << TEST::version_string << std::endl;\
154 \
155  try {\
156 
157 
168 #define END_TEST \
169  /* global try block */\
170  }\
171  catch (BALL::Exception::FileNotFound& e) { TEST::printException(e, false); }\
172  catch (BALL::Exception::GeneralException& e) { TEST::printException(e, false); }\
173  catch (std::exception& e) { TEST::printException(e, false); }\
174  catch (...) { TEST::printException(0, false); }\
175  \
176  /* clean up all temporary files */\
177  while (TEST::tmp_file_list.size() > 0 && TEST::verbose < 1)\
178  {\
179  ::BALL::File::remove(TEST::tmp_file_list.back().c_str());\
180  TEST::tmp_file_list.pop_back();\
181  }\
182  /* check for exit code */\
183  std::cout << (TEST::all_tests ? "PASSED" : "FAILED") << std::endl;\
184  return !TEST::all_tests;\
185 }\
186 
187 
202 #define CHECK(test_name) \
203  TEST::test = true;\
204  TEST::newline = false;\
205  if (TEST::verbose > 0)\
206  std::cout << "checking " << #test_name << "... " << std::flush;\
207  try\
208  {\
209  while (true)\
210  {\
211 
225 #define STATUS(message)\
226  if (TEST::verbose > 1)\
227  {\
228  if (!TEST::newline) \
229  {\
230  TEST::newline = true;\
231  std::cout << std::endl;\
232  }\
233  std::cout << " status (line " << __LINE__ << "): " << message << std::endl;\
234  }\
235 
254 #define RESULT \
255  break;\
256  }\
257  }\
258  /* catch FileNotFound exceptions to print out the file name */\
259  catch (BALL::Exception::FileNotFound& e) { TEST::printException(e, true); }\
260  catch (::BALL::Exception::GeneralException& e) { TEST::printException(e, true); }\
261  catch (std::exception& e) { TEST::printException(e, true); }\
262  catch (...) { TEST::printException(0, true); }\
263  \
264  TEST::all_tests = TEST::all_tests && TEST::test;\
265  if (TEST::verbose > 0){\
266  if (TEST::newline)\
267  std::cout << " ";\
268  std::cout << (TEST::test ? "passed" : "FAILED") << std::endl;\
269  }\
270 
276 #define SLEEP_FOR_MSECS(ms) std::this_thread::sleep_for(std::chrono::milliseconds(ms))
277 
285 #define NEW_TMP_FILE(filename)\
286  ::BALL::File::createTemporaryFilename(filename);\
287  TEST::tmp_file_list.push_back(filename);\
288  if (TEST::verbose > 1)\
289  {\
290  if (!TEST::newline) \
291  {\
292  TEST::newline = true;\
293  std::cout << std::endl;\
294  }\
295  std::cout << " creating new temporary file '" << filename << "' (line " << __LINE__ << ")" << std::endl;\
296  }\
297 
305 #define NEW_TMP_FILE_WITH_SUFFIX(filename, suffix)\
306  ::BALL::File::createTemporaryFilename(filename, suffix);\
307  TEST::tmp_file_list.push_back(filename);\
308  if (TEST::verbose > 1)\
309  {\
310  if (!TEST::newline) \
311  {\
312  TEST::newline = true;\
313  std::cout << std::endl;\
314  }\
315  std::cout << " creating new temporary file '" << filename << "' (line " << __LINE__ << ")" << std::endl;\
316  }\
317 
325 #define TEST_REAL_EQUAL(a,b) \
326  TEST::this_test = fabs((a) - (b)) < TEST::precision; \
327  TEST::test = TEST::test && TEST::this_test;\
328  if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\
329  {\
330  if (!TEST::newline)\
331  {\
332  TEST::newline = true;\
333  std::cout << std::endl;\
334  }\
335  std::cout << " (line " << __LINE__ << " TEST_REAL_EQUAL("<< #a << ", " << #b << "): got " << (a) << ", expected " << (b) << ") ";\
336  std::cout << (TEST::this_test ? " + " : " - ") << std::endl;\
337  }\
338 
349 #define TEST_EQUAL(a,b) \
350  {\
351  TEST::this_test = ((a) == (b));\
352  TEST::test = TEST::test && TEST::this_test;\
353  if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\
354  {\
355  if (!TEST::newline)\
356  {\
357  TEST::newline = true;\
358  std::cout << std::endl;\
359  }\
360  std::cout << " (line " << __LINE__ << " TEST_EQUAL(" << #a << ", " << #b << "): got " << (a) << ", expected " << (b) << ") ";\
361  std::cout << (TEST::this_test ? " + " : " - ") << std::endl;\
362  }\
363  }\
364 
373 #define TEST_NOT_EQUAL(a,b) \
374  {\
375  TEST::this_test = !((a) == (b));\
376  TEST::test = TEST::test && TEST::this_test;\
377  if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\
378  {\
379  if (!TEST::newline)\
380  {\
381  TEST::newline = true;\
382  std::cout << std::endl;\
383  }\
384  std::cout << " (line " << __LINE__ << " TEST_NOT_EQUAL(" << #a << ", " << #b << "): got " << (a) << ", forbidden is " << (b) << ") ";\
385  std::cout << (TEST::this_test ? " + " : " - ") << std::endl;\
386  }\
387  }\
388 
399 #define TEST_EXCEPTION(exception_type, command) \
400  {\
401  TEST::exception = 0;\
402  try\
403  {\
404  command;\
405  }\
406  catch (exception_type&)\
407  {\
408  TEST::exception = 1;\
409  }\
410  catch (::BALL::Exception::GeneralException& e)\
411  {\
412  TEST::exception = 2;\
413  TEST::exception_name = e.getName();\
414  }\
415  catch (...)\
416  { \
417  TEST::exception = 3;\
418  }\
419  TEST::this_test = (TEST::exception == 1);\
420  TEST::test = TEST::test && TEST::this_test;\
421  \
422  if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\
423  {\
424  if (!TEST::newline)\
425  {\
426  TEST::newline = true;\
427  std::cout << std::endl;\
428  }\
429  std::cout << " (line " << __LINE__ << " TEST_EXCEPTION(" << #exception_type << ", " << #command << "): ";\
430  switch (TEST::exception)\
431  {\
432  case 0: std::cout << " ERROR: no exception!) "; break;\
433  case 1: std::cout << " OK) "; break;\
434  case 2: std::cout << " ERROR: wrong exception: " << TEST::exception_name << ") "; break;\
435  case 3: std::cout << " ERROR: wrong exception!) "; break;\
436  }\
437  std::cout << (TEST::this_test ? " + " : " - ") << std::endl;\
438  }\
439  }\
440 
441 #ifdef BALL_DEBUG
450 #define TEST_PRECONDITION_EXCEPTION(command) \
451  {\
452  TEST::exception = 0;\
453  try\
454  {\
455  command;\
456  }\
457  catch (Exception::Precondition&)\
458  {\
459  TEST::exception = 1;\
460  }\
461  catch (::BALL::Exception::GeneralException& e)\
462  {\
463  TEST::exception = 2;\
464  TEST::exception_name = e.getName();\
465  }\
466  catch (...)\
467  { \
468  TEST::exception = 3;\
469  }\
470  TEST::this_test = (TEST::exception == 1);\
471  TEST::test = TEST::test && TEST::this_test;\
472  \
473  if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\
474  {\
475  if (!TEST::newline)\
476  {\
477  TEST::newline = true;\
478  std::cout << std::endl;\
479  }\
480  std::cout << " (line " << __LINE__ << " TEST_PRECONDITION_EXCEPTION(" << ", " << #command << "): ";\
481  switch (TEST::exception)\
482  {\
483  case 0: std::cout << " ERROR: no exception!) "; break;\
484  case 1: std::cout << " OK) "; break;\
485  case 2: std::cout << " ERROR: wrong exception: " << TEST::exception_name << ") "; break;\
486  case 3: std::cout << " ERROR: wrong exception!) "; break;\
487  }\
488  std::cout << (TEST::this_test ? " + " : " - ") << std::endl;\
489  }\
490  }\
491 
492 #else
493 
494 # define TEST_PRECONDITION_EXCEPTION(command)\
495  if (TEST::verbose > 1)\
496  {\
497  std::cout << " TEST_EXCEPTION_PRECONDITION(" #command ") : (DEBUG mode disabled!)" << std::endl;\
498  }\
499 
500 #endif // BALL_DEBUG
501 
507 #define ABORT_IF(condition) \
508  if (condition) break;
509 
517 #define TEST_FILE(filename, templatename) \
518  {\
519  TEST::equal_files = true;\
520  TEST::infile.open(filename, std::ios::in);\
521  TEST::templatefile.open(templatename, std::ios::in);\
522  \
523  if (TEST::infile.good() && TEST::templatefile.good())\
524  {\
525  String TEST_FILE__template_line;\
526  String TEST_FILE__line;\
527  \
528  while (TEST::infile.good() && TEST::templatefile.good())\
529  {\
530  TEST_FILE__template_line.getline(TEST::templatefile);\
531  TEST_FILE__line.getline(TEST::infile);\
532  \
533  TEST::equal_files &= (TEST_FILE__template_line == TEST_FILE__line);\
534  if (TEST_FILE__template_line != TEST_FILE__line)\
535  {\
536  if (TEST::verbose > 0)\
537  {\
538  if (!TEST::newline)\
539  {\
540  TEST::newline = true;\
541  std::cout << std::endl;\
542  }\
543  \
544  std::cout << " TEST_FILE: line mismatch:\n got: '" << TEST_FILE__line << "'\n expected: '" << TEST_FILE__template_line << "'" << std::endl;\
545  }\
546  }\
547  }\
548  } else {\
549  TEST::equal_files = false;\
550  \
551  if (TEST::verbose > 0)\
552  {\
553  if (!TEST::newline)\
554  {\
555  TEST::newline = true;\
556  std::cout << std::endl;\
557  }\
558  \
559  std::cout << " (line " << __LINE__ << ": TEST_FILE(" << #filename << ", " << #templatename ;\
560  std::cout << ") : " << " cannot open file: \"";\
561  if (!TEST::infile.good())\
562  {\
563  std::cout << filename << "\" (input file) ";\
564  }\
565  if (!TEST::templatefile.good())\
566  {\
567  std::cout << templatename << "\" (template file) ";\
568  }\
569  std::cout << std::endl;\
570  \
571  }\
572  }\
573  TEST::infile.close();\
574  TEST::templatefile.close();\
575  TEST::infile.clear();\
576  TEST::templatefile.clear();\
577  \
578  TEST::this_test = TEST::equal_files;\
579  TEST::test = TEST::test && TEST::this_test;\
580  if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\
581  {\
582  if (!TEST::newline)\
583  {\
584  TEST::newline = true;\
585  std::cout << std::endl;\
586  }\
587  std::cout << " (line " << __LINE__ << ": TEST_FILE("<< #filename << ", " << #templatename << "): ";\
588  std::cout << (TEST::this_test ? "true + " : "false - ") << std::endl;\
589  }\
590  }
591 
592 
601 #define TEST_FILE_REGEXP(filename, templatename) \
602  {\
603  TEST::equal_files = true;\
604  TEST::infile.open(filename, std::ios::in);\
605  TEST::templatefile.open(templatename, std::ios::in);\
606  \
607  if (TEST::infile.good() && TEST::templatefile.good())\
608  {\
609  String TEST_FILE__template_line;\
610  String TEST_FILE__line;\
611  \
612  while (TEST::infile.good() && TEST::templatefile.good())\
613  {\
614  TEST_FILE__template_line.getline(TEST::templatefile);\
615  TEST_FILE__line.getline(TEST::infile);\
616  \
617  if ((TEST_FILE__template_line.size() > 0) && (TEST_FILE__template_line[0] == '/') && (TEST_FILE__template_line[1] != '/'))\
618  {\
619  RegularExpression expression(TEST_FILE__template_line(1));\
620  bool match = expression.match(TEST_FILE__line);\
621  TEST::equal_files &= match;\
622  if (!match)\
623  {\
624  if (TEST::verbose > 0)\
625  {\
626  if (!TEST::newline)\
627  {\
628  TEST::newline = true;\
629  std::cout << std::endl;\
630  }\
631  \
632  std::cout << " TEST_FILE_REGEXP: regexp mismatch: " << TEST_FILE__line << " did not match " << TEST_FILE__template_line(1) << "." << std::endl;\
633  }\
634  }\
635  } else {\
636  TEST::equal_files &= (TEST_FILE__template_line == TEST_FILE__line);\
637  if (TEST_FILE__template_line != TEST_FILE__line)\
638  {\
639  if (TEST::verbose > 0)\
640  {\
641  if (!TEST::newline)\
642  {\
643  TEST::newline = true;\
644  std::cout << std::endl;\
645  }\
646  \
647  std::cout << " TEST_FILE: line mismatch:\n got: '" << TEST_FILE__line << "'\n expected: '" << TEST_FILE__template_line << "'" << std::endl;\
648  }\
649  }\
650  }\
651  }\
652  } else {\
653  TEST::equal_files = false;\
654  \
655  if (TEST::verbose > 0)\
656  {\
657  if (!TEST::newline)\
658  {\
659  TEST::newline = true;\
660  std::cout << std::endl;\
661  }\
662  \
663  std::cout << " (line " << __LINE__ << ": TEST_FILE_REGEXP(" << #filename << ", " << #templatename ;\
664  std::cout << ") : " << " cannot open file: \"";\
665  if (!TEST::infile.good())\
666  {\
667  std::cout << filename << "\" (input file) ";\
668  }\
669  if (!TEST::templatefile.good())\
670  {\
671  std::cout << templatename << "\" (template file) ";\
672  }\
673  std::cout << std::endl;\
674  \
675  }\
676  }\
677  TEST::infile.close();\
678  TEST::templatefile.close();\
679  TEST::infile.clear();\
680  TEST::templatefile.clear();\
681  \
682  TEST::this_test = TEST::equal_files;\
683  TEST::test = TEST::test && TEST::this_test;\
684  if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\
685  {\
686  if (!TEST::newline)\
687  {\
688  TEST::newline = true;\
689  std::cout << std::endl;\
690  }\
691  std::cout << " (line " << __LINE__ << ": TEST_FILE_REGEXP("<< #filename << ", " << #templatename << "): ";\
692  std::cout << (TEST::this_test ? "true + " : "false - ") << std::endl;\
693  }\
694  }
695 
696 
709 #define CAPTURE_OUTPUT_LEVEL(level) \
710  {\
711  std::ostringstream TEST_strstr;\
712  Log.remove(std::cout);\
713  Log.remove(std::cerr);\
714  Log.insert(TEST_strstr, level, level);
715 
728 #define CAPTURE_OUTPUT_LEVEL_RANGE(minlevel, maxlevel) \
729  {\
730  std::ostringstream TEST_strstr;\
731  Log.remove(std::cout);\
732  Log.remove(std::cerr);\
733  Log.insert(TEST_strstr, minlevel, maxlevel);
734 
739 #define COMPARE_OUTPUT(text) \
740  Log.remove(TEST_strstr);\
741  Log.insert(std::cout, LogStream::INFORMATION_LEVEL, LogStream::ERROR_LEVEL - 1);\
742  Log.insert(std::cerr, LogStream::ERROR_LEVEL);\
743  TEST::this_test = (::strncmp(TEST_strstr.str().c_str(), text, TEST_strstr.str().size()) == 0);\
744  TEST::test = TEST::test && TEST::this_test;\
745  \
746  if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\
747  {\
748  /* reserve space for the null-terminated content of the strstrem */\
749  char* TEST_strstr_contents = new char[TEST_strstr.str().size() + 1];\
750  ::strncpy(TEST_strstr_contents, TEST_strstr.str().c_str(), TEST_strstr.str().size());\
751  TEST_strstr_contents[TEST_strstr.str().size()] = '\0';\
752  \
753  if (!TEST::newline)\
754  {\
755  TEST::newline = true;\
756  std::cout << std::endl;\
757  }\
758  std::cout << " (line " << __LINE__ << " COMPARE_OUTPUT(" << #text << "): got '" << (TEST_strstr_contents) << "', expected '" << (text) << ") ";\
759  std::cout << (TEST::this_test ? " + " : " - ") << std::endl;\
760  delete [] TEST_strstr_contents;\
761  }\
762 }
763 
764 #endif // BALL_CONCEPT_CLASSTEST_H
Definition: classTest.h:17
string exception_name
Definition: classTest.h:23
void printException(T e, bool subtest)
Definition: classTest.h:87
const char * version_string
Definition: classTest.h:24
bool newline
Definition: classTest.h:25
bool this_test
Definition: classTest.h:21
void printErrorMessage(BALL::Exception::FileNotFound &e, bool subtest)
Definition: classTest.h:70
std::ifstream infile
Definition: classTest.h:27
list< string > tmp_file_list
Definition: classTest.h:26
std::ifstream templatefile
Definition: classTest.h:28
bool all_tests
Definition: classTest.h:19
bool test
Definition: classTest.h:20
double precision
Definition: classTest.h:30
int verbose
Definition: classTest.h:18
bool equal_files
Definition: classTest.h:29
const char * getName() const
Returns the name of the exception.
int getLine() const
Returns the line number where it occurred.
const char * getFile() const
Returns the file where it occurred.
const char * getMessage() const
Returns the error message of the exception.