summaryrefslogtreecommitdiffstats
path: root/Source/CTest
diff options
context:
space:
mode:
Diffstat (limited to 'Source/CTest')
-rw-r--r--Source/CTest/cmCTestBZR.cxx2
-rw-r--r--Source/CTest/cmCTestBuildHandler.cxx1
-rw-r--r--Source/CTest/cmCTestCoverageHandler.cxx128
-rw-r--r--Source/CTest/cmCTestCoverageHandler.h63
-rw-r--r--Source/CTest/cmCTestGIT.cxx14
-rw-r--r--Source/CTest/cmCTestGIT.h1
-rw-r--r--Source/CTest/cmCTestHG.cxx2
-rw-r--r--Source/CTest/cmCTestMultiProcessHandler.cxx21
-rw-r--r--Source/CTest/cmCTestRunTest.cxx86
-rw-r--r--Source/CTest/cmCTestRunTest.h9
-rw-r--r--Source/CTest/cmCTestTestCommand.cxx5
-rw-r--r--Source/CTest/cmCTestTestCommand.h7
-rw-r--r--Source/CTest/cmCTestUpdateHandler.cxx1
-rw-r--r--Source/CTest/cmCTestVC.cxx1
-rw-r--r--Source/CTest/cmCTestVC.h1
-rw-r--r--Source/CTest/cmParsePHPCoverage.cxx252
-rw-r--r--Source/CTest/cmParsePHPCoverage.h48
17 files changed, 549 insertions, 93 deletions
diff --git a/Source/CTest/cmCTestBZR.cxx b/Source/CTest/cmCTestBZR.cxx
index 55b8d5b..36302df 100644
--- a/Source/CTest/cmCTestBZR.cxx
+++ b/Source/CTest/cmCTestBZR.cxx
@@ -292,7 +292,7 @@ private:
if(this->EmailRegex.find(this->Rev.Author))
{
this->Rev.Author = this->EmailRegex.match(1);
- //email = email_regex.match(2);
+ this->Rev.EMail = this->EmailRegex.match(2);
}
}
else if(strcmp(name, "timestamp") == 0 && !this->CData.empty())
diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx
index a125459..bc02fbc 100644
--- a/Source/CTest/cmCTestBuildHandler.cxx
+++ b/Source/CTest/cmCTestBuildHandler.cxx
@@ -551,6 +551,7 @@ class cmCTestBuildHandler::FragmentCompare
{
public:
FragmentCompare(cmFileTimeComparison* ftc): FTC(ftc) {}
+ FragmentCompare(): FTC(0) {}
bool operator()(std::string const& l, std::string const& r)
{
// Order files by modification time. Use lexicographic order
diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx
index 1076886..3235bfd 100644
--- a/Source/CTest/cmCTestCoverageHandler.cxx
+++ b/Source/CTest/cmCTestCoverageHandler.cxx
@@ -10,6 +10,7 @@
See the License for more information.
============================================================================*/
#include "cmCTestCoverageHandler.h"
+#include "cmParsePHPCoverage.h"
#include "cmCTest.h"
#include "cmake.h"
#include "cmMakefile.h"
@@ -126,20 +127,6 @@ private:
//----------------------------------------------------------------------
-//**********************************************************************
-class cmCTestCoverageHandlerContainer
-{
-public:
- int Error;
- std::string SourceDir;
- std::string BinaryDir;
- typedef std::vector<int> SingleFileCoverageVector;
- typedef std::map<std::string, SingleFileCoverageVector> TotalCoverageMap;
- TotalCoverageMap TotalCoverage;
- std::ostream* OFS;
-};
-//**********************************************************************
-//----------------------------------------------------------------------
//----------------------------------------------------------------------
cmCTestCoverageHandler::cmCTestCoverageHandler()
@@ -380,7 +367,6 @@ int cmCTestCoverageHandler::ProcessHandler()
cmsys::RegularExpression(rexIt->c_str()));
}
-
if(this->HandleBullseyeCoverage(&cont))
{
return cont.Error;
@@ -396,8 +382,14 @@ int cmCTestCoverageHandler::ProcessHandler()
{
return error;
}
+ file_count += this->HandlePHPCoverage(&cont);
+ if ( file_count < 0 )
+ {
+ return error;
+ }
error = cont.Error;
+ std::set<std::string> uncovered = this->FindUncoveredFiles(&cont);
if ( file_count == 0 )
{
@@ -524,7 +516,7 @@ int cmCTestCoverageHandler::ProcessHandler()
{
cmOStringStream ostr;
ostr << "Problem reading source file: " << fullFileName.c_str()
- << " line:" << cc;
+ << " line:" << cc << " out total: " << fcov.size()-1;
errorsWhileAccumulating.push_back(ostr.str());
error ++;
break;
@@ -577,13 +569,58 @@ int cmCTestCoverageHandler::ProcessHandler()
this->WriteXMLLabels(covSumFile, shortFileName);
covSumFile << "\t</File>" << std::endl;
}
+
+ //Handle all the files in the extra coverage globs that have no cov data
+ for(std::set<std::string>::iterator i = uncovered.begin();
+ i != uncovered.end(); ++i)
+ {
+ std::string fileName = cmSystemTools::GetFilenameName(*i);
+ std::string fullPath = cont.SourceDir + "/" + *i;
+
+ covLogFile << "\t<File Name=\"" << cmXMLSafe(fileName)
+ << "\" FullPath=\"" << cmXMLSafe(*i) << "\">\n"
+ << "\t\t<Report>" << std::endl;
+
+ std::ifstream ifs(fullPath.c_str());
+ if (!ifs)
+ {
+ cmOStringStream ostr;
+ ostr << "Cannot open source file: " << fullPath.c_str();
+ errorsWhileAccumulating.push_back(ostr.str());
+ error ++;
+ continue;
+ }
+ int untested = 0;
+ std::string line;
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Actually perfoming coverage for: " << i->c_str() << std::endl);
+ while (cmSystemTools::GetLineFromStream(ifs, line))
+ {
+ covLogFile << "\t\t<Line Number=\"" << untested << "\" Count=\"0\">"
+ << cmXMLSafe(line) << "</Line>" << std::endl;
+ untested ++;
+ }
+ covLogFile << "\t\t</Report>\n\t</File>" << std::endl;
+
+ total_untested += untested;
+ covSumFile << "\t<File Name=\"" << cmXMLSafe(fileName)
+ << "\" FullPath=\"" << cmXMLSafe(i->c_str())
+ << "\" Covered=\"true\">\n"
+ << "\t\t<LOCTested>0</LOCTested>\n"
+ << "\t\t<LOCUnTested>" << untested << "</LOCUnTested>\n"
+ << "\t\t<PercentCoverage>0</PercentCoverage>\n"
+ << "\t\t<CoverageMetric>0</CoverageMetric>\n";
+ this->WriteXMLLabels(covSumFile, *i);
+ covSumFile << "\t</File>" << std::endl;
+ }
+
this->EndCoverageLogFile(covLogFile, logFileCount);
if ( errorsWhileAccumulating.size() > 0 )
{
cmCTestLog(this->CTest, ERROR_MESSAGE, std::endl);
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Error(s) while acumulating results:" << std::endl);
+ "Error(s) while accumulating results:" << std::endl);
std::vector<std::string>::iterator erIt;
for ( erIt = errorsWhileAccumulating.begin();
erIt != errorsWhileAccumulating.end();
@@ -654,6 +691,8 @@ void cmCTestCoverageHandler::PopulateCustomVectors(cmMakefile *mf)
" Add coverage exclude regular expressions." << std::endl);
this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_COVERAGE_EXCLUDE",
this->CustomCoverageExclude);
+ this->CTest->PopulateCustomVector(mf, "CTEST_EXTRA_COVERAGE_GLOB",
+ this->ExtraCoverageGlobs);
std::vector<cmStdString>::iterator it;
for ( it = this->CustomCoverageExclude.begin();
it != this->CustomCoverageExclude.end();
@@ -662,6 +701,12 @@ void cmCTestCoverageHandler::PopulateCustomVectors(cmMakefile *mf)
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Add coverage exclude: "
<< it->c_str() << std::endl);
}
+ for ( it = this->ExtraCoverageGlobs.begin();
+ it != this->ExtraCoverageGlobs.end(); ++it)
+ {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Add coverage glob: "
+ << it->c_str() << std::endl);
+ }
}
//----------------------------------------------------------------------
@@ -695,6 +740,18 @@ bool IsFileInDir(const std::string &infile, const std::string &indir)
}
//----------------------------------------------------------------------
+int cmCTestCoverageHandler::HandlePHPCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ cmParsePHPCoverage cov(*cont, this->CTest);
+ std::string coverageDir = this->CTest->GetBinaryDir() + "/xdebugCoverage";
+ if(cmSystemTools::FileIsDirectory(coverageDir.c_str()))
+ {
+ cov.ReadPHPCoverageDirectory(coverageDir.c_str());
+ }
+ return static_cast<int>(cont->TotalCoverage.size());
+}
+//----------------------------------------------------------------------
int cmCTestCoverageHandler::HandleGCovCoverage(
cmCTestCoverageHandlerContainer* cont)
{
@@ -1703,6 +1760,7 @@ int cmCTestCoverageHandler::RunBullseyeSourceSummary(
<< "</ElapsedMinutes>"
<< "</Coverage>" << std::endl;
this->CTest->EndXML(covSumFile);
+
// Now create the coverage information for each file
return this->RunBullseyeCoverageBranch(cont,
coveredFileNames,
@@ -1961,3 +2019,39 @@ bool cmCTestCoverageHandler::IsFilteredOut(std::string const& source)
}
return true;
}
+
+//----------------------------------------------------------------------
+std::set<std::string> cmCTestCoverageHandler::FindUncoveredFiles(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ std::set<std::string> extraMatches;
+
+ for(std::vector<cmStdString>::iterator i = this->ExtraCoverageGlobs.begin();
+ i != this->ExtraCoverageGlobs.end(); ++i)
+ {
+ cmsys::Glob gl;
+ gl.RecurseOn();
+ gl.RecurseThroughSymlinksOff();
+ std::string glob = cont->SourceDir + "/" + *i;
+ gl.FindFiles(glob);
+ std::vector<std::string> files = gl.GetFiles();
+ for(std::vector<std::string>::iterator f = files.begin();
+ f != files.end(); ++f)
+ {
+ extraMatches.insert(this->CTest->GetShortPathToFile(
+ f->c_str()));
+ }
+ }
+
+ if(extraMatches.size())
+ {
+ for(cmCTestCoverageHandlerContainer::TotalCoverageMap::iterator i =
+ cont->TotalCoverage.begin(); i != cont->TotalCoverage.end(); ++i)
+ {
+ std::string shortPath = this->CTest->GetShortPathToFile(
+ i->first.c_str());
+ extraMatches.erase(shortPath);
+ }
+ }
+ return extraMatches;
+}
diff --git a/Source/CTest/cmCTestCoverageHandler.h b/Source/CTest/cmCTestCoverageHandler.h
index b3e4db6..d3e8503 100644
--- a/Source/CTest/cmCTestCoverageHandler.h
+++ b/Source/CTest/cmCTestCoverageHandler.h
@@ -20,8 +20,17 @@
#include <cmsys/RegularExpression.hxx>
class cmGeneratedFileStream;
-class cmCTestCoverageHandlerContainer;
-
+class cmCTestCoverageHandlerContainer
+{
+public:
+ int Error;
+ std::string SourceDir;
+ std::string BinaryDir;
+ typedef std::vector<int> SingleFileCoverageVector;
+ typedef std::map<std::string, SingleFileCoverageVector> TotalCoverageMap;
+ TotalCoverageMap TotalCoverage;
+ std::ostream* OFS;
+};
/** \class cmCTestCoverageHandler
* \brief A class that handles coverage computaiton for ctest
*
@@ -59,6 +68,9 @@ private:
int HandleGCovCoverage(cmCTestCoverageHandlerContainer* cont);
void FindGCovFiles(std::vector<std::string>& files);
+ //! Handle coverage using xdebug php coverage
+ int HandlePHPCoverage(cmCTestCoverageHandlerContainer* cont);
+
//! Handle coverage using Bullseye
int HandleBullseyeCoverage(cmCTestCoverageHandlerContainer* cont);
int RunBullseyeSourceSummary(cmCTestCoverageHandlerContainer* cont);
@@ -66,6 +78,7 @@ private:
std::set<cmStdString>& coveredFileNames,
std::vector<std::string>& files,
std::vector<std::string>& filesFullPath);
+
int RunBullseyeCommand(
cmCTestCoverageHandlerContainer* cont,
const char* cmd,
@@ -91,52 +104,12 @@ private:
std::string FindFile(cmCTestCoverageHandlerContainer* cont,
std::string fileName);
- struct cmCTestCoverage
- {
- cmCTestCoverage()
- {
- this->AbsolutePath = "";
- this->FullPath = "";
- this->Covered = false;
- this->Tested = 0;
- this->UnTested = 0;
- this->Lines.clear();
- this->Show = false;
- }
- cmCTestCoverage(const cmCTestCoverage& rhs) :
- AbsolutePath(rhs.AbsolutePath),
- FullPath(rhs.FullPath),
- Covered(rhs.Covered),
- Tested(rhs.Tested),
- UnTested(rhs.UnTested),
- Lines(rhs.Lines),
- Show(rhs.Show)
- {
- }
- cmCTestCoverage& operator=(const cmCTestCoverage& rhs)
- {
- this->AbsolutePath = rhs.AbsolutePath;
- this->FullPath = rhs.FullPath;
- this->Covered = rhs.Covered;
- this->Tested = rhs.Tested;
- this->UnTested = rhs.UnTested;
- this->Lines = rhs.Lines;
- this->Show = rhs.Show;
- return *this;
- }
- std::string AbsolutePath;
- std::string FullPath;
- bool Covered;
- int Tested;
- int UnTested;
- std::vector<int> Lines;
- bool Show;
- };
-
+ std::set<std::string> FindUncoveredFiles(
+ cmCTestCoverageHandlerContainer* cont);
std::vector<cmStdString> CustomCoverageExclude;
std::vector<cmsys::RegularExpression> CustomCoverageExcludeRegex;
+ std::vector<cmStdString> ExtraCoverageGlobs;
- typedef std::map<std::string, cmCTestCoverage> CoverageMap;
// Map from source file to label ids.
class LabelSet: public std::set<int> {};
diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx
index 6d5bf65..f5ba361 100644
--- a/Source/CTest/cmCTestGIT.cxx
+++ b/Source/CTest/cmCTestGIT.cxx
@@ -87,9 +87,11 @@ void cmCTestGIT::NoteNewRevision()
//----------------------------------------------------------------------------
bool cmCTestGIT::UpdateImpl()
{
+ const char* git = this->CommandLineTool.c_str();
+
// Use "git pull" to update the working tree.
std::vector<char const*> git_pull;
- git_pull.push_back(this->CommandLineTool.c_str());
+ git_pull.push_back(git);
git_pull.push_back("pull");
// TODO: if(this->CTest->GetTestModel() == cmCTest::NIGHTLY)
@@ -112,7 +114,14 @@ bool cmCTestGIT::UpdateImpl()
OutputLogger out(this->Log, "pull-out> ");
OutputLogger err(this->Log, "pull-err> ");
- return this->RunUpdateCommand(&git_pull[0], &out, &err);
+ if(this->RunUpdateCommand(&git_pull[0], &out, &err))
+ {
+ char const* git_submodule[] = {git, "submodule", "update", 0};
+ OutputLogger out2(this->Log, "submodule-out> ");
+ OutputLogger err2(this->Log, "submodule-err> ");
+ return this->RunChild(git_submodule, &out2, &err2);
+ }
+ return false;
}
//----------------------------------------------------------------------------
@@ -338,6 +347,7 @@ private:
Person author;
this->ParsePerson(this->Line.c_str()+7, author);
this->Rev.Author = author.Name;
+ this->Rev.EMail = author.EMail;
// Convert the time to a human-readable format that is also easy
// to machine-parse: "CCYY-MM-DD hh:mm:ss".
diff --git a/Source/CTest/cmCTestGIT.h b/Source/CTest/cmCTestGIT.h
index 2561ed4..0b6ad2e 100644
--- a/Source/CTest/cmCTestGIT.h
+++ b/Source/CTest/cmCTestGIT.h
@@ -35,6 +35,7 @@ private:
void LoadRevisions();
void LoadModifications();
+public: // needed by older Sun compilers
// Parsing helper classes.
class OneLineParser;
class DiffParser;
diff --git a/Source/CTest/cmCTestHG.cxx b/Source/CTest/cmCTestHG.cxx
index b263677..86a7617 100644
--- a/Source/CTest/cmCTestHG.cxx
+++ b/Source/CTest/cmCTestHG.cxx
@@ -220,7 +220,7 @@ private:
}
else if ( strcmp(name, "email") == 0 && !this->CData.empty())
{
- // this->Rev.Email.assign(&this->CData[0], this->CData.size());
+ this->Rev.EMail.assign(&this->CData[0], this->CData.size());
}
else if(strcmp(name, "date") == 0 && !this->CData.empty())
{
diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx
index c1ca9ea..8a69780 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.cxx
+++ b/Source/CTest/cmCTestMultiProcessHandler.cxx
@@ -453,15 +453,24 @@ void cmCTestMultiProcessHandler::CreateTestCostList()
for(TestMap::iterator i = this->Tests.begin();
i != this->Tests.end(); ++i)
{
- std::string name = this->Properties[i->first]->Name;
- if(std::find(this->LastTestsFailed.begin(), this->LastTestsFailed.end(),
- name) != this->LastTestsFailed.end())
+ //We only want to schedule them by cost in a parallel situation
+ if(this->ParallelLevel > 1)
{
- this->TestCosts[FLT_MAX].insert(i->first);
+ std::string name = this->Properties[i->first]->Name;
+ if(std::find(this->LastTestsFailed.begin(), this->LastTestsFailed.end(),
+ name) != this->LastTestsFailed.end())
+ {
+ this->TestCosts[FLT_MAX].insert(i->first);
+ }
+ else
+ {
+ this->TestCosts[this->Properties[i->first]->Cost].insert(i->first);
+ }
}
- else
+ else //we ignore their cost
{
- this->TestCosts[this->Properties[i->first]->Cost].insert(i->first);
+ this->TestCosts[this->Tests.size()
+ - this->Properties[i->first]->Index].insert(i->first);
}
}
}
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 659cb73..4c9675b 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -14,6 +14,7 @@
#include "cmCTestMemCheckHandler.h"
#include "cmCTest.h"
#include "cmSystemTools.h"
+#include "cm_curl.h"
#include <cm_zlib.h>
#include <cmsys/Base64.h>
@@ -22,7 +23,6 @@ cmCTestRunTest::cmCTestRunTest(cmCTestTestHandler* handler)
{
this->CTest = handler->CTest;
this->TestHandler = handler;
- this->ModifyEnv = false;
this->TestProcess = 0;
this->TestResult.ExecutionTime =0;
this->TestResult.ReturnValue = 0;
@@ -138,11 +138,6 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
this->CompressOutput();
}
- //restore the old environment
- if (this->ModifyEnv)
- {
- cmSystemTools::RestoreEnv(this->OrigEnv);
- }
this->WriteLogOutputTop(completed, total);
std::string reason;
bool passed = true;
@@ -441,7 +436,7 @@ bool cmCTestRunTest::StartTest(size_t total)
}
this->StartTime = this->CTest->CurrentTime();
- return this->CreateProcess(this->TestProperties->Timeout,
+ return this->ForkProcess(this->ResolveTimeout(),
&this->TestProperties->Environment);
}
@@ -518,7 +513,71 @@ void cmCTestRunTest::DartProcessing()
}
//----------------------------------------------------------------------
-bool cmCTestRunTest::CreateProcess(double testTimeOut,
+double cmCTestRunTest::ResolveTimeout()
+{
+ double timeout = this->TestProperties->Timeout;
+
+ if(this->CTest->GetStopTime() == "")
+ {
+ return timeout;
+ }
+ struct tm* lctime;
+ time_t current_time = time(0);
+ lctime = gmtime(&current_time);
+ int gm_hour = lctime->tm_hour;
+ time_t gm_time = mktime(lctime);
+ lctime = localtime(&current_time);
+ int local_hour = lctime->tm_hour;
+
+ int tzone_offset = local_hour - gm_hour;
+ if(gm_time > current_time && gm_hour < local_hour)
+ {
+ // this means gm_time is on the next day
+ tzone_offset -= 24;
+ }
+ else if(gm_time < current_time && gm_hour > local_hour)
+ {
+ // this means gm_time is on the previous day
+ tzone_offset += 24;
+ }
+
+ tzone_offset *= 100;
+ char buf[1024];
+ // add todays year day and month to the time in str because
+ // curl_getdate no longer assumes the day is today
+ sprintf(buf, "%d%02d%02d %s %+05i",
+ lctime->tm_year + 1900,
+ lctime->tm_mon + 1,
+ lctime->tm_mday,
+ this->CTest->GetStopTime().c_str(),
+ tzone_offset);
+
+ time_t stop_time = curl_getdate(buf, &current_time);
+ if(stop_time == -1)
+ {
+ return timeout;
+ }
+
+ //the stop time refers to the next day
+ if(this->CTest->NextDayStopTime)
+ {
+ stop_time += 24*60*60;
+ }
+ int stop_timeout = (stop_time - current_time) % (24*60*60);
+ this->CTest->LastStopTimeout = stop_timeout;
+
+ if(stop_timeout <= 0 || stop_timeout > this->CTest->LastStopTimeout)
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "The stop time has been passed. "
+ "Exiting ctest." << std::endl);
+ exit(-1);
+ }
+ return timeout == 0 ? stop_timeout :
+ (timeout < stop_timeout ? timeout : stop_timeout);
+}
+
+//----------------------------------------------------------------------
+bool cmCTestRunTest::ForkProcess(double testTimeOut,
std::vector<std::string>* environment)
{
this->TestProcess = new cmProcess;
@@ -528,9 +587,6 @@ bool cmCTestRunTest::CreateProcess(double testTimeOut,
this->TestProcess->SetCommand(this->ActualCommand.c_str());
this->TestProcess->SetCommandArguments(this->Arguments);
- std::vector<std::string> origEnv;
- this->ModifyEnv = (environment && environment->size()>0);
-
// determine how much time we have
double timeout = this->CTest->GetRemainingTimeAllowed() - 120;
if (this->CTest->GetTimeOut() > 0 && this->CTest->GetTimeOut() < timeout)
@@ -553,9 +609,13 @@ bool cmCTestRunTest::CreateProcess(double testTimeOut,
this->TestProcess->SetTimeout(timeout);
- if (this->ModifyEnv)
+#ifdef CMAKE_BUILD_WITH_CMAKE
+ cmSystemTools::SaveRestoreEnvironment sre;
+#endif
+
+ if (environment && environment->size()>0)
{
- this->OrigEnv = cmSystemTools::AppendEnv(environment);
+ cmSystemTools::AppendEnv(environment);
}
return this->TestProcess->StartProcess();
diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h
index 1e4c1cc..d7d3a2f 100644
--- a/Source/CTest/cmCTestRunTest.h
+++ b/Source/CTest/cmCTestRunTest.h
@@ -59,7 +59,9 @@ public:
private:
void DartProcessing();
void ExeNotFound(std::string exe);
- bool CreateProcess(double testTimeOut,
+ // Figures out a final timeout which is min(STOP_TIME, NOW+TIMEOUT)
+ double ResolveTimeout();
+ bool ForkProcess(double testTimeOut,
std::vector<std::string>* environment);
void WriteLogOutputTop(size_t completed, size_t total);
//Run post processing of the process output for MemCheck
@@ -75,14 +77,9 @@ private:
//if this option is set to false.)
//bool OptimizeForCTest;
- //flag for whether the env was modified for this run
- bool ModifyEnv;
-
bool UsePrefixCommand;
std::string PrefixCommand;
- //stores the original environment if we are modifying it
- std::vector<std::string> OrigEnv;
std::string ProcessOutput;
std::string CompressedOutput;
double CompressionRatio;
diff --git a/Source/CTest/cmCTestTestCommand.cxx b/Source/CTest/cmCTestTestCommand.cxx
index b0adf22..5aee035 100644
--- a/Source/CTest/cmCTestTestCommand.cxx
+++ b/Source/CTest/cmCTestTestCommand.cxx
@@ -25,6 +25,7 @@ cmCTestTestCommand::cmCTestTestCommand()
this->Arguments[ctt_INCLUDE_LABEL] = "INCLUDE_LABEL";
this->Arguments[ctt_PARALLEL_LEVEL] = "PARALLEL_LEVEL";
this->Arguments[ctt_SCHEDULE_RANDOM] = "SCHEDULE_RANDOM";
+ this->Arguments[ctt_STOP_TIME] = "STOP_TIME";
this->Arguments[ctt_LAST] = 0;
this->Last = ctt_LAST;
}
@@ -98,6 +99,10 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler()
handler->SetOption("ScheduleRandom",
this->Values[ctt_SCHEDULE_RANDOM]);
}
+ if(this->Values[ctt_STOP_TIME])
+ {
+ this->CTest->SetStopTime(this->Values[ctt_STOP_TIME]);
+ }
return handler;
}
diff --git a/Source/CTest/cmCTestTestCommand.h b/Source/CTest/cmCTestTestCommand.h
index 12314df..c6fd631 100644
--- a/Source/CTest/cmCTestTestCommand.h
+++ b/Source/CTest/cmCTestTestCommand.h
@@ -62,7 +62,8 @@ public:
" [EXCLUDE_LABEL exclude regex] \n"
" [INCLUDE_LABEL label regex] \n"
" [PARALLEL_LEVEL level] \n"
- " [SCHEDULE_RANDOM on]) \n"
+ " [SCHEDULE_RANDOM on] \n"
+ " [STOP_TIME time of day]) \n"
"Tests the given build directory and stores results in Test.xml. The "
"second argument is a variable that will hold value. Optionally, "
"you can specify the starting test number START, the ending test number "
@@ -73,7 +74,8 @@ public:
"property LABEL. PARALLEL_LEVEL should be set to a positive number "
"representing the number of tests to be run in parallel. "
"SCHEDULE_RANDOM will launch tests in a random order, and is "
- "typically used to detect implicit test dependencies."
+ "typically used to detect implicit test dependencies. STOP_TIME is the "
+ "time of day at which the tests should all stop running."
"\n"
CTEST_COMMAND_APPEND_OPTION_DOCS;
}
@@ -96,6 +98,7 @@ protected:
ctt_INCLUDE_LABEL,
ctt_PARALLEL_LEVEL,
ctt_SCHEDULE_RANDOM,
+ ctt_STOP_TIME,
ctt_LAST
};
};
diff --git a/Source/CTest/cmCTestUpdateHandler.cxx b/Source/CTest/cmCTestUpdateHandler.cxx
index f87b37c..9eae3f3 100644
--- a/Source/CTest/cmCTestUpdateHandler.cxx
+++ b/Source/CTest/cmCTestUpdateHandler.cxx
@@ -306,6 +306,7 @@ int cmCTestUpdateHandler::ProcessHandler()
}
if(!updated)
{
+ os << "Update command failed:\n" << vc->GetUpdateCommandLine();
cmCTestLog(this->CTest, ERROR_MESSAGE, " Update command failed: "
<< vc->GetUpdateCommandLine() << "\n");
}
diff --git a/Source/CTest/cmCTestVC.cxx b/Source/CTest/cmCTestVC.cxx
index 35f567a..f9ad79a 100644
--- a/Source/CTest/cmCTestVC.cxx
+++ b/Source/CTest/cmCTestVC.cxx
@@ -227,6 +227,7 @@ void cmCTestVC::WriteXMLEntry(std::ostream& xml,
<< "\t\t\t<FullName>" << cmXMLSafe(full) << "</FullName>\n"
<< "\t\t\t<CheckinDate>" << cmXMLSafe(rev.Date) << "</CheckinDate>\n"
<< "\t\t\t<Author>" << cmXMLSafe(rev.Author) << "</Author>\n"
+ << "\t\t\t<Email>" << cmXMLSafe(rev.EMail) << "</Email>\n"
<< "\t\t\t<Log>" << cmXMLSafe(rev.Log) << "</Log>\n"
<< "\t\t\t<Revision>" << cmXMLSafe(rev.Rev) << "</Revision>\n"
<< "\t\t\t<PriorRevision>" << cmXMLSafe(prior) << "</PriorRevision>\n"
diff --git a/Source/CTest/cmCTestVC.h b/Source/CTest/cmCTestVC.h
index e6ea76d..d36bc8f 100644
--- a/Source/CTest/cmCTestVC.h
+++ b/Source/CTest/cmCTestVC.h
@@ -73,6 +73,7 @@ protected:
std::string Rev;
std::string Date;
std::string Author;
+ std::string EMail;
std::string Log;
};
diff --git a/Source/CTest/cmParsePHPCoverage.cxx b/Source/CTest/cmParsePHPCoverage.cxx
new file mode 100644
index 0000000..32c1ec1
--- /dev/null
+++ b/Source/CTest/cmParsePHPCoverage.cxx
@@ -0,0 +1,252 @@
+#include "cmStandardIncludes.h"
+#include "cmSystemTools.h"
+#include "cmParsePHPCoverage.h"
+#include <cmsys/Directory.hxx>
+
+/*
+ To setup coverage for php.
+
+ - edit php.ini to add auto prepend and append php files from phpunit
+ auto_prepend_file =
+ auto_append_file =
+ - run the tests
+ - run this program on all the files in c:/tmp
+
+*/
+
+cmParsePHPCoverage::cmParsePHPCoverage(cmCTestCoverageHandlerContainer& cont,
+ cmCTest* ctest)
+ :Coverage(cont), CTest(ctest)
+{
+}
+
+bool cmParsePHPCoverage::ReadUntil(std::ifstream& in, char until)
+{
+ char c = 0;
+ while(in.get(c) && c != until)
+ {
+ }
+ if(c != until)
+ {
+ return false;
+ }
+ return true;
+}
+bool cmParsePHPCoverage::ReadCoverageArray(std::ifstream& in,
+ cmStdString const& fileName)
+{
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector& coverageVector
+ = this->Coverage.TotalCoverage[fileName];
+
+ char c;
+ char buf[4];
+ in.read(buf, 3);
+ buf[3] = 0;
+ if(strcmp(buf, ";a:") != 0)
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "failed to read start of coverage array, found : "
+ << buf << "\n");
+ return false;
+ }
+ int size = 0;
+ if(!this->ReadInt(in, size))
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "failed to read size ");
+ return false;
+ }
+ if(!in.get(c) && c == '{')
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "failed to read open {\n");
+ return false;
+ }
+ for(int i =0; i < size; i++)
+ {
+ this->ReadUntil(in, ':');
+ int line = 0;
+ this->ReadInt(in, line);
+ // ok xdebug may have a bug here
+ // it seems to be 1 based but often times
+ // seems to have a 0'th line.
+ line--;
+ if(line < 0)
+ {
+ line = 0;
+ }
+ this->ReadUntil(in, ':');
+ int value = 0;
+ this->ReadInt(in, value);
+ // make sure the vector is the right size and is
+ // initialized with -1 for each line
+ while(coverageVector.size() <= static_cast<size_t>(line) )
+ {
+ coverageVector.push_back(-1);
+ }
+ // if value is less than 0, set it to zero
+ // TODO figure out the difference between
+ // -1 and -2 in xdebug coverage?? For now
+ // assume less than 0 is just not covered
+ // CDash expects -1 for non executable code (like comments)
+ // and 0 for uncovered code, and a positive value
+ // for number of times a line was executed
+ if(value < 0)
+ {
+ value = 0;
+ }
+ // if unset then set it to value
+ if(coverageVector[line] == -1)
+ {
+ coverageVector[line] = value;
+ }
+ // otherwise increment by value
+ else
+ {
+ coverageVector[line] += value;
+ }
+ }
+ return true;
+}
+
+bool cmParsePHPCoverage::ReadInt(std::ifstream& in, int& v)
+{
+ std::string s;
+ char c = 0;
+ while(in.get(c) && c != ':' && c != ';')
+ {
+ s += c;
+ }
+ v = atoi(s.c_str());
+ return true;
+}
+
+bool cmParsePHPCoverage::ReadArraySize(std::ifstream& in, int& size)
+{
+ char c = 0;
+ in.get(c);
+ if(c != 'a')
+ {
+ return false;
+ }
+ if(in.get(c) && c == ':')
+ {
+ if(this->ReadInt(in, size))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cmParsePHPCoverage::ReadFileInformation(std::ifstream& in)
+{
+ char buf[4];
+ in.read(buf, 2);
+ buf[2] = 0;
+ if(strcmp(buf, "s:") != 0)
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "failed to read start of file info found: [" << buf << "]\n");
+ return false;
+ }
+ char c;
+ int size = 0;
+ if(this->ReadInt(in, size))
+ {
+ size++; // add one for null termination
+ char* s = new char[size+1];
+ // read open quote
+ if(in.get(c) && c != '"')
+ {
+ return false;
+ }
+ // read the string data
+ in.read(s, size-1);
+ s[size-1] = 0;
+ cmStdString fileName = s;
+ delete [] s;
+ // read close quote
+ if(in.get(c) && c != '"')
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "failed to read close quote\n"
+ << "read [" << c << "]\n");
+ return false;
+ }
+ if(!this->ReadCoverageArray(in, fileName) )
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "failed to read coverage array for file: "
+ << fileName << "\n");
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+
+bool cmParsePHPCoverage::ReadPHPData(const char* file)
+{
+ std::ifstream in(file);
+ if(!in)
+ {
+ return false;
+ }
+ int size = 0;
+ this->ReadArraySize(in, size);
+ char c = 0;
+ in.get(c);
+ if(c != '{')
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "failed to read open array\n");
+ return false;
+ }
+ for(int i =0; i < size; i++)
+ {
+ if(!this->ReadFileInformation(in))
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Failed to read file #" << i << "\n");
+ return false;
+ }
+ in.get(c);
+ if(c != '}')
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "failed to read close array\n");
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cmParsePHPCoverage::ReadPHPCoverageDirectory(const char* d)
+{
+ cmsys::Directory dir;
+ if(!dir.Load(d))
+ {
+ return false;
+ }
+ size_t numf;
+ unsigned int i;
+ numf = dir.GetNumberOfFiles();
+ for (i = 0; i < numf; i++)
+ {
+ std::string file = dir.GetFile(i);
+ if(file != "." && file != ".."
+ && !cmSystemTools::FileIsDirectory(file.c_str()))
+ {
+ std::string path = d;
+ path += "/";
+ path += file;
+ if(!this->ReadPHPData(path.c_str()))
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+}
diff --git a/Source/CTest/cmParsePHPCoverage.h b/Source/CTest/cmParsePHPCoverage.h
new file mode 100644
index 0000000..ce5741d
--- /dev/null
+++ b/Source/CTest/cmParsePHPCoverage.h
@@ -0,0 +1,48 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmParsePHPCoverage_h
+#define cmParsePHPCoverage_h
+
+#include "cmStandardIncludes.h"
+#include "cmCTestCoverageHandler.h"
+
+/** \class cmParsePHPCoverage
+ * \brief Parse xdebug PHP coverage information
+ *
+ * This class is used to parse php coverage information produced
+ * by xdebug. The data is stored as a php dump of the array
+ * return by xdebug coverage. It is an array of arrays.
+ */
+class cmParsePHPCoverage
+{
+public:
+ cmParsePHPCoverage(cmCTestCoverageHandlerContainer& cont,
+ cmCTest* ctest);
+ bool ReadPHPCoverageDirectory(const char* dir);
+ void PrintCoverage();
+private:
+ bool ReadPHPData(const char* file);
+ bool ReadArraySize(std::ifstream& in, int& size);
+ bool ReadFileInformation(std::ifstream& in);
+ bool ReadInt(std::ifstream& in, int& v);
+ bool ReadCoverageArray(std::ifstream& in, cmStdString const&);
+ bool ReadUntil(std::ifstream& in, char until);
+ typedef std::map<int, int> FileLineCoverage;
+ std::map<cmStdString, FileLineCoverage> FileToCoverage;
+ std::map<int, int> FileCoverage;
+ cmCTestCoverageHandlerContainer& Coverage;
+ cmCTest* CTest;
+};
+
+
+#endif