Selaa lähdekoodia

CTest: Add Jacoco Coverage functionality

Add the ability to parse the XML output of the Jacoco tool.

Jacoco (www.eclemma.org/jacoco) is a Java coverage tool.
Add and integrate a class for the parser and
include a test which utilizes the new parser.
Joseph Snyder 11 vuotta sitten
vanhempi
sitoutus
558c2190e8

+ 1 - 0
Source/CMakeLists.txt

@@ -518,6 +518,7 @@ set(CTEST_SRCS cmCTest.cxx
   CTest/cmParseMumpsCoverage.cxx
   CTest/cmParseCacheCoverage.cxx
   CTest/cmParseGTMCoverage.cxx
+  CTest/cmParseJacocoCoverage.cxx
   CTest/cmParsePHPCoverage.cxx
   CTest/cmParseCoberturaCoverage.cxx
   CTest/cmCTestEmptyBinaryDirectoryCommand.cxx

+ 40 - 0
Source/CTest/cmCTestCoverageHandler.cxx

@@ -14,6 +14,7 @@
 #include "cmParseCoberturaCoverage.h"
 #include "cmParseGTMCoverage.h"
 #include "cmParseCacheCoverage.h"
+#include "cmParseJacocoCoverage.h"
 #include "cmCTest.h"
 #include "cmake.h"
 #include "cmMakefile.h"
@@ -415,6 +416,13 @@ int cmCTestCoverageHandler::ProcessHandler()
     return error;
     }
 
+  file_count += this->HandleJacocoCoverage(&cont);
+  error = cont.Error;
+  if ( file_count < 0 )
+    {
+    return error;
+    }
+
   std::set<std::string> uncovered = this->FindUncoveredFiles(&cont);
 
   if ( file_count == 0 )
@@ -871,6 +879,38 @@ struct cmCTestCoverageHandlerLocale
   std::string lc_all;
 };
 
+//----------------------------------------------------------------------
+int cmCTestCoverageHandler::HandleJacocoCoverage(
+  cmCTestCoverageHandlerContainer* cont)
+{
+  cmParseJacocoCoverage cov =
+   cmParseJacocoCoverage(*cont, this->CTest);
+  cmsys::Glob g;
+  std::vector<std::string> files;
+  g.SetRecurse(true);
+
+  std::string SourceDir
+    = this->CTest->GetCTestConfiguration("SourceDirectory");
+  std::string coverageFile = SourceDir+ "/*jacoco.xml";
+
+  g.FindFiles(coverageFile);
+  files=g.GetFiles();
+  if (files.size() > 0)
+    {
+    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+      "Found Jacoco Files, Performing Coverage" << std::endl);
+    cov.LoadCoverageData(files);
+    }
+  else
+    {
+    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
+      " Cannot find Jacoco coverage files: " << coverageFile
+      << std::endl);
+    }
+  return static_cast<int>(cont->TotalCoverage.size());
+}
+
+
 //----------------------------------------------------------------------
 int cmCTestCoverageHandler::HandleGCovCoverage(
   cmCTestCoverageHandlerContainer* cont)

+ 4 - 1
Source/CTest/cmCTestCoverageHandler.h

@@ -81,7 +81,10 @@ private:
   //! Handle coverage for mumps
   int HandleMumpsCoverage(cmCTestCoverageHandlerContainer* cont);
 
-  //! Handle coverage using Bullseye
+  //! Handle coverage for Jacoco
+  int HandleJacocoCoverage(cmCTestCoverageHandlerContainer* cont);
+
+//! Handle coverage using Bullseye
   int HandleBullseyeCoverage(cmCTestCoverageHandlerContainer* cont);
   int RunBullseyeSourceSummary(cmCTestCoverageHandlerContainer* cont);
   int RunBullseyeCoverageBranch(cmCTestCoverageHandlerContainer* cont,

+ 167 - 0
Source/CTest/cmParseJacocoCoverage.cxx

@@ -0,0 +1,167 @@
+#include "cmStandardIncludes.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "cmSystemTools.h"
+#include "cmXMLParser.h"
+#include "cmParseJacocoCoverage.h"
+#include <cmsys/Directory.hxx>
+#include <cmsys/Glob.hxx>
+#include <cmsys/FStream.hxx>
+
+
+class cmParseJacocoCoverage::XMLParser: public cmXMLParser
+{
+  public:
+    XMLParser(cmCTest* ctest, cmCTestCoverageHandlerContainer& cont)
+      : CTest(ctest), Coverage(cont)
+      {
+      this->PackageName = "";
+      this->ModuleName = "";
+      this->FileName = "";
+      this->CurFileName = "";
+      this->FilePaths.push_back(this->Coverage.SourceDir);
+      }
+
+    virtual ~XMLParser()
+      {
+      }
+
+  protected:
+
+    virtual void EndElement(const std::string&)
+      {
+      }
+
+    virtual void StartElement(const std::string& name,
+      const char** atts)
+      {
+      if(name == "package")
+        {
+        this->PackageName = atts[1];
+        std::string FilePath = this->Coverage.SourceDir +
+          "/" + this->ModuleName + "/src/main/java/" +
+          this->PackageName;
+        this->FilePaths.push_back(FilePath);
+        }
+      else if(name == "sourcefile")
+        {
+        this->FileName = atts[1];
+        cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Reading file: "
+                     << this->FileName << std::endl);
+          for(size_t i=0;i < FilePaths.size();i++)
+            {
+            std::string finalpath = FilePaths[i] + "/" + this->FileName;
+            if(cmSystemTools::FileExists(finalpath.c_str()))
+              {
+              this->CurFileName = finalpath;
+              break;
+              }
+            }
+          cmsys::ifstream fin(this->CurFileName.c_str());
+          if(this->CurFileName == "" || !fin )
+          {
+            this->CurFileName = this->Coverage.BinaryDir + "/" +
+                                   this->FileName;
+            fin.open(this->CurFileName.c_str());
+            if (!fin)
+            {
+              cmCTestLog(this->CTest, ERROR_MESSAGE,
+                         "Jacoco Coverage: Error opening " << this->CurFileName
+                         << std::endl);
+              this->Coverage.Error++;
+            }
+          }
+          std::string line;
+          FileLinesType& curFileLines =
+            this->Coverage.TotalCoverage[this->CurFileName];
+          curFileLines.push_back(-1);
+          while(cmSystemTools::GetLineFromStream(fin, line))
+          {
+            curFileLines.push_back(-1);
+          }
+        }
+      else if(name == "report")
+        {
+        this->ModuleName=atts[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->CurFileName];
+            if(curFileLines.size() > 0)
+               {
+               curFileLines[nr-1] = ci;
+               }
+            break;
+            }
+          ++tagCount;
+          }
+        }
+      }
+
+  private:
+    std::string PackageName;
+    std::string FileName;
+    std::string ModuleName;
+    std::string CurFileName;
+    std::vector<std::string> FilePaths;
+    typedef cmCTestCoverageHandlerContainer::SingleFileCoverageVector
+     FileLinesType;
+    cmCTest* CTest;
+    cmCTestCoverageHandlerContainer& Coverage;
+};
+
+cmParseJacocoCoverage::cmParseJacocoCoverage(
+  cmCTestCoverageHandlerContainer& cont,
+  cmCTest* ctest)
+  :Coverage(cont), CTest(ctest)
+  {
+  }
+
+bool cmParseJacocoCoverage::LoadCoverageData(
+  const std::vector<std::string> 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];
+
+    cmCTestLog(this->CTest,HANDLER_VERBOSE_OUTPUT,
+      "Reading XML File " << path  << std::endl);
+    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;
+}

+ 59 - 0
Source/CTest/cmParseJacocoCoverage.h

@@ -0,0 +1,59 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2000-2009 Kitware, Inc.
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+
+#ifndef cmParseJacocoCoverage_h
+#define cmParseJacocoCoverage_h
+
+#include "cmStandardIncludes.h"
+#include "cmCTestCoverageHandler.h"
+
+
+/** \class cmParseJacocoCoverage
+ * \brief Parse JaCoCO coverage information
+ *
+ * This class is used to parse coverage information for
+ * java using the JaCoCo tool:
+ *
+ * http://www.eclemma.org/jacoco/trunk/index.html
+ */
+class cmParseJacocoCoverage
+{
+public:
+  cmParseJacocoCoverage(cmCTestCoverageHandlerContainer& cont,
+    cmCTest* ctest);
+  bool LoadCoverageData(const std::vector<std::string> files);
+
+  std::string PackageName;
+  std::string FileName;
+  std::string ModuleName;
+  std::string CurFileName;
+private:
+  // implement virtual from parent
+  // remove files with no coverage
+  void RemoveUnCoveredFiles();
+  // Read a single mcov file
+  bool ReadJacocoXML(const char* f);
+  // split a string based on ,
+  bool SplitString(std::vector<std::string>& args,
+    std::string const& line);
+  bool FindJavaFile(std::string const& routine,
+    std::string& filepath);
+  void InitializeJavaFile(std::string& file);
+  bool LoadSource(std::string d);
+
+  class XMLParser;
+  std::map<std::string, std::string> RoutineToDirectory;
+  cmCTestCoverageHandlerContainer& Coverage;
+  cmCTest* CTest;
+};
+
+#endif

+ 16 - 0
Tests/CMakeLists.txt

@@ -2202,6 +2202,22 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
       "Process file.*CoverageTest.java.*Total LOC:.*18.*Percentage Coverage: 72.22.*"
       ENVIRONMENT COVFILE=)
 
+
+  # Adding a test case for JaCoCo Coverage
+  configure_file(
+     "${CMake_SOURCE_DIR}/Tests/JacocoCoverage/DartConfiguration.tcl.in"
+     "${CMake_BINARY_DIR}/Testing/JacocoCoverage/DartConfiguration.tcl")
+  file(COPY "${CMake_SOURCE_DIR}/Tests/JacocoCoverage/Coverage"
+    DESTINATION "${CMake_BINARY_DIR}/Testing/JacocoCoverage")
+  add_test(NAME CTestJacocoCoverage
+    COMMAND cmake -E chdir
+    ${CMake_BINARY_DIR}/Testing/JacocoCoverage
+    $<TARGET_FILE:ctest> -T Coverage --debug)
+  set_tests_properties(CTestJacocoCoverage PROPERTIES
+      PASS_REGULAR_EXPRESSION
+      "Process file.*CoverageTest.java.*Total LOC:.*17.*Percentage Coverage: 76.47*"
+      ENVIRONMENT COVFILE=)
+
   function(add_config_tests cfg)
     set(base "${CMake_BINARY_DIR}/Tests/CTestConfig")
 

+ 52 - 0
Tests/JacocoCoverage/Coverage/src/main/java/org/cmake/CoverageTest.java

@@ -0,0 +1,52 @@
+package org.cmake.Coverage;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.List;
+import java.awt.*;
+
+public class CoverageTest {
+
+  public static String VarOne = "test1";
+  public static String VarTwo = "test2";
+  private Integer IntOne = 4;
+
+  public static Boolean equalsVarOne(String inString) {
+
+    if(VarOne.equals(inString)){
+      return true;
+    }
+    else {
+      return false;
+    }
+  }
+
+  public static boolean equalsVarTwo(String inString){
+
+    if(VarTwo.equals(inString)){
+      return true;
+    }
+    else {
+      return false;
+    }
+  }
+
+  private Integer timesIntOne(Integer inVal){
+
+    return inVal * IntOne;
+  }
+
+  public static boolean whileLoop(Integer StopInt){
+
+    Integer i = 0;
+    while(i < StopInt){
+      i=i+1;
+    }
+    if (i.equals(5)){
+     return true;
+    }
+    else {
+     return false;
+    }
+  }
+}

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 0
Tests/JacocoCoverage/Coverage/target/site/jacoco.xml


+ 8 - 0
Tests/JacocoCoverage/DartConfiguration.tcl.in

@@ -0,0 +1,8 @@
+# This file is configured by CMake automatically as DartConfiguration.tcl
+# If you choose not to use CMake, this file may be hand configured, by
+# filling in the required variables.
+
+
+# Configuration directories and files
+SourceDirectory: ${CMake_BINARY_DIR}/Testing/JacocoCoverage
+BuildDirectory: ${CMake_BINARY_DIR}/Testing/JacocoCoverage

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä