| #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; |
| } |