diff options
Diffstat (limited to 'Source/CTest/cmParseGTMCoverage.cxx')
-rw-r--r-- | Source/CTest/cmParseGTMCoverage.cxx | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/Source/CTest/cmParseGTMCoverage.cxx b/Source/CTest/cmParseGTMCoverage.cxx new file mode 100644 index 0000000..d77244a --- /dev/null +++ b/Source/CTest/cmParseGTMCoverage.cxx @@ -0,0 +1,289 @@ +#include "cmStandardIncludes.h" +#include <stdio.h> +#include <stdlib.h> +#include "cmSystemTools.h" +#include "cmParseGTMCoverage.h" +#include <cmsys/Directory.hxx> +#include <cmsys/Glob.hxx> +#include <cmsys/FStream.hxx> + + +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") == line.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.size()) + { + 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 addtion 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.c_str()); + 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 = ""; + // 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 == line.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=""; + function=""; + } + else + { + // this is the format for this line + // ^COVERAGE("%RSEL","SRC",count) + linenumber = atoi(args[2].c_str()); + } + return true; +} |