summaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/CTest/cmCTestCoverageHandler.cxx759
-rw-r--r--Source/CTest/cmCTestCoverageHandler.h7
2 files changed, 487 insertions, 279 deletions
diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx
index c3295f003a..9dfef4438a 100644
--- a/Source/CTest/cmCTestCoverageHandler.cxx
+++ b/Source/CTest/cmCTestCoverageHandler.cxx
@@ -33,6 +33,22 @@
#define SAFEDIV(x,y) (((y)!=0)?((x)/(y)):(0))
//----------------------------------------------------------------------
+//**********************************************************************
+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()
{
}
@@ -186,12 +202,12 @@ int cmCTestCoverageHandler::ProcessHandler()
return error;
}
+ std::string coverage_start_time = this->CTest->CurrentTime();
+
std::string sourceDir
= this->CTest->GetCTestConfiguration("SourceDirectory");
std::string binaryDir
= this->CTest->GetCTestConfiguration("BuildDirectory");
- std::string gcovCommand
- = this->CTest->GetCTestConfiguration("CoverageCommand");
cmGeneratedFileStream ofs;
double elapsed_time_start = cmSystemTools::GetTime();
@@ -209,6 +225,298 @@ int cmCTestCoverageHandler::ProcessHandler()
std::string asfGlob = sourceDir + "/*";
std::string abfGlob = binaryDir + "/*";
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "Performing coverage" << std::endl);
+
+ cmCTestCoverageHandlerContainer cont;
+ cont.Error = error;
+ cont.SourceDir = sourceDir;
+ cont.BinaryDir = binaryDir;
+ cont.OFS = &ofs;
+
+ int file_count = 0;
+
+ file_count += this->HandleGCovCoverage(&cont);
+ if ( file_count < 0 )
+ {
+ return error;
+ }
+ file_count += this->HandleTracePyCoverage(&cont);
+ if ( file_count < 0 )
+ {
+ return error;
+ }
+ error = cont.Error;
+
+
+ if ( file_count == 0 )
+ {
+ cmCTestLog(this->CTest, WARNING,
+ " Cannot find any coverage files. Ignoring Coverage request."
+ << std::endl);
+ return error;
+ }
+ cmGeneratedFileStream covSumFile;
+ cmGeneratedFileStream covLogFile;
+
+ if (!this->StartResultingXML("Coverage", covSumFile))
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open coverage summary file." << std::endl);
+ return -1;
+ }
+
+ this->CTest->StartXML(covSumFile);
+ // Produce output xml files
+
+ covSumFile << "<Coverage>" << std::endl
+ << "\t<StartDateTime>" << coverage_start_time << "</StartDateTime>"
+ << std::endl;
+ int logFileCount = 0;
+ if ( !this->StartCoverageLogFile(covLogFile, logFileCount) )
+ {
+ return -1;
+ }
+ cmCTestCoverageHandlerContainer::TotalCoverageMap::iterator fileIterator;
+ int cnt = 0;
+ long total_tested = 0;
+ long total_untested = 0;
+ //std::string fullSourceDir = sourceDir + "/";
+ //std::string fullBinaryDir = binaryDir + "/";
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
+ cmCTestLog(this->CTest, HANDLER_OUTPUT,
+ " Acumulating results (each . represents one file):" << std::endl);
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
+
+ std::vector<std::string> errorsWhileAccumulating;
+
+ file_count = 0;
+ for ( fileIterator = cont.TotalCoverage.begin();
+ fileIterator != cont.TotalCoverage.end();
+ ++fileIterator )
+ {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "." << std::flush);
+ file_count ++;
+ if ( file_count % 50 == 0 )
+ {
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " processed: " << file_count
+ << " out of "
+ << cont.TotalCoverage.size() << std::endl);
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
+ }
+ if ( cnt % 100 == 0 )
+ {
+ this->EndCoverageLogFile(covLogFile, logFileCount);
+ logFileCount ++;
+ if ( !this->StartCoverageLogFile(covLogFile, logFileCount) )
+ {
+ return -1;
+ }
+ }
+ const std::string fullFileName = fileIterator->first;
+ const std::string fileName
+ = cmSystemTools::GetFilenameName(fullFileName.c_str());
+ std::string fullFilePath
+ = cmSystemTools::GetFilenamePath(fullFileName.c_str());
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Process file: " << fullFileName << std::endl);
+
+ cmSystemTools::ConvertToUnixSlashes(fullFilePath);
+
+ if ( !cmSystemTools::FileExists(fullFileName.c_str()) )
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot find file: "
+ << fullFileName.c_str() << std::endl);
+ continue;
+ }
+
+ bool shouldIDoCoverage
+ = this->ShouldIDoCoverage(fullFileName.c_str(),
+ sourceDir.c_str(), binaryDir.c_str());
+ if ( !shouldIDoCoverage )
+ {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ ".NoDartCoverage found, so skip coverage check for: "
+ << fullFileName.c_str()
+ << std::endl);
+ continue;
+ }
+
+ const cmCTestCoverageHandlerContainer::SingleFileCoverageVector& fcov
+ = fileIterator->second;
+ covLogFile << "\t<File Name=\""
+ << this->CTest->MakeXMLSafe(fileName.c_str())
+ << "\" FullPath=\"" << this->CTest->MakeXMLSafe(
+ this->CTest->GetShortPathToFile(
+ fileIterator->first.c_str())) << "\">" << std::endl
+ << "\t\t<Report>" << std::endl;
+
+ std::ifstream ifs(fullFileName.c_str());
+ if ( !ifs)
+ {
+ cmOStringStream ostr;
+ ostr << "Cannot open source file: " << fullFileName.c_str();
+ errorsWhileAccumulating.push_back(ostr.str());
+ error ++;
+ continue;
+ }
+
+ int tested = 0;
+ int untested = 0;
+
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector::size_type cc;
+ std::string line;
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ "Actually perfoming coverage for: " << fullFileName << std::endl);
+ for ( cc= 0; cc < fcov.size(); cc ++ )
+ {
+ if ( !cmSystemTools::GetLineFromStream(ifs, line) &&
+ cc != fcov.size() -1 )
+ {
+ cmOStringStream ostr;
+ ostr << "Problem reading source file: " << fullFileName.c_str()
+ << " line:" << cc;
+ errorsWhileAccumulating.push_back(ostr.str());
+ error ++;
+ break;
+ }
+ covLogFile << "\t\t<Line Number=\"" << cc << "\" Count=\"" << fcov[cc]
+ << "\">"
+ << this->CTest->MakeXMLSafe(line.c_str()) << "</Line>" << std::endl;
+ if ( fcov[cc] == 0 )
+ {
+ untested ++;
+ }
+ else if ( fcov[cc] > 0 )
+ {
+ tested ++;
+ }
+ }
+ if ( cmSystemTools::GetLineFromStream(ifs, line) )
+ {
+ cmOStringStream ostr;
+ ostr << "Looks like there are more lines in the file: " << line;
+ errorsWhileAccumulating.push_back(ostr.str());
+ }
+ float cper = 0;
+ float cmet = 0;
+ if ( tested + untested > 0 )
+ {
+ cper = (100 * SAFEDIV(static_cast<float>(tested),
+ static_cast<float>(tested + untested)));
+ cmet = ( SAFEDIV(static_cast<float>(tested + 10),
+ static_cast<float>(tested + untested + 10)));
+ }
+ total_tested += tested;
+ total_untested += untested;
+ covLogFile << "\t\t</Report>" << std::endl
+ << "\t</File>" << std::endl;
+ covSumFile << "\t<File Name=\"" << this->CTest->MakeXMLSafe(fileName)
+ << "\" FullPath=\"" << this->CTest->MakeXMLSafe(
+ this->CTest->GetShortPathToFile(fullFileName.c_str()))
+ << "\" Covered=\"" << (cmet>0?"true":"false") << "\">\n"
+ << "\t\t<LOCTested>" << tested << "</LOCTested>\n"
+ << "\t\t<LOCUnTested>" << untested << "</LOCUnTested>\n"
+ << "\t\t<PercentCoverage>";
+ covSumFile.setf(std::ios::fixed, std::ios::floatfield);
+ covSumFile.precision(2);
+ covSumFile << (cper) << "</PercentCoverage>\n"
+ << "\t\t<CoverageMetric>";
+ covSumFile.setf(std::ios::fixed, std::ios::floatfield);
+ covSumFile.precision(2);
+ covSumFile << (cmet) << "</CoverageMetric>\n"
+ << "\t</File>" << std::endl;
+ cnt ++;
+ }
+ 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);
+ std::vector<std::string>::iterator erIt;
+ for ( erIt = errorsWhileAccumulating.begin();
+ erIt != errorsWhileAccumulating.end();
+ ++ erIt )
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ " " << erIt->c_str() << std::endl);
+ }
+ }
+
+ int total_lines = total_tested + total_untested;
+ float percent_coverage = 100 * SAFEDIV(static_cast<float>(total_tested),
+ static_cast<float>(total_lines));
+ if ( total_lines == 0 )
+ {
+ percent_coverage = 0;
+ }
+
+ std::string end_time = this->CTest->CurrentTime();
+
+ covSumFile << "\t<LOCTested>" << total_tested << "</LOCTested>\n"
+ << "\t<LOCUntested>" << total_untested << "</LOCUntested>\n"
+ << "\t<LOC>" << total_lines << "</LOC>\n"
+ << "\t<PercentCoverage>";
+ covSumFile.setf(std::ios::fixed, std::ios::floatfield);
+ covSumFile.precision(2);
+ covSumFile << (percent_coverage)<< "</PercentCoverage>\n"
+ << "\t<EndDateTime>" << end_time << "</EndDateTime>\n";
+ covSumFile << "<ElapsedMinutes>" <<
+ static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start)/6)/10.0
+ << "</ElapsedMinutes>"
+ << "</Coverage>" << std::endl;
+ this->CTest->EndXML(covSumFile);
+
+ cmCTestLog(this->CTest, HANDLER_OUTPUT, "" << std::endl
+ << "\tCovered LOC: "
+ << total_tested << std::endl
+ << "\tNot covered LOC: " << total_untested << std::endl
+ << "\tTotal LOC: " << total_lines << std::endl
+ << "\tPercentage Coverage: "
+ << std::setiosflags(std::ios::fixed)
+ << std::setprecision(2)
+ << (percent_coverage) << "%" << std::endl);
+
+ ofs << "\tCovered LOC: " << total_tested << std::endl
+ << "\tNot covered LOC: " << total_untested << std::endl
+ << "\tTotal LOC: " << total_lines << std::endl
+ << "\tPercentage Coverage: "
+ << std::setiosflags(std::ios::fixed)
+ << std::setprecision(2)
+ << (percent_coverage) << "%" << std::endl;
+
+
+ if ( error )
+ {
+ return -1;
+ }
+ return 0;
+}
+
+//----------------------------------------------------------------------
+void cmCTestCoverageHandler::PopulateCustomVectors(cmMakefile *mf)
+{
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Add coverage exclude regular expressions." << std::endl);
+ this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_COVERAGE_EXCLUDE",
+ this->CustomCoverageExclude);
+ std::vector<cmStdString>::iterator it;
+ for ( it = this->CustomCoverageExclude.begin();
+ it != this->CustomCoverageExclude.end();
+ ++ it )
+ {
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Add coverage exclude: "
+ << it->c_str() << std::endl);
+ }
+}
+
+//----------------------------------------------------------------------
+int cmCTestCoverageHandler::HandleGCovCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ std::string gcovCommand
+ = this->CTest->GetCTestConfiguration("CoverageCommand");
// Style 1
std::string st1gcovOutputRex1
@@ -234,22 +542,13 @@ int cmCTestCoverageHandler::ProcessHandler()
cmsys::RegularExpression st2re5(st2gcovOutputRex5.c_str());
cmsys::RegularExpression st2re6(st2gcovOutputRex6.c_str());
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "Performing coverage" << std::endl);
-
- std::string coverage_start_time = this->CTest->CurrentTime();
-
- std::string testingDir = this->CTest->GetBinaryDir() + "/Testing";
- std::string tempDir = testingDir + "/CoverageInfo";
- std::string currentDirectory = cmSystemTools::GetCurrentWorkingDirectory();
- cmSystemTools::MakeDirectory(tempDir.c_str());
- cmSystemTools::ChangeDirectory(tempDir.c_str());
cmsys::Glob gl;
gl.RecurseOn();
- std::string daGlob = binaryDir + "/*.da";
+ std::string daGlob = cont->BinaryDir + "/*.da";
gl.FindFiles(daGlob);
std::vector<std::string> files = gl.GetFiles();
- daGlob = binaryDir + "/*.gcda";
+ daGlob = cont->BinaryDir + "/*.gcda";
gl.FindFiles(daGlob);
std::vector<std::string>& moreFiles = gl.GetFiles();
files.insert(files.end(), moreFiles.begin(), moreFiles.end());
@@ -257,14 +556,19 @@ int cmCTestCoverageHandler::ProcessHandler()
if ( files.size() == 0 )
{
- cmCTestLog(this->CTest, WARNING,
- " Cannot find any coverage files. Ignoring Coverage request."
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find any GCov coverage files."
<< std::endl);
// No coverage files is a valid thing, so the exit code is 0
- cmSystemTools::ChangeDirectory(currentDirectory.c_str());
return 0;
}
+ std::string testingDir = this->CTest->GetBinaryDir() + "/Testing";
+ std::string tempDir = testingDir + "/CoverageInfo";
+ std::string currentDirectory = cmSystemTools::GetCurrentWorkingDirectory();
+ cmSystemTools::MakeDirectory(tempDir.c_str());
+ cmSystemTools::ChangeDirectory(tempDir.c_str());
+
this->CustomCoverageExcludeRegex.empty();
std::vector<cmStdString>::iterator rexIt;
for ( rexIt = this->CustomCoverageExclude.begin();
@@ -275,11 +579,6 @@ int cmCTestCoverageHandler::ProcessHandler()
cmsys::RegularExpression(rexIt->c_str()));
}
- typedef std::vector<int> singleFileCoverageVector;
- typedef std::map<std::string, singleFileCoverageVector> totalCoverageMap;
-
- totalCoverageMap totalCoverage;
-
int gcovStyle = 0;
std::set<std::string> missingFiles;
@@ -300,20 +599,20 @@ int cmCTestCoverageHandler::ProcessHandler()
std::string output = "";
std::string errors = "";
int retVal = 0;
- ofs << "* Run coverage for: " << fileDir.c_str() << std::endl;
- ofs << " Command: " << command.c_str() << std::endl;
+ *cont->OFS << "* Run coverage for: " << fileDir.c_str() << std::endl;
+ *cont->OFS << " Command: " << command.c_str() << std::endl;
int res = this->CTest->RunCommand(command.c_str(), &output, &errors,
&retVal, tempDir.c_str(), 0 /*this->TimeOut*/);
- ofs << " Output: " << output.c_str() << std::endl;
- ofs << " Errors: " << errors.c_str() << std::endl;
+ *cont->OFS << " Output: " << output.c_str() << std::endl;
+ *cont->OFS << " Errors: " << errors.c_str() << std::endl;
if ( ! res )
{
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Problem running coverage on file: " << it->c_str() << std::endl);
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Command produced error: " << errors << std::endl);
- error ++;
+ cont->Error ++;
continue;
}
if ( retVal != 0 )
@@ -321,7 +620,7 @@ int cmCTestCoverageHandler::ProcessHandler()
cmCTestLog(this->CTest, ERROR_MESSAGE, "Coverage command returned: "
<< retVal << " while processing: " << it->c_str() << std::endl);
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Command produced error: " << error << std::endl);
+ "Command produced error: " << cont->Error << std::endl);
}
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"--------------------------------------------------------------"
@@ -353,7 +652,7 @@ int cmCTestCoverageHandler::ProcessHandler()
{
cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style"
<< std::endl);
- error ++;
+ cont->Error ++;
break;
}
gcovStyle = 1;
@@ -370,7 +669,7 @@ int cmCTestCoverageHandler::ProcessHandler()
{
cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style"
<< std::endl);
- error ++;
+ cont->Error ++;
break;
}
gcovStyle = 1;
@@ -386,7 +685,7 @@ int cmCTestCoverageHandler::ProcessHandler()
{
cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style"
<< std::endl);
- error ++;
+ cont->Error ++;
break;
}
gcovStyle = 2;
@@ -403,7 +702,7 @@ int cmCTestCoverageHandler::ProcessHandler()
{
cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style"
<< std::endl);
- error ++;
+ cont->Error ++;
break;
}
gcovStyle = 2;
@@ -417,7 +716,7 @@ int cmCTestCoverageHandler::ProcessHandler()
{
cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style"
<< std::endl);
- error ++;
+ cont->Error ++;
break;
}
gcovStyle = 2;
@@ -433,7 +732,7 @@ int cmCTestCoverageHandler::ProcessHandler()
{
cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style"
<< std::endl);
- error ++;
+ cont->Error ++;
break;
}
gcovStyle = 2;
@@ -450,7 +749,7 @@ int cmCTestCoverageHandler::ProcessHandler()
{
cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style"
<< std::endl);
- error ++;
+ cont->Error ++;
break;
}
gcovStyle = 2;
@@ -467,7 +766,7 @@ int cmCTestCoverageHandler::ProcessHandler()
{
cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output style"
<< std::endl);
- error ++;
+ cont->Error ++;
break;
}
gcovStyle = 2;
@@ -480,12 +779,13 @@ int cmCTestCoverageHandler::ProcessHandler()
{
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Unknown line: [" << line->c_str() << "]" << std::endl);
- error ++;
+ cont->Error ++;
//abort();
}
if ( !gcovFile.empty() && actualSourceFile.size() )
{
- singleFileCoverageVector* vec = &totalCoverage[actualSourceFile];
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector* vec
+ = &cont->TotalCoverage[actualSourceFile];
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " in file: "
<< gcovFile << std::endl);
std::ifstream ifile(gcovFile.c_str());
@@ -527,7 +827,7 @@ int cmCTestCoverageHandler::ProcessHandler()
if ( lineIdx >= 0 )
{
while ( vec->size() <=
- static_cast<singleFileCoverageVector::size_type>(lineIdx) )
+ static_cast<size_t>(lineIdx) )
{
vec->push_back(-1);
}
@@ -550,25 +850,25 @@ int cmCTestCoverageHandler::ProcessHandler()
{
gcovFile = "";
// Is it in the source dir?
- if ( sourceFile.size() > sourceDir.size() &&
- sourceFile.substr(0, sourceDir.size()) == sourceDir &&
- sourceFile[sourceDir.size()] == '/' )
+ if ( sourceFile.size() > cont->SourceDir.size() &&
+ sourceFile.substr(0, cont->SourceDir.size()) == cont->SourceDir &&
+ sourceFile[cont->SourceDir.size()] == '/' )
{
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " produced s: "
<< sourceFile.c_str() << std::endl);
- ofs << " produced in source dir: " << sourceFile.c_str()
+ *cont->OFS << " produced in source dir: " << sourceFile.c_str()
<< std::endl;
actualSourceFile
= cmSystemTools::CollapseFullPath(sourceFile.c_str());
}
// Binary dir?
- if ( sourceFile.size() > binaryDir.size() &&
- sourceFile.substr(0, binaryDir.size()) == binaryDir &&
- sourceFile[binaryDir.size()] == '/' )
+ if ( sourceFile.size() > cont->BinaryDir.size() &&
+ sourceFile.substr(0, cont->BinaryDir.size()) == cont->BinaryDir &&
+ sourceFile[cont->BinaryDir.size()] == '/' )
{
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " produced b: "
<< sourceFile.c_str() << std::endl);
- ofs << " produced in binary dir: " << sourceFile.c_str()
+ *cont->OFS << " produced in binary dir: " << sourceFile.c_str()
<< std::endl;
actualSourceFile
= cmSystemTools::CollapseFullPath(sourceFile.c_str());
@@ -582,13 +882,13 @@ int cmCTestCoverageHandler::ProcessHandler()
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "File: ["
<< sourceFile.c_str() << "]" << std::endl);
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "s: ["
- << sourceFile.substr(0, sourceDir.size()) << "]" << std::endl);
+ << sourceFile.substr(0, cont->SourceDir.size()) << "]" << std::endl);
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "b: ["
- << sourceFile.substr(0, binaryDir.size()) << "]" << std::endl);
- ofs << " Something went wrong. Cannot find: "
+ << sourceFile.substr(0, cont->BinaryDir.size()) << "]" << std::endl);
+ *cont->OFS << " Something went wrong. Cannot find: "
<< sourceFile.c_str()
- << " in source dir: " << sourceDir.c_str()
- << " or binary dir: " << binaryDir.c_str() << std::endl;
+ << " in source dir: " << cont->SourceDir.c_str()
+ << " or binary dir: " << cont->BinaryDir.c_str() << std::endl;
missingFiles.insert(actualSourceFile);
}
}
@@ -602,259 +902,160 @@ int cmCTestCoverageHandler::ProcessHandler()
cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
}
}
+ cmSystemTools::ChangeDirectory(currentDirectory.c_str());
+ return file_count;
+}
- cmGeneratedFileStream covSumFile;
- cmGeneratedFileStream covLogFile;
+//----------------------------------------------------------------------
+int cmCTestCoverageHandler::HandleTracePyCoverage(
+ cmCTestCoverageHandlerContainer* cont)
+{
+ cmsys::Glob gl;
+ gl.RecurseOn();
+ std::string daGlob = cont->BinaryDir + "/*.cover";
+ gl.FindFiles(daGlob);
+ std::vector<std::string> files = gl.GetFiles();
- if (!this->StartResultingXML("Coverage", covSumFile))
+ if ( files.size() == 0 )
{
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Cannot open coverage summary file." << std::endl);
- cmSystemTools::ChangeDirectory(currentDirectory.c_str());
- return -1;
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Cannot find any Python Trace.py coverage files."
+ << std::endl);
+ // No coverage files is a valid thing, so the exit code is 0
+ return 0;
}
- this->CTest->StartXML(covSumFile);
- // Produce output xml files
-
- covSumFile << "<Coverage>" << std::endl
- << "\t<StartDateTime>" << coverage_start_time << "</StartDateTime>"
- << std::endl;
- int logFileCount = 0;
- if ( !this->StartCoverageLogFile(covLogFile, logFileCount) )
- {
- cmSystemTools::ChangeDirectory(currentDirectory.c_str());
- return -1;
- }
- totalCoverageMap::iterator fileIterator;
- int cnt = 0;
- long total_tested = 0;
- long total_untested = 0;
- //std::string fullSourceDir = sourceDir + "/";
- //std::string fullBinaryDir = binaryDir + "/";
- cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl);
- cmCTestLog(this->CTest, HANDLER_OUTPUT,
- " Acumulating results (each . represents one file):" << std::endl);
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
+ std::string testingDir = this->CTest->GetBinaryDir() + "/Testing";
+ std::string tempDir = testingDir + "/CoverageInfo";
+ std::string currentDirectory = cmSystemTools::GetCurrentWorkingDirectory();
+ cmSystemTools::MakeDirectory(tempDir.c_str());
+ cmSystemTools::ChangeDirectory(tempDir.c_str());
- std::vector<std::string> errorsWhileAccumulating;
+ cmSystemTools::ChangeDirectory(currentDirectory.c_str());
- file_count = 0;
- for ( fileIterator = totalCoverage.begin();
- fileIterator != totalCoverage.end();
- ++fileIterator )
+ std::vector<std::string>::iterator fileIt;
+ int file_count = 0;
+ for ( fileIt = files.begin(); fileIt != files.end(); ++ fileIt )
{
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "." << std::flush);
- file_count ++;
- if ( file_count % 50 == 0 )
+ std::string fileName = this->FindFile(cont, *fileIt);
+ if ( fileName.empty() )
{
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " processed: " << file_count
- << " out of "
- << totalCoverage.size() << std::endl);
- cmCTestLog(this->CTest, HANDLER_OUTPUT, " ");
- }
- if ( cnt % 100 == 0 )
- {
- this->EndCoverageLogFile(covLogFile, logFileCount);
- logFileCount ++;
- if ( !this->StartCoverageLogFile(covLogFile, logFileCount) )
- {
- cmSystemTools::ChangeDirectory(currentDirectory.c_str());
- return -1;
- }
- }
- const std::string fullFileName = fileIterator->first;
- const std::string fileName
- = cmSystemTools::GetFilenameName(fullFileName.c_str());
- std::string fullFilePath
- = cmSystemTools::GetFilenamePath(fullFileName.c_str());
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Process file: "
- << fullFileName << std::endl);
-
- cmSystemTools::ConvertToUnixSlashes(fullFilePath);
-
- if ( !cmSystemTools::FileExists(fullFileName.c_str()) )
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot find file: "
- << fullFileName.c_str() << std::endl);
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot find source Python file corresponding to: "
+ << fileIt->c_str() << std::endl);
continue;
}
- bool shouldIDoCoverage
- = this->ShouldIDoCoverage(fullFileName.c_str(),
- sourceDir.c_str(), binaryDir.c_str());
- if ( !shouldIDoCoverage )
+ std::string actualSourceFile
+ = cmSystemTools::CollapseFullPath(fileName.c_str());
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " Check coverage for file: " << actualSourceFile.c_str()
+ << std::endl);
+ cmCTestCoverageHandlerContainer::SingleFileCoverageVector* vec
+ = &cont->TotalCoverage[actualSourceFile];
+ cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+ " in file: " << fileIt->c_str() << std::endl);
+ std::ifstream ifile(fileIt->c_str());
+ if ( ! ifile )
{
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- ".NoDartCoverage found, so skip coverage check for: "
- << fullFileName.c_str()
- << std::endl);
- continue;
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot open file: "
+ << fileIt->c_str() << std::endl);
}
-
- const singleFileCoverageVector& fcov = fileIterator->second;
- covLogFile << "\t<File Name=\""
- << this->CTest->MakeXMLSafe(fileName.c_str())
- << "\" FullPath=\"" << this->CTest->MakeXMLSafe(
- this->CTest->GetShortPathToFile(
- fileIterator->first.c_str())) << "\">" << std::endl
- << "\t\t<Report>" << std::endl;
-
- std::ifstream ifs(fullFileName.c_str());
- if ( !ifs)
+ else
{
- cmOStringStream ostr;
- ostr << "Cannot open source file: " << fullFileName.c_str();
- errorsWhileAccumulating.push_back(ostr.str());
- error ++;
- continue;
- }
+ long cnt = -1;
+ std::string nl;
+ while ( cmSystemTools::GetLineFromStream(ifile, nl) )
+ {
+ cnt ++;
- int tested = 0;
- int untested = 0;
+ // Skip empty lines
+ if ( !nl.size() )
+ {
+ continue;
+ }
- singleFileCoverageVector::size_type cc;
- std::string line;
- for ( cc= 0; cc < fcov.size(); cc ++ )
- {
- if ( !cmSystemTools::GetLineFromStream(ifs, line) &&
- cc != fcov.size() -1 )
- {
- cmOStringStream ostr;
- ostr << "Problem reading source file: " << fullFileName.c_str()
- << " line:" << cc;
- errorsWhileAccumulating.push_back(ostr.str());
- error ++;
- break;
- }
- covLogFile << "\t\t<Line Number=\"" << cc << "\" Count=\"" << fcov[cc]
- << "\">"
- << this->CTest->MakeXMLSafe(line.c_str()) << "</Line>" << std::endl;
- if ( fcov[cc] == 0 )
- {
- untested ++;
- }
- else if ( fcov[cc] > 0 )
- {
- tested ++;
- }
- }
- if ( cmSystemTools::GetLineFromStream(ifs, line) )
- {
- cmOStringStream ostr;
- ostr << "Looks like there are more lines in the file: " << line;
- errorsWhileAccumulating.push_back(ostr.str());
- }
- float cper = 0;
- float cmet = 0;
- if ( tested + untested > 0 )
- {
- cper = (100 * SAFEDIV(static_cast<float>(tested),
- static_cast<float>(tested + untested)));
- cmet = ( SAFEDIV(static_cast<float>(tested + 10),
- static_cast<float>(tested + untested + 10)));
- }
- total_tested += tested;
- total_untested += untested;
- covLogFile << "\t\t</Report>" << std::endl
- << "\t</File>" << std::endl;
- covSumFile << "\t<File Name=\"" << this->CTest->MakeXMLSafe(fileName)
- << "\" FullPath=\"" << this->CTest->MakeXMLSafe(
- this->CTest->GetShortPathToFile(fullFileName.c_str()))
- << "\" Covered=\"" << (cmet>0?"true":"false") << "\">\n"
- << "\t\t<LOCTested>" << tested << "</LOCTested>\n"
- << "\t\t<LOCUnTested>" << untested << "</LOCUnTested>\n"
- << "\t\t<PercentCoverage>";
- covSumFile.setf(std::ios::fixed, std::ios::floatfield);
- covSumFile.precision(2);
- covSumFile << (cper) << "</PercentCoverage>\n"
- << "\t\t<CoverageMetric>";
- covSumFile.setf(std::ios::fixed, std::ios::floatfield);
- covSumFile.precision(2);
- covSumFile << (cmet) << "</CoverageMetric>\n"
- << "\t</File>" << std::endl;
- cnt ++;
- }
- this->EndCoverageLogFile(covLogFile, logFileCount);
+ // Skip unused lines
+ if ( nl.size() < 12 )
+ {
+ continue;
+ }
- if ( errorsWhileAccumulating.size() > 0 )
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE, std::endl);
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Error(s) while acumulating results:" << std::endl);
- std::vector<std::string>::iterator erIt;
- for ( erIt = errorsWhileAccumulating.begin();
- erIt != errorsWhileAccumulating.end();
- ++ erIt )
- {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- " " << erIt->c_str() << std::endl);
+ // Read the coverage count from the beginning of the Trace.py output
+ // line
+ std::string prefix = nl.substr(0, 6);
+ if ( prefix[5] != ' ' && prefix[5] != ':' )
+ {
+ // This is a hack. We should really do something more elaborate
+ prefix = nl.substr(0, 7);
+ if ( prefix[6] != ' ' && prefix[6] != ':' )
+ {
+ prefix = nl.substr(0, 8);
+ if ( prefix[7] != ' ' && prefix[7] != ':' )
+ {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Currently the limit is maximum coverage of 999999"
+ << std::endl);
+ }
+ }
+ }
+ int cov = atoi(prefix.c_str());
+ if ( prefix[prefix.size()-1] != ':' )
+ {
+ // This line does not have ':' so no coverage here. That said,
+ // Trace.py does not handle not covered lines versus comments etc.
+ // So, this will be set to 0.
+ cov = 0;
+ }
+ cmCTestLog(this->CTest, DEBUG, "Prefix: " << prefix.c_str()
+ << " cov: " << cov
+ << std::endl);
+ // Read the line number starting at the 10th character of the gcov
+ // output line
+ int lineIdx = cnt;
+ if ( lineIdx >= 0 )
+ {
+ while ( vec->size() <=
+ static_cast<size_t>(lineIdx) )
+ {
+ vec->push_back(-1);
+ }
+ // Initially all entries are -1 (not used). If we get coverage
+ // information, increment it to 0 first.
+ if ( (*vec)[lineIdx] < 0 )
+ {
+ if ( cov >= 0 )
+ {
+ (*vec)[lineIdx] = 0;
+ }
+ }
+ (*vec)[lineIdx] += cov;
+ }
+ }
}
+ ++ file_count;
}
-
- int total_lines = total_tested + total_untested;
- float percent_coverage = 100 * SAFEDIV(static_cast<float>(total_tested),
- static_cast<float>(total_lines));
- if ( total_lines == 0 )
- {
- percent_coverage = 0;
- }
-
- std::string end_time = this->CTest->CurrentTime();
-
- covSumFile << "\t<LOCTested>" << total_tested << "</LOCTested>\n"
- << "\t<LOCUntested>" << total_untested << "</LOCUntested>\n"
- << "\t<LOC>" << total_lines << "</LOC>\n"
- << "\t<PercentCoverage>";
- covSumFile.setf(std::ios::fixed, std::ios::floatfield);
- covSumFile.precision(2);
- covSumFile << (percent_coverage)<< "</PercentCoverage>\n"
- << "\t<EndDateTime>" << end_time << "</EndDateTime>\n";
- covSumFile << "<ElapsedMinutes>" <<
- static_cast<int>((cmSystemTools::GetTime() - elapsed_time_start)/6)/10.0
- << "</ElapsedMinutes>"
- << "</Coverage>" << std::endl;
- this->CTest->EndXML(covSumFile);
-
- cmCTestLog(this->CTest, HANDLER_OUTPUT, "\tCovered LOC: "
- << total_tested << std::endl
- << "\tNot covered LOC: " << total_untested << std::endl
- << "\tTotal LOC: " << total_lines << std::endl
- << "\tPercentage Coverage: "
- << std::setiosflags(std::ios::fixed)
- << std::setprecision(2)
- << (percent_coverage) << "%" << std::endl);
-
- ofs << "\tCovered LOC: " << total_tested << std::endl
- << "\tNot covered LOC: " << total_untested << std::endl
- << "\tTotal LOC: " << total_lines << std::endl
- << "\tPercentage Coverage: "
- << std::setiosflags(std::ios::fixed)
- << std::setprecision(2)
- << (percent_coverage) << "%" << std::endl;
-
cmSystemTools::ChangeDirectory(currentDirectory.c_str());
-
- if ( error )
- {
- return -1;
- }
- return 0;
+ return file_count;
}
//----------------------------------------------------------------------
-void cmCTestCoverageHandler::PopulateCustomVectors(cmMakefile *mf)
+std::string cmCTestCoverageHandler::FindFile(
+ cmCTestCoverageHandlerContainer* cont,
+ std::string fileName)
{
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- " Add coverage exclude regular expressions." << std::endl);
- this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_COVERAGE_EXCLUDE",
- this->CustomCoverageExclude);
- std::vector<cmStdString>::iterator it;
- for ( it = this->CustomCoverageExclude.begin();
- it != this->CustomCoverageExclude.end();
- ++ it )
+ std::string fileNameNoE
+ = cmSystemTools::GetFilenameWithoutLastExtension(fileName);
+ // First check in source and binary directory
+ std::string fullName = cont->SourceDir + "/" + fileNameNoE + ".py";
+ if ( cmSystemTools::FileExists(fullName.c_str()) )
{
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Add coverage exclude: "
- << it->c_str() << std::endl);
+ return fullName;
+ }
+ fullName = cont->BinaryDir + "/" + fileNameNoE + ".py";
+ if ( cmSystemTools::FileExists(fullName.c_str()) )
+ {
+ return fullName;
}
+ return "";
}
diff --git a/Source/CTest/cmCTestCoverageHandler.h b/Source/CTest/cmCTestCoverageHandler.h
index d2e798b216..38422e0e34 100644
--- a/Source/CTest/cmCTestCoverageHandler.h
+++ b/Source/CTest/cmCTestCoverageHandler.h
@@ -25,6 +25,7 @@
#include <cmsys/RegularExpression.hxx>
class cmGeneratedFileStream;
+class cmCTestCoverageHandlerContainer;
/** \class cmCTestCoverageHandler
* \brief A class that handles coverage computaiton for ctest
@@ -55,6 +56,12 @@ private:
bool StartCoverageLogFile(cmGeneratedFileStream& ostr, int logFileCount);
void EndCoverageLogFile(cmGeneratedFileStream& ostr, int logFileCount);
+ int HandleGCovCoverage(cmCTestCoverageHandlerContainer* cont);
+ int HandleTracePyCoverage(cmCTestCoverageHandlerContainer* cont);
+
+ std::string FindFile(cmCTestCoverageHandlerContainer* cont,
+ std::string fileName);
+
struct cmCTestCoverage
{
cmCTestCoverage()