00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
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();
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 }
00148
00149
00150
00151
00152 namespace Teuchos {
00153
00154
00155
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
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
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 }