diff options
Diffstat (limited to 'Source/CTest/cmParseGTMCoverage.cxx')
-rw-r--r-- | Source/CTest/cmParseGTMCoverage.cxx | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/Source/CTest/cmParseGTMCoverage.cxx b/Source/CTest/cmParseGTMCoverage.cxx new file mode 100644 index 0000000..f965048 --- /dev/null +++ b/Source/CTest/cmParseGTMCoverage.cxx @@ -0,0 +1,244 @@ +#include "cmParseGTMCoverage.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 <vector> + +cmParseGTMCoverage::cmParseGTMCoverage(cmCTestCoverageHandlerContainer& cont, + cmCTest* ctest) + : cmParseMumpsCoverage(cont, ctest) +{ +} + +bool cmParseGTMCoverage::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) == ".mcov") { + if (!this->ReadMCovFile(path.c_str())) { + return false; + } + } + } + } + return true; +} + +bool cmParseGTMCoverage::ReadMCovFile(const char* file) +{ + cmsys::ifstream in(file); + if (!in) { + return false; + } + std::string line; + std::string lastfunction; + std::string lastroutine; + std::string lastpath; + int lastoffset = 0; + while (cmSystemTools::GetLineFromStream(in, line)) { + // only look at lines that have coverage data + if (line.find("^ZZCOVERAGE") == std::string::npos) { + continue; + } + std::string filepath; + std::string function; + std::string routine; + int linenumber = 0; + int count = 0; + this->ParseMCOVLine(line, routine, function, linenumber, count); + // skip this one + if (routine == "RSEL") { + continue; + } + // no need to search the file if we just did it + if (function == lastfunction && lastroutine == routine) { + if (!lastpath.empty()) { + this->Coverage.TotalCoverage[lastpath][lastoffset + linenumber] += + count; + } else { + cmCTestLog(this->CTest, ERROR_MESSAGE, "Can not find mumps file : " + << lastroutine + << " referenced in this line of mcov data:\n" + "[" + << line << "]\n"); + } + continue; + } + // Find the full path to the file + bool found = this->FindMumpsFile(routine, filepath); + if (found) { + int lineoffset = 0; + if (this->FindFunctionInMumpsFile(filepath, function, lineoffset)) { + cmCTestCoverageHandlerContainer::SingleFileCoverageVector& + coverageVector = this->Coverage.TotalCoverage[filepath]; + // This section 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[lineoffset + linenumber] == -1 && count > 0) { + coverageVector[lineoffset + linenumber] += count + 1; + } else { + coverageVector[lineoffset + linenumber] += count; + } + lastoffset = lineoffset; + } + } else { + cmCTestLog(this->CTest, ERROR_MESSAGE, "Can not find mumps file : " + << routine << " referenced in this line of mcov data:\n" + "[" + << line << "]\n"); + } + lastfunction = function; + lastroutine = routine; + lastpath = filepath; + } + return true; +} + +bool cmParseGTMCoverage::FindFunctionInMumpsFile(std::string const& filepath, + std::string const& function, + int& lineoffset) +{ + cmsys::ifstream in(filepath.c_str()); + if (!in) { + return false; + } + std::string line; + int linenum = 0; + while (cmSystemTools::GetLineFromStream(in, line)) { + std::string::size_type pos = line.find(function); + if (pos == 0) { + char nextchar = line[function.size()]; + if (nextchar == ' ' || nextchar == '(' || nextchar == '\t') { + lineoffset = linenum; + return true; + } + } + if (pos == 1) { + char prevchar = line[0]; + char nextchar = line[function.size() + 1]; + if (prevchar == '%' && (nextchar == ' ' || nextchar == '(')) { + lineoffset = linenum; + return true; + } + } + linenum++; // move to next line count + } + lineoffset = 0; + cmCTestLog(this->CTest, ERROR_MESSAGE, "Could not find entry point : " + << function << " in " << filepath << "\n"); + return false; +} + +bool cmParseGTMCoverage::ParseMCOVLine(std::string const& line, + std::string& routine, + std::string& function, int& linenumber, + int& count) +{ + // this method parses lines from the .mcov file + // each line has ^COVERAGE(...) in it, and there + // are several varients of coverage lines: + // + // ^COVERAGE("DIC11","PR1",0)="2:0:0:0" + // ( file , entry, line ) = "number_executed:timing_info" + // ^COVERAGE("%RSEL","SRC")="1:0:0:0" + // ( file , entry ) = "number_executed:timing_info" + // ^COVERAGE("%RSEL","init",8,"FOR_LOOP",1)=1 + // ( file , entry, line, IGNORE ) =number_executed + std::vector<std::string> args; + std::string::size_type pos = line.find('(', 0); + // if no ( is found, then return line has no coverage + if (pos == std::string::npos) { + return false; + } + std::string arg; + bool done = false; + // separate out all of the comma separated arguments found + // in the COVERAGE(...) line + while (line[pos] && !done) { + // save the char we are looking at + char cur = line[pos]; + // , or ) means end of argument + if (cur == ',' || cur == ')') { + // save the argument into the argument vector + args.push_back(arg); + // start on a new argument + arg.clear(); + // if we are at the end of the ), then finish while loop + if (cur == ')') { + done = true; + } + } else { + // all chars except ", (, and % get stored in the arg string + if (cur != '\"' && cur != '(' && cur != '%') { + arg.append(1, line[pos]); + } + } + // move to next char + pos++; + } + // now parse the right hand side of the = + pos = line.find('='); + // no = found, this is an error + if (pos == std::string::npos) { + return false; + } + pos++; // move past = + + // if the next positing is not a ", then this is a + // COVERAGE(..)=count line and turn the rest of the string + // past the = into an integer and set it to count + if (line[pos] != '\"') { + count = atoi(line.substr(pos).c_str()); + } else { + // this means line[pos] is a ", and we have a + // COVERAGE(...)="1:0:0:0" type of line + pos++; // move past " + // find the first : past the " + std::string::size_type pos2 = line.find(':', pos); + // turn the string between the " and the first : into an integer + // and set it to count + count = atoi(line.substr(pos, pos2 - pos).c_str()); + } + // less then two arguments is an error + if (args.size() < 2) { + cmCTestLog(this->CTest, ERROR_MESSAGE, "Error parsing mcov line: [" + << line << "]\n"); + return false; + } + routine = args[0]; // the routine is the first argument + function = args[1]; // the function in the routine is the second + // in the two argument only format + // ^COVERAGE("%RSEL","SRC"), the line offset is 0 + if (args.size() == 2) { + // To avoid double counting of line 0 of each entry point, + // Don't count the lines that do not give an explicit line + // number. + routine.clear(); + function.clear(); + } else { + // this is the format for this line + // ^COVERAGE("%RSEL","SRC",count) + linenumber = atoi(args[2].c_str()); + } + return true; +} |