CMake/Source/CTest/cmParseCacheCoverage.cxx

195 lines
5.8 KiB
C++

#include "cmStandardIncludes.h"
#include <stdio.h>
#include <stdlib.h>
#include "cmSystemTools.h"
#include "cmParseCacheCoverage.h"
#include <cmsys/Directory.hxx>
#include <cmsys/Glob.hxx>
cmParseCacheCoverage::cmParseCacheCoverage(
cmCTestCoverageHandlerContainer& cont,
cmCTest* ctest)
:cmParseMumpsCoverage(cont, ctest)
{
}
bool cmParseCacheCoverage::LoadCoverageData(const char* d)
{
// load all the .mcov files in the specified directory
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(cmSystemTools::GetFilenameLastExtension(path) == ".cmcov")
{
if(!this->ReadCMCovFile(path.c_str()))
{
return false;
}
}
}
}
return true;
}
bool cmParseCacheCoverage::SplitString(std::vector<std::string>& args,
std::string const& line)
{
std::string::size_type pos1 = 0;
std::string::size_type pos2 = line.find(',', 0);
if(pos2 == std::string::npos)
{
return false;
}
std::string arg;
while(pos2 != std::string::npos)
{
arg = line.substr(pos1, pos2-pos1);
args.push_back(arg);
pos1 = pos2+1;
pos2 = line.find(',',pos1);
}
arg = line.substr(pos1);
args.push_back(arg);
return true;
}
bool cmParseCacheCoverage::ReadCMCovFile(const char* file)
{
std::ifstream in(file);
if(!in)
{
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Can not open : "
<< file << "\n");
return false;
}
std::string line;
std::vector<std::string> separateLine;
if(!cmSystemTools::GetLineFromStream(in, line))
{
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Empty file : "
<< file << " referenced in this line of cmcov data:\n"
"[" << line << "]\n");
return false;
}
separateLine.clear();
this->SplitString(separateLine, line);
if(separateLine.size() !=4 || separateLine[0] != "Routine"
|| separateLine[1] != "Line" || separateLine[2] != "RtnLine"
|| separateLine[3] != "Code")
{
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Bad first line of cmcov file : "
<< file << " line:\n"
"[" << line << "]\n");
}
std::string routine;
std::string filepath;
while(cmSystemTools::GetLineFromStream(in, line))
{
// clear out line argument vector
separateLine.clear();
// parse the comma separated line
this->SplitString(separateLine, line);
// might have more because code could have a quoted , in it
// but we only care about the first 3 args anyway
if(separateLine.size() < 4)
{
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Bad line of cmcov file expected at least 4 found: "
<< separateLine.size() << " "
<< file << " line:\n"
"[" << line << "]\n");
for(std::string::size_type i = 0; i < separateLine.size(); ++i)
{
cmCTestLog(this->CTest, ERROR_MESSAGE,""
<< separateLine[1] << " ");
}
cmCTestLog(this->CTest, ERROR_MESSAGE, "\n");
return false;
}
// if we do not have a routine yet, then it should be
// the first argument in the vector
if(routine.size() == 0)
{
routine = separateLine[0];
// Find the full path to the file
if(!this->FindMumpsFile(routine, filepath))
{
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Could not find mumps file for routine: "
<< routine << "\n");
filepath = "";
continue; // move to next line
}
}
// if we have a routine name, check for end of routine
else
{
// Totals in arg 0 marks the end of a routine
if(separateLine[0].substr(0, 6) == "Totals")
{
routine = ""; // at the end of this routine
filepath = "";
continue; // move to next line
}
}
// 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
if(filepath.size() == 0)
{
continue;
}
// routine and filepath should be set at this point.
// see if we have visited this file before, and if not
// call InitializeMumpsFile
if( this->Coverage.TotalCoverage[filepath].size() == 0)
{
// hack, this should be done on every file, but for now
// just do it on the ones that have coverage at all
this->InitializeMumpsFile(filepath);
}
// now we are ready to set the coverage from the line of data
cmCTestCoverageHandlerContainer::SingleFileCoverageVector&
coverageVector = this->Coverage.TotalCoverage[filepath];
std::string::size_type linenumber = atoi(separateLine[1].c_str()) -1;
int count = atoi(separateLine[2].c_str());
if(linenumber > coverageVector.size())
{
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Parse error line is greater than number of lines in file: "
<< linenumber << " " << filepath << "\n");
continue; // skip setting count to avoid crash
}
// 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
while(linenumber >= coverageVector.size())
{
coverageVector.push_back(-1);
}
coverageVector[linenumber] += count;
}
return true;
}