| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 | #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() = default;  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 != std::string::npos) {        beginSet.emplace_back("begin");        coverageVector.push_back(-1);        continue;      }      if (line.find('{') != std::string::npos) {        blockComFlag = true;      } else if (line.find('}') != std::string::npos) {        blockComFlag = false;        coverageVector.push_back(-1);        continue;      } else if ((line.find("end;") != std::string::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 != std::string::npos) {        semiPos = line.find(';');        if (comPos < semiPos) {          lineComFlag = true;        }      }      // Based up what was found, add a line to the coverageVector      if (!beginSet.empty() && !line.empty() && !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 == std::string::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") != std::string::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") == std::string::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;}
 |