summaryrefslogtreecommitdiffstats
path: root/Source/CTest
diff options
context:
space:
mode:
authorZack Galbreath <zack.galbreath@kitware.com>2013-09-24 18:20:38 (GMT)
committerBrad King <brad.king@kitware.com>2013-10-08 13:18:13 (GMT)
commiteb2decc02d28f41a3e189d5387be24552c42060f (patch)
treef1995da8fc935d3ed8831213da02534eab5e7ce2 /Source/CTest
parent475635ec0f3eeae9f6db0f9daa8a9c4cd8b3f989 (diff)
downloadCMake-eb2decc02d28f41a3e189d5387be24552c42060f.zip
CMake-eb2decc02d28f41a3e189d5387be24552c42060f.tar.gz
CMake-eb2decc02d28f41a3e189d5387be24552c42060f.tar.bz2
ctest: Add --rerun-failed option
Add a new command line argument to ctest. This allows users to rerun tests that failed during the previous call to ctest. This is accomplished by analyzing the most recently modified file named "^LastTestsFailed*" in the Testing/Temporary subdirectory of the project's binary directory.
Diffstat (limited to 'Source/CTest')
-rw-r--r--Source/CTest/cmCTestTestHandler.cxx136
-rw-r--r--Source/CTest/cmCTestTestHandler.h15
2 files changed, 149 insertions, 2 deletions
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index 497774d..167d48e 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -20,6 +20,7 @@
#include <cmsys/Process.h>
#include <cmsys/RegularExpression.hxx>
#include <cmsys/Base64.h>
+#include <cmsys/Directory.hxx>
#include "cmMakefile.h"
#include "cmGlobalGenerator.h"
#include "cmLocalGenerator.h"
@@ -537,6 +538,7 @@ int cmCTestTestHandler::ProcessHandler()
this->UseExcludeRegExp();
this->SetExcludeRegExp(val);
}
+ this->SetRerunFailed(cmSystemTools::IsOn(this->GetOption("RerunFailed")));
this->TestResults.clear();
@@ -819,6 +821,13 @@ void cmCTestTestHandler::ComputeTestList()
{
this->TestList.clear(); // clear list of test
this->GetListOfTests();
+
+ if (this->RerunFailed)
+ {
+ this->ComputeTestListForRerunFailed();
+ return;
+ }
+
cmCTestTestHandler::ListOfTests::size_type tmsize = this->TestList.size();
// how many tests are in based on RegExp?
int inREcnt = 0;
@@ -881,9 +890,47 @@ void cmCTestTestHandler::ComputeTestList()
this->TotalNumberOfTests = this->TestList.size();
// Set the TestList to the final list of all test
this->TestList = finalList;
+
+ this->UpdateMaxTestNameWidth();
+}
+
+void cmCTestTestHandler::ComputeTestListForRerunFailed()
+{
+ this->ExpandTestsToRunInformationForRerunFailed();
+
+ cmCTestTestHandler::ListOfTests::iterator it;
+ ListOfTests finalList;
+ int cnt = 0;
+ for ( it = this->TestList.begin(); it != this->TestList.end(); it ++ )
+ {
+ cnt ++;
+
+ // if this test is not in our list of tests to run, then skip it.
+ if ((this->TestsToRun.size() &&
+ std::find(this->TestsToRun.begin(), this->TestsToRun.end(), cnt)
+ == this->TestsToRun.end()))
+ {
+ continue;
+ }
+
+ it->Index = cnt;
+ finalList.push_back(*it);
+ }
+
+ // Save the total number of tests before exclusions
+ this->TotalNumberOfTests = this->TestList.size();
+
+ // Set the TestList to the list of failed tests to rerun
+ this->TestList = finalList;
+
+ this->UpdateMaxTestNameWidth();
+}
+
+void cmCTestTestHandler::UpdateMaxTestNameWidth()
+{
std::string::size_type max = this->CTest->GetMaxTestNameWidth();
- for (it = this->TestList.begin();
- it != this->TestList.end(); it ++ )
+ for ( cmCTestTestHandler::ListOfTests::iterator it = this->TestList.begin();
+ it != this->TestList.end(); it ++ )
{
cmCTestTestProperties& p = *it;
if(max < p.Name.size())
@@ -1708,6 +1755,91 @@ void cmCTestTestHandler::ExpandTestsToRunInformation(size_t numTests)
this->TestsToRun.erase(new_end, this->TestsToRun.end());
}
+void cmCTestTestHandler::ExpandTestsToRunInformationForRerunFailed()
+{
+
+ std::string dirName = this->CTest->GetBinaryDir() + "/Testing/Temporary";
+
+ cmsys::Directory directory;
+ if (directory.Load(dirName.c_str()) == 0)
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Unable to read the contents of "
+ << dirName << std::endl);
+ return;
+ }
+
+ int numFiles = static_cast<int>
+ (cmsys::Directory::GetNumberOfFilesInDirectory(dirName.c_str()));
+ std::string pattern = "LastTestsFailed";
+ std::string logName = "";
+
+ for (int i = 0; i < numFiles; ++i)
+ {
+ std::string fileName = directory.GetFile(i);
+ // bcc crashes if we attempt a normal substring comparison,
+ // hence the following workaround
+ std::string fileNameSubstring = fileName.substr(0, pattern.length());
+ if (fileNameSubstring.compare(pattern) != 0)
+ {
+ continue;
+ }
+ if (logName == "")
+ {
+ logName = fileName;
+ }
+ else
+ {
+ // if multiple matching logs were found we use the most recently
+ // modified one.
+ int res;
+ cmSystemTools::FileTimeCompare(logName.c_str(), fileName.c_str(), &res);
+ if (res == -1)
+ {
+ logName = fileName;
+ }
+ }
+ }
+
+ std::string lastTestsFailedLog = this->CTest->GetBinaryDir()
+ + "/Testing/Temporary/" + logName;
+
+ if ( !cmSystemTools::FileExists(lastTestsFailedLog.c_str()) )
+ {
+ if ( !this->CTest->GetShowOnly() && !this->CTest->ShouldPrintLabels() )
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, lastTestsFailedLog
+ << " does not exist!" << std::endl);
+ }
+ return;
+ }
+
+ // parse the list of tests to rerun from LastTestsFailed.log
+ std::ifstream ifs(lastTestsFailedLog.c_str());
+ if ( ifs )
+ {
+ std::string line;
+ std::string::size_type pos;
+ while ( cmSystemTools::GetLineFromStream(ifs, line) )
+ {
+ pos = line.find(':', 0);
+ if (pos == line.npos)
+ {
+ continue;
+ }
+
+ int val = atoi(line.substr(0, pos).c_str());
+ this->TestsToRun.push_back(val);
+ }
+ ifs.close();
+ }
+ else if ( !this->CTest->GetShowOnly() && !this->CTest->ShouldPrintLabels() )
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Problem reading file: "
+ << lastTestsFailedLog.c_str() <<
+ " while generating list of previously failed tests." << std::endl);
+ }
+}
+
//----------------------------------------------------------------------
// Just for convenience
#define SPACE_REGEX "[ \t\r\n]"
diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h
index 93b793b..398f052 100644
--- a/Source/CTest/cmCTestTestHandler.h
+++ b/Source/CTest/cmCTestTestHandler.h
@@ -44,6 +44,12 @@ public:
void SetUseUnion(bool val) { this->UseUnion = val; }
/**
+ * Set whether or not CTest should only execute the tests that failed
+ * on the previous run. By default this is false.
+ */
+ void SetRerunFailed(bool val) { this->RerunFailed = val; }
+
+ /**
* This method is called when reading CTest custom file
*/
void PopulateCustomVectors(cmMakefile *mf);
@@ -213,6 +219,12 @@ private:
// based on union regex and -I stuff
void ComputeTestList();
+ // compute the lists of tests that will actually run
+ // based on LastTestFailed.log
+ void ComputeTestListForRerunFailed();
+
+ void UpdateMaxTestNameWidth();
+
bool GetValue(const char* tag,
std::string& value,
std::ifstream& fin);
@@ -235,6 +247,7 @@ private:
const char* GetTestStatus(int status);
void ExpandTestsToRunInformation(size_t numPossibleTests);
+ void ExpandTestsToRunInformationForRerunFailed();
std::vector<cmStdString> CustomPreTest;
std::vector<cmStdString> CustomPostTest;
@@ -268,6 +281,8 @@ private:
cmsys::RegularExpression DartStuff;
std::ostream* LogFile;
+
+ bool RerunFailed;
};
#endif