cmake/Source/CTest/cmParseCacheCoverage.cxx

179 lines
6.2 KiB
C++
Raw Normal View History

2012-06-27 20:52:58 +03:00
#include "cmParseCacheCoverage.h"
2016-07-09 11:21:54 +02:00
2020-02-01 23:06:01 +01:00
#include <cstdio>
#include <cstdlib>
#include <map>
#include <utility>
2020-08-30 11:54:41 +02:00
#include <vector>
2016-10-30 18:24:19 +01:00
2017-07-20 19:35:53 +02:00
#include "cmsys/Directory.hxx"
#include "cmsys/FStream.hxx"
2020-02-01 23:06:01 +01:00
#include "cmCTest.h"
#include "cmCTestCoverageHandler.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
2012-06-27 20:52:58 +03:00
cmParseCacheCoverage::cmParseCacheCoverage(
2016-07-09 11:21:54 +02:00
cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)
: cmParseMumpsCoverage(cont, ctest)
2012-06-27 20:52:58 +03:00
{
}
2020-08-30 11:54:41 +02:00
bool cmParseCacheCoverage::LoadCoverageData(std::string const& d)
2012-06-27 20:52:58 +03:00
{
// load all the .mcov files in the specified directory
cmsys::Directory dir;
2016-07-09 11:21:54 +02:00
if (!dir.Load(d)) {
2012-06-27 20:52:58 +03:00
return false;
2016-07-09 11:21:54 +02:00
}
2012-06-27 20:52:58 +03:00
size_t numf;
unsigned int i;
numf = dir.GetNumberOfFiles();
2016-07-09 11:21:54 +02:00
for (i = 0; i < numf; i++) {
2012-06-27 20:52:58 +03:00
std::string file = dir.GetFile(i);
2016-07-09 11:21:54 +02:00
if (file != "." && file != ".." && !cmSystemTools::FileIsDirectory(file)) {
2020-02-01 23:06:01 +01:00
std::string path = cmStrCat(d, '/', file);
2016-07-09 11:21:54 +02:00
if (cmSystemTools::GetFilenameLastExtension(path) == ".cmcov") {
if (!this->ReadCMCovFile(path.c_str())) {
2012-06-27 20:52:58 +03:00
return false;
}
}
}
2016-07-09 11:21:54 +02:00
}
2012-06-27 20:52:58 +03:00
return true;
}
// not currently used, but leave it in case we want it in the future
void cmParseCacheCoverage::RemoveUnCoveredFiles()
{
// loop over the coverage data computed and remove all files
// that only have -1 or 0 for the lines.
2020-02-01 23:06:01 +01:00
auto ci = this->Coverage.TotalCoverage.begin();
2016-07-09 11:21:54 +02:00
while (ci != this->Coverage.TotalCoverage.end()) {
cmCTestCoverageHandlerContainer::SingleFileCoverageVector& v = ci->second;
2012-06-27 20:52:58 +03:00
bool nothing = true;
2018-01-26 17:06:56 +01:00
for (int i : v) {
if (i > 0) {
2012-06-27 20:52:58 +03:00
nothing = false;
break;
}
2016-07-09 11:21:54 +02:00
}
if (nothing) {
2015-08-17 11:37:30 +02:00
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
2016-07-09 11:21:54 +02:00
"No coverage found in: " << ci->first << std::endl,
this->Coverage.Quiet);
2012-06-27 20:52:58 +03:00
this->Coverage.TotalCoverage.erase(ci++);
2016-07-09 11:21:54 +02:00
} else {
2012-06-27 20:52:58 +03:00
++ci;
}
2016-07-09 11:21:54 +02:00
}
2012-06-27 20:52:58 +03:00
}
bool cmParseCacheCoverage::ReadCMCovFile(const char* file)
{
2014-08-03 19:52:23 +02:00
cmsys::ifstream in(file);
2016-07-09 11:21:54 +02:00
if (!in) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "Can not open : " << file << "\n");
2012-06-27 20:52:58 +03:00
return false;
2016-07-09 11:21:54 +02:00
}
2012-06-27 20:52:58 +03:00
std::string line;
2016-07-09 11:21:54 +02:00
if (!cmSystemTools::GetLineFromStream(in, line)) {
2018-08-09 18:06:22 +02:00
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Empty file : " << file
<< " referenced in this line of cmcov data:\n"
"["
<< line << "]\n");
2012-06-27 20:52:58 +03:00
return false;
2016-07-09 11:21:54 +02:00
}
2020-08-30 11:54:41 +02:00
std::vector<std::string> separateLine =
cmSystemTools::SplitString(line, ',');
2016-07-09 11:21:54 +02:00
if (separateLine.size() != 4 || separateLine[0] != "Routine" ||
separateLine[1] != "Line" || separateLine[2] != "RtnLine" ||
separateLine[3] != "Code") {
2012-06-27 20:52:58 +03:00
cmCTestLog(this->CTest, ERROR_MESSAGE,
2018-08-09 18:06:22 +02:00
"Bad first line of cmcov file : " << file
<< " line:\n"
"["
2016-07-09 11:21:54 +02:00
<< line << "]\n");
}
2012-06-27 20:52:58 +03:00
std::string routine;
std::string filepath;
2016-07-09 11:21:54 +02:00
while (cmSystemTools::GetLineFromStream(in, line)) {
2012-06-27 20:52:58 +03:00
// parse the comma separated line
2020-08-30 11:54:41 +02:00
separateLine = cmSystemTools::SplitString(line, ',');
2012-06-27 20:52:58 +03:00
// might have more because code could have a quoted , in it
// but we only care about the first 3 args anyway
2016-07-09 11:21:54 +02:00
if (separateLine.size() < 4) {
2012-06-27 20:52:58 +03:00
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Bad line of cmcov file expected at least 4 found: "
2018-08-09 18:06:22 +02:00
<< separateLine.size() << " " << file
<< " line:\n"
"["
2016-07-09 11:21:54 +02:00
<< line << "]\n");
for (std::string::size_type i = 0; i < separateLine.size(); ++i) {
cmCTestLog(this->CTest, ERROR_MESSAGE, "" << separateLine[1] << " ");
}
2012-06-27 20:52:58 +03:00
cmCTestLog(this->CTest, ERROR_MESSAGE, "\n");
return false;
2016-07-09 11:21:54 +02:00
}
2012-06-27 20:52:58 +03:00
// if we do not have a routine yet, then it should be
// the first argument in the vector
2016-07-09 11:21:54 +02:00
if (routine.empty()) {
2012-06-27 20:52:58 +03:00
routine = separateLine[0];
// Find the full path to the file
2016-07-09 11:21:54 +02:00
if (!this->FindMumpsFile(routine, filepath)) {
2012-06-27 20:52:58 +03:00
cmCTestLog(this->CTest, ERROR_MESSAGE,
2016-07-09 11:21:54 +02:00
"Could not find mumps file for routine: " << routine
<< "\n");
2018-01-26 17:06:56 +01:00
filepath.clear();
2012-06-27 20:52:58 +03:00
continue; // move to next line
}
2016-07-09 11:21:54 +02:00
}
2012-06-27 20:52:58 +03:00
// if we have a routine name, check for end of routine
2016-07-09 11:21:54 +02:00
else {
2012-06-27 20:52:58 +03:00
// Totals in arg 0 marks the end of a routine
2020-08-30 11:54:41 +02:00
if (cmHasLiteralPrefix(separateLine[0], "Totals")) {
2018-01-26 17:06:56 +01:00
routine.clear(); // at the end of this routine
filepath.clear();
2012-06-27 20:52:58 +03:00
continue; // move to next line
}
2016-07-09 11:21:54 +02:00
}
2012-06-27 20:52:58 +03:00
// if the file path was not found for the routine
// move to next line. We should have already warned
// after the call to FindMumpsFile that we did not find
// it, so don't report again to cut down on output
2016-07-09 11:21:54 +02:00
if (filepath.empty()) {
2012-06-27 20:52:58 +03:00
continue;
2016-07-09 11:21:54 +02:00
}
2012-06-27 20:52:58 +03:00
// now we are ready to set the coverage from the line of data
2016-07-09 11:21:54 +02:00
cmCTestCoverageHandlerContainer::SingleFileCoverageVector& coverageVector =
this->Coverage.TotalCoverage[filepath];
std::string::size_type linenumber = atoi(separateLine[1].c_str()) - 1;
2012-06-27 20:52:58 +03:00
int count = atoi(separateLine[2].c_str());
2016-07-09 11:21:54 +02:00
if (linenumber > coverageVector.size()) {
2012-06-27 20:52:58 +03:00
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Parse error line is greater than number of lines in file: "
2016-07-09 11:21:54 +02:00
<< linenumber << " " << filepath << "\n");
2012-06-27 20:52:58 +03:00
continue; // skip setting count to avoid crash
2016-07-09 11:21:54 +02:00
}
2012-06-27 20:52:58 +03:00
// now add to count for linenumber
// for some reason the cache coverage adds extra lines to the
// end of the file in some cases. Since they do not exist, we will
// mark them as non executable
2016-07-09 11:21:54 +02:00
while (linenumber >= coverageVector.size()) {
2012-06-27 20:52:58 +03:00
coverageVector.push_back(-1);
2016-07-09 11:21:54 +02:00
}
2015-04-27 22:25:09 +02:00
// Accounts for lines that were previously marked
// as non-executable code (-1). if the parser comes back with
// a non-zero count, increase the count by 1 to push the line
// into the executable code set in addition to the count found.
2016-07-09 11:21:54 +02:00
if (coverageVector[linenumber] == -1 && count > 0) {
coverageVector[linenumber] += count + 1;
} else {
coverageVector[linenumber] += count;
2012-06-27 20:52:58 +03:00
}
2016-07-09 11:21:54 +02:00
}
2012-06-27 20:52:58 +03:00
return true;
}