cmake/Source/CTest/cmParseDelphiCoverage.cxx

233 lines
6.7 KiB
C++
Raw Normal View History

2016-07-09 11:21:54 +02:00
#include "cmParseDelphiCoverage.h"
2020-02-01 23:06:01 +01:00
#include <cstdio>
#include <cstdlib>
2016-10-30 18:24:19 +01:00
2017-07-20 19:35:53 +02:00
#include "cmsys/FStream.hxx"
#include "cmsys/Glob.hxx"
2020-02-01 23:06:01 +01:00
#include "cmCTest.h"
#include "cmCTestCoverageHandler.h"
#include "cmSystemTools.h"
2015-04-27 22:25:09 +02:00
class cmParseDelphiCoverage::HTMLParser
{
public:
2020-02-01 23:06:01 +01:00
using FileLinesType =
cmCTestCoverageHandlerContainer::SingleFileCoverageVector;
2015-04-27 22:25:09 +02:00
HTMLParser(cmCTest* ctest, cmCTestCoverageHandlerContainer& cont)
2016-07-09 11:21:54 +02:00
: CTest(ctest)
, Coverage(cont)
{
}
2015-04-27 22:25:09 +02:00
2019-11-11 23:01:05 +01:00
virtual ~HTMLParser() = default;
2015-04-27 22:25:09 +02:00
2016-07-09 11:21:54 +02:00
bool initializeDelphiFile(
std::string const& filename,
cmParseDelphiCoverage::HTMLParser::FileLinesType& coverageVector)
{
2015-04-27 22:25:09 +02:00
std::string line;
size_t comPos;
size_t semiPos;
2016-07-09 11:21:54 +02:00
bool blockComFlag = false;
bool lineComFlag = false;
2015-04-27 22:25:09 +02:00
std::vector<std::string> beginSet;
cmsys::ifstream in(filename.c_str());
2016-07-09 11:21:54 +02:00
if (!in) {
2015-04-27 22:25:09 +02:00
return false;
2016-07-09 11:21:54 +02:00
}
while (cmSystemTools::GetLineFromStream(in, line)) {
lineComFlag = false;
2015-04-27 22:25:09 +02:00
// Unique cases found in lines.
size_t beginPos = line.find("begin");
2016-07-09 11:21:54 +02:00
// Check that the begin is the first non-space string on the line
2017-07-20 19:35:53 +02:00
if ((beginPos == line.find_first_not_of(' ')) &&
beginPos != std::string::npos) {
2019-11-11 23:01:05 +01:00
beginSet.emplace_back("begin");
2015-04-27 22:25:09 +02:00
coverageVector.push_back(-1);
continue;
2017-07-20 19:35:53 +02:00
}
if (line.find('{') != std::string::npos) {
2016-07-09 11:21:54 +02:00
blockComFlag = true;
2017-07-20 19:35:53 +02:00
} else if (line.find('}') != std::string::npos) {
2016-07-09 11:21:54 +02:00
blockComFlag = false;
2015-04-27 22:25:09 +02:00
coverageVector.push_back(-1);
continue;
2017-07-20 19:35:53 +02:00
} else if ((line.find("end;") != std::string::npos) &&
!beginSet.empty()) {
2015-04-27 22:25:09 +02:00
beginSet.pop_back();
coverageVector.push_back(-1);
continue;
2016-07-09 11:21:54 +02:00
}
2015-04-27 22:25:09 +02:00
// This checks for comments after lines of code, finding the
// comment symbol after the ending semicolon.
comPos = line.find("//");
2017-07-20 19:35:53 +02:00
if (comPos != std::string::npos) {
2016-07-09 11:21:54 +02:00
semiPos = line.find(';');
if (comPos < semiPos) {
lineComFlag = true;
2015-04-27 22:25:09 +02:00
}
2016-07-09 11:21:54 +02:00
}
// Based up what was found, add a line to the coverageVector
2018-01-26 17:06:56 +01:00
if (!beginSet.empty() && !line.empty() && !blockComFlag &&
!lineComFlag) {
2015-04-27 22:25:09 +02:00
coverageVector.push_back(0);
2016-07-09 11:21:54 +02:00
} else {
2015-04-27 22:25:09 +02:00
coverageVector.push_back(-1);
}
}
2016-07-09 11:21:54 +02:00
return true;
}
2015-04-27 22:25:09 +02:00
bool ParseFile(const char* file)
2016-07-09 11:21:54 +02:00
{
std::string line = file;
2015-04-27 22:25:09 +02:00
std::string lineresult;
std::string lastroutine;
std::string filename;
std::string filelineoffset;
size_t afterLineNum = 0;
size_t lastoffset = 0;
size_t endcovpos = 0;
size_t endnamepos = 0;
size_t pos = 0;
/*
2017-07-20 19:35:53 +02:00
* This first 'while' section goes through the found HTML
* file name and attempts to capture the source file name
* which is set as part of the HTML file name: the name of
* the file is found in parenthesis '()'
*
* See test HTML file name: UTCovTest(UTCovTest.pas).html.
*
* Find the text inside each pair of parenthesis and check
* to see if it ends in '.pas'. If it can't be found,
* exit the function.
*/
2016-07-09 11:21:54 +02:00
while (true) {
lastoffset = line.find('(', pos);
2017-07-20 19:35:53 +02:00
if (lastoffset == std::string::npos) {
2018-08-09 18:06:22 +02:00
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
endnamepos << "File not found " << lastoffset
<< std::endl,
2016-07-09 11:21:54 +02:00
this->Coverage.Quiet);
2015-04-27 22:25:09 +02:00
return false;
2016-07-09 11:21:54 +02:00
}
endnamepos = line.find(')', lastoffset);
filename = line.substr(lastoffset + 1, (endnamepos - 1) - lastoffset);
2017-07-20 19:35:53 +02:00
if (filename.find(".pas") != std::string::npos) {
2016-07-09 11:21:54 +02:00
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Coverage found for file: " << filename
<< std::endl,
this->Coverage.Quiet);
2015-04-27 22:25:09 +02:00
break;
}
2016-07-09 11:21:54 +02:00
pos = lastoffset + 1;
}
2015-04-27 22:25:09 +02:00
/*
2017-07-20 19:35:53 +02:00
* Glob through the source directory for the
* file found above
*/
2015-04-27 22:25:09 +02:00
cmsys::Glob gl;
gl.RecurseOn();
gl.RecurseThroughSymlinksOff();
2021-09-14 00:13:48 +02:00
std::string glob = this->Coverage.SourceDir + "*/" + filename;
2015-04-27 22:25:09 +02:00
gl.FindFiles(glob);
std::vector<std::string> const& files = gl.GetFiles();
2016-07-09 11:21:54 +02:00
if (files.empty()) {
2015-04-27 22:25:09 +02:00
/*
2017-07-20 19:35:53 +02:00
* If that doesn't find any matching files
* return a failure.
*/
2016-07-09 11:21:54 +02:00
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Unable to find file matching" << glob << std::endl,
this->Coverage.Quiet);
2015-04-27 22:25:09 +02:00
return false;
2016-07-09 11:21:54 +02:00
}
FileLinesType& coverageVector = this->Coverage.TotalCoverage[files[0]];
2015-04-27 22:25:09 +02:00
/*
2017-07-20 19:35:53 +02:00
* Initialize the file to have all code between 'begin' and
* 'end' tags marked as executable
*/
2015-04-27 22:25:09 +02:00
2016-07-09 11:21:54 +02:00
this->initializeDelphiFile(files[0], coverageVector);
2015-04-27 22:25:09 +02:00
cmsys::ifstream in(file);
2016-07-09 11:21:54 +02:00
if (!in) {
2015-04-27 22:25:09 +02:00
return false;
2016-07-09 11:21:54 +02:00
}
2015-04-27 22:25:09 +02:00
/*
2017-07-20 19:35:53 +02:00
* Now read the HTML file, looking for the lines that have an
* "inline" in it. Then parse out the "class" value of that
* line to determine if the line is executed or not.
*
* Sample HTML line:
*
* <tr class="covered"><td>47</td><td><pre style="display:inline;">
* &nbsp;CheckEquals(1,2-1);</pre></td></tr>
*
*/
2015-04-27 22:25:09 +02:00
2016-07-09 11:21:54 +02:00
while (cmSystemTools::GetLineFromStream(in, line)) {
2017-07-20 19:35:53 +02:00
if (line.find("inline") == std::string::npos) {
2015-04-27 22:25:09 +02:00
continue;
2016-07-09 11:21:54 +02:00
}
2015-04-27 22:25:09 +02:00
lastoffset = line.find("class=");
2016-07-09 11:21:54 +02:00
endcovpos = line.find('>', lastoffset);
lineresult = line.substr(lastoffset + 7, (endcovpos - 8) - lastoffset);
if (lineresult == "covered") {
afterLineNum = line.find('<', endcovpos + 5);
filelineoffset =
line.substr(endcovpos + 5, afterLineNum - (endcovpos + 5));
coverageVector[atoi(filelineoffset.c_str()) - 1] = 1;
2015-04-27 22:25:09 +02:00
}
}
2016-07-09 11:21:54 +02:00
return true;
}
2015-04-27 22:25:09 +02:00
2016-07-09 11:21:54 +02:00
private:
cmCTest* CTest;
cmCTestCoverageHandlerContainer& Coverage;
2015-04-27 22:25:09 +02:00
};
cmParseDelphiCoverage::cmParseDelphiCoverage(
2016-07-09 11:21:54 +02:00
cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)
: Coverage(cont)
, CTest(ctest)
{
}
2015-04-27 22:25:09 +02:00
bool cmParseDelphiCoverage::LoadCoverageData(
2016-07-09 11:21:54 +02:00
std::vector<std::string> const& files)
{
2015-04-27 22:25:09 +02:00
size_t i;
std::string path;
size_t numf = files.size();
2016-07-09 11:21:54 +02:00
for (i = 0; i < numf; i++) {
2015-04-27 22:25:09 +02:00
path = files[i];
2016-07-09 11:21:54 +02:00
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Reading HTML File " << path << std::endl,
this->Coverage.Quiet);
if (cmSystemTools::GetFilenameLastExtension(path) == ".html") {
if (!this->ReadDelphiHTML(path.c_str())) {
2015-04-27 22:25:09 +02:00
return false;
}
}
}
2016-07-09 11:21:54 +02:00
return true;
}
2015-04-27 22:25:09 +02:00
bool cmParseDelphiCoverage::ReadDelphiHTML(const char* file)
2016-07-09 11:21:54 +02:00
{
cmParseDelphiCoverage::HTMLParser parser(this->CTest, this->Coverage);
2015-04-27 22:25:09 +02:00
parser.ParseFile(file);
return true;
2016-07-09 11:21:54 +02:00
}