Teuchos_UnitTestRepository.cpp

Go to the documentation of this file.
00001 // @HEADER
00002 // ***********************************************************************
00003 // 
00004 //                    Teuchos: Common Tools Package
00005 //                 Copyright (2004) Sandia Corporation
00006 // 
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 // 
00010 // This library is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as
00012 // published by the Free Software Foundation; either version 2.1 of the
00013 // License, or (at your option) any later version.
00014 //  
00015 // This library is distributed in the hope that it will be useful, but
00016 // WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //  
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00023 // USA
00024 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 
00025 // 
00026 // ***********************************************************************
00027 // @HEADER
00028 
00029 
00030 #include "Teuchos_UnitTestRepository.hpp"
00031 #include "Teuchos_UnitTestBase.hpp"
00032 #include "Teuchos_Array.hpp"
00033 #include "Teuchos_TestForException.hpp"
00034 #include "Teuchos_VerboseObject.hpp"
00035 #include "Teuchos_CommandLineProcessor.hpp"
00036 #include "Teuchos_Assert.hpp"
00037 #include "Teuchos_StandardCatchMacros.hpp"
00038 
00039 
00040 namespace Teuchos {
00041 
00042 
00043 struct UnitTestData {
00044 
00045   Teuchos::UnitTestBase *unitTest;
00046   std::string groupName;
00047   std::string testName;
00048 
00049   UnitTestData(Teuchos::UnitTestBase *unitTest_in,
00050     const std::string groupName_in, const std::string testName_in)
00051     :unitTest(unitTest_in), groupName(groupName_in), testName(testName_in)
00052     {
00053 #ifdef TEUCHOS_DEBUG
00054       TEUCHOS_ASSERT(unitTest_in);
00055 #endif
00056     }
00057 
00058 private:
00059   UnitTestData(); // Not defined!
00060 };
00061 
00062 
00063 
00064 bool operator<(const UnitTestData &a, const UnitTestData &b)
00065 {
00066   if (a.groupName < b.groupName) {
00067     return true;
00068   }
00069   else if (a.groupName > b.groupName) {
00070     return false;
00071   }
00072   return a.testName < b.testName;
00073 }
00074 
00075 
00076 
00077 std::string getUnitTestName(const std::string groupName,
00078   const std::string testName)
00079 {
00080   std::ostringstream oss;
00081   oss << groupName<<"_"<<testName<<"_UnitTest";
00082   return oss.str();
00083 }
00084 
00085 
00086 enum EShowTestDetails {
00087   SHOW_TEST_DETAILS_ALL,
00088   SHOW_TEST_DETAILS_TEST_NAMES,
00089   SHOW_TEST_DETAILS_FINAL_RESULTS
00090 };
00091 
00092 
00093 bool strMatch( const std::string &fullMatchStr, const std::string &str )
00094 {
00095 
00096   const std::string::size_type npos = std::string::npos;
00097 
00098   const int strLen = str.length();
00099   const int fullMatchStrLen = fullMatchStr.length();
00100 
00101   if (fullMatchStrLen == 0) {
00102     return true;
00103   }
00104 
00105   const bool beginGlob = fullMatchStr[0] == '*';
00106   const bool endGlob = fullMatchStr[fullMatchStrLen-1] == '*';
00107 
00108   const int matchStrLen =
00109   fullMatchStrLen + (beginGlob ? -1 : 0) + (endGlob ? -1 : 0);
00110 
00111   if (matchStrLen == 0) {
00112     return true;
00113   }
00114 
00115   if (matchStrLen > strLen) {
00116     return false;
00117   }
00118 
00119   if (beginGlob && endGlob) {
00120     return str.find(fullMatchStr.substr(1, matchStrLen)) != npos;
00121   }
00122 
00123   if (endGlob) {
00124     return fullMatchStr.substr(0, matchStrLen) == str.substr(0, matchStrLen);
00125   }
00126 
00127   if (beginGlob) {
00128     return fullMatchStr.substr(1, matchStrLen) ==
00129       str.substr(strLen-matchStrLen, matchStrLen);
00130   }
00131 
00132   return fullMatchStr == str;
00133 
00134 }
00135 
00136 
00137 } // namespace Teuchos
00138 
00139 
00140 
00141 
00142 namespace Teuchos {
00143 
00144 
00145 // Implementation class
00146 
00147 
00148 class UnitTestRepository::InstanceData {
00149 public:
00150 
00151   typedef Teuchos::Array<UnitTestData> unitTests_t;
00152 
00153   unitTests_t unitTests;
00154   CommandLineProcessor clp;
00155   EShowTestDetails showTestDetails;
00156   bool showSrcLocation;
00157   bool noOp;
00158   std::string groupName;
00159   std::string testName;
00160   std::string notUnitTestName;
00161 
00162   InstanceData()
00163     :clp(false),
00164      showTestDetails(SHOW_TEST_DETAILS_TEST_NAMES),
00165      showSrcLocation(false),
00166      noOp(false)
00167     {}
00168 
00169 };
00170 
00171 
00172 // public
00173 
00174 
00175 CommandLineProcessor& UnitTestRepository::getCLP()
00176 {
00177   return getData().clp;
00178 }
00179 
00180 
00181 bool UnitTestRepository::runUnitTests(FancyOStream &out)
00182 {
00183 
00184   typedef InstanceData::unitTests_t unitTests_t;
00185 
00186   out << "\n***\n*** Unit test suite ...\n***\n\n";
00187 
00188   InstanceData &data = getData();
00189 
00190   const bool showAll = data.showTestDetails == SHOW_TEST_DETAILS_ALL;
00191   const bool showTestNames = data.showTestDetails == SHOW_TEST_DETAILS_TEST_NAMES || showAll;
00192 
00193   bool success = true;
00194   int testCounter = 0;
00195   int numTestsRun = 0;
00196   int numTestsFailed = 0;
00197 
00198   try {
00199     
00200     out << "\nSorting tests by group name then by test name ...\n";
00201     std::sort( data.unitTests.begin(), data.unitTests.end() );
00202 
00203     out << "\nRunning unit tests ...\n\n";
00204     unitTests_t::iterator iter = data.unitTests.begin();
00205     for ( ; iter != data.unitTests.end(); ++iter, ++testCounter ) {
00206 
00207       const UnitTestData &utd = (*iter);
00208 
00209       const std::string unitTestName = getUnitTestName(utd.groupName, utd.testName);
00210 
00211       if (
00212         (
00213           strMatch(data.groupName, utd.groupName)
00214           &&
00215           strMatch(data.testName, utd.testName)
00216           )
00217         &&
00218         (
00219           data.notUnitTestName.length() == 0
00220           ||
00221           !strMatch(data.notUnitTestName, unitTestName)
00222           )
00223         )
00224       {
00225 
00226         ++numTestsRun;
00227 
00228         std::ostringstream testHeaderOSS;
00229         testHeaderOSS <<testCounter<<". "<<unitTestName<<" ... ";
00230         const std::string testHeader = testHeaderOSS.str();
00231 
00232         if (showAll)
00233           out <<"\n";
00234 
00235         if (showTestNames)
00236           out <<testHeader;
00237 
00238         {
00239 
00240           RCP<std::ostringstream> oss;
00241           RCP<FancyOStream> localOut;
00242           if (showAll) {
00243             out << "\n";
00244             localOut = rcpFromRef(out);
00245           }
00246           else {
00247             oss = rcp(new std::ostringstream);
00248             localOut = fancyOStream(rcp_implicit_cast<std::ostream>(oss));
00249           }
00250 
00251           OSTab tab(out);
00252 
00253           if (!data.noOp) {
00254 
00255             const bool result = utd.unitTest->runUnitTest(*localOut);
00256 
00257             if (!result) {
00258               
00259               if (!showTestNames)
00260                 out <<testHeader<<"\n";
00261               else if (!showAll)
00262                 out <<"\n";
00263               
00264               if (!is_null(oss))
00265                 out << oss->str();
00266               
00267               out
00268                 << "[FAILED]\n"
00269                 << "Location: "<<utd.unitTest->unitTestFile()<<":"
00270                 <<utd.unitTest->unitTestFileLineNumber()<<"\n";
00271               
00272               if (!is_null(oss))
00273                 out << "\n";
00274               
00275               success = false;
00276               
00277               ++numTestsFailed;
00278               
00279             }
00280             else {
00281               
00282               if (showTestNames)
00283                 out << "[Passed]\n";
00284               
00285               if (showAll && data.showSrcLocation)
00286                 out
00287                   << "Location: "<<utd.unitTest->unitTestFile()<<":"
00288                   <<utd.unitTest->unitTestFileLineNumber()<<"\n";
00289               
00290             }
00291 
00292           }
00293           else {
00294 
00295             if (showTestNames)
00296               out << "[Not Run]\n";
00297             
00298           }
00299 
00300         }
00301    
00302       }
00303 
00304     }
00305 
00306     TEUCHOS_ASSERT_EQUALITY(testCounter, as<int>(data.unitTests.size()));
00307 
00308   }
00309   TEUCHOS_STANDARD_CATCH_STATEMENTS(true, out, success);
00310 
00311   out
00312     << "\nSummary: total = " << testCounter
00313     << ", run = " << numTestsRun;
00314 
00315   if (!data.noOp) {
00316     out
00317       << ", passed = " << (numTestsRun-numTestsFailed)
00318       << ", failed = " << numTestsFailed << "\n";
00319   }
00320   else {
00321     out
00322       << ", passed = ???"
00323       << ", failed = ???\n";
00324   }
00325     
00326   return success;
00327 
00328 }
00329 
00330 
00331 int UnitTestRepository::runUnitTestsFromMain( int argc, char* argv[] )
00332 {
00333 
00334   const RCP<FancyOStream> out = VerboseObjectBase::getDefaultOStream();
00335 
00336   CommandLineProcessor &clp = getData().clp;
00337   setUpCLP(outArg(clp));
00338   CommandLineProcessor::EParseCommandLineReturn parse_return =
00339     clp.parse(argc,argv);
00340   if ( parse_return != CommandLineProcessor::PARSE_SUCCESSFUL ) {
00341     *out << "\nEnd Result: TEST FAILED" << std::endl;
00342     return parse_return;
00343   }
00344 
00345 
00346   const bool success = runUnitTests(*out);
00347 
00348   if (success)
00349     *out << "\nEnd Result: TEST PASSED" << std::endl;
00350   else
00351     *out << "\nEnd Result: TEST FAILED" << std::endl;
00352 
00353   return (success ? 0 : 1);
00354 
00355 }
00356 
00357 
00358 void UnitTestRepository::addUnitTest( UnitTestBase *unitTest,
00359   const std::string groupName, const std::string testName )
00360 {
00361   getData().unitTests.push_back(UnitTestData(unitTest, groupName, testName));
00362 }
00363 
00364 
00365 // private:
00366 
00367 
00368 UnitTestRepository::UnitTestRepository()
00369 {}
00370 
00371 
00372 void UnitTestRepository::setUpCLP(const Ptr<CommandLineProcessor>& clp)
00373 {
00374 
00375   clp->addOutputSetupOptions(true);
00376 
00377   const int numShowTestDetails = 3;
00378   const EShowTestDetails showTestDetailsValues[numShowTestDetails] =
00379     { SHOW_TEST_DETAILS_ALL,
00380       SHOW_TEST_DETAILS_TEST_NAMES,
00381       SHOW_TEST_DETAILS_FINAL_RESULTS
00382     };
00383   const char* showTestDetailsNames[numShowTestDetails] =
00384     { "ALL",
00385       "TEST_NAMES",
00386       "FINAL_RESULTS"
00387     };
00388   clp->setOption(
00389     "show-test-details", &getData().showTestDetails,
00390     numShowTestDetails, showTestDetailsValues, showTestDetailsNames,
00391     "Level of detail to show in the tests"
00392     );
00393   clp->setOption(
00394     "details", &getData().showTestDetails,
00395     numShowTestDetails, showTestDetailsValues, showTestDetailsNames,
00396     "Short for --details"
00397     );
00398 
00399   clp->setOption(
00400     "show-src-location", "no-show-src-location", &getData().showSrcLocation,
00401     "If true, then the location of the unit test source code is shown."
00402     "  Only meaningfull if --show-test-details=ALL."
00403     );
00404 
00405   clp->setOption(
00406     "group-name", &getData().groupName,
00407     "If specified, selects only tests that match the group name glob." );
00408   clp->setOption(
00409     "group", &getData().groupName,
00410     "Short for --group-name." );
00411 
00412   clp->setOption(
00413     "test-name", &getData().testName,
00414     "If specified, selects only tests that match the test name glob." );
00415   clp->setOption(
00416     "test", &getData().testName,
00417     "Short for --test-name." );
00418 
00419   clp->setOption(
00420     "not-unit-test", &getData().notUnitTestName,
00421     "If specified, full unit tests with glob matches will *not* be run." );
00422 
00423   clp->setOption(
00424     "no-op", "do-op", &getData().noOp,
00425     "If --no-op, then only the names of the tests that would be run are run."
00426     );
00427   
00428 }
00429 
00430 
00431 UnitTestRepository::InstanceData& UnitTestRepository::getData()
00432 {
00433   static UnitTestRepository::InstanceData data;
00434   return data;
00435 }
00436 
00437 
00438 } // namespace Teuchos
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on Tue Oct 20 10:14:01 2009 for Teuchos Package Browser (Single Doxygen Collection) by  doxygen 1.6.1