Revision 4564.
--- /dev/null
+<?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>
--- /dev/null
+/*
+ * 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);
+
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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");
+ }
+
+}
--- /dev/null
+/*
+ * 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();
+ }
+
+}
--- /dev/null
+/*
+ * 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();
+ }
+
+}
--- /dev/null
+/*
+ * 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());
+
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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";
+ }
+
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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";
+ }
+}
--- /dev/null
+/*
+ * 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(" ", "");
+ row.setValue2(" ", "");
+
+ 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(" ", "red");
+ }
+ }
+ return Arrays.asList(row);
+ }
+}
--- /dev/null
+/*
+ * 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));
+ }
+ }
+}
--- /dev/null
+/*
+ * 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";
+}
--- /dev/null
+<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>
--- /dev/null
+<%
+ 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 %>
--- /dev/null
+/*
+ * 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")));
+ }
+}
--- /dev/null
+/*
+ * 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"));
+ }
+
+}
--- /dev/null
+/*
+ * 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));
+ }
+}
--- /dev/null
+/*
+ * 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));
+ }
+}
--- /dev/null
+/*
+ * 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"));
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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());
+ }
+
+}
--- /dev/null
+/*
+ * 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));
+ }
+
+}
--- /dev/null
+/*
+ * 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));
+ }
+}
--- /dev/null
+<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
--- /dev/null
+<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
<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>
<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>
<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>