35 #ifndef OPENMS_CONCEPT_CLASSTEST_H
36 #define OPENMS_CONCEPT_CLASSTEST_H
53 #include <boost/lexical_cast.hpp>
55 #ifdef OPENMS_HAS_UNISTD_H
68 #define std__cout std::cout
84 validate(
const std::vector<std::string>& file_names);
87 std::string OPENMS_DLLAPI
91 inline bool OPENMS_DLLAPI
98 inline bool OPENMS_DLLAPI
105 inline bool OPENMS_DLLAPI
112 inline bool OPENMS_DLLAPI
119 template <
typename T>
133 const char* number_1_stringified,
134 bool number_1_is_realtype,
Int number_1_written_digits,
135 long double number_2,
const char* number_2_stringified,
136 bool ,
Int number_2_written_digits);
151 const std::string& string_1,
152 const char* string_1_stringified,
153 const std::string& string_2,
154 const char* string_2_stringified);
159 const std::string& string_1,
160 const char* string_1_stringified,
161 const std::string& string_2,
162 const char* string_2_stringified);
171 const std::string& filename_2);
184 const std::string& whitelist);
193 extern OPENMS_DLLAPI
double ratio;
202 extern OPENMS_DLLAPI
double absdiff;
208 extern OPENMS_DLLAPI
int verbose;
214 extern OPENMS_DLLAPI
bool test;
229 extern OPENMS_DLLAPI std::string
test_name;
247 extern OPENMS_DLLAPI std::ifstream
infile;
271 extern OPENMS_DLLAPI
bool newline;
273 template <
typename T1,
typename T2>
275 testEqual(
const char* ,
int line,
const T1& expression_1,
276 const char* expression_1_stringified,
277 const T2& expression_2,
278 const char* expression_2_stringified)
282 this_test = bool(expression_1 == T1(expression_2));
288 std__cout <<
" + line " << line <<
": TEST_EQUAL("
289 << expression_1_stringified <<
','
290 << expression_2_stringified <<
"): got " << expression_1
291 <<
", expected " << expression_2 << std::endl;
295 std__cout <<
" - line " << line <<
": TEST_EQUAL("
296 << expression_1_stringified <<
','
297 << expression_2_stringified <<
"): got " << expression_1
298 <<
", expected " << expression_2 << std::endl;
304 template <
typename T1,
typename T2>
307 const char* expression_1_stringified,
308 const T2& expression_2,
309 const char* expression_2_stringified)
313 this_test = !(expression_1 == T1(expression_2));
319 std__cout <<
" + line " << line <<
": TEST_NOT_EQUAL("
320 << expression_1_stringified <<
','
321 << expression_2_stringified <<
"): got " << expression_1
322 <<
", forbidden is " << expression_2 << std::endl;
326 std__cout <<
" - line " << line <<
": TEST_NOT_EQUAL("
327 << expression_1_stringified <<
','
328 << expression_2_stringified <<
"): got " << expression_1
329 <<
", forbidden is " << expression_2 << std::endl;
340 namespace TEST = OpenMS::Internal::ClassTest;
395 #define START_TEST(class_name, version) \
396 int main(int argc, char** argv) \
401 OpenMS::DateTime date_time; \
402 date_time.set("1999-12-31 23:59:59"); \
403 OpenMS::UniqueIdGenerator::setSeed(date_time); \
406 TEST::version_string = version; \
411 << "This is " << argv[0] << ", the test program for the\n" \
412 << # class_name " class.\n" \
414 "On successful operation it returns PASSED,\n" \
415 "otherwise FAILED is printed.\n"; \
435 catch (::OpenMS::Exception::BaseException& e) \
437 TEST::this_test = false; \
438 TEST::test = false; \
439 TEST::all_tests = false; \
441 TEST::initialNewline(); \
442 std__cout << "Error: Caught unexpected OpenMS exception of type '" \
445 if ((e.getLine() > 0) && (std::strcmp(e.getFile(), "") != 0)) \
447 std__cout << " thrown in line " << e.getLine() << " of file '" << e.getFile() \
448 << "' in function '" << e.getFunction() << "'"; \
450 std__cout << " - Message: " << e.what() << std::endl; \
454 catch (std::exception& e) \
456 TEST::this_test = false; \
457 TEST::test = false; \
458 TEST::all_tests = false; \
460 TEST::initialNewline(); \
461 std__cout << "Error: Caught unexpected std::exception" << std::endl; \
462 std__cout << " - Message: " << e.what() << std::endl; \
468 TEST::this_test = false; \
469 TEST::test = false; \
470 TEST::all_tests = false; \
472 TEST::initialNewline(); \
473 std__cout << "Error: Caught unidentified and unexpected exception - No message." \
478 if (!TEST::validate(TEST::tmp_file_list)) \
480 TEST::all_tests = false; \
483 if (!TEST::all_tests) \
485 std__cout << "FAILED" << std::endl; \
486 if (TEST::add_message != "") std__cout << "Message: " \
487 << TEST::add_message \
489 std__cout << "Failed lines: "; \
490 for (OpenMS::Size i = 0; i < TEST::failed_lines_list.size(); ++i) \
492 std__cout << TEST::failed_lines_list[i] << " "; \
494 std__cout << std::endl; \
500 for (OpenMS::Size i = 0; i < TEST::tmp_file_list.size(); ++i) \
502 if (!OpenMS::File::remove(TEST::tmp_file_list[i])) \
504 std__cout << "Warning: unable to remove temporary file '" \
505 << TEST::tmp_file_list[i] \
510 std__cout << "PASSED"; \
511 if (TEST::add_message != "") std__cout << " (" << TEST::add_message << ")"; \
512 std__cout << std::endl; \
539 #define START_SECTION(name_of_test) \
541 TEST::newline = false; \
542 TEST::test_name = # name_of_test; \
543 TEST::test_count = 0; \
544 TEST::start_section_line = __LINE__; \
545 std__cout << "checking " << TEST::test_name << " ... " << std::flush; \
576 #define END_SECTION \
580 catch (::OpenMS::Exception::BaseException& e) \
582 TEST::this_test = false; \
583 TEST::test = false; \
584 TEST::all_tests = false; \
586 TEST::initialNewline(); \
587 std__cout << "Error: Caught unexpected exception of type '" << e.getName() << "'"; \
588 if ((e.getLine() > 0) && (std::strcmp(e.getFile(), "") != 0)) \
590 std__cout << " thrown in line " << e.getLine() << " of file '" << e.getFile() \
591 << "' in function '" << e.getFunction() << "'"; \
593 std__cout << " - Message: " << e.what() << std::endl; \
597 catch (std::exception& e) \
599 TEST::this_test = false; \
600 TEST::test = false; \
601 TEST::all_tests = false; \
603 TEST::initialNewline(); \
604 std__cout << "Error: Caught std::exception" << std::endl; \
605 std__cout << " - Message: " << e.what() << std::endl; \
611 TEST::this_test = false; \
612 TEST::test = false; \
613 TEST::all_tests = false; \
615 TEST::initialNewline(); \
616 std__cout << "Error: Caught unidentified and unexpected exception - No message." \
620 TEST::all_tests = TEST::all_tests && TEST::test; \
624 std__cout << ": passed" << std::endl; \
628 std__cout << ": failed" << std::endl; \
632 if (TEST::test_count == 0) \
634 bool destructor = false; \
635 for (OpenMS::Size i = 0; i != TEST::test_name.size(); ++i) \
637 if (TEST::test_name[i] == '~') \
643 if (!destructor) std__cout << "Warning: no subtests performed in '" \
651 std__cout << std::endl;
674 #define TEST_EQUAL(a, b) TEST::testEqual(__FILE__, __LINE__, (a), (# a), (b), (# b));
687 #define TEST_NOT_EQUAL(a, b) TEST::testNotEqual(__FILE__, __LINE__, (a), (# a), (b), (# b));
701 #define TEST_STRING_EQUAL(a, b) TEST::testStringEqual(__FILE__, __LINE__, (a), (# a), (b), (# b));
717 #define TEST_FILE_EQUAL(filename, templatename) \
719 ++TEST::test_count; \
720 TEST::equal_files = true; \
721 TEST::infile.open(filename, std::ios::in); \
722 TEST::templatefile.open(templatename, std::ios::in); \
724 if (TEST::infile.good() && TEST::templatefile.good()) \
726 std::string TEST_FILE__template_line; \
727 std::string TEST_FILE__line; \
729 while (TEST::infile.good() && TEST::templatefile.good()) \
731 TEST::templatefile.getline(TEST::line_buffer, 65535); \
732 TEST_FILE__template_line = TEST::line_buffer; \
733 TEST::infile.getline(TEST::line_buffer, 65535); \
734 TEST_FILE__line = TEST::line_buffer; \
736 TEST::equal_files &= (TEST_FILE__template_line == TEST_FILE__line); \
737 if (TEST_FILE__template_line != TEST_FILE__line) \
740 TEST::initialNewline(); \
741 std__cout << " TEST_FILE_EQUAL: line mismatch:\n got: '" \
742 << TEST_FILE__line << "'\n expected: '" \
743 << TEST_FILE__template_line << "'" << std::endl; \
750 TEST::equal_files = false; \
752 TEST::initialNewline(); \
753 std__cout << " + line " \
755 << ": TEST_FILE_EQUAL(" \
759 std__cout << ") : " << " cannot open file: \""; \
760 if (!TEST::infile.good()) \
762 std__cout << filename << "\" (input file) "; \
764 if (!TEST::templatefile.good()) \
766 std__cout << templatename << "\" (template file) "; \
768 std__cout << std::endl; \
772 TEST::infile.close(); \
773 TEST::templatefile.close(); \
774 TEST::infile.clear(); \
775 TEST::templatefile.clear(); \
777 TEST::this_test = TEST::equal_files; \
778 TEST::test = TEST::test && TEST::this_test; \
780 TEST::initialNewline(); \
781 if (TEST::this_test) \
783 std__cout << " + line " \
785 << ": TEST_FILE_EQUAL(" \
793 std__cout << " - line " \
795 << ": TEST_FILE_EQUAL(" \
799 << "): false (different files: " \
804 TEST::failed_lines_list.push_back(TEST::test_line); \
824 #define TEST_REAL_SIMILAR(a, b) TEST::testRealSimilar(__FILE__, __LINE__, (a), (# a), TEST::isRealType(a), writtenDigits(a), (b), (# b), TEST::isRealType(b), writtenDigits(b));
841 #define TEST_STRING_SIMILAR(a, b) TEST::testStringSimilar(__FILE__, __LINE__, (a), (# a), (b), (# b));
857 #define TEST_FILE_SIMILAR(a, b) \
859 ++TEST::test_count; \
860 TEST::test_line = __LINE__; \
861 TEST::this_test = TEST::isFileSimilar((a), (b)); \
862 TEST::test = TEST::test && TEST::this_test; \
864 TEST::initialNewline(); \
865 if (TEST::this_test) \
867 std__cout << " + line " << __LINE__ \
868 << ": TEST_FILE_SIMILAR(" # a "," # b "): absolute: " \
869 << precisionWrapper(TEST::absdiff) \
871 << precisionWrapper(TEST::absdiff_max_allowed) \
873 << precisionWrapper(TEST::ratio) \
875 << precisionWrapper(TEST::ratio_max_allowed) \
878 std__cout << "message: \n"; \
879 std__cout << TEST::fuzzy_message; \
883 std__cout << " - line " << TEST::test_line << \
884 ": TEST_FILE_SIMILAR(" # a "," # b ") ... -\n"; \
885 std__cout << "message: \n"; \
886 std__cout << TEST::fuzzy_message; \
887 TEST::failed_lines_list.push_back(TEST::test_line); \
904 #define TOLERANCE_RELATIVE(a) \
905 TEST::ratio_max_allowed = (a); \
907 TEST::initialNewline(); \
908 std__cout << " + line " << __LINE__ << \
909 ": TOLERANCE_RELATIVE(" << TEST::ratio_max_allowed << \
910 ") (\"" # a "\")" << std::endl; \
924 #define TOLERANCE_ABSOLUTE(a) \
925 TEST::absdiff_max_allowed = (a); \
927 TEST::initialNewline(); \
928 std__cout << " + line " << __LINE__ << \
929 ": TOLERANCE_ABSOLUTE(" << TEST::absdiff_max_allowed << \
930 ") (\"" # a "\")" << std::endl; \
938 #define WHITELIST(a) TEST::setWhitelist(__FILE__, __LINE__, (a));
952 #define TEST_EXCEPTION(exception_type, command) \
954 ++TEST::test_count; \
955 TEST::test_line = __LINE__; \
956 TEST::exception = 0; \
961 catch (exception_type) \
963 TEST::exception = 1; \
965 catch (::OpenMS::Exception::BaseException e) \
967 TEST::exception = 2; \
968 TEST::exception_name = e.getName(); \
972 TEST::exception = 3; \
974 TEST::this_test = (TEST::exception == 1); \
975 TEST::test = TEST::test && TEST::this_test; \
978 TEST::initialNewline(); \
979 switch (TEST::exception) \
982 std__cout << " - line " << TEST::test_line << \
983 ": TEST_EXCEPTION(" # exception_type "," # command \
984 "): no exception thrown!" << std::endl; \
985 TEST::failed_lines_list.push_back(TEST::test_line); \
988 std__cout << " + line " << TEST::test_line << \
989 ": TEST_EXCEPTION(" # exception_type "," # command \
990 "): OK" << std::endl; \
993 std__cout << " - line " << TEST::test_line << \
994 ": TEST_EXCEPTION(" # exception_type "," # command \
995 "): wrong exception thrown! \"" \
996 << TEST::exception_name << "\"" << std::endl; \
997 TEST::failed_lines_list.push_back(TEST::test_line); \
1000 std__cout << " - line " << TEST::test_line << \
1001 ": TEST_EXCEPTION(" # exception_type "," # command \
1002 "): wrong exception thrown!" << std::endl; \
1003 TEST::failed_lines_list.push_back(TEST::test_line); \
1020 #ifdef OPENMS_ASSERTIONS
1021 #define TEST_PRECONDITION_VIOLATED(command) TEST_EXCEPTION(Exception::Precondition, command);
1023 #define TEST_PRECONDITION_VIOLATED(command) STATUS("TEST_PRECONDITION_VIOLATED(" # command ") - skipped");
1037 #ifdef OPENMS_ASSERTIONS
1038 #define TEST_POSTCONDITION_VIOLATED(command) TEST_EXCEPTION(Exception::Postcondition, command);
1040 #define TEST_POSTCONDITION_VIOLATED(command) STATUS("TEST_POSTCONDITION_VIOLATED(" # command ") - skipped");
1060 #define TEST_EXCEPTION_WITH_MESSAGE(exception_type, command, message) \
1062 ++TEST::test_count; \
1063 TEST::test_line = __LINE__; \
1064 TEST::exception = 0; \
1069 catch (exception_type et) \
1071 if (std::string(et.getMessage()) != std::string(message)) \
1073 TEST::exception = 4; \
1074 TEST::exception_message = et.getMessage(); \
1076 else TEST::exception = 1; \
1078 catch (::OpenMS::Exception::BaseException e) \
1080 TEST::exception = 2; \
1081 TEST::exception_name = e.getName(); \
1085 TEST::exception = 3; \
1087 TEST::this_test = (TEST::exception == 1); \
1088 TEST::test = TEST::test && TEST::this_test; \
1091 TEST::initialNewline(); \
1092 switch (TEST::exception) \
1095 std__cout << " - line " << TEST::test_line << \
1096 ": TEST_EXCEPTION_WITH_MESSAGE(" # exception_type "," # command ", " # message \
1097 "): no exception thrown!" << std::endl; \
1098 TEST::failed_lines_list.push_back(TEST::test_line); \
1102 std__cout << " + line " << TEST::test_line << \
1103 ": TEST_EXCEPTION_WITH_MESSAGE(" # exception_type "," # command ", " # message \
1104 "): OK" << std::endl; \
1107 std__cout << " - line " << TEST::test_line << \
1108 ": TEST_EXCEPTION_WITH_MESSAGE(" # exception_type "," # command ", " # message \
1109 "): wrong exception thrown! \"" << \
1110 TEST::exception_name << "\"" << std::endl; \
1111 TEST::failed_lines_list.push_back(TEST::test_line); \
1114 std__cout << " - line " << TEST::test_line << \
1115 ": TEST_EXCEPTION_WITH_MESSAGE(" # exception_type "," # command ", " # message \
1116 "): wrong exception thrown!" << std::endl; \
1117 TEST::failed_lines_list.push_back(TEST::test_line); \
1120 std__cout << " - line " << TEST::test_line << \
1121 ": TEST_EXCEPTION_WITH_MESSAGE(" # exception_type "," # command ", " # message \
1122 "): exception has wrong message: got '" << \
1123 TEST::exception_message << \
1124 "', expected '" << \
1127 TEST::failed_lines_list.push_back(TEST::test_line); \
1148 #define NEW_TMP_FILE(filename) \
1150 filename = TEST::tmpFileName(__FILE__, __LINE__); \
1151 TEST::tmp_file_list.push_back(filename); \
1153 TEST::initialNewline(); \
1154 std__cout << " creating new temporary filename '" \
1170 #define ABORT_IF(condition) \
1174 TEST::initialNewline(); \
1175 std__cout << " - line " << __LINE__ << \
1176 ": ABORT_IF(" # condition "): TEST ABORTED" << \
1178 TEST::failed_lines_list.push_back(TEST::test_line); \
1200 #define STATUS(message) \
1202 TEST::initialNewline(); \
1203 std__cout << " line " \
1219 #define ADD_MESSAGE(message) \
1220 TEST::add_message = message;
1231 #define NOT_TESTABLE \
1232 TEST::test_count = 1;
1236 #endif //OPENMS_CONCEPT_CLASSTEST_H
double absdiff_max_allowed
Maximum absolute difference of numbers allowed, see TOLERANCE_ABSOLUTE.
int test_count
Counter for the number of elementary tests within the current subsection.
void testStringSimilar(const char *file, int line, const std::string &string_1, const char *string_1_stringified, const std::string &string_2, const char *string_2_stringified)
Compare strings using absdiff_max_allowed and ratio_max_allowed.
std::ifstream templatefile
Template (correct) file used by TEST_FILE_EQUAL.
std::string exception_name
(Used by various macros. Stores the "name" of the exception, if applicable.)
void setWhitelist(const char *const , const int line, const std::string &whitelist)
set the whitelist_
bool newline
(Flags whether a new line is in place, depending on context and verbosity setting. Used by initialNewline() and some macros.)
bool this_test
Status of last elementary test.
std::ifstream infile
Questionable file tested by TEST_FILE_EQUAL.
int start_section_line
Line where current subsection started.
std::vector< std::string > tmp_file_list
List of tmp file names (these will be cleaned up, see NEW_TMP_FILE)
std::string add_message
See ADD_MESSAGE.
double ratio_max
Maximum ratio of numbers observed so far, see TOLERANCE_RELATIVE.
void testEqual(const char *, int line, const T1 &expression_1, const char *expression_1_stringified, const T2 &expression_2, const char *expression_2_stringified)
Definition: ClassTest.h:275
std::string tmpFileName(const std::string &file, int line)
Creates a temporary file name from the test name and the line.
char line_buffer[65536]
(A buffer for one line from a file. Used by TEST_FILE_EQUAL.)
bool isRealType(float)
This overload returns true; float is a floating point type.
Definition: ClassTest.h:92
Class to hold strings, numeric values, lists of strings and lists of numeric values.
Definition: DataValue.h:57
std::string exception_message
(Used by various macros. Stores the "message" of the exception, if applicable.)
#define std__cout
Provide a point of redirection for testing the test macros, see ClassTest_test.C. ...
Definition: ClassTest.h:68
bool equal_files
(A variable used by TEST_FILE_EQUAL)
void testNotEqual(const char *, int line, const T1 &expression_1, const char *expression_1_stringified, const T2 &expression_2, const char *expression_2_stringified)
Definition: ClassTest.h:306
int exception
(Used by various macros. Indicates a rough category of the exception being caught.)
double ratio
Recent ratio of numbers, see TOLERANCE_RELATIVE.
const char * version_string
Version string supplied with START_TEST.
bool all_tests
Status of the whole test.
int test_line
Line of current elementary test.
void testRealSimilar(const char *file, int line, long double number_1, const char *number_1_stringified, bool number_1_is_realtype, Int number_1_written_digits, long double number_2, const char *number_2_stringified, bool, Int number_2_written_digits)
Compare floating point numbers using absdiff_max_allowed and ratio_max_allowed.
void initialNewline()
make sure we have a newline before results from first subtest
std::string test_name
Name of current subsection.
std::vector< UInt > failed_lines_list
List of all failed lines for summary at the end of the test.
bool isRealSimilar(long double number_1, long double number_2)
used by testRealSimilar()
double absdiff
Recent absolute difference of numbers, see TOLERANCE_ABSOLUTE.
bool isFileSimilar(const std::string &filename_1, const std::string &filename_2)
Compare files using absdiff_max_allowed and ratio_max_allowed.
bool test
Status of the current subsection.
int Int
Signed integer type.
Definition: Types.h:100
double absdiff_max
Maximum difference of numbers observed so far, see TOLERANCE_ABSOLUTE.
bool validate(const std::vector< std::string > &file_names)
Validates the given files against the XML schema (if available)
int verbose
Verbosity level ( "-v" is 1 and "-V" is 2 )
void testStringEqual(const char *file, int line, const std::string &string_1, const char *string_1_stringified, const std::string &string_2, const char *string_2_stringified)
used by TEST_STRING_EQUAL
void printWithPrefix(const std::string &text, const int marked=-1)
print the text, each line gets a prefix, the marked line number gets a special prefix ...
std::string fuzzy_message
Last message from a fuzzy comparison. Written by isRealSimilar(), testStringSimilar(), isFileSimilar(). Read by TEST_REAL_SIMILAR, TEST_STRING_SIMILAR, TEST_FILE_SIMILAR;.
double ratio_max_allowed
Maximum ratio of numbers allowed, see TOLERANCE_RELATIVE.