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_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();
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 }
00137
00138
00139
00140
00141 namespace Teuchos {
00142
00143
00144
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
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
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 }