Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for tests in separate project #43

Merged
merged 7 commits into from
Jul 5, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 30 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ A plugin to enable the use of Scoverage in a gradle Scala project.

This has now been deployed to maven central.

Using gradle-scoverage
======================

Getting started
---------------
```groovy
Expand Down Expand Up @@ -34,29 +37,47 @@ This creates an additional task testCoverage which will run tests against instru
Then launch command :
`gradle testScoverage` or `gradle checkScoverage`

Available tasks
---------------

* testScoverage - Executes all tests and creates Scoverage XML report with information about code coverage
* reportScoverage - Generates reports (see below).
* aggregateScoverage - Aggregates reports from multiple sub-projects (see below).
* checkScoverage - See below.
* compileScoverageScala - Instruments code without running tests.

ReportScoverage
---------------

You can configure output generated by `gradle reportScoverage` using flags:

| Flag name | Default value | Description |
| ------------------------|---------------|-------------------------------------------------|
| coverageOutputCobertura | true | Enables/disables cobertura.xml file generation. |
| coverageOutputXML | true | Enables/disables scoverage XML output. |
| coverageOutputHTML | true | Enables/disables scoverage HTML output. |
| coverageDebug | false | Enables/disables scoverage debug output. |

Aggregating Reports
-------------------

There is now experimental support for aggregating coverage statistics across subprojects.
There is now experimental support for aggregating coverage statistics across sub-projects.

The project hosting the aggregation task **must** be configured as the sub-projects are;
i.e. with the scoverage plugin applied and the scoverage dependencies configured.

You also have to declare this task:

```groovy
task aggregateScoverage(type: org.scoverage.ScoverageAggregate)
```

This will produce a report into _build_ / scoverage-aggregate
This will produce a report into `build/scoverage-aggregate` directory.

Available tasks
---------
* testScoverage - Executes all tests and creates Scoverage XML report with information about code coverage
* reportScoverage - Generates HTML report.
* checkScoverage - See below.
* compileScoverageScala - Instruments code without running tests.
Aggregation uses same flags as reporting for enabling/disabling different output types.

CheckScoverage
---------
--------------

By default, when you launch `gradle checkScoverage` build fail if only 75% of project is covered by tests.

Expand Down
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ dependencies {
compile gradleApi()
compile localGroovy()
scoverage 'org.scoverage:scalac-scoverage-plugin_2.11:1.0.2'
testCompile 'org.hamcrest:hamcrest-library:1.3'
}

task groovydocJar(type: Jar, dependsOn: groovydoc) {
Expand Down
19 changes: 16 additions & 3 deletions src/main/groovy/org/scoverage/AggregateReportApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,23 @@ public static void main(String... args) {
File rootDir = new File(args[0]);
File reportDir = new File(args[1]);
Boolean clean = Boolean.parseBoolean(args[2]);
reportDir.mkdirs();

Boolean coverageOutputCobertura = java.lang.Boolean.valueOf(args[3]);
Boolean coverageOutputXML = java.lang.Boolean.valueOf(args[4]);
Boolean coverageOutputHTML = java.lang.Boolean.valueOf(args[5]);
Boolean coverageDebug = java.lang.Boolean.valueOf(args[6]);

Coverage coverage = CoverageAggregator.aggregate(rootDir, clean).get();
new ScoverageHtmlWriter(rootDir, reportDir).write(coverage);
new CoberturaXmlWriter(rootDir, reportDir).write(coverage);

ScoverageWriter.write(
rootDir,
reportDir,
coverage,
coverageOutputCobertura,
coverageOutputXML,
coverageOutputHTML,
coverageDebug
);
}

}
14 changes: 11 additions & 3 deletions src/main/groovy/org/scoverage/ScoverageAggregate.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,21 @@ class ScoverageAggregate extends JavaExec {

@Override
void exec() {
def extension = ScoveragePlugin.extensionIn(project)
setClasspath(ScoveragePlugin.extensionIn(project).pluginClasspath)
setMain('org.scoverage.AggregateReportApp')
def reportPath = reportDirOrDefault()
setArgs([project.projectDir, reportPath.absolutePath, clean])
setArgs([
project.projectDir,
reportPath.absolutePath,
clean,
// TODO - consider separate options for `report` and `aggregate` tasks
extension.coverageOutputCobertura,
extension.coverageOutputXML,
extension.coverageOutputHTML,
extension.coverageDebug
])
super.exec()
def reportEntryPoint = new File(reportPath, 'index.html').absolutePath
project.logger.lifecycle("Wrote aggregated scoverage report to ${reportEntryPoint}")
}

def reportDirOrDefault() {
Expand Down
16 changes: 16 additions & 0 deletions src/main/groovy/org/scoverage/ScoverageExtension.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.plugins.scala.ScalaPlugin
import org.gradle.api.tasks.JavaExec
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.testing.Test
import org.gradle.util.GFileUtils

Expand Down Expand Up @@ -48,6 +49,12 @@ class ScoverageExtension {

FileCollection pluginClasspath

/** Options for enabling and disabling output */
boolean coverageOutputCobertura = true
boolean coverageOutputXML = true
boolean coverageOutputHTML = true
boolean coverageDebug = false

ScoverageExtension(Project project) {

project.plugins.apply(JavaPlugin.class);
Expand Down Expand Up @@ -82,6 +89,15 @@ class ScoverageExtension {
runtimeClasspath = it.output + mainSourceSet.output + project.configurations.scoverage + project.configurations.testRuntime
}

def scoverageJar = project.tasks.create('jarScoverage', Jar.class) {
dependsOn('scoverageClasses')
classifier = ScoveragePlugin.CONFIGURATION_NAME
from mainSourceSet.output
}
project.artifacts {
scoverage project.tasks.jarScoverage
}

project.tasks.create(ScoveragePlugin.TEST_NAME, Test.class) {
conventionMapping.map("testClassesDir", new Callable<Object>() {
public Object call() throws Exception {
Expand Down
10 changes: 9 additions & 1 deletion src/main/groovy/org/scoverage/ScoverageReport.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,15 @@ class ScoverageReport extends JavaExec {
extension.reportDir.mkdirs()
setClasspath(extension.pluginClasspath)
setMain('org.scoverage.SingleReportApp')
setArgs([extension.sources.absolutePath, extension.dataDir.absolutePath, extension.reportDir.absolutePath])
setArgs([
/* sourceDir = */ extension.sources.absolutePath,
/* dataDir = */ extension.dataDir.absolutePath,
/* reportDir = */ extension.reportDir.absolutePath,
extension.coverageOutputCobertura,
extension.coverageOutputXML,
extension.coverageOutputHTML,
extension.coverageDebug
])
super.exec()
}
}
74 changes: 74 additions & 0 deletions src/main/groovy/org/scoverage/ScoverageWriter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package org.scoverage;

import scoverage.Constants;
import scoverage.Coverage;
import scoverage.report.CoberturaXmlWriter;
import scoverage.report.ScoverageHtmlWriter;
import scoverage.report.ScoverageXmlWriter;

import java.io.File;

/**
* Util for generating and saving coverage files.
* <p/>
* Copied from sbt-scoverage and converted to Java to avoid dependency to Scala.
*/
public class ScoverageWriter {

/**
* Generates all reports from given data.
*
* @param sourceDir directory with project sources
* @param reportDir directory for generate reports
* @param coverage coverage data
* @param coverageOutputCobertura switch for Cobertura output
* @param coverageOutputXML switch for Scoverage XML output
* @param coverageOutputHTML switch for Scoverage HTML output
* @param coverageDebug switch for Scoverage Debug output
*/
public static void write(File sourceDir,
File reportDir,
Coverage coverage,
Boolean coverageOutputCobertura,
Boolean coverageOutputXML,
Boolean coverageOutputHTML,
Boolean coverageDebug) {

System.out.println("[scoverage] Generating scoverage reports...");

reportDir.mkdirs();

if (coverageOutputCobertura) {
new CoberturaXmlWriter(sourceDir, reportDir).write(coverage);
System.out.println("[scoverage] Written Cobertura XML report to " +
reportDir.getAbsolutePath() +
File.separator +
"cobertura.xml");
}

if (coverageOutputXML) {
new ScoverageXmlWriter(sourceDir, reportDir, /* debug = */ false).write(coverage);
System.out.println("[scoverage] Written XML report to " +
reportDir.getAbsolutePath() +
File.separator +
Constants.XMLReportFilename());
if (coverageDebug) {
new ScoverageXmlWriter(sourceDir, reportDir, /* debug = */ true).write(coverage);
System.out.println("[scoverage] Written XML report with debug information to " +
reportDir.getAbsolutePath() +
File.separator +
Constants.XMLReportFilenameWithDebug());
}
}

if (coverageOutputHTML) {
new ScoverageHtmlWriter(sourceDir, reportDir).write(coverage);
System.out.println("[scoverage] Written HTML report to " +
reportDir.getAbsolutePath() +
File.separator +
"index.html");
}

System.out.println("[scoverage] Coverage reports completed");
}
}
41 changes: 27 additions & 14 deletions src/main/groovy/org/scoverage/SingleReportApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
import scoverage.Coverage;
import scoverage.IOUtils;
import scoverage.Serializer;
import scoverage.report.CoberturaXmlWriter;
import scoverage.report.ScoverageHtmlWriter;
import scoverage.report.ScoverageXmlWriter;

import java.io.File;
import java.util.Arrays;
Expand All @@ -21,20 +18,36 @@ public static void main(String... args) {
File sourceDir = new File(args[0]);
File dataDir = new File(args[1]);
File reportDir = new File(args[2]);
reportDir.mkdirs();

Boolean coverageOutputCobertura = java.lang.Boolean.valueOf(args[3]);
Boolean coverageOutputXML = java.lang.Boolean.valueOf(args[4]);
Boolean coverageOutputHTML = java.lang.Boolean.valueOf(args[5]);
Boolean coverageDebug = java.lang.Boolean.valueOf(args[6]);

File coverageFile = Serializer.coverageFile(dataDir);
File[] array = IOUtils.findMeasurementFiles(dataDir);
// TODO: patch scoverage core to use a consistent collection type?
Seq<File> measurementFiles = scala.collection.JavaConversions.asScalaBuffer(Arrays.asList(array));

Coverage coverage = Serializer.deserialize(coverageFile);
if (!coverageFile.exists()) {
System.out.println("[scoverage] Could not find coverage file, skipping...");
} else {
File[] array = IOUtils.findMeasurementFiles(dataDir);
// TODO: patch scoverage core to use a consistent collection type?
Seq<File> measurementFiles = scala.collection.JavaConversions.asScalaBuffer(Arrays.asList(array));

Coverage coverage = Serializer.deserialize(coverageFile);

Set<Object> measurements = IOUtils.invoked(measurementFiles);
coverage.apply(measurements);

ScoverageWriter.write(
sourceDir,
reportDir,
coverage,
coverageOutputCobertura,
coverageOutputXML,
coverageOutputHTML,
coverageDebug);
}
}

Set<Object> measurements = IOUtils.invoked(measurementFiles);
coverage.apply(measurements);

new ScoverageXmlWriter(sourceDir, reportDir, false).write(coverage);
new ScoverageHtmlWriter(sourceDir, reportDir).write(coverage);
new CoberturaXmlWriter(sourceDir, reportDir).write(coverage);
}
}
57 changes: 57 additions & 0 deletions src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package org.scoverage

import org.gradle.tooling.BuildLauncher
import org.gradle.tooling.GradleConnector
import org.hamcrest.core.Is
import org.junit.Assert

enum CoverageType {
Line('cobertura.xml', 'line-rate'),
Statement('scoverage.xml', 'statement-rate'),
Branch('scoverage.xml', 'branch-rate')

String fileName
String paramName

CoverageType(String fileName, String paramName) {
this.fileName = fileName
this.paramName = paramName
}
}

/**
* Some utils for easy acceptance testing.
*/
class AcceptanceTestUtils {

XmlParser parser

AcceptanceTestUtils() {
parser = new XmlParser()
parser.setFeature('http://apache.org/xml/features/disallow-doctype-decl', false)
parser.setFeature('http://apache.org/xml/features/nonvalidating/load-external-dtd', false)
}

protected BuildLauncher setupBuild(File projectRoot, boolean useAnt) {
return GradleConnector.
newConnector().
forProjectDirectory(projectRoot).
connect().
newBuild().
withArguments("-PuseAnt=$useAnt")
}

protected void checkFile(String description, File file, boolean shouldExist) throws Exception {
Assert.assertThat(description + ' should be created at ' + file.absolutePath, file.exists(), Is.is(shouldExist))
}

protected File reportDir(File baseDir) {
return new File(baseDir, 'build/reports/scoverage')
}

protected Double coverage(File reportDir, CoverageType coverageType) {
File reportFile = new File(reportDir, coverageType.fileName)
def xml = parser.parse(reportFile)
xml.attribute(coverageType.paramName).toDouble()
}
}
Loading