summaryrefslogtreecommitdiffstats
path: root/Source/CTest/cmParseCacheCoverage.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/CTest/cmParseCacheCoverage.cxx')
-rw-r--r--Source/CTest/cmParseCacheCoverage.cxx196
1 files changed, 196 insertions, 0 deletions
diff --git a/Source/CTest/cmParseCacheCoverage.cxx b/Source/CTest/cmParseCacheCoverage.cxx
new file mode 100644
index 0000000..0916da2
--- /dev/null
+++ b/Source/CTest/cmParseCacheCoverage.cxx
@@ -0,0 +1,196 @@
+#include "cmParseCacheCoverage.h"
+
+#include "cmSystemTools.h"
+#include <cmsys/Directory.hxx>
+#include <cmsys/FStream.hxx>
+#include <cmsys/Glob.hxx>
+#include <stdio.h>
+#include <stdlib.h>
+
+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 future
+void 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 (cmCTestCoverageHandlerContainer::SingleFileCoverageVector::iterator
+ i = v.begin();
+ i != v.end(); ++i) {
+ 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 = "";
+ 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 = ""; // at the end of this routine
+ filepath = "";
+ 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;
+}