diff options
Diffstat (limited to 'Source/CTest/cmParseDelphiCoverage.cxx')
-rw-r--r-- | Source/CTest/cmParseDelphiCoverage.cxx | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/Source/CTest/cmParseDelphiCoverage.cxx b/Source/CTest/cmParseDelphiCoverage.cxx new file mode 100644 index 0000000..ad71c85 --- /dev/null +++ b/Source/CTest/cmParseDelphiCoverage.cxx @@ -0,0 +1,253 @@ +#include "cmStandardIncludes.h" +#include <stdio.h> +#include <stdlib.h> +#include "cmSystemTools.h" +#include "cmXMLParser.h" +#include "cmParseDelphiCoverage.h" +#include <cmsys/Directory.hxx> +#include <cmsys/Glob.hxx> +#include <cmsys/FStream.hxx> + + +class cmParseDelphiCoverage::HTMLParser +{ +public: + typedef cmCTestCoverageHandlerContainer::SingleFileCoverageVector + FileLinesType; + HTMLParser(cmCTest* ctest, cmCTestCoverageHandlerContainer& cont) + : CTest(ctest), Coverage(cont) + { + } + + virtual ~HTMLParser() + { + } + + bool initializeDelphiFile(const std::string 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.size() > 0)) + { + 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.size() > 0) && 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) + { + cmCTestLog(this->CTest,HANDLER_VERBOSE_OUTPUT, + endnamepos << "File not found " << lastoffset << std::endl); + return false; + } + endnamepos = line.find(')',lastoffset); + filename = line.substr(lastoffset+1, + (endnamepos-1)-lastoffset); + if(filename.find(".pas") != filename.npos) + { + cmCTestLog(this->CTest,HANDLER_VERBOSE_OUTPUT, + "Coverage found for file: " << filename << std::endl); + break; + } + pos = lastoffset+1; + endnamepos = 0; + lastoffset =0; + } + /* + * 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.size() == 0) + { + /* + * If that doesn't find any matching files + * return a failure. + */ + cmCTestLog(this->CTest,HANDLER_VERBOSE_OUTPUT, + "Unable to find file matching" << glob << std::endl); + 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( + const std::vector<std::string> files) + { + size_t i; + std::string path; + size_t numf = files.size(); + for (i = 0; i < numf; i++) + { + path = files[i]; + + cmCTestLog(this->CTest,HANDLER_VERBOSE_OUTPUT, + "Reading HTML File " << path << std::endl); + 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; + }; |