|
Teuchos - Trilinos Tools Package Version of the Day
|
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_TestingHelpers.hpp" 00033 #include "Teuchos_Array.hpp" 00034 #include "Teuchos_TestForException.hpp" 00035 #include "Teuchos_VerboseObject.hpp" 00036 #include "Teuchos_CommandLineProcessor.hpp" 00037 #include "Teuchos_Assert.hpp" 00038 #include "Teuchos_Time.hpp" 00039 #include "Teuchos_StandardCatchMacros.hpp" 00040 00041 00042 namespace Teuchos { 00043 00044 00045 struct UnitTestData { 00046 00047 const Teuchos::UnitTestBase * unitTest; 00048 std::string groupName; 00049 std::string testName; 00050 int insertionIndex; 00051 00052 UnitTestData( 00053 Teuchos::UnitTestBase *unitTest_in, 00054 const std::string groupName_in, 00055 const std::string testName_in 00056 ) 00057 : unitTest(unitTest_in), groupName(groupName_in), testName(testName_in), 00058 insertionIndex(insersionIndexCounter_++) 00059 { 00060 #ifdef TEUCHOS_DEBUG 00061 TEUCHOS_ASSERT(unitTest_in); 00062 #endif 00063 } 00064 00065 private: 00066 UnitTestData(); // Not defined! 00067 static int insersionIndexCounter_; 00068 }; 00069 00070 00071 int UnitTestData::insersionIndexCounter_ = 0; 00072 00073 00074 bool operator<(const UnitTestData &a, const UnitTestData &b) 00075 { 00076 if (a.groupName < b.groupName) { 00077 return true; 00078 } 00079 else if (a.groupName > b.groupName) { 00080 return false; 00081 } 00082 return a.insertionIndex < b.insertionIndex; 00083 } 00084 00085 00086 00087 std::string getUnitTestName(const std::string groupName, 00088 const std::string testName) 00089 { 00090 std::ostringstream oss; 00091 oss << groupName<<"_"<<testName<<"_UnitTest"; 00092 return oss.str(); 00093 } 00094 00095 00096 enum EShowTestDetails { 00097 SHOW_TEST_DETAILS_ALL, 00098 SHOW_TEST_DETAILS_TEST_NAMES, 00099 SHOW_TEST_DETAILS_FINAL_RESULTS 00100 }; 00101 00102 00103 bool strMatch( const std::string &fullMatchStr, const std::string &str ) 00104 { 00105 00106 const std::string::size_type npos = std::string::npos; 00107 00108 const int strLen = str.length(); 00109 const int fullMatchStrLen = fullMatchStr.length(); 00110 00111 if (fullMatchStrLen == 0) { 00112 return true; 00113 } 00114 00115 const bool beginGlob = fullMatchStr[0] == '*'; 00116 const bool endGlob = fullMatchStr[fullMatchStrLen-1] == '*'; 00117 00118 const int matchStrLen = 00119 fullMatchStrLen + (beginGlob ? -1 : 0) + (endGlob ? -1 : 0); 00120 00121 if (matchStrLen == 0) { 00122 return true; 00123 } 00124 00125 if (matchStrLen > strLen) { 00126 return false; 00127 } 00128 00129 if (beginGlob && endGlob) { 00130 return str.find(fullMatchStr.substr(1, matchStrLen)) != npos; 00131 } 00132 00133 if (endGlob) { 00134 return fullMatchStr.substr(0, matchStrLen) == str.substr(0, matchStrLen); 00135 } 00136 00137 if (beginGlob) { 00138 return fullMatchStr.substr(1, matchStrLen) == 00139 str.substr(strLen-matchStrLen, matchStrLen); 00140 } 00141 00142 return fullMatchStr == str; 00143 00144 } 00145 00146 00147 } // namespace Teuchos 00148 00149 00150 00151 00152 namespace Teuchos { 00153 00154 00155 // Implementation class 00156 00157 00158 class UnitTestRepository::InstanceData { 00159 public: 00160 00161 typedef Teuchos::Array<UnitTestData> unitTests_t; 00162 00163 unitTests_t unitTests; 00164 CommandLineProcessor clp; 00165 EShowTestDetails showTestDetails; 00166 bool showSrcLocation; 00167 bool showFailSrcLocation; 00168 bool noOp; 00169 std::string groupName; 00170 std::string testName; 00171 std::string notUnitTestName; 00172 int testCounter; 00173 00174 InstanceData() 00175 :clp(false), 00176 showTestDetails(SHOW_TEST_DETAILS_TEST_NAMES), 00177 showSrcLocation(false), 00178 showFailSrcLocation(true), 00179 noOp(false), 00180 testCounter(0) 00181 {} 00182 00183 }; 00184 00185 00186 // public 00187 00188 00189 CommandLineProcessor& UnitTestRepository::getCLP() 00190 { 00191 return getData().clp; 00192 } 00193 00194 00195 bool UnitTestRepository::runUnitTests(FancyOStream &out) 00196 { 00197 00198 typedef InstanceData::unitTests_t unitTests_t; 00199 00200 using std::setprecision; 00201 00202 Time overallTimer("overallTimer", true); 00203 Time timer("timer"); 00204 00205 const int timerPrec = 3; 00206 00207 out << "\n***\n*** Unit test suite ...\n***\n\n"; 00208 00209 InstanceData &data = getData(); 00210 00211 const bool showAll = data.showTestDetails == SHOW_TEST_DETAILS_ALL; 00212 const bool showTestNames = data.showTestDetails == SHOW_TEST_DETAILS_TEST_NAMES || showAll; 00213 00214 showTestFailureLocation(data.showFailSrcLocation); 00215 00216 bool success = true; 00217 int testCounter = 0; 00218 int numTestsRun = 0; 00219 int numTestsFailed = 0; 00220 00221 Array<std::string> failedTests; 00222 00223 try { 00224 00225 out << "\nSorting tests by group name then by the order they where added ..."; 00226 timer.start(true); 00227 std::sort( data.unitTests.begin(), data.unitTests.end() ); 00228 timer.stop(); 00229 out << " (time = "<<setprecision(timerPrec)<<timer.totalElapsedTime()<<")\n"; 00230 00231 out << "\nRunning unit tests ...\n\n"; 00232 unitTests_t::iterator iter = data.unitTests.begin(); 00233 for ( ; iter != data.unitTests.end(); ++iter, ++testCounter ) { 00234 00235 const UnitTestData &utd = (*iter); 00236 00237 const std::string unitTestName = getUnitTestName(utd.groupName, utd.testName); 00238 00239 if ( 00240 ( 00241 strMatch(data.groupName, utd.groupName) 00242 && 00243 strMatch(data.testName, utd.testName) 00244 ) 00245 && 00246 ( 00247 data.notUnitTestName.length() == 0 00248 || 00249 !strMatch(data.notUnitTestName, unitTestName) 00250 ) 00251 ) 00252 { 00253 00254 ++numTestsRun; 00255 00256 std::ostringstream testHeaderOSS; 00257 testHeaderOSS <<testCounter<<". "<<unitTestName<<" ... "; 00258 const std::string testHeader = testHeaderOSS.str(); 00259 00260 if (showAll) 00261 out <<"\n"; 00262 00263 if (showTestNames) 00264 out <<testHeader<<std::flush; 00265 00266 { 00267 00268 RCP<std::ostringstream> oss; 00269 RCP<FancyOStream> localOut; 00270 if (showAll) { 00271 out << "\n"; 00272 localOut = rcpFromRef(out); 00273 } 00274 else { 00275 oss = rcp(new std::ostringstream); 00276 localOut = fancyOStream(rcp_implicit_cast<std::ostream>(oss)); 00277 } 00278 00279 OSTab tab(out); 00280 00281 if (!data.noOp) { 00282 00283 timer.start(true); 00284 const bool result = utd.unitTest->runUnitTest(*localOut); 00285 timer.stop(); 00286 00287 if (!result) { 00288 00289 failedTests.push_back(testHeader); 00290 00291 if (!showTestNames) 00292 out <<testHeader<<"\n"<<std::flush; 00293 else if (!showAll) 00294 out <<"\n"; 00295 00296 if (!is_null(oss)) 00297 out << oss->str(); 00298 00299 out 00300 <<"[FAILED] " 00301 <<" "<<setprecision(timerPrec)<<"("<<timer.totalElapsedTime()<< " sec)" 00302 <<" "<<unitTestName<<"\n" 00303 <<"Location: "<<utd.unitTest->unitTestFile()<<":" 00304 <<utd.unitTest->unitTestFileLineNumber()<<"\n"; 00305 00306 if (!is_null(oss)) 00307 out << "\n"; 00308 00309 success = false; 00310 00311 ++numTestsFailed; 00312 00313 } 00314 else { 00315 00316 if (showTestNames) 00317 out << "[Passed] " 00318 << setprecision(timerPrec)<<"("<<timer.totalElapsedTime()<<" sec)\n"; 00319 00320 if (showAll && data.showSrcLocation) 00321 out 00322 << "Location: "<<utd.unitTest->unitTestFile()<<":" 00323 <<utd.unitTest->unitTestFileLineNumber()<<"\n"; 00324 00325 } 00326 00327 } 00328 else { 00329 00330 if (showTestNames) 00331 out << "[Not Run]\n"; 00332 00333 } 00334 00335 } 00336 00337 } 00338 00339 } 00340 00341 TEUCHOS_ASSERT_EQUALITY(testCounter, as<int>(data.unitTests.size())); 00342 00343 } 00344 TEUCHOS_STANDARD_CATCH_STATEMENTS(true, out, success); 00345 00346 if (failedTests.size()) { 00347 out << "\nThe following tests FAILED:\n"; 00348 for (Teuchos_Ordinal i = 0; i < failedTests.size(); ++i) 00349 out << " " << failedTests[i] << "\n"; 00350 } 00351 00352 overallTimer.stop(); 00353 out << "\nTotal Time: " << setprecision(timerPrec) 00354 << overallTimer.totalElapsedTime() << " sec\n"; 00355 00356 out 00357 << "\nSummary: total = " << testCounter 00358 << ", run = " << numTestsRun; 00359 00360 if (!data.noOp) { 00361 out 00362 << ", passed = " << (numTestsRun-numTestsFailed) 00363 << ", failed = " << numTestsFailed << "\n"; 00364 } 00365 else { 00366 out 00367 << ", passed = ???" 00368 << ", failed = ???\n"; 00369 } 00370 00371 return success; 00372 00373 } 00374 00375 00376 int UnitTestRepository::runUnitTestsFromMain( int argc, char* argv[] ) 00377 { 00378 00379 const RCP<FancyOStream> out = VerboseObjectBase::getDefaultOStream(); 00380 00381 CommandLineProcessor &clp = getData().clp; 00382 setUpCLP(outArg(clp)); 00383 CommandLineProcessor::EParseCommandLineReturn parse_return = 00384 clp.parse(argc,argv); 00385 if ( parse_return != CommandLineProcessor::PARSE_SUCCESSFUL ) { 00386 *out << "\nEnd Result: TEST FAILED" << std::endl; 00387 return parse_return; 00388 } 00389 00390 const bool success = runUnitTests(*out); 00391 00392 if (success) 00393 *out << "\nEnd Result: TEST PASSED" << std::endl; 00394 else 00395 *out << "\nEnd Result: TEST FAILED" << std::endl; 00396 00397 return (success ? 0 : 1); 00398 00399 } 00400 00401 00402 void UnitTestRepository::addUnitTest( UnitTestBase *unitTest, 00403 const std::string groupName, const std::string testName_in ) 00404 { 00405 InstanceData &data = getData(); 00406 std::string testName = testName_in; 00407 data.unitTests.push_back(UnitTestData(unitTest, groupName, testName)); 00408 } 00409 00410 00411 // private: 00412 00413 00414 UnitTestRepository::UnitTestRepository() 00415 {} 00416 00417 00418 void UnitTestRepository::setUpCLP(const Ptr<CommandLineProcessor>& clp) 00419 { 00420 00421 clp->addOutputSetupOptions(true); 00422 00423 const int numShowTestDetails = 3; 00424 const EShowTestDetails showTestDetailsValues[numShowTestDetails] = 00425 { SHOW_TEST_DETAILS_ALL, 00426 SHOW_TEST_DETAILS_TEST_NAMES, 00427 SHOW_TEST_DETAILS_FINAL_RESULTS 00428 }; 00429 const char* showTestDetailsNames[numShowTestDetails] = 00430 { "ALL", 00431 "TEST_NAMES", 00432 "FINAL_RESULTS" 00433 }; 00434 clp->setOption( 00435 "show-test-details", &getData().showTestDetails, 00436 numShowTestDetails, showTestDetailsValues, showTestDetailsNames, 00437 "Level of detail to show in the tests" 00438 ); 00439 clp->setOption( 00440 "details", &getData().showTestDetails, 00441 numShowTestDetails, showTestDetailsValues, showTestDetailsNames, 00442 "Short for --details" 00443 ); 00444 00445 clp->setOption( 00446 "show-src-location", "no-show-src-location", &getData().showSrcLocation, 00447 "If true, then the location of the unit test source code is shown." 00448 " Only meaningfull if --show-test-details=ALL." 00449 ); 00450 00451 clp->setOption( 00452 "show-fail-src-location", "no-show-fail-src-location", &getData().showFailSrcLocation, 00453 "If true, then the location of every failed unit test check is printed." 00454 ); 00455 00456 clp->setOption( 00457 "group-name", &getData().groupName, 00458 "If specified, selects only tests that match the group name glob." ); 00459 clp->setOption( 00460 "group", &getData().groupName, 00461 "Short for --group-name." ); 00462 00463 clp->setOption( 00464 "test-name", &getData().testName, 00465 "If specified, selects only tests that match the test name glob." ); 00466 clp->setOption( 00467 "test", &getData().testName, 00468 "Short for --test-name." ); 00469 00470 clp->setOption( 00471 "not-unit-test", &getData().notUnitTestName, 00472 "If specified, full unit tests with glob matches will *not* be run." ); 00473 00474 clp->setOption( 00475 "no-op", "do-op", &getData().noOp, 00476 "If --no-op, then only the names of the tests that would be run are run." 00477 ); 00478 00479 } 00480 00481 00482 UnitTestRepository::InstanceData& UnitTestRepository::getData() 00483 { 00484 static UnitTestRepository::InstanceData data; 00485 return data; 00486 } 00487 00488 00489 } // namespace Teuchos
1.7.4