cmParseCacheCoverage.cxx 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. #include "cmStandardIncludes.h"
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include "cmSystemTools.h"
  5. #include "cmParseCacheCoverage.h"
  6. #include <cmsys/Directory.hxx>
  7. #include <cmsys/Glob.hxx>
  8. #include <cmsys/FStream.hxx>
  9. cmParseCacheCoverage::cmParseCacheCoverage(
  10. cmCTestCoverageHandlerContainer& cont,
  11. cmCTest* ctest)
  12. :cmParseMumpsCoverage(cont, ctest)
  13. {
  14. }
  15. bool cmParseCacheCoverage::LoadCoverageData(const char* d)
  16. {
  17. // load all the .mcov files in the specified directory
  18. cmsys::Directory dir;
  19. if(!dir.Load(d))
  20. {
  21. return false;
  22. }
  23. size_t numf;
  24. unsigned int i;
  25. numf = dir.GetNumberOfFiles();
  26. for (i = 0; i < numf; i++)
  27. {
  28. std::string file = dir.GetFile(i);
  29. if(file != "." && file != ".."
  30. && !cmSystemTools::FileIsDirectory(file.c_str()))
  31. {
  32. std::string path = d;
  33. path += "/";
  34. path += file;
  35. if(cmSystemTools::GetFilenameLastExtension(path) == ".cmcov")
  36. {
  37. if(!this->ReadCMCovFile(path.c_str()))
  38. {
  39. return false;
  40. }
  41. }
  42. }
  43. }
  44. return true;
  45. }
  46. // not currently used, but leave it in case we want it in the future
  47. void cmParseCacheCoverage::RemoveUnCoveredFiles()
  48. {
  49. // loop over the coverage data computed and remove all files
  50. // that only have -1 or 0 for the lines.
  51. cmCTestCoverageHandlerContainer::TotalCoverageMap::iterator ci =
  52. this->Coverage.TotalCoverage.begin();
  53. while(ci != this->Coverage.TotalCoverage.end())
  54. {
  55. cmCTestCoverageHandlerContainer::SingleFileCoverageVector& v =
  56. ci->second;
  57. bool nothing = true;
  58. for(cmCTestCoverageHandlerContainer::SingleFileCoverageVector::iterator i=
  59. v.begin(); i != v.end(); ++i)
  60. {
  61. if(*i > 0)
  62. {
  63. nothing = false;
  64. break;
  65. }
  66. }
  67. if(nothing)
  68. {
  69. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  70. "No coverage found in: " << ci->first
  71. << std::endl);
  72. this->Coverage.TotalCoverage.erase(ci++);
  73. }
  74. else
  75. {
  76. ++ci;
  77. }
  78. }
  79. }
  80. bool cmParseCacheCoverage::SplitString(std::vector<std::string>& args,
  81. std::string const& line)
  82. {
  83. std::string::size_type pos1 = 0;
  84. std::string::size_type pos2 = line.find(',', 0);
  85. if(pos2 == std::string::npos)
  86. {
  87. return false;
  88. }
  89. std::string arg;
  90. while(pos2 != std::string::npos)
  91. {
  92. arg = line.substr(pos1, pos2-pos1);
  93. args.push_back(arg);
  94. pos1 = pos2+1;
  95. pos2 = line.find(',',pos1);
  96. }
  97. arg = line.substr(pos1);
  98. args.push_back(arg);
  99. return true;
  100. }
  101. bool cmParseCacheCoverage::ReadCMCovFile(const char* file)
  102. {
  103. cmsys::ifstream in(file);
  104. if(!in)
  105. {
  106. cmCTestLog(this->CTest, ERROR_MESSAGE,
  107. "Can not open : "
  108. << file << "\n");
  109. return false;
  110. }
  111. std::string line;
  112. std::vector<std::string> separateLine;
  113. if(!cmSystemTools::GetLineFromStream(in, line))
  114. {
  115. cmCTestLog(this->CTest, ERROR_MESSAGE,
  116. "Empty file : "
  117. << file << " referenced in this line of cmcov data:\n"
  118. "[" << line << "]\n");
  119. return false;
  120. }
  121. separateLine.clear();
  122. this->SplitString(separateLine, line);
  123. if(separateLine.size() !=4 || separateLine[0] != "Routine"
  124. || separateLine[1] != "Line" || separateLine[2] != "RtnLine"
  125. || separateLine[3] != "Code")
  126. {
  127. cmCTestLog(this->CTest, ERROR_MESSAGE,
  128. "Bad first line of cmcov file : "
  129. << file << " line:\n"
  130. "[" << line << "]\n");
  131. }
  132. std::string routine;
  133. std::string filepath;
  134. while(cmSystemTools::GetLineFromStream(in, line))
  135. {
  136. // clear out line argument vector
  137. separateLine.clear();
  138. // parse the comma separated line
  139. this->SplitString(separateLine, line);
  140. // might have more because code could have a quoted , in it
  141. // but we only care about the first 3 args anyway
  142. if(separateLine.size() < 4)
  143. {
  144. cmCTestLog(this->CTest, ERROR_MESSAGE,
  145. "Bad line of cmcov file expected at least 4 found: "
  146. << separateLine.size() << " "
  147. << file << " line:\n"
  148. "[" << line << "]\n");
  149. for(std::string::size_type i = 0; i < separateLine.size(); ++i)
  150. {
  151. cmCTestLog(this->CTest, ERROR_MESSAGE,""
  152. << separateLine[1] << " ");
  153. }
  154. cmCTestLog(this->CTest, ERROR_MESSAGE, "\n");
  155. return false;
  156. }
  157. // if we do not have a routine yet, then it should be
  158. // the first argument in the vector
  159. if(routine.size() == 0)
  160. {
  161. routine = separateLine[0];
  162. // Find the full path to the file
  163. if(!this->FindMumpsFile(routine, filepath))
  164. {
  165. cmCTestLog(this->CTest, ERROR_MESSAGE,
  166. "Could not find mumps file for routine: "
  167. << routine << "\n");
  168. filepath = "";
  169. continue; // move to next line
  170. }
  171. }
  172. // if we have a routine name, check for end of routine
  173. else
  174. {
  175. // Totals in arg 0 marks the end of a routine
  176. if(separateLine[0].substr(0, 6) == "Totals")
  177. {
  178. routine = ""; // at the end of this routine
  179. filepath = "";
  180. continue; // move to next line
  181. }
  182. }
  183. // if the file path was not found for the routine
  184. // move to next line. We should have already warned
  185. // after the call to FindMumpsFile that we did not find
  186. // it, so don't report again to cut down on output
  187. if(filepath.size() == 0)
  188. {
  189. continue;
  190. }
  191. // now we are ready to set the coverage from the line of data
  192. cmCTestCoverageHandlerContainer::SingleFileCoverageVector&
  193. coverageVector = this->Coverage.TotalCoverage[filepath];
  194. std::string::size_type linenumber = atoi(separateLine[1].c_str()) -1;
  195. int count = atoi(separateLine[2].c_str());
  196. if(linenumber > coverageVector.size())
  197. {
  198. cmCTestLog(this->CTest, ERROR_MESSAGE,
  199. "Parse error line is greater than number of lines in file: "
  200. << linenumber << " " << filepath << "\n");
  201. continue; // skip setting count to avoid crash
  202. }
  203. // now add to count for linenumber
  204. // for some reason the cache coverage adds extra lines to the
  205. // end of the file in some cases. Since they do not exist, we will
  206. // mark them as non executable
  207. while(linenumber >= coverageVector.size())
  208. {
  209. coverageVector.push_back(-1);
  210. }
  211. // Accounts for lines that were previously marked
  212. // as non-executable code (-1). if the parser comes back with
  213. // a non-zero count, increase the count by 1 to push the line
  214. // into the executable code set in addition to the count found.
  215. if(coverageVector[linenumber] == -1 &&
  216. count > 0)
  217. {
  218. coverageVector[linenumber] += count+1;
  219. }
  220. else
  221. {
  222. coverageVector[linenumber] += count;
  223. }
  224. }
  225. return true;
  226. }