cmParseCacheCoverage.cxx 6.8 KB

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