| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 | #include "cmParseCacheCoverage.h"#include "cmCTest.h"#include "cmCTestCoverageHandler.h"#include "cmSystemTools.h"#include "cmsys/Directory.hxx"#include "cmsys/FStream.hxx"#include <map>#include <stdio.h>#include <stdlib.h>#include <utility>cmParseCacheCoverage::cmParseCacheCoverage(  cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)  : cmParseMumpsCoverage(cont, ctest){}bool cmParseCacheCoverage::LoadCoverageData(const char* d){  // load all the .mcov files in the specified directory  cmsys::Directory dir;  if (!dir.Load(d)) {    return false;  }  size_t numf;  unsigned int i;  numf = dir.GetNumberOfFiles();  for (i = 0; i < numf; i++) {    std::string file = dir.GetFile(i);    if (file != "." && file != ".." && !cmSystemTools::FileIsDirectory(file)) {      std::string path = d;      path += "/";      path += file;      if (cmSystemTools::GetFilenameLastExtension(path) == ".cmcov") {        if (!this->ReadCMCovFile(path.c_str())) {          return false;        }      }    }  }  return true;}// not currently used, but leave it in case we want it in the futurevoid cmParseCacheCoverage::RemoveUnCoveredFiles(){  // loop over the coverage data computed and remove all files  // that only have -1 or 0 for the lines.  cmCTestCoverageHandlerContainer::TotalCoverageMap::iterator ci =    this->Coverage.TotalCoverage.begin();  while (ci != this->Coverage.TotalCoverage.end()) {    cmCTestCoverageHandlerContainer::SingleFileCoverageVector& v = ci->second;    bool nothing = true;    for (int i : v) {      if (i > 0) {        nothing = false;        break;      }    }    if (nothing) {      cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,                         "No coverage found in: " << ci->first << std::endl,                         this->Coverage.Quiet);      this->Coverage.TotalCoverage.erase(ci++);    } else {      ++ci;    }  }}bool cmParseCacheCoverage::SplitString(std::vector<std::string>& args,                                       std::string const& line){  std::string::size_type pos1 = 0;  std::string::size_type pos2 = line.find(',', 0);  if (pos2 == std::string::npos) {    return false;  }  std::string arg;  while (pos2 != std::string::npos) {    arg = line.substr(pos1, pos2 - pos1);    args.push_back(arg);    pos1 = pos2 + 1;    pos2 = line.find(',', pos1);  }  arg = line.substr(pos1);  args.push_back(arg);  return true;}bool cmParseCacheCoverage::ReadCMCovFile(const char* file){  cmsys::ifstream in(file);  if (!in) {    cmCTestLog(this->CTest, ERROR_MESSAGE, "Can not open : " << file << "\n");    return false;  }  std::string line;  std::vector<std::string> separateLine;  if (!cmSystemTools::GetLineFromStream(in, line)) {    cmCTestLog(this->CTest, ERROR_MESSAGE,               "Empty file : " << file                               << "  referenced in this line of cmcov data:\n"                                  "["                               << line << "]\n");    return false;  }  separateLine.clear();  this->SplitString(separateLine, line);  if (separateLine.size() != 4 || separateLine[0] != "Routine" ||      separateLine[1] != "Line" || separateLine[2] != "RtnLine" ||      separateLine[3] != "Code") {    cmCTestLog(this->CTest, ERROR_MESSAGE,               "Bad first line of cmcov file : " << file                                                 << "  line:\n"                                                    "["                                                 << line << "]\n");  }  std::string routine;  std::string filepath;  while (cmSystemTools::GetLineFromStream(in, line)) {    // clear out line argument vector    separateLine.clear();    // parse the comma separated line    this->SplitString(separateLine, line);    // might have more because code could have a quoted , in it    // but we only care about the first 3 args anyway    if (separateLine.size() < 4) {      cmCTestLog(this->CTest, ERROR_MESSAGE,                 "Bad line of cmcov file expected at least 4 found: "                   << separateLine.size() << " " << file                   << "  line:\n"                      "["                   << line << "]\n");      for (std::string::size_type i = 0; i < separateLine.size(); ++i) {        cmCTestLog(this->CTest, ERROR_MESSAGE, "" << separateLine[1] << " ");      }      cmCTestLog(this->CTest, ERROR_MESSAGE, "\n");      return false;    }    // if we do not have a routine yet, then it should be    // the first argument in the vector    if (routine.empty()) {      routine = separateLine[0];      // Find the full path to the file      if (!this->FindMumpsFile(routine, filepath)) {        cmCTestLog(this->CTest, ERROR_MESSAGE,                   "Could not find mumps file for routine: " << routine                                                             << "\n");        filepath.clear();        continue; // move to next line      }    }    // if we have a routine name, check for end of routine    else {      // Totals in arg 0 marks the end of a routine      if (separateLine[0].substr(0, 6) == "Totals") {        routine.clear(); // at the end of this routine        filepath.clear();        continue; // move to next line      }    }    // if the file path was not found for the routine    // move to next line. We should have already warned    // after the call to FindMumpsFile that we did not find    // it, so don't report again to cut down on output    if (filepath.empty()) {      continue;    }    // now we are ready to set the coverage from the line of data    cmCTestCoverageHandlerContainer::SingleFileCoverageVector& coverageVector =      this->Coverage.TotalCoverage[filepath];    std::string::size_type linenumber = atoi(separateLine[1].c_str()) - 1;    int count = atoi(separateLine[2].c_str());    if (linenumber > coverageVector.size()) {      cmCTestLog(this->CTest, ERROR_MESSAGE,                 "Parse error line is greater than number of lines in file: "                   << linenumber << " " << filepath << "\n");      continue; // skip setting count to avoid crash    }    // now add to count for linenumber    // for some reason the cache coverage adds extra lines to the    // end of the file in some cases. Since they do not exist, we will    // mark them as non executable    while (linenumber >= coverageVector.size()) {      coverageVector.push_back(-1);    }    // Accounts for lines that were previously marked    // as non-executable code (-1). if the parser comes back with    // a non-zero count, increase the count by 1 to push the line    // into the executable code set in addition to the count found.    if (coverageVector[linenumber] == -1 && count > 0) {      coverageVector[linenumber] += count + 1;    } else {      coverageVector[linenumber] += count;    }  }  return true;}
 |