| #include "cmParseCacheCoverage.h" | |
| #include <cstdio> | |
| #include <cstdlib> | |
| #include <map> | |
| #include <utility> | |
| #include <vector> | |
| #include "cmsys/Directory.hxx" | |
| #include "cmsys/FStream.hxx" | |
| #include "cmCTest.h" | |
| #include "cmCTestCoverageHandler.h" | |
| #include "cmStringAlgorithms.h" | |
| #include "cmSystemTools.h" | |
| cmParseCacheCoverage::cmParseCacheCoverage( | |
| cmCTestCoverageHandlerContainer& cont, cmCTest* ctest) | |
| : cmParseMumpsCoverage(cont, ctest) | |
| { | |
| } | |
| bool cmParseCacheCoverage::LoadCoverageData(std::string const& 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 const& file = dir.GetFileName(i); | |
| if (file != "." && file != ".." && !cmSystemTools::FileIsDirectory(file)) { | |
| std::string path = cmStrCat(d, '/', 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 future | |
| void cmParseCacheCoverage::RemoveUnCoveredFiles() | |
| { | |
| // loop over the coverage data computed and remove all files | |
| // that only have -1 or 0 for the lines. | |
| auto 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, | |
| this->Coverage.Quiet, | |
| "No coverage found in: ", ci->first, '\n'); | |
| this->Coverage.TotalCoverage.erase(ci++); | |
| } else { | |
| ++ci; | |
| } | |
| } | |
| } | |
| bool cmParseCacheCoverage::ReadCMCovFile(char const* file) | |
| { | |
| cmsys::ifstream in(file); | |
| if (!in) { | |
| cmCTestLog(this->CTest, ERROR_MESSAGE, "Can not open : ", file, '\n'); | |
| return false; | |
| } | |
| std::string line; | |
| 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; | |
| } | |
| std::vector<std::string> separateLine = | |
| cmSystemTools::SplitString(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)) { | |
| // parse the comma separated line | |
| separateLine = cmSystemTools::SplitString(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 const& l : separateLine) { | |
| cmCTestLog(this->CTest, ERROR_MESSAGE, l, ' '); | |
| } | |
| 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 (cmHasLiteralPrefix(separateLine[0], "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; | |
| } |