diff options
Diffstat (limited to 'Source/CTest/cmParseDelphiCoverage.cxx')
-rw-r--r-- | Source/CTest/cmParseDelphiCoverage.cxx | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/Source/CTest/cmParseDelphiCoverage.cxx b/Source/CTest/cmParseDelphiCoverage.cxx new file mode 100644 index 0000000..7fe91f4 --- /dev/null +++ b/Source/CTest/cmParseDelphiCoverage.cxx @@ -0,0 +1,226 @@ +#include "cmParseDelphiCoverage.h" + +#include "cmCTest.h" +#include "cmCTestCoverageHandler.h" +#include "cmSystemTools.h" + +#include <cmsys/FStream.hxx> +#include <cmsys/Glob.hxx> +#include <stdio.h> +#include <stdlib.h> + +class cmParseDelphiCoverage::HTMLParser +{ +public: + typedef cmCTestCoverageHandlerContainer::SingleFileCoverageVector + FileLinesType; + HTMLParser(cmCTest* ctest, cmCTestCoverageHandlerContainer& cont) + : CTest(ctest) + , Coverage(cont) + { + } + + virtual ~HTMLParser() {} + + bool initializeDelphiFile( + std::string const& filename, + cmParseDelphiCoverage::HTMLParser::FileLinesType& coverageVector) + { + std::string line; + size_t comPos; + size_t semiPos; + bool blockComFlag = false; + bool lineComFlag = false; + std::vector<std::string> beginSet; + cmsys::ifstream in(filename.c_str()); + if (!in) { + return false; + } + while (cmSystemTools::GetLineFromStream(in, line)) { + lineComFlag = false; + // Unique cases found in lines. + size_t beginPos = line.find("begin"); + + // Check that the begin is the first non-space string on the line + if ((beginPos == line.find_first_not_of(' ')) && beginPos != line.npos) { + beginSet.push_back("begin"); + coverageVector.push_back(-1); + continue; + } else if (line.find('{') != line.npos) { + blockComFlag = true; + } else if (line.find('}') != line.npos) { + blockComFlag = false; + coverageVector.push_back(-1); + continue; + } else if ((line.find("end;") != line.npos) && !beginSet.empty()) { + beginSet.pop_back(); + coverageVector.push_back(-1); + continue; + } + + // This checks for comments after lines of code, finding the + // comment symbol after the ending semicolon. + comPos = line.find("//"); + if (comPos != line.npos) { + semiPos = line.find(';'); + if (comPos < semiPos) { + lineComFlag = true; + } + } + // Based up what was found, add a line to the coverageVector + if (!beginSet.empty() && line != "" && !blockComFlag && !lineComFlag) { + coverageVector.push_back(0); + } else { + coverageVector.push_back(-1); + } + } + return true; + } + bool ParseFile(const char* file) + { + std::string line = file; + 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; + + /* + * 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. + */ + while (true) { + lastoffset = line.find('(', pos); + if (lastoffset == line.npos) { + cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, endnamepos + << "File not found " << lastoffset << std::endl, + this->Coverage.Quiet); + return false; + } + endnamepos = line.find(')', lastoffset); + filename = line.substr(lastoffset + 1, (endnamepos - 1) - lastoffset); + if (filename.find(".pas") != filename.npos) { + cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, + "Coverage found for file: " << filename + << std::endl, + this->Coverage.Quiet); + break; + } + pos = lastoffset + 1; + } + /* + * Glob through the source directory for the + * file found above + */ + cmsys::Glob gl; + gl.RecurseOn(); + gl.RecurseThroughSymlinksOff(); + std::string glob = Coverage.SourceDir + "*/" + filename; + gl.FindFiles(glob); + std::vector<std::string> const& files = gl.GetFiles(); + if (files.empty()) { + /* + * If that doesn't find any matching files + * return a failure. + */ + cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, + "Unable to find file matching" << glob << std::endl, + this->Coverage.Quiet); + return false; + } + FileLinesType& coverageVector = this->Coverage.TotalCoverage[files[0]]; + + /* + * Initialize the file to have all code between 'begin' and + * 'end' tags marked as executable + */ + + this->initializeDelphiFile(files[0], coverageVector); + + cmsys::ifstream in(file); + if (!in) { + return false; + } + + /* + * 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;"> + * CheckEquals(1,2-1);</pre></td></tr> + * + */ + + while (cmSystemTools::GetLineFromStream(in, line)) { + if (line.find("inline") == line.npos) { + continue; + } + + lastoffset = line.find("class="); + 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; + } + } + return true; + } + +private: + cmCTest* CTest; + cmCTestCoverageHandlerContainer& Coverage; +}; + +cmParseDelphiCoverage::cmParseDelphiCoverage( + cmCTestCoverageHandlerContainer& cont, cmCTest* ctest) + : Coverage(cont) + , CTest(ctest) +{ +} + +bool cmParseDelphiCoverage::LoadCoverageData( + std::vector<std::string> const& files) +{ + size_t i; + std::string path; + size_t numf = files.size(); + for (i = 0; i < numf; i++) { + path = files[i]; + + 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())) { + return false; + } + } + } + return true; +} + +bool cmParseDelphiCoverage::ReadDelphiHTML(const char* file) +{ + cmParseDelphiCoverage::HTMLParser parser(this->CTest, this->Coverage); + parser.ParseFile(file); + return true; +} |