diff options
Diffstat (limited to 'Source/CTest/cmParseJacocoCoverage.cxx')
-rw-r--r-- | Source/CTest/cmParseJacocoCoverage.cxx | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/Source/CTest/cmParseJacocoCoverage.cxx b/Source/CTest/cmParseJacocoCoverage.cxx new file mode 100644 index 0000000..7acb5ca --- /dev/null +++ b/Source/CTest/cmParseJacocoCoverage.cxx @@ -0,0 +1,181 @@ +#include "cmParseJacocoCoverage.h" + +#include "cmCTest.h" +#include "cmCTestCoverageHandler.h" +#include "cmSystemTools.h" +#include "cmXMLParser.h" + +#include "cmsys/Directory.hxx" +#include "cmsys/FStream.hxx" +#include "cmsys/Glob.hxx" +#include <stdlib.h> +#include <string.h> + +class cmParseJacocoCoverage::XMLParser : public cmXMLParser +{ +public: + XMLParser(cmCTest* ctest, cmCTestCoverageHandlerContainer& cont) + : CTest(ctest) + , Coverage(cont) + { + this->FilePath.clear(); + this->PackagePath.clear(); + this->PackageName.clear(); + } + + ~XMLParser() override {} + +protected: + void EndElement(const std::string& /*name*/) override {} + + void StartElement(const std::string& name, const char** atts) override + { + if (name == "package") { + this->PackageName = atts[1]; + this->PackagePath.clear(); + } else if (name == "sourcefile") { + std::string fileName = atts[1]; + + if (this->PackagePath.empty()) { + if (!this->FindPackagePath(fileName)) { + cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot find file: " + << this->PackageName << "/" << fileName << std::endl); + this->Coverage.Error++; + return; + } + } + + cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, + "Reading file: " << fileName << std::endl, + this->Coverage.Quiet); + + this->FilePath = this->PackagePath + "/" + fileName; + cmsys::ifstream fin(this->FilePath.c_str()); + if (!fin) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Jacoco Coverage: Error opening " << this->FilePath + << std::endl); + } + std::string line; + FileLinesType& curFileLines = + this->Coverage.TotalCoverage[this->FilePath]; + if (fin) { + curFileLines.push_back(-1); + } + while (cmSystemTools::GetLineFromStream(fin, line)) { + curFileLines.push_back(-1); + } + } else if (name == "line") { + int tagCount = 0; + int nr = -1; + int ci = -1; + while (true) { + if (strcmp(atts[tagCount], "ci") == 0) { + ci = atoi(atts[tagCount + 1]); + } else if (strcmp(atts[tagCount], "nr") == 0) { + nr = atoi(atts[tagCount + 1]); + } + if (ci > -1 && nr > 0) { + FileLinesType& curFileLines = + this->Coverage.TotalCoverage[this->FilePath]; + if (!curFileLines.empty()) { + curFileLines[nr - 1] = ci; + } + break; + } + ++tagCount; + } + } + } + + virtual bool FindPackagePath(std::string const& fileName) + { + // Search for the source file in the source directory. + if (this->PackagePathFound(fileName, this->Coverage.SourceDir)) { + return true; + } + + // If not found there, check the binary directory. + if (this->PackagePathFound(fileName, this->Coverage.BinaryDir)) { + return true; + } + return false; + } + + virtual bool PackagePathFound(std::string const& fileName, + std::string const& baseDir) + { + // Search for the file in the baseDir and its subdirectories. + std::string packageGlob = baseDir; + packageGlob += "/"; + packageGlob += fileName; + cmsys::Glob gl; + gl.RecurseOn(); + gl.RecurseThroughSymlinksOn(); + gl.FindFiles(packageGlob); + std::vector<std::string> const& files = gl.GetFiles(); + if (files.empty()) { + return false; + } + + // Check if any of the locations found match our package. + for (std::string const& f : files) { + std::string dir = cmsys::SystemTools::GetParentDirectory(f); + if (cmsys::SystemTools::StringEndsWith(dir, this->PackageName.c_str())) { + cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, + "Found package directory for " << fileName << ": " + << dir << std::endl, + this->Coverage.Quiet); + this->PackagePath = dir; + return true; + } + } + return false; + } + +private: + std::string FilePath; + std::string PackagePath; + std::string PackageName; + typedef cmCTestCoverageHandlerContainer::SingleFileCoverageVector + FileLinesType; + cmCTest* CTest; + cmCTestCoverageHandlerContainer& Coverage; +}; + +cmParseJacocoCoverage::cmParseJacocoCoverage( + cmCTestCoverageHandlerContainer& cont, cmCTest* ctest) + : Coverage(cont) + , CTest(ctest) +{ +} + +bool cmParseJacocoCoverage::LoadCoverageData( + std::vector<std::string> const& files) +{ + // load all the jacoco.xml files in the source directory + cmsys::Directory dir; + size_t i; + std::string path; + size_t numf = files.size(); + for (i = 0; i < numf; i++) { + path = files[i]; + + cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, + "Reading XML File " << path << std::endl, + this->Coverage.Quiet); + if (cmSystemTools::GetFilenameLastExtension(path) == ".xml") { + if (!this->ReadJacocoXML(path.c_str())) { + return false; + } + } + } + return true; +} + +bool cmParseJacocoCoverage::ReadJacocoXML(const char* file) +{ + cmParseJacocoCoverage::XMLParser parser(this->CTest, this->Coverage); + parser.ParseFile(file); + return true; +} |