cmParseDelphiCoverage.cxx 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. #include "cmParseDelphiCoverage.h"
  2. #include "cmCTest.h"
  3. #include "cmCTestCoverageHandler.h"
  4. #include "cmSystemTools.h"
  5. #include "cmsys/FStream.hxx"
  6. #include "cmsys/Glob.hxx"
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. class cmParseDelphiCoverage::HTMLParser
  10. {
  11. public:
  12. typedef cmCTestCoverageHandlerContainer::SingleFileCoverageVector
  13. FileLinesType;
  14. HTMLParser(cmCTest* ctest, cmCTestCoverageHandlerContainer& cont)
  15. : CTest(ctest)
  16. , Coverage(cont)
  17. {
  18. }
  19. virtual ~HTMLParser() {}
  20. bool initializeDelphiFile(
  21. std::string const& filename,
  22. cmParseDelphiCoverage::HTMLParser::FileLinesType& coverageVector)
  23. {
  24. std::string line;
  25. size_t comPos;
  26. size_t semiPos;
  27. bool blockComFlag = false;
  28. bool lineComFlag = false;
  29. std::vector<std::string> beginSet;
  30. cmsys::ifstream in(filename.c_str());
  31. if (!in) {
  32. return false;
  33. }
  34. while (cmSystemTools::GetLineFromStream(in, line)) {
  35. lineComFlag = false;
  36. // Unique cases found in lines.
  37. size_t beginPos = line.find("begin");
  38. // Check that the begin is the first non-space string on the line
  39. if ((beginPos == line.find_first_not_of(' ')) && beginPos != line.npos) {
  40. beginSet.push_back("begin");
  41. coverageVector.push_back(-1);
  42. continue;
  43. }
  44. if (line.find('{') != line.npos) {
  45. blockComFlag = true;
  46. } else if (line.find('}') != line.npos) {
  47. blockComFlag = false;
  48. coverageVector.push_back(-1);
  49. continue;
  50. } else if ((line.find("end;") != line.npos) && !beginSet.empty()) {
  51. beginSet.pop_back();
  52. coverageVector.push_back(-1);
  53. continue;
  54. }
  55. // This checks for comments after lines of code, finding the
  56. // comment symbol after the ending semicolon.
  57. comPos = line.find("//");
  58. if (comPos != line.npos) {
  59. semiPos = line.find(';');
  60. if (comPos < semiPos) {
  61. lineComFlag = true;
  62. }
  63. }
  64. // Based up what was found, add a line to the coverageVector
  65. if (!beginSet.empty() && line != "" && !blockComFlag && !lineComFlag) {
  66. coverageVector.push_back(0);
  67. } else {
  68. coverageVector.push_back(-1);
  69. }
  70. }
  71. return true;
  72. }
  73. bool ParseFile(const char* file)
  74. {
  75. std::string line = file;
  76. std::string lineresult;
  77. std::string lastroutine;
  78. std::string filename;
  79. std::string filelineoffset;
  80. size_t afterLineNum = 0;
  81. size_t lastoffset = 0;
  82. size_t endcovpos = 0;
  83. size_t endnamepos = 0;
  84. size_t pos = 0;
  85. /*
  86. * This first 'while' section goes through the found HTML
  87. * file name and attempts to capture the source file name
  88. * which is set as part of the HTML file name: the name of
  89. * the file is found in parenthesis '()'
  90. *
  91. * See test HTML file name: UTCovTest(UTCovTest.pas).html.
  92. *
  93. * Find the text inside each pair of parenthesis and check
  94. * to see if it ends in '.pas'. If it can't be found,
  95. * exit the function.
  96. */
  97. while (true) {
  98. lastoffset = line.find('(', pos);
  99. if (lastoffset == line.npos) {
  100. cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, endnamepos
  101. << "File not found " << lastoffset << std::endl,
  102. this->Coverage.Quiet);
  103. return false;
  104. }
  105. endnamepos = line.find(')', lastoffset);
  106. filename = line.substr(lastoffset + 1, (endnamepos - 1) - lastoffset);
  107. if (filename.find(".pas") != filename.npos) {
  108. cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  109. "Coverage found for file: " << filename
  110. << std::endl,
  111. this->Coverage.Quiet);
  112. break;
  113. }
  114. pos = lastoffset + 1;
  115. }
  116. /*
  117. * Glob through the source directory for the
  118. * file found above
  119. */
  120. cmsys::Glob gl;
  121. gl.RecurseOn();
  122. gl.RecurseThroughSymlinksOff();
  123. std::string glob = Coverage.SourceDir + "*/" + filename;
  124. gl.FindFiles(glob);
  125. std::vector<std::string> const& files = gl.GetFiles();
  126. if (files.empty()) {
  127. /*
  128. * If that doesn't find any matching files
  129. * return a failure.
  130. */
  131. cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  132. "Unable to find file matching" << glob << std::endl,
  133. this->Coverage.Quiet);
  134. return false;
  135. }
  136. FileLinesType& coverageVector = this->Coverage.TotalCoverage[files[0]];
  137. /*
  138. * Initialize the file to have all code between 'begin' and
  139. * 'end' tags marked as executable
  140. */
  141. this->initializeDelphiFile(files[0], coverageVector);
  142. cmsys::ifstream in(file);
  143. if (!in) {
  144. return false;
  145. }
  146. /*
  147. * Now read the HTML file, looking for the lines that have an
  148. * "inline" in it. Then parse out the "class" value of that
  149. * line to determine if the line is executed or not.
  150. *
  151. * Sample HTML line:
  152. *
  153. * <tr class="covered"><td>47</td><td><pre style="display:inline;">
  154. * &nbsp;CheckEquals(1,2-1);</pre></td></tr>
  155. *
  156. */
  157. while (cmSystemTools::GetLineFromStream(in, line)) {
  158. if (line.find("inline") == line.npos) {
  159. continue;
  160. }
  161. lastoffset = line.find("class=");
  162. endcovpos = line.find('>', lastoffset);
  163. lineresult = line.substr(lastoffset + 7, (endcovpos - 8) - lastoffset);
  164. if (lineresult == "covered") {
  165. afterLineNum = line.find('<', endcovpos + 5);
  166. filelineoffset =
  167. line.substr(endcovpos + 5, afterLineNum - (endcovpos + 5));
  168. coverageVector[atoi(filelineoffset.c_str()) - 1] = 1;
  169. }
  170. }
  171. return true;
  172. }
  173. private:
  174. cmCTest* CTest;
  175. cmCTestCoverageHandlerContainer& Coverage;
  176. };
  177. cmParseDelphiCoverage::cmParseDelphiCoverage(
  178. cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)
  179. : Coverage(cont)
  180. , CTest(ctest)
  181. {
  182. }
  183. bool cmParseDelphiCoverage::LoadCoverageData(
  184. std::vector<std::string> const& files)
  185. {
  186. size_t i;
  187. std::string path;
  188. size_t numf = files.size();
  189. for (i = 0; i < numf; i++) {
  190. path = files[i];
  191. cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  192. "Reading HTML File " << path << std::endl,
  193. this->Coverage.Quiet);
  194. if (cmSystemTools::GetFilenameLastExtension(path) == ".html") {
  195. if (!this->ReadDelphiHTML(path.c_str())) {
  196. return false;
  197. }
  198. }
  199. }
  200. return true;
  201. }
  202. bool cmParseDelphiCoverage::ReadDelphiHTML(const char* file)
  203. {
  204. cmParseDelphiCoverage::HTMLParser parser(this->CTest, this->Coverage);
  205. parser.ParseFile(file);
  206. return true;
  207. }