diff options
Diffstat (limited to 'Source/CTest')
-rw-r--r-- | Source/CTest/cmCTestBZR.cxx | 2 | ||||
-rw-r--r-- | Source/CTest/cmCTestBuildHandler.cxx | 1 | ||||
-rw-r--r-- | Source/CTest/cmCTestCoverageHandler.cxx | 128 | ||||
-rw-r--r-- | Source/CTest/cmCTestCoverageHandler.h | 63 | ||||
-rw-r--r-- | Source/CTest/cmCTestGIT.cxx | 14 | ||||
-rw-r--r-- | Source/CTest/cmCTestGIT.h | 1 | ||||
-rw-r--r-- | Source/CTest/cmCTestHG.cxx | 2 | ||||
-rw-r--r-- | Source/CTest/cmCTestMultiProcessHandler.cxx | 21 | ||||
-rw-r--r-- | Source/CTest/cmCTestRunTest.cxx | 86 | ||||
-rw-r--r-- | Source/CTest/cmCTestRunTest.h | 9 | ||||
-rw-r--r-- | Source/CTest/cmCTestTestCommand.cxx | 5 | ||||
-rw-r--r-- | Source/CTest/cmCTestTestCommand.h | 7 | ||||
-rw-r--r-- | Source/CTest/cmCTestUpdateHandler.cxx | 1 | ||||
-rw-r--r-- | Source/CTest/cmCTestVC.cxx | 1 | ||||
-rw-r--r-- | Source/CTest/cmCTestVC.h | 1 | ||||
-rw-r--r-- | Source/CTest/cmParsePHPCoverage.cxx | 252 | ||||
-rw-r--r-- | Source/CTest/cmParsePHPCoverage.h | 48 |
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(¤t_time); + int gm_hour = lctime->tm_hour; + time_t gm_time = mktime(lctime); + lctime = localtime(¤t_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, ¤t_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 |