classTest.h

Go to the documentation of this file.
00001 // -*- Mode: C++; tab-width: 2; -*-
00002 // vi: set ts=2:
00003 //
00004 // $Id: classTest.h,v 1.57 2005/01/18 22:26:14 amoll Exp $
00005 //
00006 
00007 #ifndef BALL_CONCEPT_AUTODELETABLE_H
00008 # include <BALL/CONCEPT/autoDeletable.h>
00009 #endif
00010 
00011 #ifndef BALL_SYSTEM_H
00012 # include <BALL/SYSTEM/file.h>
00013 #endif
00014 
00015 #ifndef BALL_DATATYPE_REGULAREXPRESSION_H
00016 # include <BALL/DATATYPE/regularExpression.h>
00017 #endif
00018 
00019 #include <string>
00020 #include <list>
00021 
00022 #ifdef BALL_HAS_SSTREAM
00023 # include <sstream>
00024 #else
00025 # include <strstream>
00026 #endif
00027 
00036 #define PRECISION(a) \
00037     TEST::precision = (a);
00038 
00052 #define START_TEST(class_name, version)\
00053 /* define a special namespace for all internal variables */\
00054 /* to avoid potential collisions                         */\
00055 namespace TEST {\
00056   int           verbose = 0;\
00057   bool          all_tests = true;\
00058   bool          test = true;\
00059   bool          this_test;\
00060   int           exception = 0;\
00061   string        exception_name = "";\
00062   const char*   version_string = version;\
00063   bool          newline = false;\
00064   list<string>  tmp_file_list;\
00065   std::ifstream infile;\
00066   std::ifstream templatefile;\
00067   bool          equal_files;\
00068   double        precision = 1e-6;\
00069 }\
00070 \
00071 \
00072 int main(int argc, char **argv)\
00073 {\
00074 \
00075   if (argc == 2) {\
00076     if (!strcmp(argv[1], "-v"))\
00077       TEST::verbose = 1;\
00078     if (!strcmp(argv[1], "-V"))\
00079       TEST::verbose = 2;\
00080   };\
00081 \
00082   if ((argc > 2) || ((argc == 2) && (TEST::verbose == 0))) {\
00083     std::cerr << "Checks " #class_name " class" << std::endl;\
00084 \
00085     std::cerr << "On successful operation it simply returns OK," << std::endl;\
00086     std::cerr << "otherwise FAILURE is printed." << std::endl;\
00087     std::cerr << "If called with an argument of -v, " << argv[0] << " prints detailed" << std::endl;\
00088     std::cerr << "information about individual tests." << std::endl;\
00089     std::cerr << "Option -V provides verbose information on" << std::endl;\
00090     std::cerr << "every subtest." << std::endl;\
00091     return 1;\
00092   }\
00093 \
00094   if (TEST::verbose > 0)\
00095     std::cout << "Version: " << TEST::version_string << std::endl;\
00096 \
00097   try {\
00098 
00099 
00110 #define END_TEST \
00111   /* global try block */\
00112   }\
00113   /* catch FileNotFound exceptions to print out the file name */\
00114   catch (BALL::Exception::FileNotFound& e)\
00115   {\
00116     TEST::this_test = false;\
00117     TEST::test = false;\
00118     TEST::all_tests = false;\
00119     if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\
00120     {\
00121       if (TEST::exception == 1) /* dummy to avoid compiler warnings */\
00122         TEST::exception++;\
00123       std::cout << std::endl << "    (caught exception of type ";\
00124       std::cout << e.getName();\
00125       if ((e.getLine() > 0) && (!(e.getFile()[0] == '\0')))\
00126         std::cout << " outside a subtest, which was thrown in line " << e.getLine() << " of file " << e.getFile();\
00127       std::cout << " while looking for file " << e.getFilename();\
00128       std::cout << " - unexpected!) " << std::endl;\
00129     }\
00130   }\
00131   /* catch BALL exceptions to retrieve additional information */\
00132   catch (BALL::Exception::GeneralException& e)\
00133   {\
00134     TEST::this_test = false;\
00135     TEST::test = false;\
00136     TEST::all_tests = false;\
00137     if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\
00138     {\
00139       if (TEST::exception == 1) /* dummy to avoid compiler warnings */\
00140         TEST::exception++;\
00141       std::cout << std::endl << "    (caught exception of type ";\
00142       std::cout << e.getName();\
00143       if ((e.getLine() > 0) && (!(e.getFile()[0] == '\0')))\
00144         std::cout << " outside a subtest, which was thrown in line " << e.getLine() << " of file " << e.getFile();\
00145       std::cout << " - unexpected!) " << std::endl;\
00146       std::cout << "    (message is: " << e.getMessage() << ")" << std::endl;\
00147     }\
00148   }\
00149   /* catch all std::exception-derived exceptions */\
00150   catch (std::exception& e)\
00151   {\
00152     TEST::this_test = false;\
00153     TEST::test = false;\
00154     TEST::all_tests = false;\
00155     if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\
00156     {\
00157       std::cout << std::endl << "    (caught expected STL exception outside a subtest: " << e.what() << ")" << std::endl;\
00158     }\
00159   }\
00160 \
00161   /* catch all non-BALL/non-STL exceptions */\
00162   catch (...)\
00163   {\
00164     TEST::this_test = false;\
00165     TEST::test = false;\
00166     TEST::all_tests = false;\
00167     if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\
00168     {\
00169       std::cout << std::endl << "    (caught unidentified and unexpected exception outside a subtest!) " << std::endl;\
00170     }\
00171   }\
00172   /* clean up all temporary files */\
00173   while (TEST::tmp_file_list.size() > 0 && TEST::verbose < 1)\
00174   {\
00175     ::BALL::File::remove(TEST::tmp_file_list.back());\
00176     TEST::tmp_file_list.pop_back();\
00177   }\
00178   /* check for exit code */\
00179   if (!TEST::all_tests)\
00180   {\
00181     std::cout << "FAILED" << std::endl;\
00182     return 1;\
00183   } else {\
00184     std::cout << "PASSED" << std::endl;\
00185     return 0;\
00186   }\
00187   /* Finally, clean up pointers still pointing to */\
00188   /* AutoDeletable objects, as this might lead to strange */\
00189   /* warnings (still reachable) when using valgrind. */\
00190   BALL::AutoDeletable::clearLastPtr(); \
00191 }\
00192 
00193 
00208 #define CHECK(test_name)  \
00209   TEST::test = true;\
00210   TEST::newline = false;\
00211   if (TEST::verbose > 0)\
00212     std::cout << "checking " << #test_name << "... " << std::flush;\
00213   try\
00214   {\
00215     while (true)\
00216     {\
00217 
00218 
00231 #define STATUS(message)\
00232           if (TEST::verbose > 1)\
00233           {\
00234             if (!TEST::newline) \
00235             {\
00236               TEST::newline = true;\
00237               std::cout << std::endl;\
00238             }\
00239             std::cout << "  status (line " << __LINE__ << "): " << message << std::endl;\
00240           }\
00241 
00242 
00260 #define RESULT \
00261       break;\
00262     }\
00263   }\
00264   /* catch FileNotFound exceptions to print out the file name */\
00265   catch (BALL::Exception::FileNotFound& e)\
00266   {\
00267     TEST::this_test = false;\
00268     TEST::test = false;\
00269     TEST::all_tests = false;\
00270     if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\
00271     {\
00272       if (TEST::exception == 1) /* dummy to avoid compiler warnings */\
00273         TEST::exception++;\
00274       std::cout << std::endl << "    (caught exception of type ";\
00275       std::cout << e.getName();\
00276       if ((e.getLine() > 0) && (!(e.getFile()[0] == '\0')))\
00277         std::cout << " outside a subtest, which was thrown in line " << e.getLine() << " of file " << e.getFile();\
00278       std::cout << " while looking for file " << e.getFilename();\
00279       std::cout << " - unexpected!) " << std::endl;\
00280     }\
00281   }\
00282   catch (::BALL::Exception::GeneralException& e)\
00283   {\
00284     TEST::this_test = false;\
00285     TEST::test = false;\
00286     TEST::all_tests = false;\
00287     if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\
00288     {\
00289       if (!TEST::newline) \
00290       {\
00291         TEST::newline = true;\
00292         std::cout << std::endl;\
00293       }\
00294       std::cout << "    (caught exception of type ";\
00295       std::cout << e.getName();\
00296       if ((e.getLine() > 0) && (!(e.getFile()[0] == '\0')))\
00297         std::cout << ", which was thrown in line " << e.getLine() << " of file " << e.getFile();\
00298       std::cout << " - unexpected!) " << std::endl;\
00299       std::cout << "    (message is: " << e.getMessage() << ")" << std::endl;\
00300     }\
00301   }\
00302   catch (...)\
00303   {\
00304     TEST::this_test = false;\
00305     TEST::test = false;\
00306     TEST::all_tests = false;\
00307     if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\
00308     {\
00309       if (!TEST::newline) \
00310       {\
00311         TEST::newline = true;\
00312         std::cout << std::endl;\
00313       }\
00314       std::cout << "    (caught unidentified and unexpected exception!)" << std::endl;\
00315     }\
00316   }\
00317 \
00318   TEST::all_tests = TEST::all_tests && TEST::test;\
00319   if (TEST::verbose > 0){\
00320     if (TEST::newline)\
00321       std::cout << "    ";\
00322     if (TEST::test){\
00323       std::cout << "passed" << std::endl;\
00324     } else {\
00325       std::cout << "FAILED" << std::endl;\
00326     }\
00327   }\
00328 
00329 
00336 #define NEW_TMP_FILE(filename)\
00337           ::BALL::File::createTemporaryFilename(filename);\
00338           TEST::tmp_file_list.push_back(filename);\
00339           if (TEST::verbose > 1)\
00340           {\
00341             if (!TEST::newline) \
00342             {\
00343               TEST::newline = true;\
00344               std::cout << std::endl;\
00345             }\
00346             std::cout << "  creating new temporary file '" << filename << "' (line " << __LINE__ << ")" << std::endl;\
00347           }\
00348   
00349   
00350   
00358 #define TEST_REAL_EQUAL(a,b)  \
00359   TEST::this_test = BALL_REAL_EQUAL((a), (b), TEST::precision); \
00360   TEST::test = TEST::test && TEST::this_test;\
00361   if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\
00362   {\
00363     if (!TEST::newline)\
00364     {\
00365       TEST::newline = true;\
00366       std::cout << std::endl;\
00367     }\
00368     std::cout << "    (line " << __LINE__ << " TEST_REAL_EQUAL("<< #a << ", " << #b << "): got " << (a) << ", expected " << (b) << ") ";\
00369     if (TEST::this_test)\
00370       std::cout << " + " << std::endl;\
00371     else \
00372       std::cout << " - " << std::endl;\
00373   }\
00374 
00375 
00385 #define TEST_EQUAL(a,b)  \
00386   {\
00387     TEST::this_test = ((a) == (b));\
00388     TEST::test = TEST::test && TEST::this_test;\
00389     if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\
00390     {\
00391       if (!TEST::newline)\
00392       {\
00393         TEST::newline = true;\
00394         std::cout << std::endl;\
00395       }\
00396       std::cout << "    (line " << __LINE__ << " TEST_EQUAL(" << #a << ", " << #b << "): got " << (a) << ", expected " << (b) << ") ";\
00397       if (TEST::this_test)\
00398         std::cout << " + " << std::endl;\
00399       else \
00400         std::cout << " - " << std::endl;\
00401     }\
00402   }\
00403 
00404 
00412 #define TEST_NOT_EQUAL(a,b)  \
00413   {\
00414     TEST::this_test = !((a) == (b));\
00415     TEST::test = TEST::test && TEST::this_test;\
00416     if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\
00417     {\
00418       if (!TEST::newline)\
00419       {\
00420         TEST::newline = true;\
00421         std::cout << std::endl;\
00422       }\
00423       std::cout << "    (line " << __LINE__ << " TEST_NOT_EQUAL(" << #a << ", " << #b << "): got " << (a) << ", forbidden is " << (b) << ") ";\
00424       if (TEST::this_test)\
00425         std::cout << " + " << std::endl;\
00426       else \
00427         std::cout << " - " << std::endl;\
00428     }\
00429   }\
00430 
00431 
00441 #define TEST_EXCEPTION(exception_type, command) \
00442   {\
00443     TEST::exception = 0;\
00444     try\
00445     {\
00446       command;\
00447     }\
00448     catch (exception_type&)\
00449     {\
00450       TEST::exception = 1;\
00451     }\
00452     catch (::BALL::Exception::GeneralException& e)\
00453     {\
00454       TEST::exception = 2;\
00455       TEST::exception_name = e.getName();\
00456     }\
00457     catch (...)\
00458     { \
00459       TEST::exception = 3;\
00460     }\
00461     TEST::this_test = (TEST::exception == 1);\
00462     TEST::test = TEST::test && TEST::this_test;\
00463     \
00464     if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\
00465     {\
00466       if (!TEST::newline)\
00467       {\
00468         TEST::newline = true;\
00469         std::cout << std::endl;\
00470       }\
00471       std::cout << "    (line " << __LINE__ << " TEST_EXCEPTION(" << #exception_type << ", " << #command << "): ";\
00472       switch (TEST::exception)\
00473       {\
00474         case 0: std::cout << " ERROR: no exception!) "; break;\
00475         case 1: std::cout << " OK) "; break;\
00476         case 2: std::cout << " ERROR: wrong exception: " << TEST::exception_name << ") "; break;\
00477         case 3: std::cout << " ERROR: wrong exception!) "; break;\
00478       }\
00479       if (TEST::this_test)\
00480         std::cout << " + " << std::endl;\
00481       else \
00482         std::cout << " - " << std::endl;\
00483     }\
00484   }\
00485 
00486 #ifdef BALL_DEBUG
00487 
00495 #define TEST_PRECONDITION_EXCEPTION(command) \
00496   {\
00497     TEST::exception = 0;\
00498     try\
00499     {\
00500       command;\
00501     }\
00502     catch (Exception::Precondition&)\
00503     {\
00504       TEST::exception = 1;\
00505     }\
00506     catch (::BALL::Exception::GeneralException& e)\
00507     {\
00508       TEST::exception = 2;\
00509       TEST::exception_name = e.getName();\
00510     }\
00511     catch (...)\
00512     { \
00513       TEST::exception = 3;\
00514     }\
00515     TEST::this_test = (TEST::exception == 1);\
00516     TEST::test = TEST::test && TEST::this_test;\
00517     \
00518     if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\
00519     {\
00520       if (!TEST::newline)\
00521       {\
00522         TEST::newline = true;\
00523         std::cout << std::endl;\
00524       }\
00525       std::cout << "    (line " << __LINE__ << " TEST_PRECONDITION_EXCEPTION(" << ", " << #command << "): ";\
00526       switch (TEST::exception)\
00527       {\
00528         case 0: std::cout << " ERROR: no exception!) "; break;\
00529         case 1: std::cout << " OK) "; break;\
00530         case 2: std::cout << " ERROR: wrong exception: " << TEST::exception_name << ") "; break;\
00531         case 3: std::cout << " ERROR: wrong exception!) "; break;\
00532       }\
00533       if (TEST::this_test)\
00534         std::cout << " + " << std::endl;\
00535       else \
00536         std::cout << " - " << std::endl;\
00537     }\
00538   }\
00539 
00540 #else
00541 
00542 # define TEST_PRECONDITION_EXCEPTION(command)\
00543   if (TEST::verbose > 1)\
00544   {\
00545     std::cout << "  TEST_EXCEPTION_PRECONDITION(" #command ") : (DEBUG mode disabled!)" << std::endl;\
00546   }\
00547 
00548 #endif // BALL_DEBUG
00549 
00555 #define ABORT_IF(condition) \
00556   if (condition) break;
00557 
00565 #define TEST_FILE(filename, templatename) \
00566   {\
00567     TEST::equal_files = true;\
00568     TEST::infile.open(filename, std::ios::in);\
00569     TEST::templatefile.open(templatename, std::ios::in);\
00570     \
00571     if (TEST::infile.good() && TEST::templatefile.good())\
00572     {\
00573       String TEST_FILE__template_line;\
00574       String TEST_FILE__line;\
00575       \
00576       while (TEST::infile.good() && TEST::templatefile.good())\
00577       {\
00578         TEST_FILE__template_line.getline(TEST::templatefile);\
00579         TEST_FILE__line.getline(TEST::infile);\
00580         \
00581         TEST::equal_files &= (TEST_FILE__template_line == TEST_FILE__line);\
00582         if (TEST_FILE__template_line != TEST_FILE__line)\
00583         {\
00584           if (TEST::verbose > 0)\
00585           {\
00586             if (!TEST::newline)\
00587             {\
00588               TEST::newline = true;\
00589               std::cout << std::endl;\
00590             }\
00591             \
00592             std::cout << "   TEST_FILE: line mismatch:\n    got:      '" << TEST_FILE__line << "'\n    expected: '" << TEST_FILE__template_line << "'" << std::endl;\
00593           }\
00594         }\
00595       }\
00596     } else {\
00597       TEST::equal_files = false;\
00598       \
00599       if (TEST::verbose > 0)\
00600       {\
00601         if (!TEST::newline)\
00602         {\
00603           TEST::newline = true;\
00604           std::cout << std::endl;\
00605         }\
00606         \
00607         std::cout << "    (line " << __LINE__ << ": TEST_FILE(" << #filename << ", " << #templatename ;\
00608         std::cout << ") : " << " cannot open file: \"";\
00609         if (!TEST::infile.good())\
00610         {\
00611           std::cout << filename << "\" (input file) ";\
00612         }\
00613         if (!TEST::templatefile.good())\
00614         {\
00615           std::cout << templatename << "\" (template file) ";\
00616         }\
00617         std::cout << std::endl;\
00618         \
00619       }\
00620     }\
00621     TEST::infile.close();\
00622     TEST::templatefile.close();\
00623     TEST::infile.clear();\
00624     TEST::templatefile.clear();\
00625     \
00626     TEST::this_test = TEST::equal_files;\
00627     TEST::test = TEST::test && TEST::this_test;\
00628     if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\
00629     {\
00630       if (!TEST::newline)\
00631       {\
00632         TEST::newline = true;\
00633         std::cout << std::endl;\
00634       }\
00635       std::cout << "    (line " << __LINE__ << ": TEST_FILE("<< #filename << ", " << #templatename << "): ";\
00636       if (TEST::this_test)\
00637       {\
00638         std::cout << "true";\
00639       } else {\
00640         std::cout << "false";\
00641       }\
00642       \
00643       if (TEST::this_test)\
00644       {\
00645         std::cout << " + " << std::endl;\
00646       } else {\
00647         std::cout << " - " << std::endl;\
00648       }\
00649     }\
00650   }
00651 
00652 
00661 #define TEST_FILE_REGEXP(filename, templatename) \
00662   {\
00663     TEST::equal_files = true;\
00664     TEST::infile.open(filename, std::ios::in);\
00665     TEST::templatefile.open(templatename, std::ios::in);\
00666     \
00667     if (TEST::infile.good() && TEST::templatefile.good())\
00668     {\
00669       String TEST_FILE__template_line;\
00670       String TEST_FILE__line;\
00671       \
00672       while (TEST::infile.good() && TEST::templatefile.good())\
00673       {\
00674         TEST_FILE__template_line.getline(TEST::templatefile);\
00675         TEST_FILE__line.getline(TEST::infile);\
00676         \
00677         if ((TEST_FILE__template_line.size() > 0) && (TEST_FILE__template_line[0] == '/') && (TEST_FILE__template_line[1] != '/'))\
00678         {\
00679           RegularExpression expression(TEST_FILE__template_line(1));\
00680           bool match = expression.match(TEST_FILE__line);\
00681           TEST::equal_files &= match;\
00682           if (!match)\
00683           {\
00684             if (TEST::verbose > 0)\
00685             {\
00686               if (!TEST::newline)\
00687               {\
00688                 TEST::newline = true;\
00689                 std::cout << std::endl;\
00690               }\
00691               \
00692               std::cout << "   TEST_FILE_REGEXP: regexp mismatch: " << TEST_FILE__line << " did not match " << TEST_FILE__template_line(1) << "." << std::endl;\
00693             }\
00694           }\
00695         } else {\
00696           TEST::equal_files &= (TEST_FILE__template_line == TEST_FILE__line);\
00697           if (TEST_FILE__template_line != TEST_FILE__line)\
00698           {\
00699             if (TEST::verbose > 0)\
00700             {\
00701               if (!TEST::newline)\
00702               {\
00703                 TEST::newline = true;\
00704                 std::cout << std::endl;\
00705               }\
00706               \
00707               std::cout << "   TEST_FILE: line mismatch:\n    got:      '" << TEST_FILE__line << "'\n    expected: '" << TEST_FILE__template_line << "'" << std::endl;\
00708             }\
00709           }\
00710         }\
00711       }\
00712     } else {\
00713       TEST::equal_files = false;\
00714       \
00715       if (TEST::verbose > 0)\
00716       {\
00717         if (!TEST::newline)\
00718         {\
00719           TEST::newline = true;\
00720           std::cout << std::endl;\
00721         }\
00722         \
00723         std::cout << "    (line " << __LINE__ << ": TEST_FILE_REGEXP(" << #filename << ", " << #templatename ;\
00724         std::cout << ") : " << " cannot open file: \"";\
00725         if (!TEST::infile.good())\
00726         {\
00727           std::cout << filename << "\" (input file) ";\
00728         }\
00729         if (!TEST::templatefile.good())\
00730         {\
00731           std::cout << templatename << "\" (template file) ";\
00732         }\
00733         std::cout << std::endl;\
00734         \
00735       }\
00736     }\
00737     TEST::infile.close();\
00738     TEST::templatefile.close();\
00739     TEST::infile.clear();\
00740     TEST::templatefile.clear();\
00741     \
00742     TEST::this_test = TEST::equal_files;\
00743     TEST::test = TEST::test && TEST::this_test;\
00744     if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\
00745     {\
00746       if (!TEST::newline)\
00747       {\
00748         TEST::newline = true;\
00749         std::cout << std::endl;\
00750       }\
00751       std::cout << "    (line " << __LINE__ << ": TEST_FILE_REGEXP("<< #filename << ", " << #templatename << "): ";\
00752       if (TEST::this_test)\
00753       {\
00754         std::cout << "true";\
00755       } else {\
00756         std::cout << "false";\
00757       }\
00758       \
00759       if (TEST::this_test)\
00760       {\
00761         std::cout << " + " << std::endl;\
00762       } else {\
00763         std::cout << " - " << std::endl;\
00764       }\
00765     }\
00766   }
00767 
00768 
00781 #ifdef BALL_HAS_SSTREAM
00782 #define CAPTURE_OUTPUT_LEVEL(level) \
00783   {\
00784     std::ostringstream TEST_strstr;\
00785     Log.remove(std::cout);\
00786     Log.remove(std::cerr);\
00787     Log.insert(TEST_strstr, level, level);
00788 #else
00789 #define CAPTURE_OUTPUT_LEVEL(level) \
00790   {\
00791     std::ostrstream TEST_strstr;\
00792     Log.remove(std::cout);\
00793     Log.remove(std::cerr);\
00794     Log.insert(TEST_strstr, level, level);
00795 #endif
00796 
00809 #ifdef BALL_HAS_SSTREAM
00810 #define CAPTURE_OUTPUT_LEVEL_RANGE(minlevel, maxlevel) \
00811   {\
00812     std::ostringstream TEST_strstr;\
00813     Log.remove(std::cout);\
00814     Log.remove(std::cerr);\
00815     Log.insert(TEST_strstr, minlevel, maxlevel);
00816 #else
00817 #define CAPTURE_OUTPUT_LEVEL_RANGE(minlevel, maxlevel) \
00818   {\
00819     std::ostrstream TEST_strstr;\
00820     Log.remove(std::cout);\
00821     Log.remove(std::cerr);\
00822     Log.insert(TEST_strstr, minlevel, maxlevel);
00823 #endif
00824 
00829 #ifdef BALL_HAS_SSTREAM
00830 #define COMPARE_OUTPUT(text) \
00831                 Log.remove(TEST_strstr);\
00832                 Log.insert(std::cout, LogStream::INFORMATION_LEVEL, LogStream::ERROR_LEVEL - 1);\
00833                 Log.insert(std::cerr, LogStream::ERROR_LEVEL);\
00834                 TEST::this_test = (::strncmp(TEST_strstr.str().c_str(), text, TEST_strstr.str().size()) == 0);\
00835                 TEST::test = TEST::test && TEST::this_test;\
00836                 \
00837                 if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\
00838                 {\
00839                         /* reserve space for the null-terminated content of the strstrem */\
00840                         char* TEST_strstr_contents = new char[TEST_strstr.str().size() + 1];\
00841                         ::strncpy(TEST_strstr_contents, TEST_strstr.str().c_str(), TEST_strstr.str().size());\
00842                         TEST_strstr_contents[TEST_strstr.str().size()] = '\0';\
00843                         \
00844                         if (!TEST::newline)\
00845                         {\
00846                                 TEST::newline = true;\
00847                                 std::cout << std::endl;\
00848                         }\
00849                         std::cout << "    (line " << __LINE__ << " COMPARE_OUTPUT(" << #text << "): got '" << (TEST_strstr_contents) << "', expected '" << (text) << ") ";\
00850                         if (TEST::this_test)\
00851                                 std::cout << " + " << std::endl;\
00852                         else \
00853                                 std::cout << " - " << std::endl;\
00854                         delete [] TEST_strstr_contents;\
00855                 }\
00856         }
00857 #else
00858 #define COMPARE_OUTPUT(text) \
00859     Log.remove(TEST_strstr);\
00860     Log.insert(std::cout, LogStream::INFORMATION_LEVEL, LogStream::ERROR_LEVEL - 1);\
00861     Log.insert(std::cerr, LogStream::ERROR_LEVEL);\
00862     TEST::this_test = (::strncmp(TEST_strstr.str(), text, TEST_strstr.str()!=0?strlen(TEST_strstr.str()):0) == 0);\
00863     TEST::test = TEST::test && TEST::this_test;\
00864     \
00865     if ((TEST::verbose > 1) || (!TEST::this_test && (TEST::verbose > 0)))\
00866     {\
00867       /* reserve space for the null-terminated content of the strstrem */\
00868       char* TEST_strstr_contents = new char[TEST_strstr.str()!=0?strlen(TEST_strstr.str()):0 + 1];\
00869       ::strncpy(TEST_strstr_contents, TEST_strstr.str(), TEST_strstr.str()!=0?strlen(TEST_strstr.str()):0);\
00870       TEST_strstr_contents[TEST_strstr.str()!=0?strlen(TEST_strstr.str()):0] = '\0';\
00871       \
00872       if (!TEST::newline)\
00873       {\
00874         TEST::newline = true;\
00875         std::cout << std::endl;\
00876       }\
00877       std::cout << "    (line " << __LINE__ << " COMPARE_OUTPUT(" << #text << "): got '" << (TEST_strstr_contents) << "', expected '" << (text) << "') ";\
00878       if (TEST::this_test)\
00879         std::cout << " + " << std::endl;\
00880       else \
00881         std::cout << " - " << std::endl;\
00882       delete [] TEST_strstr_contents;\
00883     }\
00884   }
00885 
00886 #endif