Teuchos_UnitTestRepository.cpp

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 {
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   typedef std::string::size_type size_type;
00096   const size_type npos = std::string::npos;
00097 
00098   if (fullMatchStr == "*") {
00099     return true;
00100   }
00101 
00102   const size_type strLen = str.length();
00103   const size_type fullMatchStrLen = fullMatchStr.length();
00104 
00105   const bool beginGlob = (fullMatchStrLen > 0) && (fullMatchStr[0] == '*');
00106   const bool endGlob = (fullMatchStrLen > 0) && (fullMatchStr[fullMatchStrLen-1] == '*');
00107 
00108   const size_type matchStrLen = fullMatchStrLen + (beginGlob ? -1 : 0) + (endGlob ? -1 : 0);
00109 
00110   if (matchStrLen == 0) {
00111     return true;
00112   }
00113 
00114   if (matchStrLen > strLen) {
00115     return false;
00116   }
00117 
00118   if (beginGlob && endGlob) {
00119     return str.find(fullMatchStr.substr(1, matchStrLen)) != npos;
00120   }
00121 
00122   if (endGlob) {
00123     return fullMatchStr.substr(0, matchStrLen) == str.substr(0, matchStrLen);
00124   }
00125 
00126   if (beginGlob) {
00127     return fullMatchStr.substr(1, matchStrLen) ==
00128       str.substr(strLen-matchStrLen, matchStrLen);
00129   }
00130 
00131   return fullMatchStr == str;
00132 
00133 }
00134 
00135 
00136 } // namespace
00137 
00138 
00139 
00140 
00141 namespace Teuchos {
00142 
00143 
00144 // Implementation class
00145 
00146 
00147 class UnitTestRepository::InstanceData {
00148 public:
00149 
00150   typedef Teuchos::Array<UnitTestData> unitTests_t;
00151 
00152   unitTests_t unitTests;
00153   CommandLineProcessor clp;
00154   EShowTestDetails showTestDetails;
00155   bool showSrcLocation;
00156   bool noOp;
00157   std::string groupName;
00158   std::string testName;
00159 
00160   InstanceData()
00161     :clp(false),
00162      showTestDetails(SHOW_TEST_DETAILS_TEST_NAMES),
00163      showSrcLocation(false),
00164      noOp(false)
00165     {}
00166 
00167 };
00168 
00169 
00170 // public
00171 
00172 
00173 CommandLineProcessor& UnitTestRepository::getCLP()
00174 {
00175   return getData().clp;
00176 }
00177 
00178 
00179 bool UnitTestRepository::runUnitTests(FancyOStream &out)
00180 {
00181 
00182   typedef InstanceData::unitTests_t unitTests_t;
00183 
00184   out << "\n***\n*** Unit test suite ...\n***\n\n";
00185 
00186   InstanceData &data = getData();
00187 
00188   const bool showAll = data.showTestDetails == SHOW_TEST_DETAILS_ALL;
00189   const bool showTestNames = data.showTestDetails == SHOW_TEST_DETAILS_TEST_NAMES || showAll;
00190 
00191   bool success = true;
00192   int testCounter = 0;
00193   int numTestsRun = 0;
00194   int numTestsFailed = 0;
00195 
00196   try {
00197     
00198     out << "\nSorting tests by group name then by test name ...\n";
00199     std::sort( data.unitTests.begin(), data.unitTests.end() );
00200 
00201     out << "\nRunning unit tests ...\n\n";
00202     unitTests_t::iterator iter = data.unitTests.begin();
00203     for ( ; iter != data.unitTests.end(); ++iter, ++testCounter ) {
00204 
00205       const UnitTestData &utd = (*iter);
00206 
00207       if (
00208         strMatch(data.groupName, utd.groupName)
00209         &&
00210         strMatch(data.testName, utd.testName)
00211         )
00212       {
00213 
00214         ++numTestsRun;
00215 
00216         const std::string unitTestName = getUnitTestName(utd.groupName, utd.testName);
00217 
00218         std::ostringstream testHeaderOSS;
00219         testHeaderOSS <<testCounter<<". "<<unitTestName<<" ... ";
00220         const std::string testHeader = testHeaderOSS.str();
00221 
00222         if (showAll)
00223           out <<"\n";
00224 
00225         if (showTestNames)
00226           out <<testHeader;
00227 
00228         {
00229 
00230           RCP<std::ostringstream> oss;
00231           RCP<FancyOStream> localOut;
00232           if (showAll) {
00233             out << "\n";
00234             localOut = rcpFromRef(out);
00235           }
00236           else {
00237             oss = rcp(new std::ostringstream);
00238             localOut = fancyOStream(rcp_implicit_cast<std::ostream>(oss));
00239           }
00240 
00241           OSTab tab(out);
00242 
00243           if (!data.noOp) {
00244 
00245             const bool result = utd.unitTest->runUnitTest(*localOut);
00246 
00247             if (!result) {
00248               
00249               if (!showTestNames)
00250                 out <<testHeader<<"\n";
00251               else if (!showAll)
00252                 out <<"\n";
00253               
00254               if (!is_null(oss))
00255                 out << oss->str();
00256               
00257               out
00258                 << "[FAILED]\n"
00259                 << "Location: "<<utd.unitTest->unitTestFile()<<":"
00260                 <<utd.unitTest->unitTestFileLineNumber()<<"\n";
00261               
00262               if (!is_null(oss))
00263                 out << "\n";
00264               
00265               success = false;
00266               
00267               ++numTestsFailed;
00268               
00269             }
00270             else {
00271               
00272               if (showTestNames)
00273                 out << "[Passed]\n";
00274               
00275               if (showAll && data.showSrcLocation)
00276                 out
00277                   << "Location: "<<utd.unitTest->unitTestFile()<<":"
00278                   <<utd.unitTest->unitTestFileLineNumber()<<"\n";
00279               
00280             }
00281 
00282           }
00283           else {
00284 
00285             if (showTestNames)
00286               out << "[Not Run]\n";
00287             
00288           }
00289 
00290         }
00291    
00292       }
00293 
00294     }
00295 
00296     TEUCHOS_ASSERT_EQUALITY(testCounter, as<int>(data.unitTests.size()));
00297 
00298   }
00299   TEUCHOS_STANDARD_CATCH_STATEMENTS(true, out, success);
00300 
00301   out
00302     << "\nSummary: total = " << testCounter
00303     << ", run = " << numTestsRun;
00304 
00305   if (!data.noOp) {
00306     out
00307       << ", passed = " << (numTestsRun-numTestsFailed)
00308       << ", failed = " << numTestsFailed << "\n";
00309   }
00310   else {
00311     out
00312       << ", passed = ???"
00313       << ", failed = ???\n";
00314   }
00315     
00316   return success;
00317 
00318 }
00319 
00320 
00321 int UnitTestRepository::runUnitTestsFromMain( int argc, char* argv[] )
00322 {
00323 
00324   const RCP<FancyOStream> out = VerboseObjectBase::getDefaultOStream();
00325 
00326   CommandLineProcessor &clp = getData().clp;
00327   setUpCLP(outArg(clp));
00328   CommandLineProcessor::EParseCommandLineReturn parse_return =
00329     clp.parse(argc,argv);
00330   if ( parse_return != CommandLineProcessor::PARSE_SUCCESSFUL ) {
00331     *out << "\nEnd Result: TEST FAILED" << std::endl;
00332     return parse_return;
00333   }
00334 
00335 
00336   const bool success = runUnitTests(*out);
00337 
00338   if (success)
00339     *out << "\nEnd Result: TEST PASSED" << std::endl;
00340   else
00341     *out << "\nEnd Result: TEST FAILED" << std::endl;
00342 
00343   return (success ? 0 : 1);
00344 
00345 }
00346 
00347 
00348 void UnitTestRepository::addUnitTest( UnitTestBase *unitTest,
00349   const std::string groupName, const std::string testName )
00350 {
00351   getData().unitTests.push_back(UnitTestData(unitTest, groupName, testName));
00352 }
00353 
00354 
00355 // private:
00356 
00357 
00358 UnitTestRepository::UnitTestRepository()
00359 {}
00360 
00361 
00362 void UnitTestRepository::setUpCLP(const Ptr<CommandLineProcessor>& clp)
00363 {
00364 
00365   const int numShowTestDetails = 3;
00366   const EShowTestDetails showTestDetailsValues[numShowTestDetails] =
00367     { SHOW_TEST_DETAILS_ALL,
00368       SHOW_TEST_DETAILS_TEST_NAMES,
00369       SHOW_TEST_DETAILS_FINAL_RESULTS
00370     };
00371   const char* showTestDetailsNames[numShowTestDetails] =
00372     { "ALL",
00373       "TEST_NAMES",
00374       "FINAL_RESULTS"
00375     };
00376   clp->setOption(
00377     "show-test-details", &getData().showTestDetails,
00378     numShowTestDetails, showTestDetailsValues, showTestDetailsNames,
00379     "Level of detail to show in the tests"
00380     );
00381 
00382   clp->setOption(
00383     "show-src-location", "no-show-src-location", &getData().showSrcLocation,
00384     "If true, then the location of the unit test source code is shown."
00385     "  Only meaningfull if --show-test-details=ALL."
00386     );
00387 
00388   clp->setOption(
00389     "group-name", &getData().groupName,
00390     "If specified, selects only tests that match the group name glob." );
00391 
00392   clp->setOption(
00393     "test-name", &getData().testName,
00394     "If specified, selects only tests that match the test name glob." );
00395 
00396   clp->setOption(
00397     "no-op", "do-op", &getData().noOp,
00398     "If --no-op, then only the names of the tests that would be run are run."
00399     );
00400   
00401 }
00402 
00403 
00404 UnitTestRepository::InstanceData& UnitTestRepository::getData()
00405 {
00406   static UnitTestRepository::InstanceData data;
00407   return data;
00408 }
00409 
00410 
00411 } // namespace Teuchos

Generated on Wed May 12 21:40:33 2010 for Teuchos - Trilinos Tools Package by  doxygen 1.4.7