in Source/CTest/cmCTestCoverageHandler.cxx [194:577]
int cmCTestCoverageHandler::ProcessHandler()
{
this->CTest->ClearSubmitFiles(cmCTest::PartCoverage);
int error = 0;
// do we have time for this
if (this->CTest->GetRemainingTimeAllowed() < std::chrono::minutes(2)) {
return error;
}
std::string coverage_start_time = this->CTest->CurrentTime();
auto coverage_start_time_time = std::chrono::system_clock::now();
std::string sourceDir =
this->CTest->GetCTestConfiguration("SourceDirectory");
std::string binaryDir = this->CTest->GetCTestConfiguration("BuildDirectory");
if (binaryDir.empty()) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Binary directory is not set. "
"No coverage checking will be performed."
<< std::endl);
return 0;
}
this->LoadLabels();
cmGeneratedFileStream ofs;
auto elapsed_time_start = std::chrono::steady_clock::now();
if (!this->StartLogFile("Coverage", ofs)) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Cannot create LastCoverage.log file" << std::endl);
}
ofs << "Performing coverage: "
<< elapsed_time_start.time_since_epoch().count() << std::endl;
this->CleanCoverageLogFiles(ofs);
cmSystemTools::ConvertToUnixSlashes(sourceDir);
cmSystemTools::ConvertToUnixSlashes(binaryDir);
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
"Performing coverage" << std::endl, this->Quiet);
cmCTestCoverageHandlerContainer cont;
cont.Error = error;
cont.SourceDir = sourceDir;
cont.BinaryDir = binaryDir;
cont.OFS = &ofs;
cont.Quiet = this->Quiet;
// setup the regex exclude stuff
this->CustomCoverageExcludeRegex.clear();
for (std::string const& rex : this->CustomCoverageExclude) {
this->CustomCoverageExcludeRegex.emplace_back(rex);
}
if (this->HandleBullseyeCoverage(&cont)) {
return cont.Error;
}
int file_count = 0;
file_count += this->HandleGCovCoverage(&cont);
error = cont.Error;
if (file_count < 0) {
return error;
}
file_count += this->HandleLCovCoverage(&cont);
error = cont.Error;
if (file_count < 0) {
return error;
}
file_count += this->HandleTracePyCoverage(&cont);
error = cont.Error;
if (file_count < 0) {
return error;
}
file_count += this->HandlePHPCoverage(&cont);
error = cont.Error;
if (file_count < 0) {
return error;
}
file_count += this->HandleCoberturaCoverage(&cont);
error = cont.Error;
if (file_count < 0) {
return error;
}
file_count += this->HandleMumpsCoverage(&cont);
error = cont.Error;
if (file_count < 0) {
return error;
}
file_count += this->HandleJacocoCoverage(&cont);
error = cont.Error;
if (file_count < 0) {
return error;
}
file_count += this->HandleBlanketJSCoverage(&cont);
error = cont.Error;
if (file_count < 0) {
return error;
}
file_count += this->HandleDelphiCoverage(&cont);
error = cont.Error;
if (file_count < 0) {
return error;
}
std::set<std::string> uncovered = this->FindUncoveredFiles(&cont);
if (file_count == 0 && this->ExtraCoverageGlobs.empty()) {
cmCTestOptionalLog(
this->CTest, WARNING,
" Cannot find any coverage files. Ignoring Coverage request."
<< std::endl,
this->Quiet);
return error;
}
cmGeneratedFileStream covSumFile;
cmGeneratedFileStream covLogFile;
cmXMLWriter covSumXML(covSumFile);
cmXMLWriter covLogXML(covLogFile);
if (!this->StartResultingXML(cmCTest::PartCoverage, "Coverage",
covSumFile)) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Cannot open coverage summary file." << std::endl);
return -1;
}
covSumFile.setf(std::ios::fixed, std::ios::floatfield);
covSumFile.precision(2);
this->CTest->StartXML(covSumXML, this->CMake, this->AppendXML);
// Produce output xml files
covSumXML.StartElement("Coverage");
covSumXML.Element("StartDateTime", coverage_start_time);
covSumXML.Element("StartTime", coverage_start_time_time);
int logFileCount = 0;
if (!this->StartCoverageLogFile(covLogFile, logFileCount)) {
return -1;
}
this->StartCoverageLogXML(covLogXML);
int cnt = 0;
long total_tested = 0;
long total_untested = 0;
// std::string fullSourceDir = sourceDir + "/";
// std::string fullBinaryDir = binaryDir + "/";
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, std::endl, this->Quiet);
cmCTestOptionalLog(
this->CTest, HANDLER_OUTPUT,
" Accumulating results (each . represents one file):" << std::endl,
this->Quiet);
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " ", this->Quiet);
std::vector<std::string> errorsWhileAccumulating;
file_count = 0;
for (auto const& file : cont.TotalCoverage) {
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "." << std::flush,
this->Quiet);
file_count++;
if (file_count % 50 == 0) {
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
" processed: " << file_count << " out of "
<< cont.TotalCoverage.size()
<< std::endl,
this->Quiet);
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " ", this->Quiet);
}
std::string const fullFileName = file.first;
bool shouldIDoCoverage =
this->ShouldIDoCoverage(fullFileName, sourceDir, binaryDir);
if (!shouldIDoCoverage) {
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
".NoDartCoverage found, so skip coverage check for: "
<< fullFileName << std::endl,
this->Quiet);
continue;
}
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Process file: " << fullFileName << std::endl,
this->Quiet);
if (!cmSystemTools::FileExists(fullFileName)) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Cannot find file: " << fullFileName << std::endl);
continue;
}
if (++cnt % 100 == 0) {
this->EndCoverageLogXML(covLogXML);
this->EndCoverageLogFile(covLogFile, logFileCount);
logFileCount++;
if (!this->StartCoverageLogFile(covLogFile, logFileCount)) {
return -1;
}
this->StartCoverageLogXML(covLogXML);
}
std::string const fileName = cmSystemTools::GetFilenameName(fullFileName);
std::string const shortFileName =
this->CTest->GetShortPathToFile(fullFileName);
cmCTestCoverageHandlerContainer::SingleFileCoverageVector const& fcov =
file.second;
covLogXML.StartElement("File");
covLogXML.Attribute("Name", fileName);
covLogXML.Attribute("FullPath", shortFileName);
covLogXML.StartElement("Report");
cmsys::ifstream ifs(fullFileName.c_str());
if (!ifs) {
std::ostringstream ostr;
ostr << "Cannot open source file: " << fullFileName;
errorsWhileAccumulating.push_back(ostr.str());
error++;
continue;
}
int tested = 0;
int untested = 0;
cmCTestCoverageHandlerContainer::SingleFileCoverageVector::size_type cc;
std::string line;
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Actually performing coverage for: " << fullFileName
<< std::endl,
this->Quiet);
for (cc = 0; cc < fcov.size(); cc++) {
if (!cmSystemTools::GetLineFromStream(ifs, line) &&
cc != fcov.size() - 1) {
std::ostringstream ostr;
ostr << "Problem reading source file: " << fullFileName
<< " line:" << cc << " out total: " << fcov.size() - 1;
errorsWhileAccumulating.push_back(ostr.str());
error++;
break;
}
covLogXML.StartElement("Line");
covLogXML.Attribute("Number", cc);
covLogXML.Attribute("Count", fcov[cc]);
covLogXML.Content(line);
covLogXML.EndElement(); // Line
if (fcov[cc] == 0) {
untested++;
} else if (fcov[cc] > 0) {
tested++;
}
}
if (cmSystemTools::GetLineFromStream(ifs, line)) {
std::ostringstream ostr;
ostr << "Looks like there are more lines in the file: " << fullFileName;
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;
covLogXML.EndElement(); // Report
covLogXML.EndElement(); // File
covSumXML.StartElement("File");
covSumXML.Attribute("Name", fileName);
covSumXML.Attribute("FullPath",
this->CTest->GetShortPathToFile(fullFileName));
covSumXML.Attribute("Covered", tested + untested > 0 ? "true" : "false");
covSumXML.Element("LOCTested", tested);
covSumXML.Element("LOCUnTested", untested);
covSumXML.Element("PercentCoverage", cper);
covSumXML.Element("CoverageMetric", cmet);
this->WriteXMLLabels(covSumXML, shortFileName);
covSumXML.EndElement(); // File
}
// Handle all the files in the extra coverage globs that have no cov data
for (std::string const& u : uncovered) {
std::string fileName = cmSystemTools::GetFilenameName(u);
std::string fullPath = cont.SourceDir + "/" + u;
covLogXML.StartElement("File");
covLogXML.Attribute("Name", fileName);
covLogXML.Attribute("FullPath", u);
covLogXML.StartElement("Report");
cmsys::ifstream ifs(fullPath.c_str());
if (!ifs) {
std::ostringstream ostr;
ostr << "Cannot open source file: " << fullPath;
errorsWhileAccumulating.push_back(ostr.str());
error++;
covLogXML.EndElement(); // Report
covLogXML.EndElement(); // File
continue;
}
int untested = 0;
std::string line;
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Actually performing coverage for: " << u << std::endl,
this->Quiet);
while (cmSystemTools::GetLineFromStream(ifs, line)) {
covLogXML.StartElement("Line");
covLogXML.Attribute("Number", untested);
covLogXML.Attribute("Count", 0);
covLogXML.Content(line);
covLogXML.EndElement(); // Line
untested++;
}
covLogXML.EndElement(); // Report
covLogXML.EndElement(); // File
total_untested += untested;
covSumXML.StartElement("File");
covSumXML.Attribute("Name", fileName);
covSumXML.Attribute("FullPath", u);
covSumXML.Attribute("Covered", "true");
covSumXML.Element("LOCTested", 0);
covSumXML.Element("LOCUnTested", untested);
covSumXML.Element("PercentCoverage", 0);
covSumXML.Element("CoverageMetric", 0);
this->WriteXMLLabels(covSumXML, u);
covSumXML.EndElement(); // File
}
this->EndCoverageLogXML(covLogXML);
this->EndCoverageLogFile(covLogFile, logFileCount);
if (!errorsWhileAccumulating.empty()) {
cmCTestLog(this->CTest, ERROR_MESSAGE, std::endl);
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Error(s) while accumulating results:" << std::endl);
for (std::string const& er : errorsWhileAccumulating) {
cmCTestLog(this->CTest, ERROR_MESSAGE, " " << er << std::endl);
}
}
long 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();
covSumXML.Element("LOCTested", total_tested);
covSumXML.Element("LOCUntested", total_untested);
covSumXML.Element("LOC", total_lines);
covSumXML.Element("PercentCoverage", percent_coverage);
covSumXML.Element("EndDateTime", end_time);
covSumXML.Element("EndTime", std::chrono::system_clock::now());
covSumXML.Element("ElapsedMinutes",
std::chrono::duration_cast<std::chrono::minutes>(
std::chrono::steady_clock::now() - elapsed_time_start)
.count());
covSumXML.EndElement(); // Coverage
this->CTest->EndXML(covSumXML);
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;
}