#include "cmParseMumpsCoverage.h" #include #include #include #include #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); } else if (type == "coverage_dir") { this->LoadCoverageData(path); } 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(std::string const& 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); name.erase(name.size() - 2); this->RoutineToDirectory[name] = 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; }