summaryrefslogtreecommitdiffstats
path: root/Source/CTest/cmParseMumpsCoverage.cxx
blob: b16f1014ac66409b0ed2e9c80bd22d67d9dc7b33 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include "cmParseMumpsCoverage.h"

#include <map>
#include <string>
#include <utility>
#include <vector>

#include "cmsys/FStream.hxx"
#include "cmsys/Glob.hxx"

#include "cmCTest.h"
#include "cmCTestCoverageHandler.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"

cmParseMumpsCoverage::cmParseMumpsCoverage(
  cmCTestCoverageHandlerContainer& cont, cmCTest* ctest)
  : Coverage(cont)
  , CTest(ctest)
{
}

cmParseMumpsCoverage::~cmParseMumpsCoverage() = default;

bool cmParseMumpsCoverage::ReadCoverageFile(const char* file)
{
  // Read the gtm_coverage.mcov file, that has two lines of data:
  // packages:/full/path/to/Vista/Packages
  // coverage_dir:/full/path/to/dir/with/*.mcov
  cmsys::ifstream in(file);
  if (!in) {
    return false;
  }
  std::string line;
  while (cmSystemTools::GetLineFromStream(in, line)) {
    std::string::size_type pos = line.find(':', 0);
    std::string packages;
    if (pos != std::string::npos) {
      std::string type = line.substr(0, pos);
      std::string path = line.substr(pos + 1);
      if (type == "packages") {
        this->LoadPackages(path.c_str());
      } else if (type == "coverage_dir") {
        this->LoadCoverageData(path.c_str());
      } else {
        cmCTestLog(this->CTest, ERROR_MESSAGE,
                   "Parse Error in Mumps coverage file :\n"
                     << file << "\ntype: [" << type << "]\npath:[" << path
                     << "]\n"
                        "input line: ["
                     << line << "]\n");
      }
    }
  }
  return true;
}

void cmParseMumpsCoverage::InitializeMumpsFile(std::string& file)
{
  // initialize the coverage information for a given mumps file
  cmsys::ifstream in(file.c_str());
  if (!in) {
    return;
  }
  std::string line;
  cmCTestCoverageHandlerContainer::SingleFileCoverageVector& coverageVector =
    this->Coverage.TotalCoverage[file];
  if (!cmSystemTools::GetLineFromStream(in, line)) {
    return;
  }
  // first line of a .m file can never be run
  coverageVector.push_back(-1);
  while (cmSystemTools::GetLineFromStream(in, line)) {
    // putting in a 0 for a line means it is executable code
    // putting in a -1 for a line means it is not executable code
    int val = -1; // assume line is not executable
    bool found = false;
    std::string::size_type i = 0;
    // (1) Search for the first whitespace or semicolon character on a line.
    // This will skip over labels if the line starts with one, or will simply
    // be the first character on the line for non-label lines.
    for (; i < line.size(); ++i) {
      if (line[i] == ' ' || line[i] == '\t' || line[i] == ';') {
        found = true;
        break;
      }
    }
    if (found) {
      // (2) If the first character found above is whitespace or a period
      // then continue the search for the first following non-whitespace
      // character.
      if (line[i] == ' ' || line[i] == '\t') {
        while (i < line.size() &&
               (line[i] == ' ' || line[i] == '\t' || line[i] == '.')) {
          i++;
        }
      }
      // (3) If the character found is not a semicolon then the line counts for
      // coverage.
      if (i < line.size() && line[i] != ';') {
        val = 0;
      }
    }
    coverageVector.push_back(val);
  }
}

bool cmParseMumpsCoverage::LoadPackages(const char* d)
{
  cmsys::Glob glob;
  glob.RecurseOn();
  std::string pat = cmStrCat(d, "/*.m");
  glob.FindFiles(pat);
  for (std::string& file : glob.GetFiles()) {
    std::string name = cmSystemTools::GetFilenameName(file);
    this->RoutineToDirectory[name.substr(0, name.size() - 2)] = file;
    // initialize each file, this is left out until CDash is fixed
    // to handle large numbers of files
    this->InitializeMumpsFile(file);
  }
  return true;
}

bool cmParseMumpsCoverage::FindMumpsFile(std::string const& routine,
                                         std::string& filepath)
{
  auto i = this->RoutineToDirectory.find(routine);
  if (i != this->RoutineToDirectory.end()) {
    filepath = i->second;
    return true;
  }
  // try some alternate names
  const char* tryname[] = { "GUX", "GTM", "ONT", nullptr };
  for (int k = 0; tryname[k] != nullptr; k++) {
    std::string routine2 = routine + tryname[k];
    i = this->RoutineToDirectory.find(routine2);
    if (i != this->RoutineToDirectory.end()) {
      filepath = i->second;
      return true;
    }
  }
  return false;
}