]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-2792 Import code of JaCoCo plugin from Plugins Forge
authorEvgeny Mandrikov <mandrikov@gmail.com>
Thu, 13 Oct 2011 21:05:25 +0000 (01:05 +0400)
committerEvgeny Mandrikov <mandrikov@gmail.com>
Thu, 13 Oct 2011 21:48:01 +0000 (01:48 +0400)
Revision 4564.

39 files changed:
plugins/sonar-jacoco-plugin/pom.xml [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/AbstractAnalyzer.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoAgentDownloader.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoMavenPluginHandler.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoPlugin.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoSensor.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoUtils.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JacocoAntInitializer.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JacocoConfiguration.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JacocoMavenInitializer.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/AbstractCoverageDecorator.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/ItBranchCoverageDecorator.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/ItCoverageDecorator.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/ItCoverageWidget.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/ItLineCoverageDecorator.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/JaCoCoItMetrics.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/JaCoCoItSensor.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/viewer/CoverageViewerDefinition.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/viewer/client/CoveragePanel.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/viewer/client/CoverageViewer.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/viewer/client/Metrics.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/main/resources/org/sonar/plugins/jacoco/itcoverage/viewer/CoverageViewer.gwt.xml [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/main/resources/org/sonar/plugins/jacoco/itcoverage/widget.html.erb [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/AbstractAnalyzerTest.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/JaCoCoMavenPluginHandlerTest.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/JaCoCoPluginTest.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/JaCoCoSensorTest.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/JacocoConfigurationTest.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/JacocoMavenInitializerTest.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/itcoverage/ItCoverageWidgetTest.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/itcoverage/JaCoCoItMetricsTest.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/itcoverage/JaCoCoItSensorTest.java [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/test/resources/org/sonar/plugins/jacoco/JaCoCoMavenPluginHandlerTest/pom.xml [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/test/resources/org/sonar/plugins/jacoco/JaCoCoMavenPluginHandlerTest/pom2.xml [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/test/resources/org/sonar/plugins/jacoco/JaCoCoSensorTest/Hello.class [new file with mode: 0644]
plugins/sonar-jacoco-plugin/src/test/resources/org/sonar/plugins/jacoco/JaCoCoSensorTest/jacoco.exec [new file with mode: 0644]
pom.xml
sonar-application/pom.xml
sonar-server/pom.xml

diff --git a/plugins/sonar-jacoco-plugin/pom.xml b/plugins/sonar-jacoco-plugin/pom.xml
new file mode 100644 (file)
index 0000000..ba44b83
--- /dev/null
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.codehaus.sonar</groupId>
+    <artifactId>sonar</artifactId>
+    <version>2.12-SNAPSHOT</version>
+    <relativePath>../..</relativePath>
+  </parent>
+
+  <groupId>org.codehaus.sonar.plugins</groupId>
+  <artifactId>sonar-jacoco-plugin</artifactId>
+  <packaging>sonar-plugin</packaging>
+
+  <name>Sonar :: Plugins :: JaCoCo</name>
+  <description>JaCoCo is an alternative to Clover and Cobertura to measure coverage by unit tests.</description>
+  <url>http://docs.codehaus.org/display/SONAR/JaCoCo+Plugin</url>
+  <inceptionYear>2010</inceptionYear>
+  <organization>
+    <name>SonarSource</name>
+    <url>http://www.sonarsource.com</url>
+  </organization>
+  <licenses>
+    <license>
+      <name>GNU LGPL 3</name>
+      <url>http://www.gnu.org/licenses/lgpl.txt</url>
+      <distribution>repo</distribution>
+    </license>
+  </licenses>
+
+  <developers>
+    <developer>
+      <id>godin</id>
+      <name>Evgeny Mandrikov</name>
+    </developer>
+  </developers>
+
+  <properties>
+    <jacoco.version>0.5.3.201107060350</jacoco.version>
+
+    <sonar.pluginName>JaCoCo</sonar.pluginName>
+    <sonar.pluginClass>org.sonar.plugins.jacoco.JaCoCoPlugin</sonar.pluginClass>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.jacoco</groupId>
+      <artifactId>org.jacoco.core</artifactId>
+      <version>${jacoco.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.jacoco</groupId>
+      <artifactId>org.jacoco.agent</artifactId>
+      <version>${jacoco.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.sonar</groupId>
+      <artifactId>sonar-plugin-api</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.sonar</groupId>
+      <artifactId>sonar-gwt-api</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <!-- Would be provided by environment -->
+    <dependency>
+      <groupId>org.apache.ant</groupId>
+      <artifactId>ant</artifactId>
+      <version>1.7.0</version>
+      <scope>provided</scope>
+    </dependency>
+    <!-- unit tests -->
+    <dependency>
+      <groupId>org.codehaus.sonar</groupId>
+      <artifactId>sonar-testing-harness</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-project</artifactId>
+      <version>2.0.7</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <!-- TODO Godin: investigate why doesn't work without declaration of this plugin here -->
+      <plugin>
+        <groupId>org.codehaus.sonar</groupId>
+        <artifactId>sonar-packaging-maven-plugin</artifactId>
+        <extensions>true</extensions>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>gwt-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <configuration>
+              <modules>
+                <module>org.sonar.plugins.jacoco.itcoverage.viewer.CoverageViewer</module>
+              </modules>
+                <skip>${skipGwt}</skip>
+              <webappDirectory>${project.build.directory}/classes</webappDirectory>
+
+              <!-- do not break on two lines -->
+              <extraJvmArgs>${extraJvmArgs}</extraJvmArgs>
+            </configuration>
+            <goals>
+              <goal>compile</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.sonar</groupId>
+        <artifactId>sonar-dev-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>trim</id>
+            <phase>process-resources</phase>
+            <goals>
+              <goal>trim</goal>
+            </goals>
+            <configuration>
+              <directory>${project.build.outputDirectory}</directory>
+              <includes>
+                <include>**/*.erb</include>
+              </includes>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/AbstractAnalyzer.java b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/AbstractAnalyzer.java
new file mode 100644 (file)
index 0000000..2b226f2
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco;
+
+import org.apache.commons.lang.StringUtils;
+import org.jacoco.core.analysis.*;
+import org.jacoco.core.data.ExecutionDataReader;
+import org.jacoco.core.data.ExecutionDataStore;
+import org.jacoco.core.data.SessionInfoStore;
+import org.sonar.api.batch.SensorContext;
+import org.sonar.api.measures.CoverageMeasuresBuilder;
+import org.sonar.api.measures.Measure;
+import org.sonar.api.resources.JavaFile;
+import org.sonar.api.resources.Project;
+import org.sonar.api.utils.SonarException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Collection;
+
+/**
+ * @author Evgeny Mandrikov
+ */
+public abstract class AbstractAnalyzer {
+
+  public final void analyse(Project project, SensorContext context) {
+    final File buildOutputDir = project.getFileSystem().getBuildOutputDir();
+    if (!buildOutputDir.exists()) {
+      JaCoCoUtils.LOG.info("Can't find build output directory: {}. Skipping JaCoCo analysis.", buildOutputDir);
+      return;
+    }
+    String path = getReportPath(project);
+    File jacocoExecutionData = project.getFileSystem().resolvePath(path);
+    try {
+      readExecutionData(jacocoExecutionData, buildOutputDir, context);
+    } catch (IOException e) {
+      throw new SonarException(e);
+    }
+  }
+
+  public final void readExecutionData(File jacocoExecutionData, File buildOutputDir, SensorContext context) throws IOException {
+    SessionInfoStore sessionInfoStore = new SessionInfoStore();
+    ExecutionDataStore executionDataStore = new ExecutionDataStore();
+
+    if (jacocoExecutionData == null || !jacocoExecutionData.exists() || !jacocoExecutionData.isFile()) {
+      JaCoCoUtils.LOG.info("Can't find JaCoCo execution data : {}. Project coverage is set to 0%.", jacocoExecutionData);
+    } else {
+      JaCoCoUtils.LOG.info("Analysing {}", jacocoExecutionData);
+      ExecutionDataReader reader = new ExecutionDataReader(new FileInputStream(jacocoExecutionData));
+      reader.setSessionInfoVisitor(sessionInfoStore);
+      reader.setExecutionDataVisitor(executionDataStore);
+      reader.read();
+    }
+
+    CoverageBuilder coverageBuilder = new CoverageBuilder();
+    Analyzer analyzer = new Analyzer(executionDataStore, coverageBuilder);
+    analyzeAll(analyzer, buildOutputDir);
+
+    int analyzedResources = 0;
+    for (ISourceFileCoverage coverage : coverageBuilder.getSourceFiles()) {
+      JavaFile resource = getResource(coverage);
+      // Do not save measures on resource which doesn't exist in the context
+      if (context.getResource(resource) != null) {
+        analyzeFile(resource, coverage, context);
+        analyzedResources++;
+      }
+    }
+    if (analyzedResources == 0) {
+      JaCoCoUtils.LOG.warn("Coverage information was not collected. Perhaps you forget to include debug information into compiled classes?");
+    }
+  }
+
+  static JavaFile getResource(ISourceFileCoverage coverage) {
+    String packageName = StringUtils.replaceChars(coverage.getPackageName(), '/', '.');
+    String fileName = StringUtils.substringBeforeLast(coverage.getName(), ".");
+    return new JavaFile(packageName, fileName);
+  }
+
+  /**
+   * Copied from {@link Analyzer#analyzeAll(File)} in order to add logging.
+   */
+  private void analyzeAll(Analyzer analyzer, File file) {
+    if (file.isDirectory()) {
+      for (File f : file.listFiles()) {
+        analyzeAll(analyzer, f);
+      }
+    } else {
+      try {
+        analyzer.analyzeAll(file);
+      } catch (Exception e) {
+        JaCoCoUtils.LOG.warn("Exception during analysis of file " + file.getAbsolutePath(), e);
+      }
+    }
+  }
+
+  private void analyzeFile(JavaFile resource, ISourceFileCoverage coverage, SensorContext context) {
+    CoverageMeasuresBuilder builder = CoverageMeasuresBuilder.create();
+    for (int lineId = coverage.getFirstLine(); lineId <= coverage.getLastLine(); lineId++) {
+      final int hits;
+      ILine line = coverage.getLine(lineId);
+      switch (line.getInstructionCounter().getStatus()) {
+        case ICounter.FULLY_COVERED:
+        case ICounter.PARTLY_COVERED:
+          hits = 1;
+          break;
+        case ICounter.NOT_COVERED:
+          hits = 0;
+          break;
+        case ICounter.EMPTY:
+          continue;
+        default:
+          JaCoCoUtils.LOG.warn("Unknown status for line {} in {}", lineId, resource);
+          continue;
+      }
+      builder.setHits(lineId, hits);
+
+      ICounter branchCounter = line.getBranchCounter();
+      int conditions = branchCounter.getTotalCount();
+      if (conditions > 0) {
+        int coveredConditions = branchCounter.getCoveredCount();
+        builder.setConditions(lineId, conditions, coveredConditions);
+      }
+    }
+
+    saveMeasures(context, resource, builder.createMeasures());
+  }
+
+  protected abstract void saveMeasures(SensorContext context, JavaFile resource, Collection<Measure> measures);
+
+  protected abstract String getReportPath(Project project);
+
+}
diff --git a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoAgentDownloader.java b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoAgentDownloader.java
new file mode 100644 (file)
index 0000000..30589df
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco;
+
+import org.apache.commons.io.FileUtils;
+import org.jacoco.agent.AgentJar;
+import org.jacoco.core.JaCoCo;
+import org.sonar.api.BatchExtension;
+import org.sonar.api.utils.SonarException;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * @author Evgeny Mandrikov
+ */
+public class JaCoCoAgentDownloader implements BatchExtension {
+
+  /**
+   * Dirty hack, but it allows to extract agent only once during Sonar analyzes for multi-module project.
+   */
+  private static File agentJarFile;
+
+  public JaCoCoAgentDownloader() {
+  }
+
+  public synchronized File getAgentJarFile() {
+    if (agentJarFile == null) {
+      agentJarFile = extractAgent();
+    }
+    return agentJarFile;
+  }
+
+  private File extractAgent() {
+    try {
+      File agent = File.createTempFile("jacocoagent", ".jar");
+      AgentJar.extractTo(agent);
+      FileUtils.forceDeleteOnExit(agent); // TODO evil method
+      JaCoCoUtils.LOG.info("JaCoCo agent (version " + JaCoCo.VERSION + ") extracted: {}", agent);
+      return agent;
+    } catch (IOException e) {
+      throw new SonarException(e);
+    }
+  }
+}
diff --git a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoMavenPluginHandler.java b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoMavenPluginHandler.java
new file mode 100644 (file)
index 0000000..522dd14
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco;
+
+import java.io.File;
+
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.batch.maven.MavenPlugin;
+import org.sonar.api.batch.maven.MavenPluginHandler;
+import org.sonar.api.batch.maven.MavenSurefireUtils;
+import org.sonar.api.resources.Project;
+import org.sonar.api.utils.SonarException;
+
+/**
+ * @author Evgeny Mandrikov
+ */
+public class JaCoCoMavenPluginHandler implements MavenPluginHandler {
+
+  private static final String ARG_LINE_PARAMETER = "argLine";
+  private static final String TEST_FAILURE_IGNORE_PARAMETER = "testFailureIgnore";
+
+  private final String groupId;
+  private final String artifactId;
+  private final String version;
+
+  private JacocoConfiguration configuration;
+
+  public JaCoCoMavenPluginHandler(JacocoConfiguration configuration) {
+    this.configuration = configuration;
+    groupId = MavenSurefireUtils.GROUP_ID;
+    artifactId = MavenSurefireUtils.ARTIFACT_ID;
+    version = MavenSurefireUtils.VERSION;
+  }
+
+  public String getGroupId() {
+    return groupId;
+  }
+
+  public String getArtifactId() {
+    return artifactId;
+  }
+
+  public String getVersion() {
+    return version;
+  }
+
+  public boolean isFixedVersion() {
+    return false;
+  }
+
+  public String[] getGoals() {
+    return new String[] { "test" };
+  }
+
+  public void configure(Project project, MavenPlugin plugin) {
+    // See SONARPLUGINS-600
+    String destfilePath = configuration.getReportPath();
+    File destfile = project.getFileSystem().resolvePath(destfilePath);
+    if (destfile.exists() && destfile.isFile()) {
+      JaCoCoUtils.LOG.info("Deleting {}", destfile);
+      if (!destfile.delete()) {
+        throw new SonarException("Unable to delete " + destfile);
+      }
+    }
+
+    String argument = configuration.getJvmArgument();
+
+    String argLine = plugin.getParameter(ARG_LINE_PARAMETER);
+    argLine = StringUtils.isBlank(argLine) ? argument : argument + " " + argLine;
+    JaCoCoUtils.LOG.info("JVM options: {}", argLine);
+    plugin.setParameter(ARG_LINE_PARAMETER, argLine);
+
+    plugin.setParameter(TEST_FAILURE_IGNORE_PARAMETER, "true");
+  }
+
+}
diff --git a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoPlugin.java b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoPlugin.java
new file mode 100644 (file)
index 0000000..811efa1
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.sonar.api.Plugin;
+import org.sonar.api.Properties;
+import org.sonar.api.Property;
+import org.sonar.plugins.jacoco.itcoverage.*;
+import org.sonar.plugins.jacoco.itcoverage.viewer.CoverageViewerDefinition;
+
+@Properties({
+    @Property(
+        key = JacocoConfiguration.REPORT_PATH_PROPERTY,
+        name = "File with execution data",
+        defaultValue = JacocoConfiguration.REPORT_PATH_DEFAULT_VALUE,
+        description = "Path (absolute or relative) to the file with execution data.",
+        global = false,
+        module = true,
+        project = true
+    ),
+    @Property(
+        key = JacocoConfiguration.INCLUDES_PROPERTY,
+        name = "Includes",
+        description = "A list of class names that should be included in execution analysis." +
+            " The list entries are separated by a colon (:) and may use wildcard characters (* and ?)." +
+            " Except for performance optimization or technical corner cases this option is normally not required.",
+        global = true,
+        project = true,
+        module = true
+    ),
+    @Property(
+        key = JacocoConfiguration.EXCLUDES_PROPERTY,
+        name = "Excludes",
+        description = "A list of class names that should be excluded from execution analysis." +
+            " The list entries are separated by a colon (:) and may use wildcard characters (* and ?)." +
+            " Except for performance optimization or technical corner cases this option is normally not required.",
+        global = true,
+        project = true,
+        module = true
+    ),
+    @Property(
+        key = JacocoConfiguration.EXCLCLASSLOADER_PROPERTY,
+        name = "Excluded class loaders",
+        description = "A list of class loader names that should be excluded from execution analysis." +
+            " The list entries are separated by a colon (:) and may use wildcard characters (* and ?)." +
+            " This option might be required in case of special frameworks that conflict with JaCoCo code" +
+            " instrumentation, in particular class loaders that do not have access to the Java runtime classes.",
+        global = true,
+        project = true,
+        module = true
+    ),
+    @Property(
+        key = JacocoConfiguration.IT_REPORT_PATH_PROPERTY,
+        name = "File with execution data for integration tests",
+        defaultValue = JacocoConfiguration.IT_REPORT_PATH_DEFAULT_VALUE,
+        description = "Path (absolute or relative) to the file with execution data.",
+        global = false,
+        module = true,
+        project = true
+    ),
+    @Property(
+        key = JacocoConfiguration.ANT_TARGETS_PROPERTY,
+        name = "Ant targets",
+        defaultValue = JacocoConfiguration.ANT_TARGETS_DEFAULT_VALUE,
+        description = "Comma separated list of Ant targets for execution of tests.",
+        global = true,
+        module = true,
+        project = true
+    ) })
+public class JaCoCoPlugin implements Plugin {
+
+  public String getKey() {
+    return "jacoco";
+  }
+
+  public String getName() {
+    return "JaCoCo";
+  }
+
+  public String getDescription() {
+    return "<a href='http://www.eclemma.org/jacoco/'>JaCoCo</a> calculates coverage of unit tests." +
+        " Set the parameter 'Code coverage plugin' to <code>jacoco</code> in the General plugin.";
+  }
+
+  public List getExtensions() {
+    return Arrays.asList(
+        JacocoConfiguration.class,
+        JaCoCoAgentDownloader.class,
+        // Ant
+        JacocoAntInitializer.class,
+        // Maven
+        JacocoMavenInitializer.class,
+        JaCoCoMavenPluginHandler.class,
+        // Unit tests
+        JaCoCoSensor.class,
+
+        // Integration tests
+        JaCoCoItMetrics.class,
+        JaCoCoItSensor.class,
+        ItCoverageWidget.class,
+        ItCoverageDecorator.class,
+        ItLineCoverageDecorator.class,
+        ItBranchCoverageDecorator.class,
+        CoverageViewerDefinition.class);
+  }
+
+  @Override
+  public String toString() {
+    return getKey();
+  }
+
+}
diff --git a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoSensor.java b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoSensor.java
new file mode 100644 (file)
index 0000000..6c2f703
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco;
+
+import org.sonar.api.batch.CoverageExtension;
+import org.sonar.api.batch.Sensor;
+import org.sonar.api.batch.SensorContext;
+import org.sonar.api.measures.Measure;
+import org.sonar.api.resources.Java;
+import org.sonar.api.resources.JavaFile;
+import org.sonar.api.resources.Project;
+
+import java.util.Collection;
+
+/**
+ * @author Evgeny Mandrikov
+ */
+public class JaCoCoSensor implements Sensor, CoverageExtension {
+
+  private JacocoConfiguration configuration;
+
+  public JaCoCoSensor(JacocoConfiguration configuration) {
+    this.configuration = configuration;
+  }
+
+  public void analyse(Project project, SensorContext context) {
+    new UnitTestsAnalyzer().analyse(project, context);
+  }
+
+  public boolean shouldExecuteOnProject(Project project) {
+    return Java.KEY.equals(project.getLanguageKey());
+  }
+
+  class UnitTestsAnalyzer extends AbstractAnalyzer {
+    @Override
+    protected String getReportPath(Project project) {
+      return configuration.getReportPath();
+    }
+
+    @Override
+    protected void saveMeasures(SensorContext context, JavaFile resource, Collection<Measure> measures) {
+      for (Measure measure : measures) {
+        context.saveMeasure(resource, measure);
+      }
+    }
+  }
+
+  @Override
+  public String toString() {
+    return getClass().getSimpleName();
+  }
+
+}
diff --git a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoUtils.java b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JaCoCoUtils.java
new file mode 100644 (file)
index 0000000..54433ca
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Evgeny Mandrikov
+ */
+public final class JaCoCoUtils {
+
+  /**
+   * Utility class constructor.
+   */
+  private JaCoCoUtils() {
+  }
+
+  public static final Logger LOG = LoggerFactory.getLogger(JaCoCoPlugin.class.getName());
+
+}
diff --git a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JacocoAntInitializer.java b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JacocoAntInitializer.java
new file mode 100644 (file)
index 0000000..e74e2a7
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco;
+
+import org.apache.tools.ant.*;
+import org.sonar.api.batch.CoverageExtension;
+import org.sonar.api.batch.Initializer;
+import org.sonar.api.batch.SupportedEnvironment;
+import org.sonar.api.resources.Project;
+
+import java.util.Hashtable;
+
+@SupportedEnvironment("ant")
+public class JacocoAntInitializer extends Initializer implements CoverageExtension {
+
+  private final TaskEnhancer[] taskEnhancers = new TaskEnhancer[] { new JavaLikeTaskEnhancer("java"), new JavaLikeTaskEnhancer("junit"), new TestngTaskEnhancer() };
+
+  private org.apache.tools.ant.Project antProject;
+  private JacocoConfiguration configuration;
+
+  public JacocoAntInitializer(org.apache.tools.ant.Project antProject, JacocoConfiguration configuration) {
+    this.antProject = antProject;
+    this.configuration = configuration;
+  }
+
+  @Override
+  public boolean shouldExecuteOnProject(org.sonar.api.resources.Project project) {
+    return project.getAnalysisType().equals(Project.AnalysisType.DYNAMIC);
+    // TODO return project.getAnalysisType().equals(Project.AnalysisType.DYNAMIC) && project.getFileSystem().hasTestFiles(Java.INSTANCE);
+  }
+
+  @Override
+  public void execute(org.sonar.api.resources.Project project) {
+    Hashtable<String, Target> hastable = antProject.getTargets();
+    String jvmArg = configuration.getJvmArgument();
+    String[] names = configuration.getAntTargets();
+    for (String name : names) {
+      Target target = hastable.get(name);
+      if (target == null) {
+        JaCoCoUtils.LOG.warn("Target '{}' not found", name);
+      } else {
+        // Enhance target
+        for (Task task : target.getTasks()) {
+          for (TaskEnhancer enhancer : taskEnhancers) {
+            if (enhancer.supportsTask(task)) {
+              enhancer.enhanceTask(task, jvmArg);
+            }
+          }
+        }
+        // Execute target
+        // TODO antProject.getExecutor().executeTargets(antProject, new String[] { "test" });
+        target.performTasks();
+      }
+    }
+  }
+
+  private static class TestngTaskEnhancer extends TaskEnhancer {
+    @Override
+    public boolean supportsTask(Task task) {
+      return "testng".equals(task.getTaskName());
+    }
+  }
+
+  /**
+   * Basic task enhancer that can handle all 'java like' tasks. That is, tasks
+   * that have a top level fork attribute and nested jvmargs elements
+   */
+  private static class JavaLikeTaskEnhancer extends TaskEnhancer {
+    private String taskName;
+
+    public JavaLikeTaskEnhancer(String taskName) {
+      this.taskName = taskName;
+    }
+
+    public boolean supportsTask(final Task task) {
+      return taskName.equals(task.getTaskName());
+    }
+
+    @Override
+    public void enhanceTask(final Task task, final String jvmArg) {
+      final RuntimeConfigurable configurableWrapper = task.getRuntimeConfigurableWrapper();
+
+      final String forkValue = (String) configurableWrapper.getAttributeMap().get("fork");
+
+      if (forkValue == null || !org.apache.tools.ant.Project.toBoolean(forkValue)) {
+        throw new BuildException("Coverage can only be applied on a forked VM");
+      }
+
+      super.enhanceTask(task, jvmArg);
+    }
+
+  }
+
+  private static abstract class TaskEnhancer {
+    /**
+     * @param task Task instance to enhance
+     * @return <code>true</code> if this enhancer is capable of enhancing the requested task
+     */
+    public abstract boolean supportsTask(Task task);
+
+    /**
+     * Attempt to enhance the supplied task with coverage information. This
+     * operation may fail if the task is being executed in the current VM
+     * 
+     * @param task Task instance to enhance (usually an {@link UnknownElement})
+     * @param jvmArg
+     * @throws BuildException Thrown if this enhancer can handle this type of task, but this instance can not be enhanced for some reason.
+     */
+    public void enhanceTask(Task task, String jvmArg) {
+      addJvmArg((UnknownElement) task, jvmArg);
+    }
+
+    public void addJvmArg(final UnknownElement task, final String jvmArg) {
+      final UnknownElement el = new UnknownElement("jvmarg");
+      el.setTaskName("jvmarg");
+      el.setQName("jvmarg");
+
+      final RuntimeConfigurable runtimeConfigurableWrapper = el.getRuntimeConfigurableWrapper();
+      runtimeConfigurableWrapper.setAttribute("value", jvmArg);
+
+      task.getRuntimeConfigurableWrapper().addChild(runtimeConfigurableWrapper);
+
+      task.addChild(el);
+    }
+  }
+
+}
diff --git a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JacocoConfiguration.java b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JacocoConfiguration.java
new file mode 100644 (file)
index 0000000..373c7e9
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.lang.StringUtils;
+import org.jacoco.core.runtime.AgentOptions;
+import org.sonar.api.BatchExtension;
+
+public class JacocoConfiguration implements BatchExtension {
+
+  public static final String REPORT_PATH_PROPERTY = "sonar.jacoco.reportPath";
+  public static final String REPORT_PATH_DEFAULT_VALUE = "target/jacoco.exec";
+  public static final String IT_REPORT_PATH_PROPERTY = "sonar.jacoco.itReportPath";
+  public static final String IT_REPORT_PATH_DEFAULT_VALUE = "";
+  public static final String INCLUDES_PROPERTY = "sonar.jacoco.includes";
+  public static final String EXCLUDES_PROPERTY = "sonar.jacoco.excludes";
+  public static final String EXCLCLASSLOADER_PROPERTY = "sonar.jacoco.exclclassloader";
+  public static final String ANT_TARGETS_PROPERTY = "sonar.jacoco.antTargets";
+  public static final String ANT_TARGETS_DEFAULT_VALUE = "";
+
+  private Configuration configuration;
+  private JaCoCoAgentDownloader downloader;
+
+  public JacocoConfiguration(Configuration configuration, JaCoCoAgentDownloader downloader) {
+    this.configuration = configuration;
+    this.downloader = downloader;
+  }
+
+  public String getReportPath() {
+    return configuration.getString(REPORT_PATH_PROPERTY, REPORT_PATH_DEFAULT_VALUE);
+  }
+
+  public String getItReportPath() {
+    return configuration.getString(IT_REPORT_PATH_PROPERTY, IT_REPORT_PATH_DEFAULT_VALUE);
+  }
+
+  public String getJvmArgument() {
+    AgentOptions options = new AgentOptions();
+    options.setDestfile(getReportPath());
+    String includes = configuration.getString(INCLUDES_PROPERTY);
+    if (StringUtils.isNotBlank(includes)) {
+      options.setIncludes(includes);
+    }
+    String excludes = configuration.getString(EXCLUDES_PROPERTY);
+    if (StringUtils.isNotBlank(excludes)) {
+      options.setExcludes(excludes);
+    }
+    String exclclassloader = configuration.getString(EXCLCLASSLOADER_PROPERTY);
+    if (StringUtils.isNotBlank(exclclassloader)) {
+      options.setExclClassloader(exclclassloader);
+    }
+    return options.getVMArgument(downloader.getAgentJarFile());
+  }
+
+  public String[] getAntTargets() {
+    return configuration.getStringArray(ANT_TARGETS_PROPERTY);
+  }
+}
diff --git a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JacocoMavenInitializer.java b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/JacocoMavenInitializer.java
new file mode 100644 (file)
index 0000000..07ed54e
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco;
+
+import org.sonar.api.batch.CoverageExtension;
+import org.sonar.api.batch.Initializer;
+import org.sonar.api.batch.SupportedEnvironment;
+import org.sonar.api.batch.maven.DependsUponMavenPlugin;
+import org.sonar.api.batch.maven.MavenPluginHandler;
+import org.sonar.api.resources.Java;
+import org.sonar.api.resources.Project;
+
+@SupportedEnvironment("maven")
+public class JacocoMavenInitializer extends Initializer implements CoverageExtension, DependsUponMavenPlugin {
+
+  private JaCoCoMavenPluginHandler handler;
+
+  public JacocoMavenInitializer(JaCoCoMavenPluginHandler handler) {
+    this.handler = handler;
+  }
+
+  @Override
+  public boolean shouldExecuteOnProject(Project project) {
+    return project.getAnalysisType().equals(Project.AnalysisType.DYNAMIC) && project.getFileSystem().hasTestFiles(Java.INSTANCE);
+  }
+
+  @Override
+  public void execute(Project project) {
+    // nothing to do
+  }
+
+  public MavenPluginHandler getMavenPluginHandler(Project project) {
+    return handler;
+  }
+
+}
diff --git a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/AbstractCoverageDecorator.java b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/AbstractCoverageDecorator.java
new file mode 100644 (file)
index 0000000..71f5364
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco.itcoverage;
+
+import org.sonar.api.batch.Decorator;
+import org.sonar.api.batch.DecoratorContext;
+import org.sonar.api.batch.DependedUpon;
+import org.sonar.api.measures.Metric;
+import org.sonar.api.resources.Project;
+import org.sonar.api.resources.Resource;
+import org.sonar.api.resources.ResourceUtils;
+
+/**
+ * Copied from org.sonar.plugins.core.sensors.AbstractCoverageDecorator
+ */
+public abstract class AbstractCoverageDecorator implements Decorator {
+
+  public boolean shouldExecuteOnProject(Project project) {
+    return project.getAnalysisType().isDynamic(true);
+  }
+
+  @DependedUpon
+  public Metric generatesCoverage() {
+    return getTargetMetric();
+  }
+
+  public void decorate(final Resource resource, final DecoratorContext context) {
+    if (shouldDecorate(resource, context)) {
+      saveCoverage(context);
+    }
+  }
+
+  protected boolean shouldDecorate(final Resource resource, final DecoratorContext context) {
+    return context.getMeasure(getTargetMetric()) == null && !ResourceUtils.isUnitTestClass(resource);
+  }
+
+  private void saveCoverage(DecoratorContext context) {
+    Double elements = countElements(context);
+    Double coveredElements = countCoveredElements(context);
+
+    if (elements != null && elements > 0.0 && coveredElements != null) {
+      context.saveMeasure(getTargetMetric(), calculateCoverage(coveredElements, elements));
+    }
+  }
+
+  private double calculateCoverage(final Double coveredElements, final Double elements) {
+    return (100.0 * coveredElements) / elements;
+  }
+
+  protected abstract Metric getTargetMetric();
+
+  protected abstract Double countCoveredElements(DecoratorContext context);
+
+  protected abstract Double countElements(DecoratorContext context);
+}
diff --git a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/ItBranchCoverageDecorator.java b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/ItBranchCoverageDecorator.java
new file mode 100644 (file)
index 0000000..d3a4147
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco.itcoverage;
+
+import org.sonar.api.batch.DecoratorContext;
+import org.sonar.api.batch.DependsUpon;
+import org.sonar.api.measures.MeasureUtils;
+import org.sonar.api.measures.Metric;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Copied from org.sonar.plugins.core.sensors.BranchCoverageDecorator
+ */
+public final class ItBranchCoverageDecorator extends AbstractCoverageDecorator {
+  @Override
+  protected Metric getTargetMetric() {
+    return JaCoCoItMetrics.IT_BRANCH_COVERAGE;
+  }
+
+  @DependsUpon
+  public List<Metric> dependsUponMetrics() {
+    return Arrays.asList(JaCoCoItMetrics.IT_UNCOVERED_CONDITIONS, JaCoCoItMetrics.IT_CONDITIONS_TO_COVER);
+  }
+
+  @Override
+  protected Double countCoveredElements(DecoratorContext context) {
+    double uncoveredConditions = MeasureUtils.getValue(context.getMeasure(JaCoCoItMetrics.IT_UNCOVERED_CONDITIONS), 0.0);
+    double conditions = MeasureUtils.getValue(context.getMeasure(JaCoCoItMetrics.IT_CONDITIONS_TO_COVER), 0.0);
+    return conditions - uncoveredConditions;
+  }
+
+  @Override
+  protected Double countElements(DecoratorContext context) {
+    return MeasureUtils.getValue(context.getMeasure(JaCoCoItMetrics.IT_CONDITIONS_TO_COVER), 0.0);
+  }
+}
diff --git a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/ItCoverageDecorator.java b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/ItCoverageDecorator.java
new file mode 100644 (file)
index 0000000..49e0290
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco.itcoverage;
+
+import org.sonar.api.batch.DecoratorContext;
+import org.sonar.api.batch.DependsUpon;
+import org.sonar.api.measures.MeasureUtils;
+import org.sonar.api.measures.Metric;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Copied from org.sonar.plugins.core.sensors.CoverageDecorator
+ */
+public class ItCoverageDecorator extends AbstractCoverageDecorator {
+
+  @Override
+  protected Metric getTargetMetric() {
+    return JaCoCoItMetrics.IT_COVERAGE;
+  }
+
+  @DependsUpon
+  public List<Metric> dependsUponMetrics() {
+    return Arrays.asList(JaCoCoItMetrics.IT_LINES_TO_COVER, JaCoCoItMetrics.IT_UNCOVERED_LINES, JaCoCoItMetrics.IT_CONDITIONS_TO_COVER, JaCoCoItMetrics.IT_UNCOVERED_CONDITIONS);
+  }
+
+  @Override
+  protected Double countCoveredElements(DecoratorContext context) {
+    double uncoveredLines = MeasureUtils.getValue(context.getMeasure(JaCoCoItMetrics.IT_UNCOVERED_LINES), 0.0);
+    double lines = MeasureUtils.getValue(context.getMeasure(JaCoCoItMetrics.IT_LINES_TO_COVER), 0.0);
+    double uncoveredConditions = MeasureUtils.getValue(context.getMeasure(JaCoCoItMetrics.IT_UNCOVERED_CONDITIONS), 0.0);
+    double conditions = MeasureUtils.getValue(context.getMeasure(JaCoCoItMetrics.IT_CONDITIONS_TO_COVER), 0.0);
+    return lines + conditions - uncoveredConditions - uncoveredLines;
+  }
+
+  @Override
+  protected Double countElements(DecoratorContext context) {
+    double lines = MeasureUtils.getValue(context.getMeasure(JaCoCoItMetrics.IT_LINES_TO_COVER), 0.0);
+    double conditions = MeasureUtils.getValue(context.getMeasure(JaCoCoItMetrics.IT_CONDITIONS_TO_COVER), 0.0);
+    return lines + conditions;
+  }
+
+}
diff --git a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/ItCoverageWidget.java b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/ItCoverageWidget.java
new file mode 100644 (file)
index 0000000..65ef6ef
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco.itcoverage;
+
+import org.sonar.api.web.AbstractRubyTemplate;
+import org.sonar.api.web.NavigationSection;
+import org.sonar.api.web.RubyRailsWidget;
+import org.sonar.api.web.UserRole;
+
+@NavigationSection(NavigationSection.RESOURCE)
+@UserRole(UserRole.USER)
+public class ItCoverageWidget extends AbstractRubyTemplate implements RubyRailsWidget {
+
+  @Override
+  protected String getTemplatePath() {
+    return "/org/sonar/plugins/jacoco/itcoverage/widget.html.erb";
+  }
+
+  public String getId() {
+    return "it-coverage";
+  }
+
+  public String getTitle() {
+    return "IT Coverage widget";
+  }
+
+}
diff --git a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/ItLineCoverageDecorator.java b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/ItLineCoverageDecorator.java
new file mode 100644 (file)
index 0000000..797c3f3
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco.itcoverage;
+
+import org.sonar.api.batch.DecoratorContext;
+import org.sonar.api.batch.DependsUpon;
+import org.sonar.api.measures.MeasureUtils;
+import org.sonar.api.measures.Metric;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Copied from org.sonar.plugins.core.sensors.LineCoverageDecorator
+ */
+public class ItLineCoverageDecorator extends AbstractCoverageDecorator {
+  @Override
+  protected Metric getTargetMetric() {
+    return JaCoCoItMetrics.IT_LINE_COVERAGE;
+  }
+
+  @DependsUpon
+  public List<Metric> dependsUponMetrics() {
+    return Arrays.asList(JaCoCoItMetrics.IT_UNCOVERED_LINES, JaCoCoItMetrics.IT_LINES_TO_COVER);
+  }
+
+  @Override
+  protected Double countCoveredElements(DecoratorContext context) {
+    double uncoveredLines = MeasureUtils.getValue(context.getMeasure(JaCoCoItMetrics.IT_UNCOVERED_LINES), 0.0);
+    double lines = MeasureUtils.getValue(context.getMeasure(JaCoCoItMetrics.IT_LINES_TO_COVER), 0.0);
+    return lines - uncoveredLines;
+  }
+
+  @Override
+  protected Double countElements(DecoratorContext context) {
+    return MeasureUtils.getValue(context.getMeasure(JaCoCoItMetrics.IT_LINES_TO_COVER), 0.0);
+  }
+}
diff --git a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/JaCoCoItMetrics.java b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/JaCoCoItMetrics.java
new file mode 100644 (file)
index 0000000..591d737
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco.itcoverage;
+
+import org.sonar.api.measures.Metric;
+import org.sonar.api.measures.Metrics;
+import org.sonar.api.measures.SumChildValuesFormula;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Should be in {@link org.sonar.api.measures.CoreMetrics}
+ *
+ * @author Evgeny Mandrikov
+ */
+public final class JaCoCoItMetrics implements Metrics {
+
+  public static final String DOMAIN_IT_TESTS = "Integration Tests";
+
+  public static final String IT_COVERAGE_KEY = "it_coverage";
+  public static final Metric IT_COVERAGE = new Metric.Builder(IT_COVERAGE_KEY, "IT Coverage", Metric.ValueType.PERCENT)
+      .setDescription("Coverage by integration tests")
+      .setDirection(Metric.DIRECTION_BETTER)
+      .setQualitative(true)
+      .setDomain(DOMAIN_IT_TESTS)
+      .setWorstValue(0.0)
+      .setBestValue(100.0)
+      .create();
+
+  public static final String IT_LINES_TO_COVER_KEY = "it_lines_to_cover";
+  public static final Metric IT_LINES_TO_COVER = new Metric.Builder(IT_LINES_TO_COVER_KEY, "IT lines to cover", Metric.ValueType.INT)
+      .setDescription("IT lines to cover")
+      .setDirection(Metric.DIRECTION_BETTER)
+      .setDomain(DOMAIN_IT_TESTS)
+      .setQualitative(false)
+      .setFormula(new SumChildValuesFormula(false))
+      .setHidden(true)
+      .create();
+
+  public static final String IT_UNCOVERED_LINES_KEY = "it_uncovered_lines";
+  public static final Metric IT_UNCOVERED_LINES = new Metric.Builder(IT_UNCOVERED_LINES_KEY, "IT uncovered lines", Metric.ValueType.INT)
+      .setDescription("IT uncovered lines")
+      .setDirection(Metric.DIRECTION_WORST)
+      .setQualitative(false)
+      .setDomain(DOMAIN_IT_TESTS)
+      .setFormula(new SumChildValuesFormula(false))
+      .create();
+
+  public static final String IT_LINE_COVERAGE_KEY = "it_line_coverage";
+  public static final Metric IT_LINE_COVERAGE = new Metric.Builder(IT_LINE_COVERAGE_KEY, "IT line coverage", Metric.ValueType.PERCENT)
+      .setDescription("IT line coverage")
+      .setDirection(Metric.DIRECTION_BETTER)
+      .setQualitative(true)
+      .setDomain(DOMAIN_IT_TESTS)
+      .create();
+
+  public static final String IT_COVERAGE_LINE_HITS_DATA_KEY = "it_coverage_line_hits_data";
+  public static final Metric IT_COVERAGE_LINE_HITS_DATA = new Metric.Builder(IT_COVERAGE_LINE_HITS_DATA_KEY, "IT Coverage hits data", Metric.ValueType.DATA)
+      .setDescription("IT Code coverage line hits data")
+      .setDirection(Metric.DIRECTION_NONE)
+      .setQualitative(false)
+      .setDomain(DOMAIN_IT_TESTS)
+      .create();
+
+  public static final String IT_CONDITIONS_TO_COVER_KEY = "it_conditions_to_cover";
+  public static final Metric IT_CONDITIONS_TO_COVER = new Metric.Builder(IT_CONDITIONS_TO_COVER_KEY, "IT Conditions to cover", Metric.ValueType.INT)
+      .setDescription("IT Conditions to cover")
+      .setDirection(Metric.DIRECTION_BETTER)
+      .setQualitative(false)
+      .setDomain(DOMAIN_IT_TESTS)
+      .setFormula(new SumChildValuesFormula(false))
+      .setHidden(true)
+      .create();
+
+  public static final String IT_UNCOVERED_CONDITIONS_KEY = "it_uncovered_conditions";
+  public static final Metric IT_UNCOVERED_CONDITIONS = new Metric.Builder(IT_UNCOVERED_CONDITIONS_KEY, "IT Uncovered conditions", Metric.ValueType.INT)
+      .setDescription("IT Uncovered conditions")
+      .setDirection(Metric.DIRECTION_WORST)
+      .setDomain(DOMAIN_IT_TESTS)
+      .setFormula(new SumChildValuesFormula(false))
+      .create();
+
+  public static final String IT_BRANCH_COVERAGE_KEY = "it_branch_coverage";
+  public static final Metric IT_BRANCH_COVERAGE = new Metric.Builder(IT_BRANCH_COVERAGE_KEY, "IT Branch coverage", Metric.ValueType.PERCENT)
+      .setDescription("IT Branch coverage")
+      .setDirection(Metric.DIRECTION_BETTER)
+      .setQualitative(true)
+      .setDomain(DOMAIN_IT_TESTS)
+      .setWorstValue(0.0)
+      .setBestValue(100.0)
+      .create();
+
+  public static final String IT_CONDITIONS_BY_LINE_KEY = "it_conditions_by_line";
+
+  public static final Metric IT_CONDITIONS_BY_LINE = new Metric.Builder(IT_CONDITIONS_BY_LINE_KEY, "IT Conditions by line", Metric.ValueType.DATA)
+      .setDomain(DOMAIN_IT_TESTS)
+      .create();
+
+  public static final String IT_COVERED_CONDITIONS_BY_LINE_KEY = "it_covered_conditions_by_line";
+
+  public static final Metric IT_COVERED_CONDITIONS_BY_LINE = new Metric.Builder(IT_COVERED_CONDITIONS_BY_LINE_KEY, "IT Covered conditions by line", Metric.ValueType.DATA)
+      .setDomain(DOMAIN_IT_TESTS)
+      .create();
+
+
+  public List<Metric> getMetrics() {
+    return Arrays.asList(IT_COVERAGE, IT_LINES_TO_COVER, IT_UNCOVERED_LINES, IT_LINE_COVERAGE, IT_COVERAGE_LINE_HITS_DATA,
+        IT_CONDITIONS_TO_COVER, IT_UNCOVERED_CONDITIONS, IT_BRANCH_COVERAGE, 
+        IT_CONDITIONS_BY_LINE, IT_COVERED_CONDITIONS_BY_LINE);
+  }
+
+}
diff --git a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/JaCoCoItSensor.java b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/JaCoCoItSensor.java
new file mode 100644 (file)
index 0000000..f043d16
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco.itcoverage;
+
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.batch.Sensor;
+import org.sonar.api.batch.SensorContext;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.measures.Measure;
+import org.sonar.api.resources.JavaFile;
+import org.sonar.api.resources.Project;
+import org.sonar.plugins.jacoco.AbstractAnalyzer;
+import org.sonar.plugins.jacoco.JacocoConfiguration;
+
+import java.util.Collection;
+
+/**
+ * Note that this class can't extend {@link org.sonar.api.batch.AbstractCoverageExtension}, because in this case this extension will be
+ * disabled under Sonar 2.3, if JaCoCo is not defined as the default code coverage plugin.
+ * 
+ * @author Evgeny Mandrikov
+ */
+public class JaCoCoItSensor implements Sensor {
+  private JacocoConfiguration configuration;
+
+  public JaCoCoItSensor(JacocoConfiguration configuration) {
+    this.configuration = configuration;
+  }
+
+  public boolean shouldExecuteOnProject(Project project) {
+    return StringUtils.isNotBlank(configuration.getItReportPath())
+        && project.getAnalysisType().isDynamic(true);
+  }
+
+  public void analyse(Project project, SensorContext context) {
+    new ITAnalyzer().analyse(project, context);
+  }
+
+  class ITAnalyzer extends AbstractAnalyzer {
+    @Override
+    protected String getReportPath(Project project) {
+      return configuration.getItReportPath();
+    }
+
+    @Override
+    protected void saveMeasures(SensorContext context, JavaFile resource, Collection<Measure> measures) {
+      for (Measure measure : measures) {
+        Measure itMeasure = convertForIT(measure);
+        if (itMeasure != null) {
+          context.saveMeasure(resource, itMeasure);
+        }
+      }
+    }
+
+    private Measure convertForIT(Measure measure) {
+      Measure itMeasure = null;
+      if (CoreMetrics.LINES_TO_COVER.equals(measure.getMetric())) {
+        itMeasure = new Measure(JaCoCoItMetrics.IT_LINES_TO_COVER, measure.getValue());
+
+      } else if (CoreMetrics.UNCOVERED_LINES.equals(measure.getMetric())) {
+        itMeasure = new Measure(JaCoCoItMetrics.IT_UNCOVERED_LINES, measure.getValue());
+
+      } else if (CoreMetrics.COVERAGE_LINE_HITS_DATA.equals(measure.getMetric())) {
+        itMeasure = new Measure(JaCoCoItMetrics.IT_COVERAGE_LINE_HITS_DATA, measure.getData());
+
+      } else if (CoreMetrics.CONDITIONS_TO_COVER.equals(measure.getMetric())) {
+        itMeasure = new Measure(JaCoCoItMetrics.IT_CONDITIONS_TO_COVER, measure.getValue());
+
+      } else if (CoreMetrics.UNCOVERED_CONDITIONS.equals(measure.getMetric())) {
+        itMeasure = new Measure(JaCoCoItMetrics.IT_UNCOVERED_CONDITIONS, measure.getValue());
+
+      } else if (CoreMetrics.COVERED_CONDITIONS_BY_LINE.equals(measure.getMetric())) {
+        itMeasure = new Measure(JaCoCoItMetrics.IT_COVERED_CONDITIONS_BY_LINE, measure.getData());
+
+      } else if (CoreMetrics.CONDITIONS_BY_LINE.equals(measure.getMetric())) {
+        itMeasure = new Measure(JaCoCoItMetrics.IT_CONDITIONS_BY_LINE, measure.getData());
+      }
+      return itMeasure;
+    }
+  }
+
+  @Override
+  public String toString() {
+    return getClass().getSimpleName();
+  }
+}
diff --git a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/viewer/CoverageViewerDefinition.java b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/viewer/CoverageViewerDefinition.java
new file mode 100644 (file)
index 0000000..995353c
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco.itcoverage.viewer;
+
+import org.sonar.api.resources.Resource;
+import org.sonar.api.web.*;
+import org.sonar.plugins.jacoco.itcoverage.JaCoCoItMetrics;
+
+@ResourceQualifier(Resource.QUALIFIER_CLASS)
+@NavigationSection(NavigationSection.RESOURCE_TAB)
+@DefaultTab(metrics = { JaCoCoItMetrics.IT_COVERAGE_KEY, JaCoCoItMetrics.IT_LINES_TO_COVER_KEY, JaCoCoItMetrics.IT_UNCOVERED_LINES_KEY, JaCoCoItMetrics.IT_LINE_COVERAGE_KEY, JaCoCoItMetrics.IT_CONDITIONS_TO_COVER_KEY, JaCoCoItMetrics.IT_UNCOVERED_CONDITIONS_KEY, JaCoCoItMetrics.IT_BRANCH_COVERAGE_KEY })
+@UserRole(UserRole.CODEVIEWER)
+public class CoverageViewerDefinition extends GwtPage {
+
+  public String getTitle() {
+    return "IT Coverage";
+  }
+
+  public String getGwtId() {
+    return "org.sonar.plugins.jacoco.itcoverage.viewer.CoverageViewer";
+  }
+}
diff --git a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/viewer/client/CoveragePanel.java b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/viewer/client/CoveragePanel.java
new file mode 100644 (file)
index 0000000..80651a9
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco.itcoverage.viewer.client;
+
+import org.sonar.gwt.ui.SourcePanel;
+import org.sonar.wsclient.gwt.AbstractCallback;
+import org.sonar.wsclient.gwt.Sonar;
+import org.sonar.wsclient.services.Resource;
+import org.sonar.wsclient.services.ResourceQuery;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Copied from org.sonar.plugins.core.coverageviewer.client.CoveragePanel
+ */
+public class CoveragePanel extends SourcePanel {
+
+  private Map<Integer, Integer> hitsByLine = new HashMap<Integer, Integer>();
+  private Map<Integer, Integer> conditionsByLine = new HashMap<Integer, Integer>();
+  private Map<Integer, Integer> coveredConditionsByLine = new HashMap<Integer, Integer>();
+  private Map<Integer, String> branchCoverageByLine = new HashMap<Integer, String>();
+
+  public CoveragePanel(Resource resource) {
+    super(resource);
+    loadCoverageHits(resource);
+  }
+
+  private void loadCoverageHits(Resource resource) {
+    ResourceQuery query = ResourceQuery.createForResource(resource, Metrics.IT_COVERAGE_LINE_HITS_DATA, Metrics.IT_BRANCH_COVERAGE_HITS_DATA, Metrics.IT_CONDITIONS_BY_LINE, Metrics.IT_COVERED_CONDITIONS_BY_LINE);
+    Sonar.getInstance().find(query, new AbstractCallback<Resource>() {
+
+      @Override
+      protected void doOnResponse(Resource resource) {
+        handleLineHits(resource);
+        handleLineConditions(resource);
+        handleDeprecatedBranchCoverage(resource);
+        setStarted();
+      }
+    });
+  }
+
+  private void handleLineHits(Resource resource) {
+    parseDataMap(resource, Metrics.IT_COVERAGE_LINE_HITS_DATA, hitsByLine);
+  }
+
+  private void handleLineConditions(Resource resource) {
+    parseDataMap(resource, Metrics.IT_CONDITIONS_BY_LINE, conditionsByLine);
+    parseDataMap(resource, Metrics.IT_COVERED_CONDITIONS_BY_LINE, coveredConditionsByLine);
+  }
+
+  private void parseDataMap(Resource resource, String metric, Map<Integer, Integer> map) {
+    if (resource == null || resource.getMeasure(metric) == null) {
+      return;
+    }
+
+    map.clear();
+    String data = resource.getMeasure(metric).getData();
+    for (String lineWithValue : data.split(";")) {
+      String[] elt = lineWithValue.split("=");
+      if (elt != null && elt.length == 2) {
+        map.put(Integer.parseInt(elt[0]), Integer.parseInt(elt[1]));
+      }
+    }
+  }
+
+  private void handleDeprecatedBranchCoverage(Resource resource) {
+    if (resource == null || resource.getMeasure(Metrics.IT_BRANCH_COVERAGE_HITS_DATA) == null) {
+      return;
+    }
+
+    branchCoverageByLine.clear();
+    String data = resource.getMeasure(Metrics.IT_BRANCH_COVERAGE_HITS_DATA).getData();
+    for (String lineWithValue : data.split(";")) {
+      String[] elt = lineWithValue.split("=");
+      if (elt != null && elt.length == 2) {
+        branchCoverageByLine.put(Integer.parseInt(elt[0]), elt[1]);
+      }
+    }
+  }
+
+  @Override
+  protected boolean shouldDecorateLine(int index) {
+    return index > 0;
+  }
+
+  @Override
+  protected List<Row> decorateLine(int index, String source) {
+    Row row = new Row().setLineIndex(index, "");
+
+    Integer hits = hitsByLine.get(index);
+    Integer conditions = conditionsByLine.get(index);
+    Integer coveredConditions = coveredConditionsByLine.get(index);
+    String branchCoverage = branchCoverageByLine.get(index);
+    if (branchCoverage == null && conditions != null && coveredConditions != null) {
+      branchCoverage = String.valueOf(conditions - coveredConditions) + "/" + String.valueOf(conditions);
+    }
+
+    boolean hasLineCoverage = (hits != null);
+    boolean hasBranchCoverage = (branchCoverage != null);
+    boolean lineIsCovered = (hasLineCoverage && hits > 0);
+    boolean branchIsCovered = ("100%".equals(branchCoverage) || (conditions != null && coveredConditions != null && coveredConditions == conditions));
+
+    row.setSource(source, "");
+    row.setValue("&nbsp;", "");
+    row.setValue2("&nbsp;", "");
+
+    if (lineIsCovered) {
+      if (branchIsCovered) {
+        row.setValue(String.valueOf(hits), "green");
+        row.setValue2(branchCoverage, "green");
+
+      } else if (hasBranchCoverage) {
+        row.setValue(String.valueOf(hits), "orange");
+        row.setValue2(branchCoverage, "orange");
+        row.setSource(source, "orange");
+      } else {
+        row.setValue(String.valueOf(hits), "green");
+      }
+    } else if (hasLineCoverage) {
+      row.setValue(String.valueOf(hits), "red");
+      row.setSource(source, "red");
+      if (hasBranchCoverage) {
+        row.setValue2(branchCoverage, "red");
+      } else {
+        row.setValue2("&nbsp;", "red");
+      }
+    }
+    return Arrays.asList(row);
+  }
+}
diff --git a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/viewer/client/CoverageViewer.java b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/viewer/client/CoverageViewer.java
new file mode 100644 (file)
index 0000000..1d9b3ae
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco.itcoverage.viewer.client;
+
+import org.sonar.gwt.ui.Page;
+import org.sonar.gwt.ui.ViewerHeader;
+import org.sonar.wsclient.services.Measure;
+import org.sonar.wsclient.services.Resource;
+
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * Copied from org.sonar.plugins.core.coverageviewer.client.CoverageViewer
+ */
+public class CoverageViewer extends Page {
+  @Override
+  protected Widget doOnResourceLoad(Resource resource) {
+    FlowPanel panel = new FlowPanel();
+    panel.setWidth("100%");
+    panel.add(new CoverageHeader(resource));
+    panel.add(new CoveragePanel(resource));
+    return panel;
+  }
+
+  private static class CoverageHeader extends ViewerHeader {
+    public CoverageHeader(Resource resource) {
+      super(resource, new String[] { Metrics.IT_COVERAGE, Metrics.IT_LINE_COVERAGE, Metrics.IT_UNCOVERED_LINES, Metrics.IT_BRANCH_COVERAGE, Metrics.IT_UNCOVERED_CONDITIONS });
+    }
+
+    @Override
+    protected void display(FlowPanel header, Resource resource) {
+      HorizontalPanel panel = new HorizontalPanel();
+      header.add(panel);
+
+      Measure measure = resource.getMeasure(Metrics.IT_COVERAGE);
+      if (measure == null) {
+        addBigCell(panel, "-");
+      } else {
+        addBigCell(panel, measure.getFormattedValue());
+      }
+
+      addCell(panel, resource.getMeasure(Metrics.IT_LINE_COVERAGE));
+      addCell(panel, resource.getMeasure(Metrics.IT_UNCOVERED_LINES));
+      addCell(panel, resource.getMeasure(Metrics.IT_LINES_TO_COVER));
+      addCell(panel, resource.getMeasure(Metrics.IT_BRANCH_COVERAGE));
+      addCell(panel, resource.getMeasure(Metrics.IT_UNCOVERED_CONDITIONS));
+      addCell(panel, resource.getMeasure(Metrics.IT_CONDITIONS_TO_COVER));
+    }
+  }
+}
diff --git a/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/viewer/client/Metrics.java b/plugins/sonar-jacoco-plugin/src/main/java/org/sonar/plugins/jacoco/itcoverage/viewer/client/Metrics.java
new file mode 100644 (file)
index 0000000..3e3190f
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco.itcoverage.viewer.client;
+
+/**
+ * Should be in {@link org.sonar.gwt.Metrics}
+ */
+public interface Metrics {
+  String IT_COVERAGE = "it_coverage";
+  String IT_LINES_TO_COVER = "it_lines_to_cover";
+  String IT_UNCOVERED_LINES = "it_uncovered_lines";
+  String IT_LINE_COVERAGE = "it_line_coverage";
+  String IT_COVERAGE_LINE_HITS_DATA = "it_coverage_line_hits_data";
+  String IT_CONDITIONS_TO_COVER = "it_conditions_to_cover";
+  String IT_UNCOVERED_CONDITIONS = "it_uncovered_conditions";
+  String IT_BRANCH_COVERAGE = "it_branch_coverage";
+  String IT_CONDITIONS_BY_LINE = "it_conditions_by_line";
+  String IT_COVERED_CONDITIONS_BY_LINE = "it_covered_conditions_by_line";
+
+  /**
+   * @deprecated use IT_CONDITIONS_BY_LINE and IT_COVERED_CONDITIONS_BY_LINE
+   */
+  @Deprecated
+  String IT_BRANCH_COVERAGE_HITS_DATA = "it_branch_coverage_hits_data";
+}
diff --git a/plugins/sonar-jacoco-plugin/src/main/resources/org/sonar/plugins/jacoco/itcoverage/viewer/CoverageViewer.gwt.xml b/plugins/sonar-jacoco-plugin/src/main/resources/org/sonar/plugins/jacoco/itcoverage/viewer/CoverageViewer.gwt.xml
new file mode 100644 (file)
index 0000000..3817671
--- /dev/null
@@ -0,0 +1,10 @@
+<module>
+  <inherits name="com.google.gwt.user.User"/>
+  <inherits name="com.google.gwt.json.JSON"/>
+  <inherits name="com.google.gwt.http.HTTP"/>
+  <inherits name="org.sonar.Sonar"/>
+  <inherits name="com.google.gwt.gen2.table.Table"/>
+
+  <entry-point class="org.sonar.plugins.jacoco.itcoverage.viewer.client.CoverageViewer"/>
+
+</module>
diff --git a/plugins/sonar-jacoco-plugin/src/main/resources/org/sonar/plugins/jacoco/itcoverage/widget.html.erb b/plugins/sonar-jacoco-plugin/src/main/resources/org/sonar/plugins/jacoco/itcoverage/widget.html.erb
new file mode 100644 (file)
index 0000000..00f91c0
--- /dev/null
@@ -0,0 +1,32 @@
+<%
+   it_coverage_measure=measure('it_coverage')
+   if it_coverage_measure %>
+  <table width="100%">
+    <tr>
+      <td valign="top" width="100%">
+        <div class="dashbox">
+          <p class="title">IT Code coverage</p>
+
+          <p>
+            <span class="big"><%= format_measure(it_coverage_measure, :suffix => '', :url => url_for_drilldown('it_coverage'), :default => '-') %></span>
+            <%= dashboard_configuration.selected_period? ? format_variation(it_coverage_measure) : trend_icon(it_coverage_measure) -%>
+          </p>
+          <% it_line_coverage=measure('it_line_coverage')
+             if it_line_coverage %>
+            <p>
+              <%= format_measure(it_line_coverage, :suffix => ' IT line coverage', :url => url_for_drilldown('it_uncovered_lines', :highlight => 'it_line_coverage')) %>
+              <%= dashboard_configuration.selected_period? ? format_variation(it_line_coverage) : trend_icon(it_line_coverage) -%>
+            </p>
+          <% end %>
+          <% it_branch_coverage=measure('it_branch_coverage')
+             if it_branch_coverage %>
+            <p>
+              <%= format_measure(it_branch_coverage, :suffix => ' IT branch coverage', :url => url_for_drilldown('it_uncovered_conditions', :highlight => 'it_branch_coverage')) %>
+              <%= dashboard_configuration.selected_period? ? format_variation(it_branch_coverage) : trend_icon(it_branch_coverage) -%>
+            </p>
+          <% end %>
+        </div>
+      </td>
+    </tr>
+  </table>
+<% end %>
diff --git a/plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/AbstractAnalyzerTest.java b/plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/AbstractAnalyzerTest.java
new file mode 100644 (file)
index 0000000..49ad852
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.jacoco.core.analysis.ISourceFileCoverage;
+import org.junit.Test;
+import org.sonar.api.resources.JavaFile;
+
+public class AbstractAnalyzerTest {
+  @Test
+  public void defaultPackage() {
+    ISourceFileCoverage coverage = mock(ISourceFileCoverage.class);
+    when(coverage.getPackageName()).thenReturn("").thenReturn("org/example");
+    when(coverage.getName()).thenReturn("Hello.java");
+    assertThat(AbstractAnalyzer.getResource(coverage), is(new JavaFile("[default].Hello")));
+    assertThat(AbstractAnalyzer.getResource(coverage), is(new JavaFile("org.example.Hello")));
+  }
+}
diff --git a/plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/JaCoCoMavenPluginHandlerTest.java b/plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/JaCoCoMavenPluginHandlerTest.java
new file mode 100644 (file)
index 0000000..81d102b
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+
+import org.apache.commons.configuration.BaseConfiguration;
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.batch.maven.MavenPlugin;
+import org.sonar.api.batch.maven.MavenSurefireUtils;
+import org.sonar.api.resources.Project;
+import org.sonar.api.test.MavenTestUtils;
+
+/**
+ * @author Evgeny Mandrikov
+ */
+public class JaCoCoMavenPluginHandlerTest {
+
+  private JacocoConfiguration configuration;
+  private JaCoCoMavenPluginHandler handler;
+
+  @Before
+  public void setUp() throws Exception {
+    JaCoCoAgentDownloader downloader = mock(JaCoCoAgentDownloader.class);
+    when(downloader.getAgentJarFile()).thenReturn(new File("jacocoagent.jar"));
+    Project project = mock(Project.class);
+    when(project.getConfiguration()).thenReturn(new BaseConfiguration());
+    configuration = spy(new JacocoConfiguration(project.getConfiguration(), downloader));
+
+    handler = new JaCoCoMavenPluginHandler(configuration);
+  }
+
+  @Test
+  public void testMavenPluginDefinition() {
+    assertThat(handler.getGroupId(), is(MavenSurefireUtils.GROUP_ID));
+    assertThat(handler.getArtifactId(), is(MavenSurefireUtils.ARTIFACT_ID));
+    assertThat(handler.getVersion(), is(MavenSurefireUtils.VERSION));
+    assertThat(handler.getGoals(), is(new String[] { "test" }));
+    assertThat(handler.isFixedVersion(), is(false));
+  }
+
+  @Test
+  public void testConfigureMavenPlugin() {
+    Project project = MavenTestUtils.loadProjectFromPom(getClass(), "pom.xml");
+    MavenPlugin plugin = new MavenPlugin(handler.getGroupId(), handler.getArtifactId(), handler.getVersion());
+
+    handler.configure(project, plugin);
+
+    verify(configuration).getJvmArgument();
+    assertThat(plugin.getParameter("argLine"), is("-javaagent:jacocoagent.jar=destfile=target/jacoco.exec"));
+    assertThat(plugin.getParameter("testFailureIgnore"), is("true"));
+  }
+
+  @Test
+  public void testReconfigureMavenPlugin() {
+    Project project = MavenTestUtils.loadProjectFromPom(getClass(), "pom2.xml");
+    MavenPlugin plugin = MavenPlugin.getPlugin(project.getPom(), handler.getGroupId(), handler.getArtifactId());
+
+    handler.configure(project, plugin);
+
+    verify(configuration).getJvmArgument();
+    assertThat(plugin.getParameter("argLine"), is("-javaagent:jacocoagent.jar=destfile=target/jacoco.exec -esa"));
+    assertThat(plugin.getParameter("testFailureIgnore"), is("true"));
+  }
+
+}
diff --git a/plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/JaCoCoPluginTest.java b/plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/JaCoCoPluginTest.java
new file mode 100644 (file)
index 0000000..33a9898
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco;
+
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Evgeny Mandrikov
+ */
+public class JaCoCoPluginTest {
+  private JaCoCoPlugin plugin = new JaCoCoPlugin();
+
+  @Before
+  public void setUp() {
+    plugin = new JaCoCoPlugin();
+  }
+
+  @Test
+  public void testPluginDefition() {
+    assertThat(plugin.getKey(), is("jacoco"));
+    assertThat(plugin.getName(), notNullValue());
+    assertThat(plugin.getDescription(), notNullValue());
+    assertThat(plugin.toString(), is("jacoco"));
+  }
+
+  @Test
+  public void testExtensions() {
+    assertThat(plugin.getExtensions().size(), greaterThan(0));
+  }
+}
diff --git a/plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/JaCoCoSensorTest.java b/plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/JaCoCoSensorTest.java
new file mode 100644 (file)
index 0000000..e3066e5
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.*;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.batch.SensorContext;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.measures.Measure;
+import org.sonar.api.resources.*;
+import org.sonar.api.test.IsMeasure;
+
+import java.io.File;
+
+/**
+ * @author Evgeny Mandrikov
+ */
+public class JaCoCoSensorTest {
+
+  private JacocoConfiguration configuration;
+  private JaCoCoSensor sensor;
+
+  @Before
+  public void setUp() {
+    configuration = mock(JacocoConfiguration.class);
+    sensor = new JaCoCoSensor(configuration);
+  }
+
+  @Test
+  public void testSensorDefinition() {
+    assertThat(sensor.toString(), is("JaCoCoSensor"));
+  }
+
+  @Test
+  public void shouldNotExecuteOnProject() {
+    Project project = mock(Project.class);
+    when(project.getLanguageKey()).thenReturn("flex");
+    assertThat(sensor.shouldExecuteOnProject(project), is(false));
+  }
+
+  @Test
+  public void shouldExecuteOnProject() {
+    Project project = mock(Project.class);
+    when(project.getLanguageKey()).thenReturn(Java.KEY);
+    assertThat(sensor.shouldExecuteOnProject(project), is(true));
+  }
+
+  @Test
+  public void testReadExecutionData() throws Exception {
+    File jacocoExecutionData = new File(getClass().getResource("/org/sonar/plugins/jacoco/JaCoCoSensorTest/jacoco.exec").getFile());
+    File buildOutputDir = jacocoExecutionData.getParentFile();
+    SensorContext context = mock(SensorContext.class);
+
+    final JavaFile resource = new JavaFile("org.sonar.plugins.jacoco.tests.Hello");
+    when(context.getResource(any(Resource.class))).thenReturn(resource);
+
+    ProjectFileSystem pfs = mock(ProjectFileSystem.class);
+    when(pfs.getBuildOutputDir()).thenReturn(buildOutputDir);
+    when(pfs.resolvePath(anyString())).thenReturn(jacocoExecutionData);
+
+    Project project = mock(Project.class);
+    when(project.getFileSystem()).thenReturn(pfs);
+
+    sensor.analyse(project, context);
+
+    verify(context).getResource(eq(resource));
+    verify(context).saveMeasure(eq(resource), argThat(new IsMeasure(CoreMetrics.LINES_TO_COVER, 7.0)));
+    verify(context).saveMeasure(eq(resource), argThat(new IsMeasure(CoreMetrics.UNCOVERED_LINES, 3.0)));
+    verify(context).saveMeasure(eq(resource),
+        argThat(new IsMeasure(CoreMetrics.COVERAGE_LINE_HITS_DATA, "6=1;7=1;8=1;11=1;15=0;16=0;18=0")));
+    verify(context).saveMeasure(eq(resource), argThat(new IsMeasure(CoreMetrics.CONDITIONS_TO_COVER, 2.0)));
+    verify(context).saveMeasure(eq(resource), argThat(new IsMeasure(CoreMetrics.UNCOVERED_CONDITIONS, 2.0)));
+    verify(context).saveMeasure(eq(resource), argThat(new IsMeasure(CoreMetrics.CONDITIONS_BY_LINE, "15=2")));
+    verify(context).saveMeasure(eq(resource), argThat(new IsMeasure(CoreMetrics.COVERED_CONDITIONS_BY_LINE, "15=0")));
+    verifyNoMoreInteractions(context);
+  }
+
+  @Test
+  public void doNotSaveMeasureOnResourceWhichDoesntExistInTheContext() throws Exception {
+    File jacocoExecutionData = new File(getClass().getResource("/org/sonar/plugins/jacoco/JaCoCoSensorTest/jacoco.exec").getFile());
+    File buildOutputDir = jacocoExecutionData.getParentFile();
+    SensorContext context = mock(SensorContext.class);
+    when(context.getResource(any(Resource.class))).thenReturn(null);
+
+    ProjectFileSystem pfs = mock(ProjectFileSystem.class);
+    when(pfs.getBuildOutputDir()).thenReturn(buildOutputDir);
+
+    Project project = mock(Project.class);
+    when(project.getFileSystem()).thenReturn(pfs);
+
+    sensor.analyse(project, context);
+
+    verify(context, never()).saveMeasure(any(Resource.class), any(Measure.class));
+  }
+}
diff --git a/plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/JacocoConfigurationTest.java b/plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/JacocoConfigurationTest.java
new file mode 100644 (file)
index 0000000..ef855eb
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.apache.commons.configuration.BaseConfiguration;
+import org.apache.commons.configuration.Configuration;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+
+public class JacocoConfigurationTest {
+
+  private Configuration configuration;
+  private JacocoConfiguration jacocoConfiguration;
+
+  @Before
+  public void setUp() {
+    JaCoCoAgentDownloader downloader = mock(JaCoCoAgentDownloader.class);
+    when(downloader.getAgentJarFile()).thenReturn(new File("jacocoagent.jar"));
+
+    configuration = new BaseConfiguration();
+
+    jacocoConfiguration = new JacocoConfiguration(configuration, downloader);
+  }
+
+  @Test
+  public void defaults() {
+    assertThat(jacocoConfiguration.getReportPath(), is("target/jacoco.exec"));
+    assertThat(jacocoConfiguration.getJvmArgument(), is("-javaagent:jacocoagent.jar=destfile=target/jacoco.exec"));
+
+    assertThat(jacocoConfiguration.getItReportPath(), is(""));
+
+    assertThat(jacocoConfiguration.getAntTargets(), is(new String[] {}));
+  }
+
+  @Test
+  public void shouldReturnAntTargets() {
+    configuration.setProperty(JacocoConfiguration.ANT_TARGETS_PROPERTY, "test");
+    assertThat(jacocoConfiguration.getAntTargets(), is(new String[] { "test" }));
+
+    configuration.setProperty(JacocoConfiguration.ANT_TARGETS_PROPERTY, "test1,test2");
+    assertThat(jacocoConfiguration.getAntTargets(), is(new String[] { "test1", "test2" }));
+  }
+
+  @Test
+  public void shouldReturnItReportPath() {
+    configuration.setProperty(JacocoConfiguration.IT_REPORT_PATH_PROPERTY, "target/it-jacoco.exec");
+
+    assertThat(jacocoConfiguration.getItReportPath(), is("target/it-jacoco.exec"));
+  }
+
+  @Test
+  public void shouldSetDestfile() {
+    configuration.setProperty(JacocoConfiguration.REPORT_PATH_PROPERTY, "jacoco.exec");
+
+    assertThat(jacocoConfiguration.getReportPath(), is("jacoco.exec"));
+    assertThat(jacocoConfiguration.getJvmArgument(), is("-javaagent:jacocoagent.jar=destfile=jacoco.exec"));
+  }
+
+  @Test
+  public void shouldSetIncludesAndExcludes() {
+    configuration.setProperty(JacocoConfiguration.INCLUDES_PROPERTY, "org.sonar.*");
+    configuration.setProperty(JacocoConfiguration.EXCLUDES_PROPERTY, "org.sonar.api.*");
+    configuration.setProperty(JacocoConfiguration.EXCLCLASSLOADER_PROPERTY, "sun.reflect.DelegatingClassLoader");
+
+    assertThat(jacocoConfiguration.getJvmArgument(),
+        is("-javaagent:jacocoagent.jar=destfile=target/jacoco.exec,includes=org.sonar.*,excludes=org.sonar.api.*,exclclassloader=sun.reflect.DelegatingClassLoader"));
+  }
+
+}
diff --git a/plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/JacocoMavenInitializerTest.java b/plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/JacocoMavenInitializerTest.java
new file mode 100644 (file)
index 0000000..44e3a50
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco;
+
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.resources.Java;
+import org.sonar.api.resources.Project;
+import org.sonar.api.resources.ProjectFileSystem;
+
+public class JacocoMavenInitializerTest {
+  private JaCoCoMavenPluginHandler mavenPluginHandler;
+  private JacocoMavenInitializer initializer;
+
+  @Before
+  public void setUp() {
+    mavenPluginHandler = mock(JaCoCoMavenPluginHandler.class);
+    initializer = new JacocoMavenInitializer(mavenPluginHandler);
+  }
+
+  @Test
+  public void shouldDoNothing() {
+    Project project = mockProject();
+    initializer.execute(project);
+    verifyNoMoreInteractions(project);
+    verifyNoMoreInteractions(mavenPluginHandler);
+  }
+
+  @Test
+  public void shouldExecuteMaven() {
+    Project project = mockProject();
+    when(project.getFileSystem().hasTestFiles(argThat(is(Java.INSTANCE)))).thenReturn(true);
+    when(project.getAnalysisType()).thenReturn(Project.AnalysisType.DYNAMIC);
+
+    assertThat(initializer.shouldExecuteOnProject(project), is(true));
+    assertThat(initializer.getMavenPluginHandler(project), instanceOf(JaCoCoMavenPluginHandler.class));
+  }
+
+  @Test
+  public void shouldNotExecuteMavenWhenReuseReports() {
+    Project project = mockProject();
+    when(project.getFileSystem().hasTestFiles(argThat(is(Java.INSTANCE)))).thenReturn(true);
+    when(project.getAnalysisType()).thenReturn(Project.AnalysisType.REUSE_REPORTS);
+
+    assertThat(initializer.shouldExecuteOnProject(project), is(false));
+  }
+
+  @Test
+  public void shouldNotExecuteMavenWhenNoTests() {
+    Project project = mockProject();
+    when(project.getFileSystem().hasTestFiles(argThat(is(Java.INSTANCE)))).thenReturn(false);
+    when(project.getAnalysisType()).thenReturn(Project.AnalysisType.DYNAMIC);
+
+    assertThat(initializer.shouldExecuteOnProject(project), is(false));
+  }
+
+  private Project mockProject() {
+    Project project = mock(Project.class);
+    ProjectFileSystem projectFileSystem = mock(ProjectFileSystem.class);
+    when(project.getFileSystem()).thenReturn(projectFileSystem);
+    return project;
+  }
+}
diff --git a/plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/itcoverage/ItCoverageWidgetTest.java b/plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/itcoverage/ItCoverageWidgetTest.java
new file mode 100644 (file)
index 0000000..bb5870e
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco.itcoverage;
+
+import org.junit.Test;
+
+import static org.hamcrest.Matchers.notNullValue;
+import static org.junit.Assert.assertThat;
+
+/**
+ * @author Evgeny Mandrikov
+ */
+public class ItCoverageWidgetTest {
+
+  @Test
+  public void testGetTemplatePath() {
+    String path = new ItCoverageWidget().getTemplatePath();
+    assertThat(getClass().getResource(path), notNullValue());
+  }
+
+}
diff --git a/plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/itcoverage/JaCoCoItMetricsTest.java b/plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/itcoverage/JaCoCoItMetricsTest.java
new file mode 100644 (file)
index 0000000..b931fb1
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco.itcoverage;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Test;
+
+public class JaCoCoItMetricsTest {
+
+  @Test
+  public void metricsDefinition() {
+    assertThat(new JaCoCoItMetrics().getMetrics().size(), is(10));
+  }
+
+}
diff --git a/plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/itcoverage/JaCoCoItSensorTest.java b/plugins/sonar-jacoco-plugin/src/test/java/org/sonar/plugins/jacoco/itcoverage/JaCoCoItSensorTest.java
new file mode 100644 (file)
index 0000000..aca9c9b
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.jacoco.itcoverage;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.*;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.batch.SensorContext;
+import org.sonar.api.measures.Measure;
+import org.sonar.api.resources.*;
+import org.sonar.api.resources.Project.AnalysisType;
+import org.sonar.api.test.IsMeasure;
+import org.sonar.plugins.jacoco.JacocoConfiguration;
+
+import java.io.File;
+
+public class JaCoCoItSensorTest {
+  private JacocoConfiguration configuration;
+  private JaCoCoItSensor sensor;
+
+  @Before
+  public void setUp() {
+    configuration = mock(JacocoConfiguration.class);
+    sensor = new JaCoCoItSensor(configuration);
+  }
+
+  @Test
+  public void testSensorDefinition() {
+    assertThat(sensor.toString(), is("JaCoCoItSensor"));
+  }
+
+  @Test
+  public void doNotExecuteWhenReportPathNotSpecified() {
+    when(configuration.getItReportPath()).thenReturn("");
+    Project project = mock(Project.class);
+    assertThat(sensor.shouldExecuteOnProject(project), is(false));
+  }
+
+  @Test
+  public void shouldExecuteOnProject() {
+    when(configuration.getItReportPath()).thenReturn("target/it-jacoco.exec");
+    Project project = mock(Project.class);
+    when(project.getAnalysisType()).thenReturn(AnalysisType.DYNAMIC).thenReturn(AnalysisType.REUSE_REPORTS);
+    assertThat(sensor.shouldExecuteOnProject(project), is(true));
+    assertThat(sensor.shouldExecuteOnProject(project), is(true));
+  }
+
+  @Test
+  public void testReadExecutionData() throws Exception {
+    File jacocoExecutionData = new File(getClass().getResource("/org/sonar/plugins/jacoco/JaCoCoSensorTest/jacoco.exec").getFile());
+    File buildOutputDir = jacocoExecutionData.getParentFile();
+    SensorContext context = mock(SensorContext.class);
+
+    final JavaFile resource = new JavaFile("org.sonar.plugins.jacoco.tests.Hello");
+    when(context.getResource(any(Resource.class))).thenReturn(resource);
+
+    ProjectFileSystem pfs = mock(ProjectFileSystem.class);
+    when(pfs.getBuildOutputDir()).thenReturn(buildOutputDir);
+    when(pfs.resolvePath(anyString())).thenReturn(jacocoExecutionData);
+
+    Project project = mock(Project.class);
+    when(project.getFileSystem()).thenReturn(pfs);
+
+    sensor.analyse(project, context);
+
+    verify(context).getResource(eq(resource));
+    verify(context).saveMeasure(eq(resource), argThat(new IsMeasure(JaCoCoItMetrics.IT_LINES_TO_COVER, 7.0)));
+    verify(context).saveMeasure(eq(resource), argThat(new IsMeasure(JaCoCoItMetrics.IT_UNCOVERED_LINES, 3.0)));
+    verify(context).saveMeasure(eq(resource),
+        argThat(new IsMeasure(JaCoCoItMetrics.IT_COVERAGE_LINE_HITS_DATA, "6=1;7=1;8=1;11=1;15=0;16=0;18=0")));
+    verify(context).saveMeasure(eq(resource), argThat(new IsMeasure(JaCoCoItMetrics.IT_CONDITIONS_TO_COVER, 2.0)));
+    verify(context).saveMeasure(eq(resource), argThat(new IsMeasure(JaCoCoItMetrics.IT_UNCOVERED_CONDITIONS, 2.0)));
+    verify(context).saveMeasure(eq(resource), argThat(new IsMeasure(JaCoCoItMetrics.IT_CONDITIONS_BY_LINE, "15=2")));
+    verify(context).saveMeasure(eq(resource), argThat(new IsMeasure(JaCoCoItMetrics.IT_COVERED_CONDITIONS_BY_LINE, "15=0")));
+    verifyNoMoreInteractions(context);
+  }
+
+  @Test
+  public void doNotSaveMeasureOnResourceWhichDoesntExistInTheContext() throws Exception {
+    File jacocoExecutionData = new File(getClass().getResource("/org/sonar/plugins/jacoco/JaCoCoSensorTest/jacoco.exec").getFile());
+    File buildOutputDir = jacocoExecutionData.getParentFile();
+    SensorContext context = mock(SensorContext.class);
+    when(context.getResource(any(Resource.class))).thenReturn(null);
+
+    ProjectFileSystem pfs = mock(ProjectFileSystem.class);
+    when(pfs.getBuildOutputDir()).thenReturn(buildOutputDir);
+
+    Project project = mock(Project.class);
+    when(project.getFileSystem()).thenReturn(pfs);
+
+    sensor.analyse(project, context);
+
+    verify(context, never()).saveMeasure(any(Resource.class), any(Measure.class));
+  }
+}
diff --git a/plugins/sonar-jacoco-plugin/src/test/resources/org/sonar/plugins/jacoco/JaCoCoMavenPluginHandlerTest/pom.xml b/plugins/sonar-jacoco-plugin/src/test/resources/org/sonar/plugins/jacoco/JaCoCoMavenPluginHandlerTest/pom.xml
new file mode 100644 (file)
index 0000000..0cc5322
--- /dev/null
@@ -0,0 +1,18 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>foo</groupId>
+  <artifactId>bar</artifactId>
+  <version>0.2-SNAPSHOT</version>
+  <packaging>jar</packaging>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <target>1.5</target>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
\ No newline at end of file
diff --git a/plugins/sonar-jacoco-plugin/src/test/resources/org/sonar/plugins/jacoco/JaCoCoMavenPluginHandlerTest/pom2.xml b/plugins/sonar-jacoco-plugin/src/test/resources/org/sonar/plugins/jacoco/JaCoCoMavenPluginHandlerTest/pom2.xml
new file mode 100644 (file)
index 0000000..127ec72
--- /dev/null
@@ -0,0 +1,25 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>foo</groupId>
+  <artifactId>bar</artifactId>
+  <version>0.2-SNAPSHOT</version>
+  <packaging>jar</packaging>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <target>1.5</target>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <argLine>-esa</argLine>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
\ No newline at end of file
diff --git a/plugins/sonar-jacoco-plugin/src/test/resources/org/sonar/plugins/jacoco/JaCoCoSensorTest/Hello.class b/plugins/sonar-jacoco-plugin/src/test/resources/org/sonar/plugins/jacoco/JaCoCoSensorTest/Hello.class
new file mode 100644 (file)
index 0000000..e004f4f
Binary files /dev/null and b/plugins/sonar-jacoco-plugin/src/test/resources/org/sonar/plugins/jacoco/JaCoCoSensorTest/Hello.class differ
diff --git a/plugins/sonar-jacoco-plugin/src/test/resources/org/sonar/plugins/jacoco/JaCoCoSensorTest/jacoco.exec b/plugins/sonar-jacoco-plugin/src/test/resources/org/sonar/plugins/jacoco/JaCoCoSensorTest/jacoco.exec
new file mode 100644 (file)
index 0000000..c7cadcc
Binary files /dev/null and b/plugins/sonar-jacoco-plugin/src/test/resources/org/sonar/plugins/jacoco/JaCoCoSensorTest/jacoco.exec differ
diff --git a/pom.xml b/pom.xml
index 0789a6f8c0a57147c2ee6b28162e9862e7aee8ad..d41bb56dd7015d0a1dc28ae8e80d7c3f0c52c27a 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -48,6 +48,7 @@
     <module>plugins/sonar-design-plugin</module>
     <module>plugins/sonar-l10n-en-plugin</module>
     <module>plugins/sonar-email-notifications-plugin</module>
+    <module>plugins/sonar-jacoco-plugin</module>
   </modules>
 
   <organization>
index f4c91172d7aa3276b6331863b3f17b0c68176f71..4f14a8459ecd9ee0e2ddcd15cd4d8622ff086908 100644 (file)
       <version>${project.version}</version>
       <scope>runtime</scope>
     </dependency>
+    <dependency>
+      <groupId>org.codehaus.sonar.plugins</groupId>
+      <artifactId>sonar-jacoco-plugin</artifactId>
+      <version>${project.version}</version>
+      <scope>runtime</scope>
+    </dependency>
     <dependency>
       <groupId>org.sonatype.jsw-binaries</groupId>
       <artifactId>jsw-binaries</artifactId>
index 0142081d64e95c6aae77666ef73e627474a1d898..3341f21b830707682acded8b9c9176a9b896e1ff 100644 (file)
           <version>${project.version}</version>
           <scope>provided</scope>
         </dependency>
+        <dependency>
+          <groupId>org.codehaus.sonar.plugins</groupId>
+          <artifactId>sonar-jacoco-plugin</artifactId>
+          <version>${project.version}</version>
+          <scope>provided</scope>
+        </dependency>
       </dependencies>
     </profile>