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 */\
16namespace TEST
17{
18 int verbose = 0;
19 bool all_tests = true;
20 bool test = true;
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\
130int 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 * getFile() const
Returns the file where it occurred.
int getLine() const
Returns the line number where it occurred.
const char * getMessage() const
Returns the error message of the exception.
const char * getName() const
Returns the name of the exception.