From af4f38ca28bed28027091180a69773f97074f40a Mon Sep 17 00:00:00 2001 From: Stu Date: Tue, 29 Dec 2015 14:18:16 +0000 Subject: [PATCH 001/167] bad merge of README puts ```groovy tag in the wrong place --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c59a98d..77de109 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,6 @@ A plugin to enable the use of Scoverage in a gradle Scala project. Getting started --------------- -```groovy http://plugins.gradle.org/plugin/org.scoverage This creates an additional task `testScoverage` which will run tests against instrumented code. @@ -15,6 +14,7 @@ A further task `reportScoverage` produces XML and HTML reports for analysing tes You need to configure the version of Scoverage that will be used. This plugin should be compatible with all 1+ versions. +```groovy dependencies { scoverage 'org.scoverage:scalac-scoverage-plugin_2.11:1.1.0', 'org.scoverage:scalac-scoverage-runtime_2.11:1.1.0' } From 531bc3d27a67ee52749e48712ba834524222646a Mon Sep 17 00:00:00 2001 From: Stu Date: Wed, 30 Dec 2015 10:35:18 +0000 Subject: [PATCH 002/167] gradle publish plugin requires a string for the version --- build.gradle | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index 3350136..f3287c3 100644 --- a/build.gradle +++ b/build.gradle @@ -12,12 +12,8 @@ buildscript { apply plugin: "com.gradle.plugin-publish" description = 'gradle-scoverage is a Gradle plugin for calculating code coverage using Scoverage' -version = { - if (project.hasProperty('version')) { - return project.getProperty('version') - } else { - return '2.0.0-SNAPSHOT' - } +if (project.version == 'unspecified') { + version = '2.0.0-SNAPSHOT' } repositories { From d0ec054f6e8415d0cf619d75be9e38a332e05b1f Mon Sep 17 00:00:00 2001 From: Stu Date: Sat, 16 Jan 2016 20:59:20 +0000 Subject: [PATCH 003/167] Issue 55 - Scala compilation removes Java classes compiled previously --- src/main/groovy/org/scoverage/ScoverageExtension.groovy | 2 +- src/test/happy day/src/main/java/old/World.java | 7 +++++++ src/test/happy day/src/main/scala/hello/World.scala | 5 ++++- 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 src/test/happy day/src/main/java/old/World.java diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index a7af8a3..8e0b40c 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -69,8 +69,8 @@ class ScoverageExtension { def mainSourceSet = project.sourceSets.create('scoverage') { def original = project.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) - java.source(original.java) resources.source(original.resources) + scala.source(original.java) scala.source(original.scala) compileClasspath += original.compileClasspath + project.configurations.scoverage diff --git a/src/test/happy day/src/main/java/old/World.java b/src/test/happy day/src/main/java/old/World.java new file mode 100644 index 0000000..97f710f --- /dev/null +++ b/src/test/happy day/src/main/java/old/World.java @@ -0,0 +1,7 @@ +package old; + +public class World { + public String getMessage() { + return "Hello old boy"; + } +} \ No newline at end of file diff --git a/src/test/happy day/src/main/scala/hello/World.scala b/src/test/happy day/src/main/scala/hello/World.scala index 7a1589a..cd1117d 100644 --- a/src/test/happy day/src/main/scala/hello/World.scala +++ b/src/test/happy day/src/main/scala/hello/World.scala @@ -1,5 +1,8 @@ package hello object World { - def say() = println("ahoy") + def say() = { + println(new old.World().getMessage()) + println("ahoy") + } } \ No newline at end of file From 8312d8a543ead5cdc381cb693394facffca4bf95 Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 21 Aug 2016 12:17:36 +0100 Subject: [PATCH 004/167] bump to scoverage 1.1.1 --- build.gradle | 2 +- init-scoverage.gradle | 7 +++++++ src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy | 5 ++++- src/test/happy day/build.gradle | 3 +-- src/test/runtime/build.gradle | 3 +-- src/test/separate-tests/build.gradle | 3 +-- src/test/water/build.gradle | 3 +-- 7 files changed, 16 insertions(+), 10 deletions(-) create mode 100644 init-scoverage.gradle diff --git a/build.gradle b/build.gradle index f3287c3..3f20f50 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ configurations { dependencies { compile gradleApi() compile localGroovy() - scoverage 'org.scoverage:scalac-scoverage-plugin_2.11:1.0.2' + scoverage "org.scoverage:scalac-scoverage-plugin_2.11:1.1.1" testCompile 'org.hamcrest:hamcrest-library:1.3' } diff --git a/init-scoverage.gradle b/init-scoverage.gradle new file mode 100644 index 0000000..0d7837a --- /dev/null +++ b/init-scoverage.gradle @@ -0,0 +1,7 @@ +gradle.beforeProject { p -> + p.ext { + scoverageVersion = '1.1.1' + scoverageLib = ["org.scoverage:scalac-scoverage-plugin_2.11:${scoverageVersion}", + "org.scoverage:scalac-scoverage-runtime_2.11:${scoverageVersion}"] + } +} diff --git a/src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy b/src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy index 0cc9773..dfd52c4 100644 --- a/src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy +++ b/src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy @@ -26,7 +26,10 @@ class AcceptanceTestUtils { forProjectDirectory(projectRoot). connect(). newBuild(). - withArguments("-PuseAnt=$useAnt") + withArguments( + "-PuseAnt=$useAnt", + '--init-script', + new File(System.properties.getProperty('user.dir'), 'init-scoverage.gradle').toString()) } protected void checkFile(String description, File file, boolean shouldExist) throws Exception { diff --git a/src/test/happy day/build.gradle b/src/test/happy day/build.gradle index 86af52b..c2c4f43 100644 --- a/src/test/happy day/build.gradle +++ b/src/test/happy day/build.gradle @@ -17,8 +17,7 @@ repositories { } dependencies { - scoverage 'org.scoverage:scalac-scoverage-plugin_2.11:1.0.1', - 'org.scoverage:scalac-scoverage-runtime_2.11:1.0.1' + scoverage scoverageLib compile 'org.scala-lang:scala-library:2.11.0' testCompile 'junit:junit:4.11' } diff --git a/src/test/runtime/build.gradle b/src/test/runtime/build.gradle index 8856440..0ed527f 100644 --- a/src/test/runtime/build.gradle +++ b/src/test/runtime/build.gradle @@ -17,8 +17,7 @@ repositories { } dependencies { - scoverage 'org.scoverage:scalac-scoverage-plugin_2.11:1.0.1', - 'org.scoverage:scalac-scoverage-runtime_2.11:1.0.1' + scoverage scoverageLib compile 'org.scala-lang:scala-library:2.11.0' } diff --git a/src/test/separate-tests/build.gradle b/src/test/separate-tests/build.gradle index e84bfb7..8a258dd 100644 --- a/src/test/separate-tests/build.gradle +++ b/src/test/separate-tests/build.gradle @@ -21,8 +21,7 @@ subprojects { dependencies { compile 'org.scala-lang:scala-library:2.11.4' - scoverage 'org.scoverage:scalac-scoverage-plugin_2.11:1.0.4', - 'org.scoverage:scalac-scoverage-runtime_2.11:1.0.4' + scoverage scoverageLib testCompile 'junit:junit:4.11' } diff --git a/src/test/water/build.gradle b/src/test/water/build.gradle index d487e80..d65b65c 100644 --- a/src/test/water/build.gradle +++ b/src/test/water/build.gradle @@ -20,8 +20,7 @@ allprojects { apply plugin: 'org.scoverage' dependencies { - scoverage 'org.scoverage:scalac-scoverage-plugin_2.11:1.0.4', - 'org.scoverage:scalac-scoverage-runtime_2.11:1.0.4' + scoverage scoverageLib compile 'org.scala-lang:scala-library:2.11.5' testCompile 'junit:junit:4.11' From 96e41cc26fe2e233cd3a103df612a1f64be8b5b0 Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 21 Aug 2016 12:18:36 +0100 Subject: [PATCH 005/167] bump to gradle 3.0 --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- .../org/scoverage/ScoverageExtension.groovy | 22 +++------------- .../org/scoverage/AcceptanceTestUtils.groovy | 3 +-- .../AggregationAcceptanceTest.groovy | 25 ++++--------------- .../scoverage/ScoverageExtensionTest.groovy | 21 ---------------- .../SeparateTestsAcceptanceTest.groovy | 24 +++--------------- .../SimpleReportAcceptanceTest.groovy | 20 ++++----------- src/test/happy day/build.gradle | 4 --- 9 files changed, 19 insertions(+), 104 deletions(-) delete mode 100644 src/test/groovy/org/scoverage/ScoverageExtensionTest.groovy diff --git a/build.gradle b/build.gradle index 3f20f50..5dba0ec 100644 --- a/build.gradle +++ b/build.gradle @@ -45,7 +45,7 @@ dependencies { compile gradleApi() compile localGroovy() scoverage "org.scoverage:scalac-scoverage-plugin_2.11:1.1.1" - testCompile 'org.hamcrest:hamcrest-library:1.3' + testCompile 'junit:junit:4.12', 'org.hamcrest:hamcrest-library:1.3' } task groovydocJar(type: Jar, dependsOn: groovydoc) { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 39622f4..73ac16e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-2.9-bin.zip +distributionUrl=http\://services.gradle.org/distributions/gradle-3.0-all.zip diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index 8e0b40c..f866287 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -21,18 +21,6 @@ import java.util.concurrent.Callable */ class ScoverageExtension { - private static boolean isEscaped(String argument) { - return (argument.startsWith('"') && argument.endsWith('"')) || (argument.startsWith('\'') && argument.endsWith('\'')) - } - - static String escape(String argument) { - if (isEscaped(argument)) { - return argument - } else { - return "\"$argument\"" - } - } - /** a directory to write working files to */ File dataDir /** a directory to write final output to */ @@ -158,14 +146,10 @@ class ScoverageExtension { if (extension.highlighting) { parameters.add('-Yrangepos') } - if (scalaCompileOptions.useAnt) { - scalaCompileOptions.additionalParameters = parameters.collect { escape(it) } - } else { - doFirst { - GFileUtils.deleteDirectory(destinationDir) - } - scalaCompileOptions.additionalParameters = parameters + doFirst { + GFileUtils.deleteDirectory(destinationDir) } + scalaCompileOptions.additionalParameters = parameters // the compile task creates a store of measured statements outputs.file(new File(extension.dataDir, 'scoverage.coverage.xml')) } diff --git a/src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy b/src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy index dfd52c4..803da60 100644 --- a/src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy +++ b/src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy @@ -20,14 +20,13 @@ class AcceptanceTestUtils { parser.setFeature('http://apache.org/xml/features/nonvalidating/load-external-dtd', false) } - protected BuildLauncher setupBuild(File projectRoot, boolean useAnt) { + protected BuildLauncher setupBuild(File projectRoot) { return GradleConnector. newConnector(). forProjectDirectory(projectRoot). connect(). newBuild(). withArguments( - "-PuseAnt=$useAnt", '--init-script', new File(System.properties.getProperty('user.dir'), 'init-scoverage.gradle').toString()) } diff --git a/src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy b/src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy index a0ac493..f5e2cf5 100644 --- a/src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy +++ b/src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy @@ -4,39 +4,24 @@ import org.junit.Test class AggregationAcceptanceTest extends AcceptanceTestUtils { - private static File aggregateReportDir(File baseDir) { - return new File(baseDir, 'build/scoverage-aggregate') - } - - private testWater(boolean useAnt) throws Exception { + @Test + public void testMultiProjectAggregationWithZinc() throws Exception { File projectDir = new File('src/test/water') - - def build = setupBuild(projectDir, useAnt) + def build = setupBuild(projectDir) build.forTasks('clean', 'reportScoverage', 'aggregateScoverage').run() - def indexHtml = new File(aggregateReportDir(projectDir), 'index.html') checkFile('an aggregated index HTML file', indexHtml, true) - def cobertura = new File(aggregateReportDir(projectDir), 'cobertura.xml') checkFile('an aggregated cobertura XML file', cobertura, true) - def scoverageXml = new File(aggregateReportDir(projectDir), 'scoverage.xml') checkFile('an aggregated scoverage XML file', scoverageXml, true) - def krillsHtml = new File(aggregateReportDir(projectDir), 'krills.html') checkFile('a HTML file for \'krills\' sub-project', krillsHtml, true) - def whalesHtml = new File(aggregateReportDir(projectDir), 'whales.html') checkFile('a HTML file for \'whales\' sub-project', whalesHtml, true) } - @Test - public void testMultiProjectAggregationWithAnt() throws Exception { - testWater(true) - } - - @Test - public void testMultiProjectAggregationWithZinc() throws Exception { - testWater(false) + private static File aggregateReportDir(File baseDir) { + return new File(baseDir, 'build/scoverage-aggregate') } } diff --git a/src/test/groovy/org/scoverage/ScoverageExtensionTest.groovy b/src/test/groovy/org/scoverage/ScoverageExtensionTest.groovy deleted file mode 100644 index e8572ce..0000000 --- a/src/test/groovy/org/scoverage/ScoverageExtensionTest.groovy +++ /dev/null @@ -1,21 +0,0 @@ -package org.scoverage - -import org.junit.Test - -import static org.hamcrest.CoreMatchers.equalTo -import static org.hamcrest.MatcherAssert.assertThat - -class ScoverageExtensionTest { - - static def quote(String s) { '\'' + s + '\'' } - - static def doubleQuote(String s) { '"' + s + '"' } - - @Test - public void testStringEscaping() throws Exception { - def parameter = 'my param' - assertThat(ScoverageExtension.escape(parameter), equalTo(doubleQuote(parameter))) - assertThat(ScoverageExtension.escape(quote(parameter)), equalTo(quote(parameter))) - assertThat(ScoverageExtension.escape(doubleQuote(parameter)), equalTo(doubleQuote(parameter))) - } -} diff --git a/src/test/groovy/org/scoverage/SeparateTestsAcceptanceTest.groovy b/src/test/groovy/org/scoverage/SeparateTestsAcceptanceTest.groovy index f9b7158..54c7ec2 100644 --- a/src/test/groovy/org/scoverage/SeparateTestsAcceptanceTest.groovy +++ b/src/test/groovy/org/scoverage/SeparateTestsAcceptanceTest.groovy @@ -7,40 +7,22 @@ import static org.junit.Assert.assertThat class SeparateTestsAcceptanceTest extends AcceptanceTestUtils { - private void testSeparate(boolean useAnt) throws Exception { + @Test + public void testSeparateTestsWithZinc() throws Exception { File projectDir = new File('src/test/separate-tests') File subprojectDir = new File(projectDir, 'a') File testsSubprojectDir = new File(projectDir, 'a-tests') - - def build = setupBuild(projectDir, useAnt) + def build = setupBuild(projectDir) build.forTasks('clean', 'reportScoverage').run() - - // ensure report is generated in base project ... def indexHtml = new File(reportDir(subprojectDir), 'index.html') checkFile('an index HTML file', indexHtml, true) - - // ... but not in test project ... def testsIndexHtml = new File(reportDir(testsSubprojectDir), 'index.html') checkFile('an index HTML file', testsIndexHtml, false) - - // ... and 'Hello.scala' is present there ... def helloHtml = new File(reportDir(subprojectDir), 'src/main/scala/hello/Hello.scala.html') checkFile('Hello.scala html file', helloHtml, true) - - // ... and both statement and branch coverage is 100% def branchCoverage = coverage(reportDir(subprojectDir), CoverageType.Branch) def statementCoverage = coverage(reportDir(subprojectDir), CoverageType.Statement) assertThat('Branch coverage should be 100%, was ' + branchCoverage, branchCoverage, closeTo(100.0, 1.0)) assertThat('Statement coverage should be 100%, was ' + statementCoverage, statementCoverage, closeTo(100.0, 1.0)) } - - @Test - public void testSeparateTestsWithAnt() throws Exception { - testSeparate(true) - } - - @Test - public void testSeparateTestsWithZinc() throws Exception { - testSeparate(false) - } } diff --git a/src/test/groovy/org/scoverage/SimpleReportAcceptanceTest.groovy b/src/test/groovy/org/scoverage/SimpleReportAcceptanceTest.groovy index 630d1f9..39641d5 100644 --- a/src/test/groovy/org/scoverage/SimpleReportAcceptanceTest.groovy +++ b/src/test/groovy/org/scoverage/SimpleReportAcceptanceTest.groovy @@ -4,12 +4,12 @@ import org.junit.Test class SimpleReportAcceptanceTest extends AcceptanceTestUtils { - private testHappyDay(boolean useAnt) throws Exception { - File projectRoot = new File('src/test/happy day') - def build = setupBuild(projectRoot, useAnt) + @Test + public void testZincProjectWithCompleteCoverage() throws Exception { + File projectRoot = new File('src/test/happy day') + def build = setupBuild(projectRoot) build.forTasks('clean', 'checkScoverage').run() - def html = new File(reportDir(projectRoot), 'index.html') checkFile('an index HTML file', html, true) def cobertura = new File(reportDir(projectRoot), 'cobertura.xml') @@ -18,20 +18,10 @@ class SimpleReportAcceptanceTest extends AcceptanceTestUtils { checkFile('a scoverage XML file', scoverageXml, true) } - @Test - public void testAntProjectWithCompleteCoverage() throws Exception { - testHappyDay(true) - } - - @Test - public void testZincProjectWithCompleteCoverage() throws Exception { - testHappyDay(false) - } - @Test public void testRun() throws Exception { File projectRoot = new File('src/test/runtime') - def build = setupBuild(projectRoot, true) + def build = setupBuild(projectRoot) build.forTasks('clean', 'run').run() } } diff --git a/src/test/happy day/build.gradle b/src/test/happy day/build.gradle index c2c4f43..a4a19ef 100644 --- a/src/test/happy day/build.gradle +++ b/src/test/happy day/build.gradle @@ -25,8 +25,4 @@ dependencies { checkScoverage { minimumRate = 1.0 coverageType = 'Line' -} - -tasks.withType(ScalaCompile) { - scalaCompileOptions.useAnt = project.hasProperty('useAnt') ? project.property('useAnt').toBoolean() : true } \ No newline at end of file From f4e8762e82fc90cf5df139993b9d9661e6893afc Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 21 Aug 2016 19:54:30 +0100 Subject: [PATCH 006/167] demonstrate use of task dependencies for aggregate coverage --- .../org/scoverage/AggregationAcceptanceTest.groovy | 2 +- src/test/water/build.gradle | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy b/src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy index f5e2cf5..931e9fb 100644 --- a/src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy +++ b/src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy @@ -8,7 +8,7 @@ class AggregationAcceptanceTest extends AcceptanceTestUtils { public void testMultiProjectAggregationWithZinc() throws Exception { File projectDir = new File('src/test/water') def build = setupBuild(projectDir) - build.forTasks('clean', 'reportScoverage', 'aggregateScoverage').run() + build.forTasks('clean', 'aggregateScoverage').run() def indexHtml = new File(aggregateReportDir(projectDir), 'index.html') checkFile('an aggregated index HTML file', indexHtml, true) def cobertura = new File(aggregateReportDir(projectDir), 'cobertura.xml') diff --git a/src/test/water/build.gradle b/src/test/water/build.gradle index d65b65c..9c64d97 100644 --- a/src/test/water/build.gradle +++ b/src/test/water/build.gradle @@ -10,8 +10,6 @@ buildscript { } } -task aggregateScoverage(type: org.scoverage.ScoverageAggregate) - allprojects { repositories { mavenCentral() @@ -26,3 +24,10 @@ allprojects { testCompile 'junit:junit:4.11' } } + +task aggregateScoverage(type: org.scoverage.ScoverageAggregate) + +subprojects { + aggregateScoverage.dependsOn(it.tasks) +} + From 617ddb7d09a93ca8186a555a4959a2910d4e0000 Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 21 Aug 2016 19:55:53 +0100 Subject: [PATCH 007/167] IntelliJ now seems to create its own compilation output directory --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 7a275d3..39e1fda 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +classes build .gradle From 2dc12ad27454a530596ec6502504d6eb4ef011d9 Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 21 Aug 2016 20:06:13 +0100 Subject: [PATCH 008/167] increase travis logging --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 87912d4..bdc0c3d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,3 @@ language: groovy script: - - "gradle build test" \ No newline at end of file + - "gradle --info --stacktrace test" \ No newline at end of file From 3410cf2a19de18e913e1cd99867c096ca52cc84f Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 21 Aug 2016 20:22:58 +0100 Subject: [PATCH 009/167] update test names to reflect that there is no longer an ant/zinc divide --- src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy | 2 +- src/test/groovy/org/scoverage/SimpleReportAcceptanceTest.groovy | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy b/src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy index 931e9fb..d5883f2 100644 --- a/src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy +++ b/src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy @@ -5,7 +5,7 @@ import org.junit.Test class AggregationAcceptanceTest extends AcceptanceTestUtils { @Test - public void testMultiProjectAggregationWithZinc() throws Exception { + public void testMultiProjectAggregation() throws Exception { File projectDir = new File('src/test/water') def build = setupBuild(projectDir) build.forTasks('clean', 'aggregateScoverage').run() diff --git a/src/test/groovy/org/scoverage/SimpleReportAcceptanceTest.groovy b/src/test/groovy/org/scoverage/SimpleReportAcceptanceTest.groovy index 39641d5..8be41e5 100644 --- a/src/test/groovy/org/scoverage/SimpleReportAcceptanceTest.groovy +++ b/src/test/groovy/org/scoverage/SimpleReportAcceptanceTest.groovy @@ -6,7 +6,7 @@ class SimpleReportAcceptanceTest extends AcceptanceTestUtils { @Test - public void testZincProjectWithCompleteCoverage() throws Exception { + public void testProjectWithCompleteCoverage() throws Exception { File projectRoot = new File('src/test/happy day') def build = setupBuild(projectRoot) build.forTasks('clean', 'checkScoverage').run() From d25b2db7b6d1df448d64f6e8149024f9e63f409a Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 21 Aug 2016 20:27:52 +0100 Subject: [PATCH 010/167] attempt to make Travis use the Gradle Wrapper rather than the bundled gradle --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index bdc0c3d..3b53e86 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,3 @@ language: groovy script: - - "gradle --info --stacktrace test" \ No newline at end of file + - "./gradlew --info --stacktrace test" \ No newline at end of file From e1995951cb9cbe242b3e026abd5a12e28358fb78 Mon Sep 17 00:00:00 2001 From: Stu Date: Wed, 21 Jun 2017 06:48:27 +0100 Subject: [PATCH 011/167] bump to gradle 4.0 --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 73ac16e..eb8dfdf 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-3.0-all.zip +distributionUrl=http\://services.gradle.org/distributions/gradle-4.0-all.zip From 2ec5d1afcc514d502d634cb5e72e21b967663af4 Mon Sep 17 00:00:00 2001 From: Stu Date: Fri, 27 Apr 2018 21:00:59 +0100 Subject: [PATCH 012/167] declare that the testScoverage task write to the data directory --- src/main/groovy/org/scoverage/ScoverageExtension.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index f866287..35e7237 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -153,6 +153,7 @@ class ScoverageExtension { // the compile task creates a store of measured statements outputs.file(new File(extension.dataDir, 'scoverage.coverage.xml')) } + t.tasks[ScoveragePlugin.TEST_NAME].outputs.dir(extension.dataDir) } } } From b5769ac31d8778bcee17ef9916d12872fa9ed9cc Mon Sep 17 00:00:00 2001 From: Stu Date: Fri, 27 Apr 2018 21:17:52 +0100 Subject: [PATCH 013/167] respect the base classpaths to support the new implementation and testImplementation configurations --- src/main/groovy/org/scoverage/ScoverageExtension.groovy | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index 35e7237..ee198b0 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -62,7 +62,7 @@ class ScoverageExtension { scala.source(original.scala) compileClasspath += original.compileClasspath + project.configurations.scoverage - runtimeClasspath = it.output + project.configurations.scoverage + project.configurations.runtime + runtimeClasspath = it.output + project.configurations.scoverage + original.runtimeClasspath } def testSourceSet = project.sourceSets.create('testScoverage') { @@ -72,8 +72,8 @@ class ScoverageExtension { resources.source(original.resources) scala.source(original.scala) - compileClasspath = mainSourceSet.output + project.configurations.testCompile - runtimeClasspath = it.output + mainSourceSet.output + project.configurations.scoverage + project.configurations.testRuntime + compileClasspath = mainSourceSet.output + original.compileClasspath + runtimeClasspath = it.output + mainSourceSet.output + project.configurations.scoverage + original.runtimeClasspath } def scoverageJar = project.tasks.create('jarScoverage', Jar.class) { From 2b7a743baf9b8795906835849763e01b1c5b886f Mon Sep 17 00:00:00 2001 From: Stu Date: Fri, 27 Apr 2018 21:21:55 +0100 Subject: [PATCH 014/167] bump to gradle 4.7 --- gradle/wrapper/gradle-wrapper.properties | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index eb8dfdf..8263b14 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-4.0-all.zip +distributionUrl=http\://services.gradle.org/distributions/gradle-4.7-all.zip +distributionSha256Sum=203f4537da8b8075e38c036a6d14cb71b1149de5bf0a8f6db32ac2833a1d1294 \ No newline at end of file From cfb856217e81ba8ee9334a149e0abed12682b944 Mon Sep 17 00:00:00 2001 From: Stu Date: Tue, 8 May 2018 21:54:53 +0100 Subject: [PATCH 015/167] declare that the reportScoverage task uses the dataDir for input and the reportDir for output --- src/main/groovy/org/scoverage/ScoverageExtension.groovy | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index ee198b0..bc3bcd1 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -154,6 +154,10 @@ class ScoverageExtension { outputs.file(new File(extension.dataDir, 'scoverage.coverage.xml')) } t.tasks[ScoveragePlugin.TEST_NAME].outputs.dir(extension.dataDir) + t.tasks[ScoveragePlugin.REPORT_NAME].configure { + inputs.dir(extension.dataDir) + outputs.dir(extension.reportDir) + } } } } From 12b196a909693b9f2937368e02470188f5a4fba0 Mon Sep 17 00:00:00 2001 From: Stu Date: Tue, 8 May 2018 21:56:47 +0100 Subject: [PATCH 016/167] bump plugin-publish-plugin to 0.9.10 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5dba0ec..171c260 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { } } dependencies { - classpath "com.gradle.publish:plugin-publish-plugin:0.9.2" + classpath "com.gradle.publish:plugin-publish-plugin:0.9.10" } } From ffe6daa7935ee7ec240492ab42b82d4132e095e2 Mon Sep 17 00:00:00 2001 From: Stu Date: Thu, 10 May 2018 20:48:05 +0100 Subject: [PATCH 017/167] add @CacheableTask --- src/main/groovy/org/scoverage/OverallCheckTask.groovy | 6 ++++-- src/main/groovy/org/scoverage/ScoverageReport.groovy | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/groovy/org/scoverage/OverallCheckTask.groovy b/src/main/groovy/org/scoverage/OverallCheckTask.groovy index f56d0ad..b674ac7 100644 --- a/src/main/groovy/org/scoverage/OverallCheckTask.groovy +++ b/src/main/groovy/org/scoverage/OverallCheckTask.groovy @@ -2,6 +2,7 @@ package org.scoverage import org.gradle.api.DefaultTask import org.gradle.api.GradleException +import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.TaskAction import java.text.DecimalFormat @@ -37,6 +38,7 @@ enum CoverageType { /** * Throws a GradleException if overall coverage dips below the configured percentage. */ +@CacheableTask class OverallCheckTask extends DefaultTask { /** Type of coverage to check. Available options: Line, Statement and Branch */ @@ -77,8 +79,8 @@ class OverallCheckTask extends DefaultTask { try { Node xml = parser.parse(reportFile) - NumberFormat nf = NumberFormat.getInstance(locale == null ? Locale.getDefault() : locale); - Double coverageValue = nf.parse(xml.attribute(coverageType.paramName) as String).doubleValue(); + NumberFormat nf = NumberFormat.getInstance(locale == null ? Locale.getDefault() : locale) + Double coverageValue = nf.parse(xml.attribute(coverageType.paramName) as String).doubleValue() Double overallRate = coverageType.normalize(coverageValue) def difference = (minimumRate - overallRate) diff --git a/src/main/groovy/org/scoverage/ScoverageReport.groovy b/src/main/groovy/org/scoverage/ScoverageReport.groovy index ab1f1b7..ddf81ac 100644 --- a/src/main/groovy/org/scoverage/ScoverageReport.groovy +++ b/src/main/groovy/org/scoverage/ScoverageReport.groovy @@ -1,7 +1,9 @@ package org.scoverage +import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.JavaExec +@CacheableTask class ScoverageReport extends JavaExec { @Override From be3dfab53026522680cf4da3e2bd1a2513d51563 Mon Sep 17 00:00:00 2001 From: Stu Date: Thu, 10 May 2018 20:48:34 +0100 Subject: [PATCH 018/167] optimise imports --- src/main/groovy/org/scoverage/AggregateReportApp.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/groovy/org/scoverage/AggregateReportApp.java b/src/main/groovy/org/scoverage/AggregateReportApp.java index 914bc89..2bf2f14 100644 --- a/src/main/groovy/org/scoverage/AggregateReportApp.java +++ b/src/main/groovy/org/scoverage/AggregateReportApp.java @@ -1,9 +1,7 @@ package org.scoverage; import scoverage.Coverage; -import scoverage.report.CoberturaXmlWriter; import scoverage.report.CoverageAggregator; -import scoverage.report.ScoverageHtmlWriter; import java.io.File; From 0ce1fb80c1fe92d6c7aace9cf7e7b661eefc5fc3 Mon Sep 17 00:00:00 2001 From: Stu Date: Fri, 11 May 2018 21:05:49 +0100 Subject: [PATCH 019/167] clear dependencies from published plugin pom --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 171c260..3a87c1e 100644 --- a/build.gradle +++ b/build.gradle @@ -80,7 +80,7 @@ pluginBundle { vcsUrl = project.vcsUrl description = project.description tags = ['coverage', 'scala', 'scoverage'] - + withDependencies { it.clear() } plugins { scoveragePlugin { id = 'org.scoverage' From 5cd2fe5596105863ec8aae1bd7e3c5d0fb2d363f Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 9 Sep 2018 11:22:49 +0100 Subject: [PATCH 020/167] state that the test task owns the measurement files --- .../org/scoverage/ScoverageExtension.groovy | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index bc3bcd1..feede0d 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -44,8 +44,8 @@ class ScoverageExtension { ScoverageExtension(Project project) { - project.plugins.apply(JavaPlugin.class); - project.plugins.apply(ScalaPlugin.class); + project.plugins.apply(JavaPlugin.class) + project.plugins.apply(ScalaPlugin.class) project.afterEvaluate(configureRuntimeOptions) project.configurations.create(ScoveragePlugin.CONFIGURATION_NAME) { @@ -82,18 +82,18 @@ class ScoverageExtension { from mainSourceSet.output } project.artifacts { - scoverage project.tasks.jarScoverage + scoverage scoverageJar } project.tasks.create(ScoveragePlugin.TEST_NAME, Test.class) { conventionMapping.map("testClassesDir", new Callable() { - public Object call() throws Exception { - return testSourceSet.output.classesDir; + Object call() throws Exception { + return testSourceSet.output.classesDir } }) conventionMapping.map("classpath", new Callable() { - public Object call() throws Exception { - return testSourceSet.runtimeClasspath; + Object call() throws Exception { + return testSourceSet.runtimeClasspath } }) } @@ -126,7 +126,7 @@ class ScoverageExtension { File pluginFile try { pluginFile = configuration.filter { it.name.contains('plugin') }.iterator().next() - } catch(NoSuchElementException e) { + } catch(NoSuchElementException ignored) { throw new GradleException("Could not find a plugin jar in configuration '${ScoveragePlugin.CONFIGURATION_NAME}'") } @@ -153,7 +153,7 @@ class ScoverageExtension { // the compile task creates a store of measured statements outputs.file(new File(extension.dataDir, 'scoverage.coverage.xml')) } - t.tasks[ScoveragePlugin.TEST_NAME].outputs.dir(extension.dataDir) + t.tasks[ScoveragePlugin.TEST_NAME].outputs.files("${extension.dataDir}/scoverage.measurements.*") t.tasks[ScoveragePlugin.REPORT_NAME].configure { inputs.dir(extension.dataDir) outputs.dir(extension.reportDir) From f70b6963b122c9ab8c6319591b033db615ead362 Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 9 Sep 2018 12:30:51 +0100 Subject: [PATCH 021/167] remove the unnecessary compilation of test classes --- .../org/scoverage/ScoverageExtension.groovy | 26 +++++-------------- .../org/scoverage/ScoveragePlugin.groovy | 3 +-- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index feede0d..406362b 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -54,7 +54,7 @@ class ScoverageExtension { description = 'Scoverage dependencies' } - def mainSourceSet = project.sourceSets.create('scoverage') { + def instrumentedSourceSet = project.sourceSets.create('scoverage') { def original = project.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) resources.source(original.resources) @@ -65,35 +65,23 @@ class ScoverageExtension { runtimeClasspath = it.output + project.configurations.scoverage + original.runtimeClasspath } - def testSourceSet = project.sourceSets.create('testScoverage') { - def original = project.sourceSets.getByName(SourceSet.TEST_SOURCE_SET_NAME) - - java.source(original.java) - resources.source(original.resources) - scala.source(original.scala) - - compileClasspath = mainSourceSet.output + original.compileClasspath - runtimeClasspath = it.output + mainSourceSet.output + project.configurations.scoverage + original.runtimeClasspath - } - def scoverageJar = project.tasks.create('jarScoverage', Jar.class) { dependsOn('scoverageClasses') classifier = ScoveragePlugin.CONFIGURATION_NAME - from mainSourceSet.output + from instrumentedSourceSet.output } project.artifacts { scoverage scoverageJar } project.tasks.create(ScoveragePlugin.TEST_NAME, Test.class) { - conventionMapping.map("testClassesDir", new Callable() { - Object call() throws Exception { - return testSourceSet.output.classesDir - } - }) conventionMapping.map("classpath", new Callable() { Object call() throws Exception { - return testSourceSet.runtimeClasspath + def testSourceSet = project.sourceSets.getByName(SourceSet.TEST_SOURCE_SET_NAME) + return testSourceSet.output + + instrumentedSourceSet.output + + project.configurations.scoverage + + testSourceSet.runtimeClasspath } }) } diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 31b955e..16a87be 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -10,7 +10,6 @@ class ScoveragePlugin implements Plugin { static String REPORT_NAME = 'reportScoverage' static String CHECK_NAME = 'checkScoverage' static String COMPILE_NAME = 'compileScoverageScala' - static String COMPILE_TEST_NAME = 'compileTestScoverageScala' @Override void apply(Project t) { @@ -20,6 +19,6 @@ class ScoveragePlugin implements Plugin { } protected static ScoverageExtension extensionIn(Project project) { - project.extensions[CONFIGURATION_NAME] + project.extensions[CONFIGURATION_NAME] as ScoverageExtension } } From 37fa6e193687f7cbe97367102a21a7d85206a4fa Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 9 Sep 2018 12:48:47 +0100 Subject: [PATCH 022/167] add scoverage tasks to the verification group --- src/main/groovy/org/scoverage/ScoverageExtension.groovy | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index 406362b..075d537 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -84,15 +84,18 @@ class ScoverageExtension { testSourceSet.runtimeClasspath } }) + group = 'verification' } project.tasks.create(ScoveragePlugin.REPORT_NAME, ScoverageReport.class) { dependsOn(project.tasks[ScoveragePlugin.TEST_NAME]) onlyIf { ScoveragePlugin.extensionIn(project).dataDir.list() } + group = 'verification' } project.tasks.create(ScoveragePlugin.CHECK_NAME, OverallCheckTask.class) { dependsOn(project.tasks[ScoveragePlugin.REPORT_NAME]) + group = 'verification' } sources = project.projectDir From 35bb88e72a83587e8cf45ebb76c97a5db52376aa Mon Sep 17 00:00:00 2001 From: Stu Date: Sat, 20 Oct 2018 21:28:02 +0100 Subject: [PATCH 023/167] wildcard patterns are not supported on windows --- .../groovy/org/scoverage/ScoverageExtension.groovy | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index 075d537..7c47d1e 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -144,11 +144,19 @@ class ScoverageExtension { // the compile task creates a store of measured statements outputs.file(new File(extension.dataDir, 'scoverage.coverage.xml')) } - t.tasks[ScoveragePlugin.TEST_NAME].outputs.files("${extension.dataDir}/scoverage.measurements.*") + t.tasks[ScoveragePlugin.TEST_NAME].outputs.upToDateWhen { extension.dataDir.listFiles(measurementFile) } t.tasks[ScoveragePlugin.REPORT_NAME].configure { inputs.dir(extension.dataDir) outputs.dir(extension.reportDir) } } + + FilenameFilter measurementFile = new FilenameFilter() { + @Override + boolean accept(File dir, String name) { + return name.startsWith("scoverage.measurements.") + } + } + } } From b4f96d030dcd6f9050c07c4250f80f8a63f5a91c Mon Sep 17 00:00:00 2001 From: Stu Date: Fri, 28 Dec 2018 20:18:11 +0000 Subject: [PATCH 024/167] bump to gradle 5 (OverallCheckTaskTest still broken) --- gradle/wrapper/gradle-wrapper.properties | 4 ++-- src/test/happy day/settings.gradle | 0 src/test/runtime/settings.gradle | 0 src/test/water/build.gradle | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 src/test/happy day/settings.gradle create mode 100644 src/test/runtime/settings.gradle diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8263b14..47e24fa 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,5 +3,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-4.7-all.zip -distributionSha256Sum=203f4537da8b8075e38c036a6d14cb71b1149de5bf0a8f6db32ac2833a1d1294 \ No newline at end of file +distributionUrl=http\://services.gradle.org/distributions/gradle-5.0-all.zip +distributionSha256Sum=17847c8e12b2bcfce26a79f425f082c31d4ded822f99a66127eee2d96bf18216 \ No newline at end of file diff --git a/src/test/happy day/settings.gradle b/src/test/happy day/settings.gradle new file mode 100644 index 0000000..e69de29 diff --git a/src/test/runtime/settings.gradle b/src/test/runtime/settings.gradle new file mode 100644 index 0000000..e69de29 diff --git a/src/test/water/build.gradle b/src/test/water/build.gradle index 9c64d97..a878fe5 100644 --- a/src/test/water/build.gradle +++ b/src/test/water/build.gradle @@ -28,6 +28,6 @@ allprojects { task aggregateScoverage(type: org.scoverage.ScoverageAggregate) subprojects { - aggregateScoverage.dependsOn(it.tasks) + aggregateScoverage.dependsOn(it.tasks.reportScoverage) } From 08a7f5021798aa7b57119b69c1109fea48bc2a76 Mon Sep 17 00:00:00 2001 From: Stu Date: Fri, 28 Dec 2018 20:36:01 +0000 Subject: [PATCH 025/167] remove use of Task.execute() from OverallCheckTaskTest --- .../org/scoverage/OverallCheckTask.groovy | 40 +++--- .../org/scoverage/OverallCheckTaskTest.groovy | 126 +++++++----------- 2 files changed, 68 insertions(+), 98 deletions(-) diff --git a/src/main/groovy/org/scoverage/OverallCheckTask.groovy b/src/main/groovy/org/scoverage/OverallCheckTask.groovy index b674ac7..356ca6e 100644 --- a/src/main/groovy/org/scoverage/OverallCheckTask.groovy +++ b/src/main/groovy/org/scoverage/OverallCheckTask.groovy @@ -4,6 +4,7 @@ import org.gradle.api.DefaultTask import org.gradle.api.GradleException import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.TaskAction +import org.gradle.internal.impldep.com.google.common.annotations.VisibleForTesting import java.text.DecimalFormat import java.text.NumberFormat @@ -51,35 +52,38 @@ class OverallCheckTask extends DefaultTask { /** Overwrite to test for a specific locale. */ Locale locale - protected XmlParser parser + @TaskAction + void requireLineCoverage() { + def extension = ScoveragePlugin.extensionIn(project) - protected DecimalFormat df = new DecimalFormat("#.##") + NumberFormat nf = NumberFormat.getInstance(locale == null ? Locale.getDefault() : locale) - OverallCheckTask() { - 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) + Exception failure = checkLineCoverage(nf, reportDir == null ? extension.reportDir : reportDir, coverageType, minimumRate) + + if (failure) throw failure } - /** Extracted to method for testing purposes */ - static String errorMsg(String actual, String expected, CoverageType type) { + @VisibleForTesting + protected static String errorMsg(String actual, String expected, CoverageType type) { return "Only $actual% of project is covered by tests instead of $expected% (coverageType: $type)" } - /** Extracted to method for testing purposes */ - static String fileNotFoundErrorMsg(CoverageType coverageType) { + @VisibleForTesting + protected static String fileNotFoundErrorMsg(CoverageType coverageType) { return "Coverage file (type: $coverageType) not found, check your configuration." } - @TaskAction - void requireLineCoverage() { - def extension = ScoveragePlugin.extensionIn(project) + @VisibleForTesting + protected static Exception checkLineCoverage(NumberFormat nf, File reportDir, CoverageType coverageType, double minimumRate) { + XmlParser 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) - File reportFile = new File(reportDir ? reportDir : extension.reportDir, coverageType.fileName) + DecimalFormat df = new DecimalFormat("#.##") try { + File reportFile = new File(reportDir, coverageType.fileName) Node xml = parser.parse(reportFile) - NumberFormat nf = NumberFormat.getInstance(locale == null ? Locale.getDefault() : locale) Double coverageValue = nf.parse(xml.attribute(coverageType.paramName) as String).doubleValue() Double overallRate = coverageType.normalize(coverageValue) def difference = (minimumRate - overallRate) @@ -87,11 +91,11 @@ class OverallCheckTask extends DefaultTask { if (difference > 1e-7) { String is = df.format(overallRate * 100) String needed = df.format(minimumRate * 100) - throw new GradleException(errorMsg(is, needed, coverageType)) + return new GradleException(errorMsg(is, needed, coverageType)) } } catch (FileNotFoundException fnfe) { - throw new GradleException(fileNotFoundErrorMsg(coverageType), fnfe) + return new GradleException(fileNotFoundErrorMsg(coverageType), fnfe) } - + return null } } diff --git a/src/test/groovy/org/scoverage/OverallCheckTaskTest.groovy b/src/test/groovy/org/scoverage/OverallCheckTaskTest.groovy index aeb3389..fcc26ab 100644 --- a/src/test/groovy/org/scoverage/OverallCheckTaskTest.groovy +++ b/src/test/groovy/org/scoverage/OverallCheckTaskTest.groovy @@ -1,155 +1,121 @@ package org.scoverage import org.gradle.api.GradleException -import org.gradle.api.Project -import org.gradle.testfixtures.ProjectBuilder import org.hamcrest.Description +import org.hamcrest.Matcher import org.hamcrest.TypeSafeMatcher -import org.junit.After -import org.junit.AfterClass -import org.junit.Before -import org.junit.BeforeClass -import org.junit.Rule import org.junit.Test -import org.junit.rules.ExpectedException -import javax.swing.text.NumberFormatter import java.text.NumberFormat +import static org.junit.Assert.assertNull +import static org.junit.Assert.assertThat +import static org.scoverage.OverallCheckTask.checkLineCoverage + /** * Copied from the Internet, just to check if we have correct exception thrown. */ class CauseMatcher extends TypeSafeMatcher { - private final Class type; - private final String expectedMessage; + private final Class type + private final String expectedMessage - public CauseMatcher(Class type, String expectedMessage) { - this.type = type; - this.expectedMessage = expectedMessage; + CauseMatcher(Class type, String expectedMessage) { + this.type = type + this.expectedMessage = expectedMessage } @Override protected boolean matchesSafely(Throwable item) { - return item.getClass().isAssignableFrom(type) && item.getMessage().contains(expectedMessage); + return item.getClass().isAssignableFrom(type) && item.getMessage().contains(expectedMessage) } @Override - public void describeTo(Description description) { + void describeTo(Description description) { description.appendText("expects type ") .appendValue(type) .appendText(" and a message ") - .appendValue(expectedMessage); + .appendValue(expectedMessage) } } class OverallCheckTaskTest { - @Rule - public ExpectedException expectedException = ExpectedException.none() - - private Project projectForRate(Number coverageRate, CoverageType type) { - Project project = ProjectBuilder.builder().build() - project.plugins.apply(ScoveragePlugin) - project.tasks.create('bob', OverallCheckTask) { - locale = Locale.US - minimumRate = coverageRate - reportDir = new File('src/test/resources') - coverageType = type - } - project + private NumberFormat numberFormat = NumberFormat.getInstance(Locale.US) + + private static File reportDir = new File('src/test/resources') + + private static Matcher failsWith(String message) { + return new CauseMatcher( + GradleException.class, + message + ) } // error when report file is not there @Test void failsWhenReportFileIsNotFound() { - Project project = ProjectBuilder.builder().build() - project.plugins.apply(ScoveragePlugin) - project.tasks.create('bob', OverallCheckTask) { - locale = Locale.US - minimumRate = 1.0 - reportDir = new File('src/test/nothingthere') - coverageType = CoverageType.Line - } - expectedException.expectCause(new CauseMatcher( - GradleException.class, - OverallCheckTask.fileNotFoundErrorMsg(CoverageType.Line) - )) - project.tasks.bob.execute() + assertThat( + checkLineCoverage(numberFormat, new File('src/test/nothingthere'), CoverageType.Line, 0.0), + failsWith(OverallCheckTask.fileNotFoundErrorMsg(CoverageType.Line))) } // line coverage @Test void failsWhenLineRateIsBelowTarget() { - Project project = projectForRate(1, CoverageType.Line) - expectedException.expectCause(new CauseMatcher( - GradleException.class, - OverallCheckTask.errorMsg("66", "100", CoverageType.Line) - )) - project.tasks.bob.execute() + assertThat( + checkLineCoverage(numberFormat, reportDir, CoverageType.Line, 1.0), + failsWith(OverallCheckTask.errorMsg("66", "100", CoverageType.Line))) } @Test - void doesNotFailWhenLineRateIsAtTarget() throws Exception { - Project project = projectForRate(0.66, CoverageType.Line) - project.tasks.bob.execute() + void doesNotFailWhenLineRateIsAtTarget() { + assertNull(checkLineCoverage(numberFormat, reportDir, CoverageType.Line, 0.66)) } @Test - void doesNotFailWhenLineRateIsAboveTarget() throws Exception { - Project project = projectForRate(0.6, CoverageType.Line) - project.tasks.bob.execute() + void doesNotFailWhenLineRateIsAboveTarget() { + assertNull(checkLineCoverage(numberFormat, reportDir, CoverageType.Line, 0.6)) } // Statement coverage @Test void failsWhenStatementRateIsBelowTarget() { - Project project = projectForRate(1, CoverageType.Statement) - NumberFormat nf = NumberFormat.getInstance() - expectedException.expectCause(new CauseMatcher( - GradleException.class, - OverallCheckTask.errorMsg(nf.format(new Double(33.33)), "100", CoverageType.Statement) - )) - project.tasks.bob.execute() + assertThat( + checkLineCoverage(numberFormat, reportDir, CoverageType.Statement, 1.0), + failsWith(OverallCheckTask.errorMsg(numberFormat.format(new Double(33.33)), "100", CoverageType.Statement))) } @Test - void doesNotFailWhenStatementRateIsAtTarget() throws Exception { - Project project = projectForRate(0.33, CoverageType.Statement) - project.tasks.bob.execute() + void doesNotFailWhenStatementRateIsAtTarget() { + assertNull(checkLineCoverage(numberFormat, reportDir, CoverageType.Statement, 0.33)) } @Test - void doesNotFailWhenStatementRateIsAboveTarget() throws Exception { - Project project = projectForRate(0.3, CoverageType.Statement) - project.tasks.bob.execute() + void doesNotFailWhenStatementRateIsAboveTarget() { + assertNull(checkLineCoverage(numberFormat, reportDir, CoverageType.Statement, 0.3)) } // Branch coverage @Test void failsWhenBranchRateIsBelowTarget() { - Project project = projectForRate(1, CoverageType.Branch) - expectedException.expectCause(new CauseMatcher( - GradleException.class, - OverallCheckTask.errorMsg("50", "100", CoverageType.Branch) - )) - project.tasks.bob.execute() + assertThat( + checkLineCoverage(numberFormat, reportDir, CoverageType.Branch, 1.0), + failsWith(OverallCheckTask.errorMsg("50", "100", CoverageType.Branch))) } @Test - void doesNotFailWhenBranchRateIsAtTarget() throws Exception { - Project project = projectForRate(0.50, CoverageType.Branch) - project.tasks.bob.execute() + void doesNotFailWhenBranchRateIsAtTarget() { + assertNull(checkLineCoverage(numberFormat, reportDir, CoverageType.Branch, 0.5)) } @Test - void doesNotFailWhenBranchRateIsAboveTarget() throws Exception { - Project project = projectForRate(0.45, CoverageType.Branch) - project.tasks.bob.execute() + void doesNotFailWhenBranchRateIsAboveTarget() { + assertNull(checkLineCoverage(numberFormat, reportDir, CoverageType.Branch, 0.45)) } } From 9c2c0961cad67b6cec1a18b346c15248719138ca Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Tue, 29 Jan 2019 10:34:50 +0200 Subject: [PATCH 026/167] Update the project according to the current (gradle 5.0) plugin development configurations --- .gitignore | 1 + build.gradle | 103 ++++++++++-------- init-scoverage.gradle | 7 -- .../org/scoverage/AcceptanceTestUtils.groovy | 22 ++-- .../AggregationAcceptanceTest.groovy | 3 +- .../SeparateTestsAcceptanceTest.groovy | 3 +- .../SimpleReportAcceptanceTest.groovy | 6 +- src/test/happy day/build.gradle | 19 +--- src/test/runtime/build.gradle | 19 +--- src/test/separate-tests/build.gradle | 22 ++-- src/test/water/build.gradle | 19 ++-- 11 files changed, 103 insertions(+), 121 deletions(-) delete mode 100644 init-scoverage.gradle diff --git a/.gitignore b/.gitignore index 39e1fda..143f20e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ classes build +out .gradle *.iml diff --git a/build.gradle b/build.gradle index 3a87c1e..cf31903 100644 --- a/build.gradle +++ b/build.gradle @@ -1,25 +1,17 @@ -// First, apply the publishing plugin -buildscript { - repositories { - maven { - url "https://plugins.gradle.org/m2/" - } - } - dependencies { - classpath "com.gradle.publish:plugin-publish-plugin:0.9.10" - } -} - -apply plugin: "com.gradle.plugin-publish" -description = 'gradle-scoverage is a Gradle plugin for calculating code coverage using Scoverage' -if (project.version == 'unspecified') { - version = '2.0.0-SNAPSHOT' +plugins { + id 'java-gradle-plugin' + id "com.gradle.plugin-publish" version "0.10.0" + id "org.jetbrains.gradle.plugin.idea-ext" version "0.4.2" } repositories { - mavenCentral() + jcenter() } +group 'org.scoverage' +description = 'gradle-scoverage is a Gradle plugin for calculating code coverage using Scoverage' +version = '2.0.0-SNAPSHOT' + ext { website = 'http://scoverage.org' vcsUrl = 'https://github.com/scoverage/gradle-scoverage.git' @@ -28,24 +20,37 @@ ext { sonatypePass = System.env.SONATYPE_PASS } -apply plugin: 'idea' +gradlePlugin { + plugins { + gradleScoverage { + id = 'org.scoverage' + implementationClass = 'org.scoverage.ScoveragePlugin' + } + } +} + +pluginBundle { + website = project.website + vcsUrl = ext.vcsUrl + description = project.description + tags = ['coverage', 'scala', 'scoverage'] + plugins { + scoveragePlugin { + displayName = 'Gradle Scoverage plugin' + } + } +} + apply plugin: 'maven' apply plugin: 'groovy' -group 'org.scoverage' sourceCompatibility = '1.6' targetCompatibility = '1.6' -configurations { - scoverage - compile.extendsFrom scoverage -} - dependencies { - compile gradleApi() - compile localGroovy() - scoverage "org.scoverage:scalac-scoverage-plugin_2.11:1.1.1" - testCompile 'junit:junit:4.12', 'org.hamcrest:hamcrest-library:1.3' + compile "org.scoverage:scalac-scoverage-plugin_2.12:1.3.1" + testCompile 'junit:junit:4.12' + testCompile 'org.hamcrest:hamcrest-library:1.3' } task groovydocJar(type: Jar, dependsOn: groovydoc) { @@ -58,10 +63,6 @@ task sourcesJar(type: Jar) { classifier = 'sources' } -test { - dependsOn jar -} - artifacts { archives jar archives groovydocJar @@ -75,25 +76,11 @@ if (project.properties.containsKey('signing.keyId')) { } } -pluginBundle { - website = project.website - vcsUrl = project.vcsUrl - description = project.description - tags = ['coverage', 'scala', 'scoverage'] - withDependencies { it.clear() } - plugins { - scoveragePlugin { - id = 'org.scoverage' - displayName = 'Gradle Scoverage plugin' - } - } -} - uploadArchives { repositories { mavenDeployer { if (project.properties.containsKey('signing.keyId')) { - beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } } snapshotRepository(url: 'https://oss.sonatype.org/content/repositories/snapshots') { @@ -132,8 +119,30 @@ uploadArchives { developer { id 'D-Roch' } + developer { + id 'eyalroth' + } } } } } } + +// see https://stackoverflow.com/questions/44679007 +task fixIdeaPluginClasspath { + doFirst { + configure(tasks.pluginUnderTestMetadata) { + def ideaClassesPath = project.buildDir.toPath().resolveSibling("out").resolve("production") + def newClasspath = pluginClasspath as List + newClasspath.add(0, ideaClassesPath) + pluginClasspath.setFrom(newClasspath) + } + } +} +pluginUnderTestMetadata.mustRunAfter(fixIdeaPluginClasspath) + +idea.project.settings { + taskTriggers { + beforeBuild fixIdeaPluginClasspath, pluginUnderTestMetadata + } +} \ No newline at end of file diff --git a/init-scoverage.gradle b/init-scoverage.gradle deleted file mode 100644 index 0d7837a..0000000 --- a/init-scoverage.gradle +++ /dev/null @@ -1,7 +0,0 @@ -gradle.beforeProject { p -> - p.ext { - scoverageVersion = '1.1.1' - scoverageLib = ["org.scoverage:scalac-scoverage-plugin_2.11:${scoverageVersion}", - "org.scoverage:scalac-scoverage-runtime_2.11:${scoverageVersion}"] - } -} diff --git a/src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy b/src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy index 803da60..00498c5 100644 --- a/src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy +++ b/src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy @@ -1,7 +1,6 @@ package org.scoverage -import org.gradle.tooling.BuildLauncher -import org.gradle.tooling.GradleConnector +import org.gradle.testkit.runner.GradleRunner import org.hamcrest.core.Is import org.junit.Assert @@ -20,15 +19,16 @@ class AcceptanceTestUtils { parser.setFeature('http://apache.org/xml/features/nonvalidating/load-external-dtd', false) } - protected BuildLauncher setupBuild(File projectRoot) { - return GradleConnector. - newConnector(). - forProjectDirectory(projectRoot). - connect(). - newBuild(). - withArguments( - '--init-script', - new File(System.properties.getProperty('user.dir'), 'init-scoverage.gradle').toString()) + protected void runBuild(File projectRoot, String... tasks) { + def runner = GradleRunner + .create() + .withProjectDir(projectRoot) + .withPluginClasspath() + .forwardOutput() + + def arguments = tasks + "-PscoverageVersion=1.3.1" + + runner.withArguments(arguments as List).build() } protected void checkFile(String description, File file, boolean shouldExist) throws Exception { diff --git a/src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy b/src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy index d5883f2..90bdb51 100644 --- a/src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy +++ b/src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy @@ -7,8 +7,7 @@ class AggregationAcceptanceTest extends AcceptanceTestUtils { @Test public void testMultiProjectAggregation() throws Exception { File projectDir = new File('src/test/water') - def build = setupBuild(projectDir) - build.forTasks('clean', 'aggregateScoverage').run() + runBuild(projectDir, 'clean', 'aggregateScoverage') def indexHtml = new File(aggregateReportDir(projectDir), 'index.html') checkFile('an aggregated index HTML file', indexHtml, true) def cobertura = new File(aggregateReportDir(projectDir), 'cobertura.xml') diff --git a/src/test/groovy/org/scoverage/SeparateTestsAcceptanceTest.groovy b/src/test/groovy/org/scoverage/SeparateTestsAcceptanceTest.groovy index 54c7ec2..4308937 100644 --- a/src/test/groovy/org/scoverage/SeparateTestsAcceptanceTest.groovy +++ b/src/test/groovy/org/scoverage/SeparateTestsAcceptanceTest.groovy @@ -12,8 +12,7 @@ class SeparateTestsAcceptanceTest extends AcceptanceTestUtils { File projectDir = new File('src/test/separate-tests') File subprojectDir = new File(projectDir, 'a') File testsSubprojectDir = new File(projectDir, 'a-tests') - def build = setupBuild(projectDir) - build.forTasks('clean', 'reportScoverage').run() + runBuild(projectDir, 'clean', 'reportScoverage') def indexHtml = new File(reportDir(subprojectDir), 'index.html') checkFile('an index HTML file', indexHtml, true) def testsIndexHtml = new File(reportDir(testsSubprojectDir), 'index.html') diff --git a/src/test/groovy/org/scoverage/SimpleReportAcceptanceTest.groovy b/src/test/groovy/org/scoverage/SimpleReportAcceptanceTest.groovy index 8be41e5..0c2ca6c 100644 --- a/src/test/groovy/org/scoverage/SimpleReportAcceptanceTest.groovy +++ b/src/test/groovy/org/scoverage/SimpleReportAcceptanceTest.groovy @@ -8,8 +8,7 @@ class SimpleReportAcceptanceTest extends AcceptanceTestUtils { @Test public void testProjectWithCompleteCoverage() throws Exception { File projectRoot = new File('src/test/happy day') - def build = setupBuild(projectRoot) - build.forTasks('clean', 'checkScoverage').run() + runBuild(projectRoot, 'clean', 'checkScoverage') def html = new File(reportDir(projectRoot), 'index.html') checkFile('an index HTML file', html, true) def cobertura = new File(reportDir(projectRoot), 'cobertura.xml') @@ -21,7 +20,6 @@ class SimpleReportAcceptanceTest extends AcceptanceTestUtils { @Test public void testRun() throws Exception { File projectRoot = new File('src/test/runtime') - def build = setupBuild(projectRoot) - build.forTasks('clean', 'run').run() + runBuild(projectRoot, 'clean', 'run') } } diff --git a/src/test/happy day/build.gradle b/src/test/happy day/build.gradle index a4a19ef..e47e145 100644 --- a/src/test/happy day/build.gradle +++ b/src/test/happy day/build.gradle @@ -1,23 +1,16 @@ -description = 'a project that builds successfully with 100% coverage' - -buildscript { - repositories { - // need to get up to the working directory of gradle-plugins build - flatDir dir: "${project.projectDir}/../../../build/libs" - } - dependencies { - classpath name: 'gradle-scoverage', version: '+' - } +plugins { + id 'org.scoverage' } -apply plugin: 'org.scoverage' +description = 'a project that builds successfully with 100% coverage' repositories { - mavenCentral() + jcenter() } dependencies { - scoverage scoverageLib + scoverage "org.scoverage:scalac-scoverage-plugin_2.11:${scoverageVersion}", + "org.scoverage:scalac-scoverage-runtime_2.11:${scoverageVersion}" compile 'org.scala-lang:scala-library:2.11.0' testCompile 'junit:junit:4.11' } diff --git a/src/test/runtime/build.gradle b/src/test/runtime/build.gradle index 0ed527f..e8e1171 100644 --- a/src/test/runtime/build.gradle +++ b/src/test/runtime/build.gradle @@ -1,23 +1,16 @@ -description = 'a project that runs an application and captures scoverage' - -buildscript { - repositories { - // need to get up to the working directory of gradle-plugins build - flatDir dir: "${project.projectDir}/../../../build/libs" - } - dependencies { - classpath name: 'gradle-scoverage', version: '+' - } +plugins { + id 'org.scoverage' } -apply plugin: 'org.scoverage' +description = 'a project that runs an application and captures scoverage' repositories { - mavenCentral() + jcenter() } dependencies { - scoverage scoverageLib + scoverage "org.scoverage:scalac-scoverage-plugin_2.11:${scoverageVersion}", + "org.scoverage:scalac-scoverage-runtime_2.11:${scoverageVersion}" compile 'org.scala-lang:scala-library:2.11.0' } diff --git a/src/test/separate-tests/build.gradle b/src/test/separate-tests/build.gradle index 8a258dd..83522c7 100644 --- a/src/test/separate-tests/build.gradle +++ b/src/test/separate-tests/build.gradle @@ -1,27 +1,29 @@ +plugins { + id 'org.scoverage' +} + description = 'a multi-project with separate tests setup for gradle-scoverage' -buildscript { +allprojects { + repositories { - // need to get up to the working directory of gradle-plugins build - flatDir dir: "${project.projectDir}/../../../build/libs" + jcenter() } + + apply plugin: 'org.scoverage' + dependencies { - classpath name: 'gradle-scoverage', version: '+' + scoverage "org.scoverage:scalac-scoverage-plugin_2.11:${scoverageVersion}", + "org.scoverage:scalac-scoverage-runtime_2.11:${scoverageVersion}" } } subprojects { - repositories { - mavenCentral() - } - apply plugin: 'scala' - apply plugin: 'org.scoverage' dependencies { compile 'org.scala-lang:scala-library:2.11.4' - scoverage scoverageLib testCompile 'junit:junit:4.11' } diff --git a/src/test/water/build.gradle b/src/test/water/build.gradle index a878fe5..f4d5a6e 100644 --- a/src/test/water/build.gradle +++ b/src/test/water/build.gradle @@ -1,24 +1,19 @@ -description = 'a multi-project setup for gradle-scoverage' - -buildscript { - repositories { - // need to get up to the working directory of gradle-plugins build - flatDir dir: "${project.projectDir}/../../../build/libs" - } - dependencies { - classpath name: 'gradle-scoverage', version: '+' - } +plugins { + id 'org.scoverage' } +description = 'a multi-project setup for gradle-scoverage' + allprojects { repositories { - mavenCentral() + jcenter() } apply plugin: 'org.scoverage' dependencies { - scoverage scoverageLib + scoverage "org.scoverage:scalac-scoverage-plugin_2.11:${scoverageVersion}", + "org.scoverage:scalac-scoverage-runtime_2.11:${scoverageVersion}" compile 'org.scala-lang:scala-library:2.11.5' testCompile 'junit:junit:4.11' From de988f122a2e005044b876fe9ab15c4205c581e8 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Tue, 29 Jan 2019 11:10:37 +0200 Subject: [PATCH 027/167] Add new functional tests --- .travis.yml | 2 +- build.gradle | 25 ++++ .../org.scoverage/ScalaSingleModuleTest.java | 92 ++++++++++++ .../ScoverageFunctionalTest.java | 138 ++++++++++++++++++ .../projects/scala-single-module/build.gradle | 34 +++++ .../scala-single-module/settings.gradle | 0 .../src/main/scala/org/hello/World.scala | 9 ++ .../scala/org/hello/TestNothingSuite.scala | 12 ++ .../src/test/scala/org/hello/WorldSuite.scala | 13 ++ .../org/scoverage/ScoveragePlugin.groovy | 1 + 10 files changed, 325 insertions(+), 1 deletion(-) create mode 100644 src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java create mode 100644 src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java create mode 100644 src/functionalTest/resources/projects/scala-single-module/build.gradle create mode 100644 src/functionalTest/resources/projects/scala-single-module/settings.gradle create mode 100644 src/functionalTest/resources/projects/scala-single-module/src/main/scala/org/hello/World.scala create mode 100644 src/functionalTest/resources/projects/scala-single-module/src/test/scala/org/hello/TestNothingSuite.scala create mode 100644 src/functionalTest/resources/projects/scala-single-module/src/test/scala/org/hello/WorldSuite.scala diff --git a/.travis.yml b/.travis.yml index 3b53e86..1e5da93 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,3 @@ language: groovy script: - - "./gradlew --info --stacktrace test" \ No newline at end of file + - "./gradlew --info --stacktrace check" \ No newline at end of file diff --git a/build.gradle b/build.gradle index cf31903..d82bb5d 100644 --- a/build.gradle +++ b/build.gradle @@ -53,6 +53,31 @@ dependencies { testCompile 'org.hamcrest:hamcrest-library:1.3' } +sourceSets { + functionalTest { + java { + srcDir file('src/functionalTest/java') + } + resources { + srcDir file('src/functionalTest/resources') + } + compileClasspath += sourceSets.main.output + configurations.testRuntime + runtimeClasspath += output + compileClasspath + } +} + +task functionalTest(type: Test) { + testClassesDirs = sourceSets.functionalTest.output.classesDirs + classpath = sourceSets.functionalTest.runtimeClasspath +} + +functionalTest.mustRunAfter(test) +check.dependsOn functionalTest + +gradlePlugin { + testSourceSets sourceSets.test, sourceSets.functionalTest +} + task groovydocJar(type: Jar, dependsOn: groovydoc) { classifier = 'groovydoc' from "$buildDir/docs/groovydoc" diff --git a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java new file mode 100644 index 0000000..4a6e594 --- /dev/null +++ b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java @@ -0,0 +1,92 @@ +package org.scoverage; + +import org.gradle.testkit.runner.TaskOutcome; +import org.junit.Test; + +public class ScalaSingleModuleTest extends ScoverageFunctionalTest { + + public ScalaSingleModuleTest() { + super("scala-single-module"); + } + + @Test + public void test() { + + AssertableBuildResult result = dryRun("clean", "test"); + + result.assertTaskDoesntExist(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getTEST_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); + } + + @Test + public void build() { + + AssertableBuildResult result = dryRun("clean", "build"); + + result.assertTaskDoesntExist(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getTEST_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); + } + + @Test + public void testScoverage() { + + AssertableBuildResult result = dryRun("clean", ScoveragePlugin.getTEST_NAME()); + + result.assertTaskExists(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskExists(ScoveragePlugin.getTEST_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); + } + + @Test + public void reportScoverage() { + + AssertableBuildResult result = dryRun("clean", ScoveragePlugin.getREPORT_NAME()); + + result.assertTaskExists(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskExists(ScoveragePlugin.getTEST_NAME()); + result.assertTaskExists(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); + } + + @Test + public void aggregateScoverage() { + + AssertableBuildResult result = runAndFail("clean", ScoveragePlugin.getAGGREGATE_NAME()); + + result.assertNoTasks(); + } + + @Test + public void checkScoverage() { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME()); + + result.assertTaskOutcome(ScoveragePlugin.getCOMPILE_NAME(), TaskOutcome.SUCCESS); + result.assertTaskOutcome(ScoveragePlugin.getTEST_NAME(), TaskOutcome.SUCCESS); + result.assertTaskOutcome(ScoveragePlugin.getREPORT_NAME(), TaskOutcome.SUCCESS); + result.assertTaskOutcome(ScoveragePlugin.getCHECK_NAME(), TaskOutcome.SUCCESS); + result.assertTaskSkipped(ScoveragePlugin.getAGGREGATE_NAME()); + } + + @Test + public void checkScoverageFails() { + + AssertableBuildResult result = runAndFail("clean", ScoveragePlugin.getCHECK_NAME(), + ScoveragePlugin.getTEST_NAME(), "--tests", "org.hello.TestNothingSuite"); + + result.assertTaskOutcome(ScoveragePlugin.getCOMPILE_NAME(), TaskOutcome.SUCCESS); + result.assertTaskOutcome(ScoveragePlugin.getTEST_NAME(), TaskOutcome.SUCCESS); + result.assertTaskOutcome(ScoveragePlugin.getREPORT_NAME(), TaskOutcome.SUCCESS); + result.assertTaskOutcome(ScoveragePlugin.getCHECK_NAME(), TaskOutcome.FAILED); + result.assertTaskSkipped(ScoveragePlugin.getAGGREGATE_NAME()); + } +} \ No newline at end of file diff --git a/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java b/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java new file mode 100644 index 0000000..bba1e8a --- /dev/null +++ b/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java @@ -0,0 +1,138 @@ +package org.scoverage; + +import org.gradle.testkit.runner.BuildResult; +import org.gradle.testkit.runner.BuildTask; +import org.gradle.testkit.runner.GradleRunner; +import org.gradle.testkit.runner.TaskOutcome; +import org.junit.Assert; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public abstract class ScoverageFunctionalTest { + + private final String projectName; + private final GradleRunner runner; + + protected ScoverageFunctionalTest(String projectName) { + + this.projectName = projectName; + this.runner = GradleRunner.create() + .withProjectDir(projectDir()) + .withPluginClasspath() + .forwardOutput(); + + + List filteredPluginClassPath = new ArrayList(); + + for (File file : runner.getPluginClasspath()) { + if (!file.getName().contains("scalac-scoverage-plugin")) { + filteredPluginClassPath.add(file); + } + } + + runner.withPluginClasspath(filteredPluginClassPath); + } + + protected File projectDir() { + + return new File("src/functionalTest/resources/projects/" + projectName); + } + + protected AssertableBuildResult run(String... arguments) { + + configureArguments(arguments); + return new AssertableBuildResult(runner.build()); + } + + protected AssertableBuildResult runAndFail(String... arguments) { + + configureArguments(arguments); + return new AssertableBuildResult(runner.buildAndFail()); + } + + protected AssertableBuildResult dryRun(String... arguments) { + + List withDryArgument = new ArrayList(Arrays.asList(arguments)); + withDryArgument.add("--dry-run"); + return run(withDryArgument.toArray(new String[]{})); + } + + private void configureArguments(String... arguments) { + + List fullArguments = new ArrayList(); + + fullArguments.add("-PscalaVersionMajor=2"); + fullArguments.add("-PscalaVersionMinor=11"); + fullArguments.add("-PscalaVersionBuild=5"); + fullArguments.add("-PjunitVersion=5.3.2"); + fullArguments.add("-PjunitPlatformVersion=1.3.2"); + fullArguments.add("-PscalatestVersion=3.0.5"); + fullArguments.add("-PscoverageVersion=1.3.1"); + fullArguments.addAll(Arrays.asList(arguments)); + + runner.withArguments(fullArguments); + } + + protected static class AssertableBuildResult { + + private final BuildResult result; + + private AssertableBuildResult(BuildResult result) { + + this.result = result; + } + + public BuildResult getResult() { + + return result; + } + + public void assertNoTasks() { + + Assert.assertEquals(0, result.getTasks().size()); + } + + public void assertTaskExists(String taskName) { + + Assert.assertTrue(taskExists(taskName)); + } + + public void assertTaskDoesntExist(String taskName) { + + Assert.assertFalse(taskExists(taskName)); + } + + public void assertTaskSkipped(String taskName) { + + BuildTask task = getTask(taskName); + Assert.assertTrue(task == null || task.getOutcome() == TaskOutcome.SKIPPED); + } + + public void assertTaskOutcome(String taskName, TaskOutcome outcome) { + + BuildTask task = getTask(taskName); + Assert.assertNotNull(task); + Assert.assertEquals(outcome, task.getOutcome()); + + } + + private BuildTask getTask(String taskName) { + + return result.task(fullTaskName(taskName)); + } + + private String fullTaskName(String taskName) { + + return ":" + taskName; + } + + private boolean taskExists(String taskName) { + + return result.getOutput().contains(fullTaskName(taskName) + " "); + } + } +} + diff --git a/src/functionalTest/resources/projects/scala-single-module/build.gradle b/src/functionalTest/resources/projects/scala-single-module/build.gradle new file mode 100644 index 0000000..cad5985 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-single-module/build.gradle @@ -0,0 +1,34 @@ +plugins { + id 'org.scoverage' +} + +repositories { + jcenter() +} + +description = 'a single-module Scala project that builds successfully with 100% coverage' + +apply plugin: 'java' +apply plugin: 'scala' + +dependencies { + compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + + testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion + + def fullScoverageVersion = "${scalaVersionMajor}.${scalaVersionMinor}:${scoverageVersion}" + + scoverage "org.scoverage:scalac-scoverage-plugin_${fullScoverageVersion}", + "org.scoverage:scalac-scoverage-runtime_${fullScoverageVersion}" +} + +test { + useJUnitPlatform() +} + +checkScoverage { + minimumRate = 0.5 +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-single-module/settings.gradle b/src/functionalTest/resources/projects/scala-single-module/settings.gradle new file mode 100644 index 0000000..e69de29 diff --git a/src/functionalTest/resources/projects/scala-single-module/src/main/scala/org/hello/World.scala b/src/functionalTest/resources/projects/scala-single-module/src/main/scala/org/hello/World.scala new file mode 100644 index 0000000..27dbe28 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-single-module/src/main/scala/org/hello/World.scala @@ -0,0 +1,9 @@ +package org.hello + +class World { + + def foo(): String = { + val s = "a" + "b" + s + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-single-module/src/test/scala/org/hello/TestNothingSuite.scala b/src/functionalTest/resources/projects/scala-single-module/src/test/scala/org/hello/TestNothingSuite.scala new file mode 100644 index 0000000..1ac25b5 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-single-module/src/test/scala/org/hello/TestNothingSuite.scala @@ -0,0 +1,12 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class TestNothingSuite extends FunSuite { + + test("nothing") { + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-single-module/src/test/scala/org/hello/WorldSuite.scala b/src/functionalTest/resources/projects/scala-single-module/src/test/scala/org/hello/WorldSuite.scala new file mode 100644 index 0000000..7281a12 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-single-module/src/test/scala/org/hello/WorldSuite.scala @@ -0,0 +1,13 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldSuite extends FunSuite { + + test("foo") { + new World().foo() + } +} \ No newline at end of file diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 16a87be..cc4b25b 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -10,6 +10,7 @@ class ScoveragePlugin implements Plugin { static String REPORT_NAME = 'reportScoverage' static String CHECK_NAME = 'checkScoverage' static String COMPILE_NAME = 'compileScoverageScala' + static String AGGREGATE_NAME = 'aggregateScoverage' @Override void apply(Project t) { From 78dc56f9a451fe227c76446aa712f7b23cccff5b Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Tue, 29 Jan 2019 13:37:15 +0200 Subject: [PATCH 028/167] Make the plugin configure the scalac-plugin classpath and the aggregation task automatically --- README.md | 16 +- build.gradle | 2 +- .../org.scoverage/ScalaSingleModuleTest.java | 4 +- .../ScoverageFunctionalTest.java | 16 +- .../projects/scala-single-module/build.gradle | 5 - .../org/scoverage/AggregateReportApp.java | 33 --- .../org/scoverage/OverallCheckTask.groovy | 8 +- .../org/scoverage/ScoverageAggregate.groovy | 55 +++-- .../org/scoverage/ScoverageExtension.groovy | 184 +++++----------- .../org/scoverage/ScoveragePlugin.groovy | 201 ++++++++++++++++-- .../org/scoverage/ScoverageReport.groovy | 74 +++++-- .../org/scoverage/ScoverageRunner.groovy | 32 +++ .../groovy/org/scoverage/SingleReportApp.java | 53 ----- .../org/scoverage/AcceptanceTestUtils.groovy | 4 +- src/test/happy day/build.gradle | 2 - src/test/runtime/build.gradle | 2 - src/test/separate-tests/build.gradle | 16 +- src/test/water/build.gradle | 11 +- 18 files changed, 376 insertions(+), 342 deletions(-) delete mode 100644 src/main/groovy/org/scoverage/AggregateReportApp.java create mode 100644 src/main/groovy/org/scoverage/ScoverageRunner.groovy delete mode 100644 src/main/groovy/org/scoverage/SingleReportApp.java diff --git a/README.md b/README.md index 77de109..bbbb87c 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,12 @@ This creates an additional task `testScoverage` which will run tests against ins A further task `reportScoverage` produces XML and HTML reports for analysing test code coverage. -You need to configure the version of Scoverage that will be used. This plugin should be compatible with all 1+ versions. +You can configure the version of Scoverage that will be used. This plugin should be compatible with all 1+ versions. ```groovy -dependencies { - scoverage 'org.scoverage:scalac-scoverage-plugin_2.11:1.1.0', 'org.scoverage:scalac-scoverage-runtime_2.11:1.1.0' +scoverage { + scoverageVersion = "1.3.1" + scoverageScalaVersion = "2.12" // will be overridden by the 'scala-library' version (if configured) } ``` @@ -49,14 +50,7 @@ Aggregating Reports 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) -``` +When applied on a project with sub-projects, the plugin will create the aggregation task `aggregateScoverage`. This will produce a report into `build/scoverage-aggregate` directory. diff --git a/build.gradle b/build.gradle index d82bb5d..4cbd2b9 100644 --- a/build.gradle +++ b/build.gradle @@ -48,7 +48,7 @@ sourceCompatibility = '1.6' targetCompatibility = '1.6' dependencies { - compile "org.scoverage:scalac-scoverage-plugin_2.12:1.3.1" + compileOnly "org.scoverage:scalac-scoverage-plugin_2.12:1.3.1" testCompile 'junit:junit:4.12' testCompile 'org.hamcrest:hamcrest-library:1.3' } diff --git a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java index 4a6e594..d4c3706 100644 --- a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java @@ -74,7 +74,7 @@ public void checkScoverage() { result.assertTaskOutcome(ScoveragePlugin.getTEST_NAME(), TaskOutcome.SUCCESS); result.assertTaskOutcome(ScoveragePlugin.getREPORT_NAME(), TaskOutcome.SUCCESS); result.assertTaskOutcome(ScoveragePlugin.getCHECK_NAME(), TaskOutcome.SUCCESS); - result.assertTaskSkipped(ScoveragePlugin.getAGGREGATE_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); } @Test @@ -87,6 +87,6 @@ public void checkScoverageFails() { result.assertTaskOutcome(ScoveragePlugin.getTEST_NAME(), TaskOutcome.SUCCESS); result.assertTaskOutcome(ScoveragePlugin.getREPORT_NAME(), TaskOutcome.SUCCESS); result.assertTaskOutcome(ScoveragePlugin.getCHECK_NAME(), TaskOutcome.FAILED); - result.assertTaskSkipped(ScoveragePlugin.getAGGREGATE_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); } } \ No newline at end of file diff --git a/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java b/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java index bba1e8a..06311c6 100644 --- a/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java +++ b/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java @@ -23,17 +23,6 @@ protected ScoverageFunctionalTest(String projectName) { .withProjectDir(projectDir()) .withPluginClasspath() .forwardOutput(); - - - List filteredPluginClassPath = new ArrayList(); - - for (File file : runner.getPluginClasspath()) { - if (!file.getName().contains("scalac-scoverage-plugin")) { - filteredPluginClassPath.add(file); - } - } - - runner.withPluginClasspath(filteredPluginClassPath); } protected File projectDir() { @@ -65,12 +54,11 @@ private void configureArguments(String... arguments) { List fullArguments = new ArrayList(); fullArguments.add("-PscalaVersionMajor=2"); - fullArguments.add("-PscalaVersionMinor=11"); - fullArguments.add("-PscalaVersionBuild=5"); + fullArguments.add("-PscalaVersionMinor=12"); + fullArguments.add("-PscalaVersionBuild=8"); fullArguments.add("-PjunitVersion=5.3.2"); fullArguments.add("-PjunitPlatformVersion=1.3.2"); fullArguments.add("-PscalatestVersion=3.0.5"); - fullArguments.add("-PscoverageVersion=1.3.1"); fullArguments.addAll(Arrays.asList(arguments)); runner.withArguments(fullArguments); diff --git a/src/functionalTest/resources/projects/scala-single-module/build.gradle b/src/functionalTest/resources/projects/scala-single-module/build.gradle index cad5985..b0a4ec6 100644 --- a/src/functionalTest/resources/projects/scala-single-module/build.gradle +++ b/src/functionalTest/resources/projects/scala-single-module/build.gradle @@ -18,11 +18,6 @@ dependencies { testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion - - def fullScoverageVersion = "${scalaVersionMajor}.${scalaVersionMinor}:${scoverageVersion}" - - scoverage "org.scoverage:scalac-scoverage-plugin_${fullScoverageVersion}", - "org.scoverage:scalac-scoverage-runtime_${fullScoverageVersion}" } test { diff --git a/src/main/groovy/org/scoverage/AggregateReportApp.java b/src/main/groovy/org/scoverage/AggregateReportApp.java deleted file mode 100644 index 2bf2f14..0000000 --- a/src/main/groovy/org/scoverage/AggregateReportApp.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.scoverage; - -import scoverage.Coverage; -import scoverage.report.CoverageAggregator; - -import java.io.File; - -public class AggregateReportApp { - - public static void main(String... args) { - File rootDir = new File(args[0]); - File reportDir = new File(args[1]); - Boolean clean = Boolean.parseBoolean(args[2]); - - 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(); - - ScoverageWriter.write( - rootDir, - reportDir, - coverage, - coverageOutputCobertura, - coverageOutputXML, - coverageOutputHTML, - coverageDebug - ); - } - -} \ No newline at end of file diff --git a/src/main/groovy/org/scoverage/OverallCheckTask.groovy b/src/main/groovy/org/scoverage/OverallCheckTask.groovy index 356ca6e..810c0ad 100644 --- a/src/main/groovy/org/scoverage/OverallCheckTask.groovy +++ b/src/main/groovy/org/scoverage/OverallCheckTask.groovy @@ -2,6 +2,7 @@ package org.scoverage import org.gradle.api.DefaultTask import org.gradle.api.GradleException +import org.gradle.api.provider.Property import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.TaskAction import org.gradle.internal.impldep.com.google.common.annotations.VisibleForTesting @@ -46,19 +47,16 @@ class OverallCheckTask extends DefaultTask { CoverageType coverageType = CoverageType.Statement double minimumRate = 0.75 - /** Set if want to change default from 'reportDir' in scoverage extension. */ - File reportDir + final Property reportDir = project.objects.property(File) /** Overwrite to test for a specific locale. */ Locale locale @TaskAction void requireLineCoverage() { - def extension = ScoveragePlugin.extensionIn(project) - NumberFormat nf = NumberFormat.getInstance(locale == null ? Locale.getDefault() : locale) - Exception failure = checkLineCoverage(nf, reportDir == null ? extension.reportDir : reportDir, coverageType, minimumRate) + Exception failure = checkLineCoverage(nf, reportDir.get(), coverageType, minimumRate) if (failure) throw failure } diff --git a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy index 8703d09..9e96781 100644 --- a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy +++ b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy @@ -1,32 +1,43 @@ package org.scoverage -import org.gradle.api.tasks.JavaExec +import org.gradle.api.DefaultTask +import org.gradle.api.provider.Property +import org.gradle.api.tasks.TaskAction +import scoverage.report.CoverageAggregator -class ScoverageAggregate extends JavaExec { +class ScoverageAggregate extends DefaultTask { + ScoverageRunner runner + + // TODO - consider separate options for `report` and `aggregate` tasks + final Property coverageOutputCobertura = project.objects.property(Boolean) + final Property coverageOutputXML = project.objects.property(Boolean) + final Property coverageOutputHTML = project.objects.property(Boolean) + final Property coverageDebug = project.objects.property(Boolean) + + // TODO get these from extension boolean clean = false File reportDir - @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, - // TODO - consider separate options for `report` and `aggregate` tasks - extension.coverageOutputCobertura, - extension.coverageOutputXML, - extension.coverageOutputHTML, - extension.coverageDebug - ]) - super.exec() - } + @TaskAction + def aggregate() { + runner.run { + def rootDir = project.projectDir + def reportPath = reportDir ? reportDir : new File(project.buildDir, 'scoverage-aggregate') + + def coverage = CoverageAggregator.aggregate(rootDir, clean) - def reportDirOrDefault() { - return reportDir ? reportDir : new File(project.buildDir, 'scoverage-aggregate') + if (coverage.nonEmpty()) { + ScoverageWriter.write( + rootDir, + reportPath, + coverage.get(), + coverageOutputCobertura.get(), + coverageOutputXML.get(), + coverageOutputHTML.get(), + coverageDebug.get() + ) + } + } } } diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index 7c47d1e..997b467 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -1,18 +1,10 @@ package org.scoverage -import org.gradle.api.Action -import org.gradle.api.GradleException import org.gradle.api.Project -import org.gradle.api.artifacts.Configuration -import org.gradle.api.file.FileCollection import org.gradle.api.plugins.JavaPlugin import org.gradle.api.plugins.scala.ScalaPlugin -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 - -import java.util.concurrent.Callable +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.Property /** * Defines a new SourceSet for the code to be instrumented. @@ -21,142 +13,70 @@ import java.util.concurrent.Callable */ class ScoverageExtension { + /** Version of scoverage to use for the scalac plugin */ + final Property scoverageVersion + + /** Version of scala to use for the scalac plugin */ + final Property scoverageScalaVersion + /** a directory to write working files to */ - File dataDir + final Property dataDir /** a directory to write final output to */ - File reportDir + final Property reportDir /** sources to highlight */ - File sources + final Property sources /** range positioning for highlighting */ - boolean highlighting = true + final Property highlighting /** regex for each excluded package */ - List excludedPackages = [] + final ListProperty excludedPackages /** regex for each excluded file */ - List excludedFiles = [] - - FileCollection pluginClasspath + final ListProperty excludedFiles /** Options for enabling and disabling output */ - boolean coverageOutputCobertura = true - boolean coverageOutputXML = true - boolean coverageOutputHTML = true - boolean coverageDebug = false + final Property coverageOutputCobertura + final Property coverageOutputXML + final Property coverageOutputHTML + final Property coverageDebug ScoverageExtension(Project project) { project.plugins.apply(JavaPlugin.class) project.plugins.apply(ScalaPlugin.class) - project.afterEvaluate(configureRuntimeOptions) - - project.configurations.create(ScoveragePlugin.CONFIGURATION_NAME) { - visible = false - transitive = true - description = 'Scoverage dependencies' - } - - def instrumentedSourceSet = project.sourceSets.create('scoverage') { - def original = project.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) - - resources.source(original.resources) - scala.source(original.java) - scala.source(original.scala) - - compileClasspath += original.compileClasspath + project.configurations.scoverage - runtimeClasspath = it.output + project.configurations.scoverage + original.runtimeClasspath - } - - def scoverageJar = project.tasks.create('jarScoverage', Jar.class) { - dependsOn('scoverageClasses') - classifier = ScoveragePlugin.CONFIGURATION_NAME - from instrumentedSourceSet.output - } - project.artifacts { - scoverage scoverageJar - } - - project.tasks.create(ScoveragePlugin.TEST_NAME, Test.class) { - conventionMapping.map("classpath", new Callable() { - Object call() throws Exception { - def testSourceSet = project.sourceSets.getByName(SourceSet.TEST_SOURCE_SET_NAME) - return testSourceSet.output + - instrumentedSourceSet.output + - project.configurations.scoverage + - testSourceSet.runtimeClasspath - } - }) - group = 'verification' - } - - project.tasks.create(ScoveragePlugin.REPORT_NAME, ScoverageReport.class) { - dependsOn(project.tasks[ScoveragePlugin.TEST_NAME]) - onlyIf { ScoveragePlugin.extensionIn(project).dataDir.list() } - group = 'verification' - } - - project.tasks.create(ScoveragePlugin.CHECK_NAME, OverallCheckTask.class) { - dependsOn(project.tasks[ScoveragePlugin.REPORT_NAME]) - group = 'verification' - } - - sources = project.projectDir - dataDir = new File(project.buildDir, 'scoverage') - reportDir = new File(project.buildDir, 'reports' + File.separatorChar + 'scoverage') - def classLocation = ScoverageExtension.class.getProtectionDomain().getCodeSource().getLocation() - pluginClasspath = project.files(classLocation.file) + project.configurations.scoverage - } - private Action configureRuntimeOptions = new Action() { - - @Override - void execute(Project t) { - - def extension = ScoveragePlugin.extensionIn(t) - extension.dataDir.mkdirs() - - Configuration configuration = t.configurations[ScoveragePlugin.CONFIGURATION_NAME] - File pluginFile - try { - pluginFile = configuration.filter { it.name.contains('plugin') }.iterator().next() - } catch(NoSuchElementException ignored) { - throw new GradleException("Could not find a plugin jar in configuration '${ScoveragePlugin.CONFIGURATION_NAME}'") - } - - t.tasks[ScoveragePlugin.COMPILE_NAME].configure { - List parameters = ['-Xplugin:' + pluginFile.absolutePath] - List existingParameters = scalaCompileOptions.additionalParameters - if (existingParameters) { - parameters.addAll(existingParameters) - } - parameters.add("-P:scoverage:dataDir:${extension.dataDir.absolutePath}".toString()) - if (extension.excludedPackages) { - parameters.add("-P:scoverage:excludedPackages:${extension.excludedPackages.join(';')}".toString()) - } - if (extension.excludedFiles) { - parameters.add("-P:scoverage:excludedFiles:${extension.excludedFiles.join(';')}".toString()) - } - if (extension.highlighting) { - parameters.add('-Yrangepos') - } - doFirst { - GFileUtils.deleteDirectory(destinationDir) - } - scalaCompileOptions.additionalParameters = parameters - // the compile task creates a store of measured statements - outputs.file(new File(extension.dataDir, 'scoverage.coverage.xml')) - } - t.tasks[ScoveragePlugin.TEST_NAME].outputs.upToDateWhen { extension.dataDir.listFiles(measurementFile) } - t.tasks[ScoveragePlugin.REPORT_NAME].configure { - inputs.dir(extension.dataDir) - outputs.dir(extension.reportDir) - } - } - - FilenameFilter measurementFile = new FilenameFilter() { - @Override - boolean accept(File dir, String name) { - return name.startsWith("scoverage.measurements.") - } - } + scoverageVersion = project.objects.property(String) + scoverageVersion.set('1.3.1') + + scoverageScalaVersion = project.objects.property(String) + scoverageScalaVersion.set('2.12') + + sources = project.objects.property(File) + sources.set(project.projectDir) + + dataDir = project.objects.property(File) + dataDir.set(new File(project.buildDir, 'scoverage')) + + reportDir = project.objects.property(File) + reportDir.set(new File(project.buildDir, 'reports' + File.separatorChar + 'scoverage')) + + highlighting = project.objects.property(Boolean) + highlighting.set(true) + + excludedPackages = project.objects.listProperty(String) + excludedPackages.set([]) + + excludedFiles = project.objects.listProperty(String) + excludedFiles.set([]) + + coverageOutputCobertura = project.objects.property(Boolean) + coverageOutputCobertura.set(true) + + coverageOutputXML = project.objects.property(Boolean) + coverageOutputXML.set(true) + + coverageOutputHTML = project.objects.property(Boolean) + coverageOutputHTML.set(true) + coverageDebug = project.objects.property(Boolean) + coverageDebug.set(false) } } diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index cc4b25b..9609619 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -1,25 +1,200 @@ package org.scoverage +import org.gradle.api.GradleException import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.api.invocation.Gradle +import org.gradle.api.plugins.PluginAware +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 -class ScoveragePlugin implements Plugin { - static String CONFIGURATION_NAME = 'scoverage' +import java.util.concurrent.Callable - static String TEST_NAME = 'testScoverage' - static String REPORT_NAME = 'reportScoverage' - static String CHECK_NAME = 'checkScoverage' - static String COMPILE_NAME = 'compileScoverageScala' - static String AGGREGATE_NAME = 'aggregateScoverage' +class ScoveragePlugin implements Plugin { + + static final String CONFIGURATION_NAME = 'scoverage' + static final String TEST_NAME = 'testScoverage' + static final String REPORT_NAME = 'reportScoverage' + static final String CHECK_NAME = 'checkScoverage' + static final String COMPILE_NAME = 'compileScoverageScala' + static final String AGGREGATE_NAME = 'aggregateScoverage' @Override - void apply(Project t) { - if (t.extensions.findByName(CONFIGURATION_NAME) == null) { - t.extensions.create(CONFIGURATION_NAME, ScoverageExtension, t) + void apply(PluginAware pluginAware) { + if (pluginAware instanceof Project) { + applyProject(pluginAware) + if (pluginAware == pluginAware.rootProject) { + pluginAware.subprojects { p -> + p.plugins.apply(ScoveragePlugin) + } + } + } else if (pluginAware instanceof Gradle) { + pluginAware.allprojects { p -> + p.plugins.apply(ScoveragePlugin) + } + } else { + throw new IllegalArgumentException("${pluginAware.getClass()} is currently not supported as an apply target, please report if you need it") + } + } + + void applyProject(Project project) { + + if (project.plugins.hasPlugin(ScoveragePlugin)) { + project.logger.info("Project ${project.name} already has the scoverage plugin") + return + } + project.logger.info("Applying scoverage plugin to $project.name") + + def extension = project.extensions.create('scoverage', ScoverageExtension, project) + if (!project.configurations.asMap[CONFIGURATION_NAME]) { + project.configurations.create(CONFIGURATION_NAME) { + visible = false + transitive = true + description = 'Scoverage dependencies' + } + + project.afterEvaluate { + def scoverageVersion = project.extensions.scoverage.scoverageVersion.get() + def scalaVersion = project.extensions.scoverage.scoverageScalaVersion.get() + + def scalaLibrary = project.configurations.compile.dependencies.find { + it.group == "org.scala-lang" && it.name == "scala-library" + } + + if (scalaLibrary != null) { + scalaVersion = scalaLibrary.version.substring(0, scalaLibrary.version.lastIndexOf(".")) + } + + def fullScoverageVersion = "$scalaVersion:$scoverageVersion" + + project.logger.info("Using scoverage scalac plugin version '$fullScoverageVersion'") + + project.dependencies { + scoverage("org.scoverage:scalac-scoverage-plugin_$fullScoverageVersion") + scoverage("org.scoverage:scalac-scoverage-runtime_$fullScoverageVersion") + } + } + } + + ScoverageRunner scoverageRunner = new ScoverageRunner(project.configurations.scoverage) + + createTasks(project, extension, scoverageRunner) + + project.afterEvaluate { + configureAfterEvaluation(project, extension, scoverageRunner) } } - protected static ScoverageExtension extensionIn(Project project) { - project.extensions[CONFIGURATION_NAME] as ScoverageExtension + private void createTasks(Project project, ScoverageExtension extension, ScoverageRunner scoverageRunner) { + + + def instrumentedSourceSet = project.sourceSets.create('scoverage') { + def original = project.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) + + resources.source(original.resources) + scala.source(original.java) + scala.source(original.scala) + + compileClasspath += original.compileClasspath + project.configurations.scoverage + runtimeClasspath = it.output + project.configurations.scoverage + original.runtimeClasspath + } + + def scoverageJar = project.tasks.create('jarScoverage', Jar.class) { + dependsOn('scoverageClasses') + classifier = CONFIGURATION_NAME + from instrumentedSourceSet.output + } + project.artifacts { + scoverage scoverageJar + } + + project.tasks.create(TEST_NAME, Test.class) { + conventionMapping.map("classpath", new Callable() { + Object call() throws Exception { + def testSourceSet = project.sourceSets.getByName(SourceSet.TEST_SOURCE_SET_NAME) + return testSourceSet.output + + instrumentedSourceSet.output + + project.configurations.scoverage + + testSourceSet.runtimeClasspath + } + }) + group = 'verification' + + FilenameFilter measurementFile = new FilenameFilter() { + @Override + boolean accept(File dir, String name) { + return name.startsWith("scoverage.measurements.") + } + } + outputs.upToDateWhen { extension.dataDir.get().listFiles(measurementFile) } + } + + project.tasks.create(REPORT_NAME, ScoverageReport.class) { + dependsOn(project.tasks[TEST_NAME]) + onlyIf { extension.dataDir.get().list() } + group = 'verification' + runner = scoverageRunner + reportDir = extension.reportDir + sources = extension.sources + dataDir = extension.dataDir + coverageOutputCobertura = extension.coverageOutputCobertura + coverageOutputXML = extension.coverageOutputXML + coverageOutputHTML = extension.coverageOutputHTML + coverageDebug = extension.coverageDebug + } + + project.tasks.create(CHECK_NAME, OverallCheckTask.class) { + dependsOn(project.tasks[REPORT_NAME]) + group = 'verification' + reportDir = extension.reportDir + } + + } + + private void configureAfterEvaluation(Project project, ScoverageExtension extension, ScoverageRunner scoverageRunner) { + + if (project.childProjects.size() > 0) { + def reportTasks = project.getSubprojects().collect { it.tasks.withType(ScoverageReport) } + project.tasks.create(AGGREGATE_NAME, ScoverageAggregate.class) { + dependsOn(reportTasks) + group = 'verification' + runner = scoverageRunner + coverageOutputCobertura = extension.coverageOutputCobertura + coverageOutputXML = extension.coverageOutputXML + coverageOutputHTML = extension.coverageOutputHTML + coverageDebug = extension.coverageDebug + } + } + + project.tasks[COMPILE_NAME].configure { + File pluginFile = project.configurations[CONFIGURATION_NAME].find { + it.name.startsWith("scalac-scoverage-plugin") + } + List parameters = ['-Xplugin:' + pluginFile.absolutePath] + List existingParameters = scalaCompileOptions.additionalParameters + if (existingParameters) { + parameters.addAll(existingParameters) + } + parameters.add("-P:scoverage:dataDir:${extension.dataDir.get().absolutePath}".toString()) + if (extension.excludedPackages.get()) { + def packages = extension.excludedPackages.get().join(';') + parameters.add("-P:scoverage:excludedPackages:$packages".toString()) + } + if (extension.excludedFiles.get()) { + def packages = extension.excludedFiles.get().join(';') + parameters.add("-P:scoverage:excludedFiles:$packages".toString()) + } + if (extension.highlighting.get()) { + parameters.add('-Yrangepos') + } + doFirst { + GFileUtils.deleteDirectory(destinationDir) + } + scalaCompileOptions.additionalParameters = parameters + // the compile task creates a store of measured statements + outputs.file(new File(extension.dataDir.get(), 'scoverage.coverage.xml')) + } } -} +} \ No newline at end of file diff --git a/src/main/groovy/org/scoverage/ScoverageReport.groovy b/src/main/groovy/org/scoverage/ScoverageReport.groovy index ddf81ac..3e53858 100644 --- a/src/main/groovy/org/scoverage/ScoverageReport.groovy +++ b/src/main/groovy/org/scoverage/ScoverageReport.groovy @@ -1,26 +1,62 @@ package org.scoverage +import org.gradle.api.DefaultTask +import org.gradle.api.provider.Property import org.gradle.api.tasks.CacheableTask -import org.gradle.api.tasks.JavaExec +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.TaskAction +import scala.collection.Seq +import scala.collection.Set +import scoverage.Coverage +import scoverage.IOUtils +import scoverage.Serializer @CacheableTask -class ScoverageReport extends JavaExec { - - @Override - void exec() { - def extension = ScoveragePlugin.extensionIn(project) - extension.reportDir.mkdirs() - setClasspath(extension.pluginClasspath) - setMain('org.scoverage.SingleReportApp') - setArgs([ - /* sourceDir = */ extension.sources.absolutePath, - /* dataDir = */ extension.dataDir.absolutePath, - /* reportDir = */ extension.reportDir.absolutePath, - extension.coverageOutputCobertura, - extension.coverageOutputXML, - extension.coverageOutputHTML, - extension.coverageDebug - ]) - super.exec() +class ScoverageReport extends DefaultTask { + + ScoverageRunner runner + + @Input + final Property dataDir = project.objects.property(File) + + @OutputFile + final Property reportDir = project.objects.property(File) + + final Property sources = project.objects.property(File) + final Property coverageOutputCobertura = project.objects.property(Boolean) + final Property coverageOutputXML = project.objects.property(Boolean) + final Property coverageOutputHTML = project.objects.property(Boolean) + final Property coverageDebug = project.objects.property(Boolean) + + @TaskAction + def report() { + runner.run { + reportDir.get().mkdirs() + + File coverageFile = Serializer.coverageFile(dataDir.get()) + + if (!coverageFile.exists()) { + project.logger.info("[scoverage] Could not find coverage file, skipping...") + } else { + File[] array = IOUtils.findMeasurementFiles(dataDir.get()) + // TODO: patch scoverage core to use a consistent collection type? + Seq measurementFiles = scala.collection.JavaConversions.asScalaBuffer(Arrays.asList(array)) + + Coverage coverage = Serializer.deserialize(coverageFile) + + Set measurements = IOUtils.invoked(measurementFiles) + coverage.apply(measurements) + + ScoverageWriter.write( + sources.get(), + reportDir.get(), + coverage, + coverageOutputCobertura.get(), + coverageOutputXML.get(), + coverageOutputHTML.get(), + coverageDebug.get()) + } + } } } diff --git a/src/main/groovy/org/scoverage/ScoverageRunner.groovy b/src/main/groovy/org/scoverage/ScoverageRunner.groovy new file mode 100644 index 0000000..48889e7 --- /dev/null +++ b/src/main/groovy/org/scoverage/ScoverageRunner.groovy @@ -0,0 +1,32 @@ +package org.scoverage + +import org.gradle.api.file.FileCollection + +import java.lang.reflect.Method + +class ScoverageRunner { + + private FileCollection runtimeClasspath + + ScoverageRunner(FileCollection runtimeClasspath) { + + this.runtimeClasspath = runtimeClasspath + } + + def run(Closure action) { + + URLClassLoader cloader = (URLClassLoader) Thread.currentThread().getContextClassLoader() + + Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class) + method.setAccessible(true) + + runtimeClasspath.files.each { f -> + def url = f.toURL() + if (!cloader.getURLs().contains(url)) { + method.invoke(cloader, url) + } + } + + action.call() + } +} diff --git a/src/main/groovy/org/scoverage/SingleReportApp.java b/src/main/groovy/org/scoverage/SingleReportApp.java deleted file mode 100644 index 998cb83..0000000 --- a/src/main/groovy/org/scoverage/SingleReportApp.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.scoverage; - -import scala.collection.Seq; -import scala.collection.Set; -import scoverage.Coverage; -import scoverage.IOUtils; -import scoverage.Serializer; - -import java.io.File; -import java.util.Arrays; - -/** - * late binding of scoverage core libraries (without a dependency on groovy) - */ -public class SingleReportApp { - - public static void main(String... args) { - File sourceDir = new File(args[0]); - File dataDir = new File(args[1]); - File reportDir = new File(args[2]); - - 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); - - 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 measurementFiles = scala.collection.JavaConversions.asScalaBuffer(Arrays.asList(array)); - - Coverage coverage = Serializer.deserialize(coverageFile); - - Set measurements = IOUtils.invoked(measurementFiles); - coverage.apply(measurements); - - ScoverageWriter.write( - sourceDir, - reportDir, - coverage, - coverageOutputCobertura, - coverageOutputXML, - coverageOutputHTML, - coverageDebug); - } - } - - -} \ No newline at end of file diff --git a/src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy b/src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy index 00498c5..14e22c2 100644 --- a/src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy +++ b/src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy @@ -26,9 +26,7 @@ class AcceptanceTestUtils { .withPluginClasspath() .forwardOutput() - def arguments = tasks + "-PscoverageVersion=1.3.1" - - runner.withArguments(arguments as List).build() + runner.withArguments(tasks).build() } protected void checkFile(String description, File file, boolean shouldExist) throws Exception { diff --git a/src/test/happy day/build.gradle b/src/test/happy day/build.gradle index e47e145..17a1522 100644 --- a/src/test/happy day/build.gradle +++ b/src/test/happy day/build.gradle @@ -9,8 +9,6 @@ repositories { } dependencies { - scoverage "org.scoverage:scalac-scoverage-plugin_2.11:${scoverageVersion}", - "org.scoverage:scalac-scoverage-runtime_2.11:${scoverageVersion}" compile 'org.scala-lang:scala-library:2.11.0' testCompile 'junit:junit:4.11' } diff --git a/src/test/runtime/build.gradle b/src/test/runtime/build.gradle index e8e1171..ec21818 100644 --- a/src/test/runtime/build.gradle +++ b/src/test/runtime/build.gradle @@ -9,8 +9,6 @@ repositories { } dependencies { - scoverage "org.scoverage:scalac-scoverage-plugin_2.11:${scoverageVersion}", - "org.scoverage:scalac-scoverage-runtime_2.11:${scoverageVersion}" compile 'org.scala-lang:scala-library:2.11.0' } diff --git a/src/test/separate-tests/build.gradle b/src/test/separate-tests/build.gradle index 83522c7..1aeb9b8 100644 --- a/src/test/separate-tests/build.gradle +++ b/src/test/separate-tests/build.gradle @@ -9,13 +9,6 @@ allprojects { repositories { jcenter() } - - apply plugin: 'org.scoverage' - - dependencies { - scoverage "org.scoverage:scalac-scoverage-plugin_2.11:${scoverageVersion}", - "org.scoverage:scalac-scoverage-runtime_2.11:${scoverageVersion}" - } } subprojects { @@ -45,20 +38,13 @@ subprojects { configure(subprojects.findAll { it.name.endsWith('-tests') }) { def mainProject = project(":${project.name.minus('-tests')}") dependencies { - testCompile mainProject - scoverage mainProject.configurations.scoverage.artifacts.files + testCompile mainProject.sourceSets.scoverage.output } scoverage { sources = mainProject.extensions.scoverage.sources dataDir = mainProject.extensions.scoverage.dataDir reportDir = mainProject.extensions.scoverage.reportDir } - sourceSets { - testScoverage { - compileClasspath += sourceSets.main.output - runtimeClasspath += sourceSets.main.output - } - } compileScoverageScala { onlyIf { false } } diff --git a/src/test/water/build.gradle b/src/test/water/build.gradle index f4d5a6e..b9bb87c 100644 --- a/src/test/water/build.gradle +++ b/src/test/water/build.gradle @@ -9,20 +9,11 @@ allprojects { jcenter() } - apply plugin: 'org.scoverage' + apply plugin: 'scala' dependencies { - scoverage "org.scoverage:scalac-scoverage-plugin_2.11:${scoverageVersion}", - "org.scoverage:scalac-scoverage-runtime_2.11:${scoverageVersion}" compile 'org.scala-lang:scala-library:2.11.5' - testCompile 'junit:junit:4.11' } } -task aggregateScoverage(type: org.scoverage.ScoverageAggregate) - -subprojects { - aggregateScoverage.dependsOn(it.tasks.reportScoverage) -} - From b2fbb84ba5dbaf8ef7af4426a1a44483dfacafaf Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Tue, 29 Jan 2019 17:05:23 +0200 Subject: [PATCH 029/167] Properly handle report, check and aggregation tasks in multi-module projects --- README.md | 22 +-- .../org.scoverage/ScalaMultiModuleTest.java | 167 ++++++++++++++++++ .../org.scoverage/ScalaSingleModuleTest.java | 16 +- .../ScoverageFunctionalTest.java | 14 +- .../a/src/main/scala/org/hello/a/WorldA.scala | 9 + .../scala/org/hello/a/TestNothingASuite.scala | 12 ++ .../test/scala/org/hello/a/WorldASuite.scala | 13 ++ .../b/src/main/scala/org/hello/b/WorldB.scala | 9 + .../scala/org/hello/b/TestNothingBSuite.scala | 12 ++ .../test/scala/org/hello/b/WorldBSuite.scala | 13 ++ .../projects/scala-multi-module/build.gradle | 38 ++++ .../scala-multi-module/settings.gradle | 1 + .../src/main/scala/org/hello/World.scala | 9 + .../scala/org/hello/TestNothingSuite.scala | 12 ++ .../src/test/scala/org/hello/WorldSuite.scala | 13 ++ .../org/scoverage/ScoverageAggregate.groovy | 17 +- .../org/scoverage/ScoverageExtension.groovy | 5 + .../org/scoverage/ScoveragePlugin.groovy | 9 +- .../org/scoverage/ScoverageReport.groovy | 8 +- .../AggregationAcceptanceTest.groovy | 2 +- 20 files changed, 368 insertions(+), 33 deletions(-) create mode 100644 src/functionalTest/java/org.scoverage/ScalaMultiModuleTest.java create mode 100644 src/functionalTest/resources/projects/scala-multi-module/a/src/main/scala/org/hello/a/WorldA.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module/a/src/test/scala/org/hello/a/TestNothingASuite.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module/a/src/test/scala/org/hello/a/WorldASuite.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module/b/src/main/scala/org/hello/b/WorldB.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module/b/src/test/scala/org/hello/b/TestNothingBSuite.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module/b/src/test/scala/org/hello/b/WorldBSuite.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module/build.gradle create mode 100644 src/functionalTest/resources/projects/scala-multi-module/settings.gradle create mode 100644 src/functionalTest/resources/projects/scala-multi-module/src/main/scala/org/hello/World.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module/src/test/scala/org/hello/TestNothingSuite.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module/src/test/scala/org/hello/WorldSuite.scala diff --git a/README.md b/README.md index bbbb87c..696adb5 100644 --- a/README.md +++ b/README.md @@ -48,25 +48,27 @@ You can configure output generated by `gradle reportScoverage` using flags: Aggregating Reports ------------------- -There is now experimental support for aggregating coverage statistics across sub-projects. -When applied on a project with sub-projects, the plugin will create the aggregation task `aggregateScoverage`. +There is now experimental support for aggregating coverage statistics in composite builds. -This will produce a report into `build/scoverage-aggregate` directory. +When applied on a project with sub-projects, the plugin will create the aggregation task `aggregateScoverage`, which +will first generate reports for each project individually (including the parent project), and will then generate an +aggregated result based on these reports. -Aggregation uses same flags as reporting for enabling/disabling different output types. +The aggregated report will override the parent-project specific report (`parent-project/build/reports/scoverage`). -For checking coverage of the aggregated result, configure the checkScoverage task: +One can still use `reportScoverage` in order to generate a report without aggregation. -```groovy -checkScoverage { - reportDir = file("$buildDir/scoverage-aggregate") -} -``` +Aggregation uses same flags as reporting for enabling/disabling different output types. CheckScoverage -------------- +The `checkScoverage` task validates coverage status according the generated reports. + +`gradle checkScoverage` will automatically generate reports via `reportScoverage` but it won't generate aggregated reports. +In order to check coverage of aggregated reports one should use `gradle checkScoverage aggregateScoverage`. + By default, when you launch `gradle checkScoverage` build fail if only 75% of statements in project is covered by tests. To configure it as you want, add this configuration : diff --git a/src/functionalTest/java/org.scoverage/ScalaMultiModuleTest.java b/src/functionalTest/java/org.scoverage/ScalaMultiModuleTest.java new file mode 100644 index 0000000..92b427c --- /dev/null +++ b/src/functionalTest/java/org.scoverage/ScalaMultiModuleTest.java @@ -0,0 +1,167 @@ +package org.scoverage; + +import org.junit.Test; + +public class ScalaMultiModuleTest extends ScoverageFunctionalTest { + + public ScalaMultiModuleTest() { + super("scala-multi-module"); + } + + @Test + public void reportScoverage() { + + AssertableBuildResult result = dryRun("clean", ScoveragePlugin.getREPORT_NAME()); + + result.assertTaskExists(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("a:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("b:" + ScoveragePlugin.getREPORT_NAME()); + } + + @Test + public void reportScoverageOnlyRoot() { + + AssertableBuildResult result = dryRun("clean", ":" + ScoveragePlugin.getREPORT_NAME()); + + result.assertTaskExists(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist("a:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist("b:" + ScoveragePlugin.getREPORT_NAME()); + } + + @Test + public void reportScoverageOnlyA() { + + AssertableBuildResult result = dryRun("clean", ":a:" + ScoveragePlugin.getREPORT_NAME()); + + result.assertTaskDoesntExist(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("a:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist("b:" + ScoveragePlugin.getREPORT_NAME()); + } + + @Test + public void aggregateScoverage() { + + AssertableBuildResult result = dryRun("clean", ScoveragePlugin.getAGGREGATE_NAME()); + + result.assertTaskExists(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("a:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists(ScoveragePlugin.getAGGREGATE_NAME()); + } + + @Test + public void checkScoverage() { + + AssertableBuildResult result = dryRun("clean", ScoveragePlugin.getCHECK_NAME()); + + result.assertTaskExists(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("a:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskExists("a:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskExists("b:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + } + + @Test + public void checkScoverageOnlyRoot() { + + AssertableBuildResult result = dryRun("clean", ":" + ScoveragePlugin.getCHECK_NAME()); + + result.assertTaskExists(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist("a:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist("a:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist("b:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + } + + @Test + public void checkScoverageOnlyA() { + + AssertableBuildResult result = dryRun("clean", ":a:" + ScoveragePlugin.getCHECK_NAME()); + + result.assertTaskDoesntExist(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("a:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskExists("a:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist("b:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + } + + @Test + public void checkAndAggregateScoverage() { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME(), ScoveragePlugin.getAGGREGATE_NAME()); + + result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("a:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded("a:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded("b:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); + } + + @Test + public void checkScoverageWithoutCoverageInRoot() { + + AssertableBuildResult result = runAndFail("clean", ScoveragePlugin.getCHECK_NAME(), + ScoveragePlugin.getTEST_NAME(), + "--tests", "org.hello.TestNothingSuite", + "--tests", "org.hello.a.WorldASuite", + "--tests", "org.hello.b.WorldBSuite"); + + result.assertTaskFailed(ScoveragePlugin.getCHECK_NAME()); + } + + @Test + public void checkScoverageWithoutCoverageInA() { + + AssertableBuildResult result = runAndFail("clean", ScoveragePlugin.getCHECK_NAME(), + ScoveragePlugin.getTEST_NAME(), + "--tests", "org.hello.a.TestNothingASuite", + "--tests", "org.hello.WorldSuite", + "--tests", "org.hello.b.WorldBSuite"); + + result.assertTaskFailed("a:" + ScoveragePlugin.getCHECK_NAME()); + } + + @Test + public void checkAndAggregateScoverageWithoutCoverageInRoot() { + + // should pass as the check on the root is for the aggregation (which covers > 50%) + + AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME(), + ScoveragePlugin.getAGGREGATE_NAME(), ScoveragePlugin.getTEST_NAME(), + "--tests", "org.hello.TestNothingSuite", + "--tests", "org.hello.a.WorldASuite", + "--tests", "org.hello.b.WorldBSuite"); + + result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("a:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded("a:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded("b:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); + } + + @Test + public void checkAndAggregateScoverageWithoutCoverageInAll() { + + AssertableBuildResult result = runAndFail("clean", ScoveragePlugin.getCHECK_NAME(), + ScoveragePlugin.getAGGREGATE_NAME(), ScoveragePlugin.getTEST_NAME(), + "--tests", "org.hello.TestNothingSuite", + "--tests", "org.hello.a.TestNothingASuite", + "--tests", "org.hello.b.TestNothingBSuite"); + + result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("a:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); + result.assertTaskFailed(ScoveragePlugin.getCHECK_NAME()); + } +} \ No newline at end of file diff --git a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java index d4c3706..ea4823a 100644 --- a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java @@ -70,10 +70,10 @@ public void checkScoverage() { AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME()); - result.assertTaskOutcome(ScoveragePlugin.getCOMPILE_NAME(), TaskOutcome.SUCCESS); - result.assertTaskOutcome(ScoveragePlugin.getTEST_NAME(), TaskOutcome.SUCCESS); - result.assertTaskOutcome(ScoveragePlugin.getREPORT_NAME(), TaskOutcome.SUCCESS); - result.assertTaskOutcome(ScoveragePlugin.getCHECK_NAME(), TaskOutcome.SUCCESS); + result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getTEST_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); } @@ -83,10 +83,10 @@ public void checkScoverageFails() { AssertableBuildResult result = runAndFail("clean", ScoveragePlugin.getCHECK_NAME(), ScoveragePlugin.getTEST_NAME(), "--tests", "org.hello.TestNothingSuite"); - result.assertTaskOutcome(ScoveragePlugin.getCOMPILE_NAME(), TaskOutcome.SUCCESS); - result.assertTaskOutcome(ScoveragePlugin.getTEST_NAME(), TaskOutcome.SUCCESS); - result.assertTaskOutcome(ScoveragePlugin.getREPORT_NAME(), TaskOutcome.SUCCESS); - result.assertTaskOutcome(ScoveragePlugin.getCHECK_NAME(), TaskOutcome.FAILED); + result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getTEST_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskFailed(ScoveragePlugin.getCHECK_NAME()); result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); } } \ No newline at end of file diff --git a/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java b/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java index 06311c6..eb64c61 100644 --- a/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java +++ b/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java @@ -10,6 +10,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.regex.Pattern; public abstract class ScoverageFunctionalTest { @@ -99,6 +100,16 @@ public void assertTaskSkipped(String taskName) { Assert.assertTrue(task == null || task.getOutcome() == TaskOutcome.SKIPPED); } + public void assertTaskSucceeded(String taskName) { + + assertTaskOutcome(taskName, TaskOutcome.SUCCESS); + } + + public void assertTaskFailed(String taskName) { + + assertTaskOutcome(taskName, TaskOutcome.FAILED); + } + public void assertTaskOutcome(String taskName, TaskOutcome outcome) { BuildTask task = getTask(taskName); @@ -119,7 +130,8 @@ private String fullTaskName(String taskName) { private boolean taskExists(String taskName) { - return result.getOutput().contains(fullTaskName(taskName) + " "); + Pattern regex = Pattern.compile("^" + fullTaskName(taskName), Pattern.MULTILINE); + return regex.matcher(result.getOutput()).find(); } } } diff --git a/src/functionalTest/resources/projects/scala-multi-module/a/src/main/scala/org/hello/a/WorldA.scala b/src/functionalTest/resources/projects/scala-multi-module/a/src/main/scala/org/hello/a/WorldA.scala new file mode 100644 index 0000000..301f445 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module/a/src/main/scala/org/hello/a/WorldA.scala @@ -0,0 +1,9 @@ +package org.hello.a + +class WorldA { + + def fooA(): String = { + val s = "a" + "a" + s + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/a/src/test/scala/org/hello/a/TestNothingASuite.scala b/src/functionalTest/resources/projects/scala-multi-module/a/src/test/scala/org/hello/a/TestNothingASuite.scala new file mode 100644 index 0000000..996857c --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module/a/src/test/scala/org/hello/a/TestNothingASuite.scala @@ -0,0 +1,12 @@ +package org.hello.a + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class TestNothingASuite extends FunSuite { + + test("nothing") { + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/a/src/test/scala/org/hello/a/WorldASuite.scala b/src/functionalTest/resources/projects/scala-multi-module/a/src/test/scala/org/hello/a/WorldASuite.scala new file mode 100644 index 0000000..840bdcc --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module/a/src/test/scala/org/hello/a/WorldASuite.scala @@ -0,0 +1,13 @@ +package org.hello.a + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldASuite extends FunSuite { + + test("fooA") { + new WorldA().fooA() + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/b/src/main/scala/org/hello/b/WorldB.scala b/src/functionalTest/resources/projects/scala-multi-module/b/src/main/scala/org/hello/b/WorldB.scala new file mode 100644 index 0000000..bb7a579 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module/b/src/main/scala/org/hello/b/WorldB.scala @@ -0,0 +1,9 @@ +package org.hello.b + +class WorldB { + + def fooB(): String = { + val s = "b" + "b" + s + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/b/src/test/scala/org/hello/b/TestNothingBSuite.scala b/src/functionalTest/resources/projects/scala-multi-module/b/src/test/scala/org/hello/b/TestNothingBSuite.scala new file mode 100644 index 0000000..bebfee8 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module/b/src/test/scala/org/hello/b/TestNothingBSuite.scala @@ -0,0 +1,12 @@ +package org.hello.b + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class TestNothingBSuite extends FunSuite { + + test("nothing") { + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/b/src/test/scala/org/hello/b/WorldBSuite.scala b/src/functionalTest/resources/projects/scala-multi-module/b/src/test/scala/org/hello/b/WorldBSuite.scala new file mode 100644 index 0000000..fdb8d68 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module/b/src/test/scala/org/hello/b/WorldBSuite.scala @@ -0,0 +1,13 @@ +package org.hello.b + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldBSuite extends FunSuite { + + test("fooB") { + new WorldB().fooB() + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/build.gradle b/src/functionalTest/resources/projects/scala-multi-module/build.gradle new file mode 100644 index 0000000..805ce48 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module/build.gradle @@ -0,0 +1,38 @@ +plugins { + id 'org.scoverage' +} + +allprojects { + repositories { + jcenter() + } +} + +description = 'a multi-module Scala project that builds successfully with 100% coverage' + +allprojects { + + apply plugin: 'java' + apply plugin: 'scala' + + dependencies { + compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + + testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion + } + + test { + useJUnitPlatform() + } + + checkScoverage { + minimumRate = 0.5 + } +} + +checkScoverage { + minimumRate = 0.5 +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/settings.gradle b/src/functionalTest/resources/projects/scala-multi-module/settings.gradle new file mode 100644 index 0000000..dd79722 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module/settings.gradle @@ -0,0 +1 @@ +include 'a', 'b' \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/src/main/scala/org/hello/World.scala b/src/functionalTest/resources/projects/scala-multi-module/src/main/scala/org/hello/World.scala new file mode 100644 index 0000000..27dbe28 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module/src/main/scala/org/hello/World.scala @@ -0,0 +1,9 @@ +package org.hello + +class World { + + def foo(): String = { + val s = "a" + "b" + s + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/src/test/scala/org/hello/TestNothingSuite.scala b/src/functionalTest/resources/projects/scala-multi-module/src/test/scala/org/hello/TestNothingSuite.scala new file mode 100644 index 0000000..1ac25b5 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module/src/test/scala/org/hello/TestNothingSuite.scala @@ -0,0 +1,12 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class TestNothingSuite extends FunSuite { + + test("nothing") { + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/src/test/scala/org/hello/WorldSuite.scala b/src/functionalTest/resources/projects/scala-multi-module/src/test/scala/org/hello/WorldSuite.scala new file mode 100644 index 0000000..7281a12 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module/src/test/scala/org/hello/WorldSuite.scala @@ -0,0 +1,13 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldSuite extends FunSuite { + + test("foo") { + new World().foo() + } +} \ No newline at end of file diff --git a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy index 9e96781..1e40907 100644 --- a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy +++ b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy @@ -2,6 +2,7 @@ package org.scoverage import org.gradle.api.DefaultTask import org.gradle.api.provider.Property +import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction import scoverage.report.CoverageAggregator @@ -9,28 +10,30 @@ class ScoverageAggregate extends DefaultTask { ScoverageRunner runner + @OutputDirectory + final Property reportDir = project.objects.property(File) + + final Property deleteReportsOnAggregation = project.objects.property(Boolean) + // TODO - consider separate options for `report` and `aggregate` tasks final Property coverageOutputCobertura = project.objects.property(Boolean) final Property coverageOutputXML = project.objects.property(Boolean) final Property coverageOutputHTML = project.objects.property(Boolean) final Property coverageDebug = project.objects.property(Boolean) - // TODO get these from extension - boolean clean = false - File reportDir - @TaskAction def aggregate() { runner.run { def rootDir = project.projectDir - def reportPath = reportDir ? reportDir : new File(project.buildDir, 'scoverage-aggregate') - def coverage = CoverageAggregator.aggregate(rootDir, clean) + def coverage = CoverageAggregator.aggregate(rootDir, deleteReportsOnAggregation.get()) + + reportDir.get().deleteDir() if (coverage.nonEmpty()) { ScoverageWriter.write( rootDir, - reportPath, + reportDir.get(), coverage.get(), coverageOutputCobertura.get(), coverageOutputXML.get(), diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index 997b467..419224f 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -38,6 +38,8 @@ class ScoverageExtension { final Property coverageOutputHTML final Property coverageDebug + final Property deleteReportsOnAggregation + ScoverageExtension(Project project) { project.plugins.apply(JavaPlugin.class) @@ -78,5 +80,8 @@ class ScoverageExtension { coverageDebug = project.objects.property(Boolean) coverageDebug.set(false) + + deleteReportsOnAggregation = project.objects.property(Boolean) + deleteReportsOnAggregation.set(false) } } diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 9609619..418ffe3 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -1,6 +1,6 @@ package org.scoverage -import org.gradle.api.GradleException + import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.invocation.Gradle @@ -156,16 +156,19 @@ class ScoveragePlugin implements Plugin { private void configureAfterEvaluation(Project project, ScoverageExtension extension, ScoverageRunner scoverageRunner) { if (project.childProjects.size() > 0) { - def reportTasks = project.getSubprojects().collect { it.tasks.withType(ScoverageReport) } - project.tasks.create(AGGREGATE_NAME, ScoverageAggregate.class) { + def reportTasks = project.getAllprojects().collect { it.tasks.withType(ScoverageReport) } + def aggregationTask = project.tasks.create(AGGREGATE_NAME, ScoverageAggregate.class) { dependsOn(reportTasks) group = 'verification' runner = scoverageRunner + reportDir = extension.reportDir + deleteReportsOnAggregation = extension.deleteReportsOnAggregation coverageOutputCobertura = extension.coverageOutputCobertura coverageOutputXML = extension.coverageOutputXML coverageOutputHTML = extension.coverageOutputHTML coverageDebug = extension.coverageDebug } + project.tasks[CHECK_NAME].mustRunAfter(aggregationTask) } project.tasks[COMPILE_NAME].configure { diff --git a/src/main/groovy/org/scoverage/ScoverageReport.groovy b/src/main/groovy/org/scoverage/ScoverageReport.groovy index 3e53858..cb9c5d2 100644 --- a/src/main/groovy/org/scoverage/ScoverageReport.groovy +++ b/src/main/groovy/org/scoverage/ScoverageReport.groovy @@ -4,7 +4,7 @@ import org.gradle.api.DefaultTask import org.gradle.api.provider.Property import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.Input -import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction import scala.collection.Seq import scala.collection.Set @@ -20,10 +20,12 @@ class ScoverageReport extends DefaultTask { @Input final Property dataDir = project.objects.property(File) - @OutputFile + @Input + final Property sources = project.objects.property(File) + + @OutputDirectory final Property reportDir = project.objects.property(File) - final Property sources = project.objects.property(File) final Property coverageOutputCobertura = project.objects.property(Boolean) final Property coverageOutputXML = project.objects.property(Boolean) final Property coverageOutputHTML = project.objects.property(Boolean) diff --git a/src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy b/src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy index 90bdb51..2b425ff 100644 --- a/src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy +++ b/src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy @@ -21,6 +21,6 @@ class AggregationAcceptanceTest extends AcceptanceTestUtils { } private static File aggregateReportDir(File baseDir) { - return new File(baseDir, 'build/scoverage-aggregate') + return new File(baseDir, 'build/reports/scoverage') } } From 22be0bd56ac2bf9a886d62b4965a243694d38a9e Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Wed, 30 Jan 2019 17:45:18 +0200 Subject: [PATCH 030/167] Move the coverage XML validation to the functional tests and remove the "separate tests" use-case --- build.gradle | 14 ++-- .../org.scoverage/ScalaMultiModuleTest.java | 69 +++++++++++++++++-- .../org.scoverage/ScalaSingleModuleTest.java | 18 ++++- .../ScoverageFunctionalTest.java | 53 ++++++++++++++ .../org/scoverage/ScoverageExtension.groovy | 2 +- .../org/scoverage/ScoveragePlugin.groovy | 2 + .../org/scoverage/AcceptanceTestUtils.groovy | 47 ------------- .../AggregationAcceptanceTest.groovy | 26 ------- .../org/scoverage/OverallCheckTaskTest.groovy | 11 ++- .../SeparateTestsAcceptanceTest.groovy | 27 -------- .../SimpleReportAcceptanceTest.groovy | 25 ------- src/test/happy day/build.gradle | 19 ----- src/test/happy day/settings.gradle | 0 .../happy day/src/main/java/old/World.java | 7 -- .../happy day/src/main/resources/main.txt | 0 .../src/main/scala/hello/World.scala | 8 --- .../happy day/src/test/resources/test.txt | 0 .../src/test/scala/hello/ResourcesTest.scala | 14 ---- .../src/test/scala/hello/WorldTest.scala | 10 --- .../resources/{ => checkTask}/cobertura.xml | 0 .../resources/{ => checkTask}/scoverage.xml | 0 src/test/runtime/build.gradle | 20 ------ src/test/runtime/settings.gradle | 0 .../runtime/src/main/scala/hello/World.scala | 5 -- .../src/main/scala/hello/BaseTest.scala | 7 -- .../src/test/scala/hello/HelloTest.scala | 13 ---- .../a/src/main/scala/hello/Hello.scala | 5 -- src/test/separate-tests/build.gradle | 51 -------------- src/test/separate-tests/settings.gradle | 1 - .../src/main/scala/whales/BlueWhale.scala | 5 -- .../src/test/scala/whales/BlueWhaleTest.scala | 11 --- src/test/water/build.gradle | 19 ----- .../src/main/scala/krills/NorthernKrill.scala | 5 -- .../test/scala/krills/NorthernKrillTest.scala | 11 --- src/test/water/settings.gradle | 1 - 35 files changed, 147 insertions(+), 359 deletions(-) delete mode 100644 src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy delete mode 100644 src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy delete mode 100644 src/test/groovy/org/scoverage/SeparateTestsAcceptanceTest.groovy delete mode 100644 src/test/groovy/org/scoverage/SimpleReportAcceptanceTest.groovy delete mode 100644 src/test/happy day/build.gradle delete mode 100644 src/test/happy day/settings.gradle delete mode 100644 src/test/happy day/src/main/java/old/World.java delete mode 100644 src/test/happy day/src/main/resources/main.txt delete mode 100644 src/test/happy day/src/main/scala/hello/World.scala delete mode 100644 src/test/happy day/src/test/resources/test.txt delete mode 100644 src/test/happy day/src/test/scala/hello/ResourcesTest.scala delete mode 100644 src/test/happy day/src/test/scala/hello/WorldTest.scala rename src/test/resources/{ => checkTask}/cobertura.xml (100%) rename src/test/resources/{ => checkTask}/scoverage.xml (100%) delete mode 100644 src/test/runtime/build.gradle delete mode 100644 src/test/runtime/settings.gradle delete mode 100644 src/test/runtime/src/main/scala/hello/World.scala delete mode 100644 src/test/separate-tests/a-tests/src/main/scala/hello/BaseTest.scala delete mode 100644 src/test/separate-tests/a-tests/src/test/scala/hello/HelloTest.scala delete mode 100644 src/test/separate-tests/a/src/main/scala/hello/Hello.scala delete mode 100644 src/test/separate-tests/build.gradle delete mode 100644 src/test/separate-tests/settings.gradle delete mode 100644 src/test/water/bluewhale/src/main/scala/whales/BlueWhale.scala delete mode 100644 src/test/water/bluewhale/src/test/scala/whales/BlueWhaleTest.scala delete mode 100644 src/test/water/build.gradle delete mode 100644 src/test/water/krill/src/main/scala/krills/NorthernKrill.scala delete mode 100644 src/test/water/krill/src/test/scala/krills/NorthernKrillTest.scala delete mode 100644 src/test/water/settings.gradle diff --git a/build.gradle b/build.gradle index 4cbd2b9..606cc15 100644 --- a/build.gradle +++ b/build.gradle @@ -55,27 +55,25 @@ dependencies { sourceSets { functionalTest { - java { - srcDir file('src/functionalTest/java') - } - resources { - srcDir file('src/functionalTest/resources') - } + java.srcDir file('src/functionalTest/java') + resources.srcDir file('src/functionalTest/resources') compileClasspath += sourceSets.main.output + configurations.testRuntime runtimeClasspath += output + compileClasspath } } task functionalTest(type: Test) { + description = 'Runs the functional tests.' + group = 'verification' testClassesDirs = sourceSets.functionalTest.output.classesDirs classpath = sourceSets.functionalTest.runtimeClasspath + mustRunAfter test } -functionalTest.mustRunAfter(test) check.dependsOn functionalTest gradlePlugin { - testSourceSets sourceSets.test, sourceSets.functionalTest + testSourceSets sourceSets.functionalTest } task groovydocJar(type: Jar, dependsOn: groovydoc) { diff --git a/src/functionalTest/java/org.scoverage/ScalaMultiModuleTest.java b/src/functionalTest/java/org.scoverage/ScalaMultiModuleTest.java index 92b427c..68d7a92 100644 --- a/src/functionalTest/java/org.scoverage/ScalaMultiModuleTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaMultiModuleTest.java @@ -1,7 +1,10 @@ package org.scoverage; +import org.junit.Assert; import org.junit.Test; +import java.io.File; + public class ScalaMultiModuleTest extends ScoverageFunctionalTest { public ScalaMultiModuleTest() { @@ -92,9 +95,10 @@ public void checkScoverageOnlyA() { } @Test - public void checkAndAggregateScoverage() { + public void checkAndAggregateScoverage() throws Exception { - AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME(), ScoveragePlugin.getAGGREGATE_NAME()); + AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME(), + ScoveragePlugin.getAGGREGATE_NAME()); result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded("a:" + ScoveragePlugin.getREPORT_NAME()); @@ -103,10 +107,13 @@ public void checkAndAggregateScoverage() { result.assertTaskSucceeded("a:" + ScoveragePlugin.getCHECK_NAME()); result.assertTaskSucceeded("b:" + ScoveragePlugin.getCHECK_NAME()); result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); + + assertAllReportFilesExist(); + assertCoverage(100.0); } @Test - public void checkScoverageWithoutCoverageInRoot() { + public void checkScoverageWithoutCoverageInRoot() throws Exception { AssertableBuildResult result = runAndFail("clean", ScoveragePlugin.getCHECK_NAME(), ScoveragePlugin.getTEST_NAME(), @@ -115,10 +122,13 @@ public void checkScoverageWithoutCoverageInRoot() { "--tests", "org.hello.b.WorldBSuite"); result.assertTaskFailed(ScoveragePlugin.getCHECK_NAME()); + + assertRootReportFilesExist(); + assertCoverage(0.0); } @Test - public void checkScoverageWithoutCoverageInA() { + public void checkScoverageWithoutCoverageInA() throws Exception { AssertableBuildResult result = runAndFail("clean", ScoveragePlugin.getCHECK_NAME(), ScoveragePlugin.getTEST_NAME(), @@ -127,10 +137,13 @@ public void checkScoverageWithoutCoverageInA() { "--tests", "org.hello.b.WorldBSuite"); result.assertTaskFailed("a:" + ScoveragePlugin.getCHECK_NAME()); + + assertAReportFilesExist(); + assertCoverage(0.0, reportDir(projectDir().toPath().resolve("a").toFile())); } @Test - public void checkAndAggregateScoverageWithoutCoverageInRoot() { + public void checkAndAggregateScoverageWithoutCoverageInRoot() throws Exception { // should pass as the check on the root is for the aggregation (which covers > 50%) @@ -147,10 +160,13 @@ public void checkAndAggregateScoverageWithoutCoverageInRoot() { result.assertTaskSucceeded("a:" + ScoveragePlugin.getCHECK_NAME()); result.assertTaskSucceeded("b:" + ScoveragePlugin.getCHECK_NAME()); result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); + + assertAllReportFilesExist(); + assertCoverage(66.6); } @Test - public void checkAndAggregateScoverageWithoutCoverageInAll() { + public void checkAndAggregateScoverageWithoutCoverageInAll() throws Exception { AssertableBuildResult result = runAndFail("clean", ScoveragePlugin.getCHECK_NAME(), ScoveragePlugin.getAGGREGATE_NAME(), ScoveragePlugin.getTEST_NAME(), @@ -163,5 +179,44 @@ public void checkAndAggregateScoverageWithoutCoverageInAll() { result.assertTaskSucceeded("b:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); result.assertTaskFailed(ScoveragePlugin.getCHECK_NAME()); + + assertAllReportFilesExist(); + assertCoverage(0.0); + } + + private void assertAllReportFilesExist() { + + assertRootReportFilesExist(); + assertAReportFilesExist(); + assertBReportFilesExist(); + assertAggregationFilesExist(); + } + + private void assertAggregationFilesExist() { + + assertRootReportFilesExist(); + Assert.assertTrue(resolve(reportDir(), "a/src/main/scala/org/hello/a/WorldA.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "b/src/main/scala/org/hello/b/WorldB.scala.html").exists()); + } + + private void assertRootReportFilesExist() { + + Assert.assertTrue(resolve(reportDir(), "index.html").exists()); + Assert.assertTrue(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + } + + private void assertAReportFilesExist() { + + File aReportDir = reportDir(projectDir().toPath().resolve("a").toFile()); + Assert.assertTrue(resolve(aReportDir, "index.html").exists()); + Assert.assertTrue(resolve(aReportDir, "src/main/scala/org/hello/a/WorldA.scala.html").exists()); + } + + private void assertBReportFilesExist() { + + File bReportDir = reportDir(projectDir().toPath().resolve("b").toFile()); + Assert.assertTrue(resolve(bReportDir, "index.html").exists()); + Assert.assertTrue(resolve(bReportDir, "src/main/scala/org/hello/b/WorldB.scala.html").exists()); + } -} \ No newline at end of file +} diff --git a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java index ea4823a..3734bc8 100644 --- a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java @@ -1,6 +1,6 @@ package org.scoverage; -import org.gradle.testkit.runner.TaskOutcome; +import org.junit.Assert; import org.junit.Test; public class ScalaSingleModuleTest extends ScoverageFunctionalTest { @@ -66,7 +66,7 @@ public void aggregateScoverage() { } @Test - public void checkScoverage() { + public void checkScoverage() throws Exception { AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME()); @@ -75,10 +75,13 @@ public void checkScoverage() { result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + + assertReportFilesExist(); + assertCoverage(100.0); } @Test - public void checkScoverageFails() { + public void checkScoverageFails() throws Exception { AssertableBuildResult result = runAndFail("clean", ScoveragePlugin.getCHECK_NAME(), ScoveragePlugin.getTEST_NAME(), "--tests", "org.hello.TestNothingSuite"); @@ -88,5 +91,14 @@ public void checkScoverageFails() { result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); result.assertTaskFailed(ScoveragePlugin.getCHECK_NAME()); result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + + assertReportFilesExist(); + assertCoverage(0.0); + } + + private void assertReportFilesExist() { + + Assert.assertTrue(resolve(reportDir(), "index.html").exists()); + Assert.assertTrue(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); } } \ No newline at end of file diff --git a/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java b/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java index eb64c61..a9481fe 100644 --- a/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java +++ b/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java @@ -1,21 +1,31 @@ package org.scoverage; +import groovy.util.Node; +import groovy.util.XmlParser; import org.gradle.testkit.runner.BuildResult; import org.gradle.testkit.runner.BuildTask; import org.gradle.testkit.runner.GradleRunner; import org.gradle.testkit.runner.TaskOutcome; import org.junit.Assert; +import org.xml.sax.SAXException; import java.io.File; +import java.io.IOException; +import java.text.NumberFormat; +import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.regex.Pattern; +import static org.hamcrest.number.IsCloseTo.closeTo; +import static org.junit.Assert.assertThat; + public abstract class ScoverageFunctionalTest { private final String projectName; private final GradleRunner runner; + private final XmlParser parser; protected ScoverageFunctionalTest(String projectName) { @@ -24,6 +34,14 @@ protected ScoverageFunctionalTest(String projectName) { .withProjectDir(projectDir()) .withPluginClasspath() .forwardOutput(); + + try { + this.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); + } catch (Exception e) { + throw new RuntimeException(e); + } } protected File projectDir() { @@ -31,6 +49,16 @@ protected File projectDir() { return new File("src/functionalTest/resources/projects/" + projectName); } + protected File reportDir() { + + return reportDir(projectDir()); + } + + protected File reportDir(File projectDir) { + + return projectDir.toPath().resolve("build").resolve(ScoveragePlugin.getDEFAULT_REPORT_DIR()).toFile(); + } + protected AssertableBuildResult run(String... arguments) { configureArguments(arguments); @@ -50,6 +78,31 @@ protected AssertableBuildResult dryRun(String... arguments) { return run(withDryArgument.toArray(new String[]{})); } + protected void assertCoverage(Double expected) throws Exception { + + assertCoverage(expected, reportDir()); + } + + protected void assertCoverage(Double expected, File reportDir) throws Exception { + + assertThat(coverage(reportDir, CoverageType.Statement), closeTo(expected, 1.0)); + assertThat(coverage(reportDir, CoverageType.Line), closeTo(expected, 1.0)); + } + + protected File resolve(File file, String relativePath) { + + return file.toPath().resolve(relativePath).toFile(); + } + + private Double coverage(File reportDir, CoverageType coverageType) throws IOException, SAXException, ParseException { + + File reportFile = reportDir.toPath().resolve(coverageType.getFileName()).toFile(); + Node xml = parser.parse(reportFile); + Object attribute = xml.attribute(coverageType.getParamName()); + double rawValue = NumberFormat.getInstance().parse(attribute.toString()).doubleValue(); + return coverageType.normalize(rawValue) * 100.0; + } + private void configureArguments(String... arguments) { List fullArguments = new ArrayList(); diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index 419224f..ae99167 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -58,7 +58,7 @@ class ScoverageExtension { dataDir.set(new File(project.buildDir, 'scoverage')) reportDir = project.objects.property(File) - reportDir.set(new File(project.buildDir, 'reports' + File.separatorChar + 'scoverage')) + reportDir.set(new File(project.buildDir, ScoveragePlugin.DEFAULT_REPORT_DIR)) highlighting = project.objects.property(Boolean) highlighting.set(true) diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 418ffe3..9afe93c 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -21,6 +21,8 @@ class ScoveragePlugin implements Plugin { static final String COMPILE_NAME = 'compileScoverageScala' static final String AGGREGATE_NAME = 'aggregateScoverage' + static final String DEFAULT_REPORT_DIR = 'reports' + File.separatorChar + 'scoverage' + @Override void apply(PluginAware pluginAware) { if (pluginAware instanceof Project) { diff --git a/src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy b/src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy deleted file mode 100644 index 14e22c2..0000000 --- a/src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy +++ /dev/null @@ -1,47 +0,0 @@ -package org.scoverage - -import org.gradle.testkit.runner.GradleRunner -import org.hamcrest.core.Is -import org.junit.Assert - -import java.text.NumberFormat - -/** - * 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 void runBuild(File projectRoot, String... tasks) { - def runner = GradleRunner - .create() - .withProjectDir(projectRoot) - .withPluginClasspath() - .forwardOutput() - - runner.withArguments(tasks).build() - } - - 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) - println("reportfile path: ${reportFile.absolutePath}") - NumberFormat nf = NumberFormat.getInstance(); - nf.parse(xml.attribute(coverageType.paramName) as String).doubleValue(); - } -} diff --git a/src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy b/src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy deleted file mode 100644 index 2b425ff..0000000 --- a/src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy +++ /dev/null @@ -1,26 +0,0 @@ -package org.scoverage - -import org.junit.Test - -class AggregationAcceptanceTest extends AcceptanceTestUtils { - - @Test - public void testMultiProjectAggregation() throws Exception { - File projectDir = new File('src/test/water') - runBuild(projectDir, 'clean', 'aggregateScoverage') - def indexHtml = new File(aggregateReportDir(projectDir), 'index.html') - checkFile('an aggregated index HTML file', indexHtml, true) - def cobertura = new File(aggregateReportDir(projectDir), 'cobertura.xml') - checkFile('an aggregated cobertura XML file', cobertura, true) - def scoverageXml = new File(aggregateReportDir(projectDir), 'scoverage.xml') - checkFile('an aggregated scoverage XML file', scoverageXml, true) - def krillsHtml = new File(aggregateReportDir(projectDir), 'krills.html') - checkFile('a HTML file for \'krills\' sub-project', krillsHtml, true) - def whalesHtml = new File(aggregateReportDir(projectDir), 'whales.html') - checkFile('a HTML file for \'whales\' sub-project', whalesHtml, true) - } - - private static File aggregateReportDir(File baseDir) { - return new File(baseDir, 'build/reports/scoverage') - } -} diff --git a/src/test/groovy/org/scoverage/OverallCheckTaskTest.groovy b/src/test/groovy/org/scoverage/OverallCheckTaskTest.groovy index fcc26ab..27c68dc 100644 --- a/src/test/groovy/org/scoverage/OverallCheckTaskTest.groovy +++ b/src/test/groovy/org/scoverage/OverallCheckTaskTest.groovy @@ -4,8 +4,11 @@ import org.gradle.api.GradleException import org.hamcrest.Description import org.hamcrest.Matcher import org.hamcrest.TypeSafeMatcher +import org.junit.Rule import org.junit.Test +import org.junit.rules.TemporaryFolder +import java.nio.file.Paths import java.text.NumberFormat import static org.junit.Assert.assertNull @@ -43,7 +46,10 @@ class OverallCheckTaskTest { private NumberFormat numberFormat = NumberFormat.getInstance(Locale.US) - private static File reportDir = new File('src/test/resources') + private File reportDir = Paths.get(getClass().getClassLoader().getResource("checkTask").toURI()).toFile() + + @Rule + public TemporaryFolder tempDir = new TemporaryFolder() private static Matcher failsWith(String message) { return new CauseMatcher( @@ -57,7 +63,7 @@ class OverallCheckTaskTest { @Test void failsWhenReportFileIsNotFound() { assertThat( - checkLineCoverage(numberFormat, new File('src/test/nothingthere'), CoverageType.Line, 0.0), + checkLineCoverage(numberFormat, tempDir.getRoot(), CoverageType.Line, 0.0), failsWith(OverallCheckTask.fileNotFoundErrorMsg(CoverageType.Line))) } @@ -117,5 +123,4 @@ class OverallCheckTaskTest { void doesNotFailWhenBranchRateIsAboveTarget() { assertNull(checkLineCoverage(numberFormat, reportDir, CoverageType.Branch, 0.45)) } - } diff --git a/src/test/groovy/org/scoverage/SeparateTestsAcceptanceTest.groovy b/src/test/groovy/org/scoverage/SeparateTestsAcceptanceTest.groovy deleted file mode 100644 index 4308937..0000000 --- a/src/test/groovy/org/scoverage/SeparateTestsAcceptanceTest.groovy +++ /dev/null @@ -1,27 +0,0 @@ -package org.scoverage - -import static org.hamcrest.number.IsCloseTo.closeTo -import org.junit.Test - -import static org.junit.Assert.assertThat - -class SeparateTestsAcceptanceTest extends AcceptanceTestUtils { - - @Test - public void testSeparateTestsWithZinc() throws Exception { - File projectDir = new File('src/test/separate-tests') - File subprojectDir = new File(projectDir, 'a') - File testsSubprojectDir = new File(projectDir, 'a-tests') - runBuild(projectDir, 'clean', 'reportScoverage') - def indexHtml = new File(reportDir(subprojectDir), 'index.html') - checkFile('an index HTML file', indexHtml, true) - def testsIndexHtml = new File(reportDir(testsSubprojectDir), 'index.html') - checkFile('an index HTML file', testsIndexHtml, false) - def helloHtml = new File(reportDir(subprojectDir), 'src/main/scala/hello/Hello.scala.html') - checkFile('Hello.scala html file', helloHtml, true) - def branchCoverage = coverage(reportDir(subprojectDir), CoverageType.Branch) - def statementCoverage = coverage(reportDir(subprojectDir), CoverageType.Statement) - assertThat('Branch coverage should be 100%, was ' + branchCoverage, branchCoverage, closeTo(100.0, 1.0)) - assertThat('Statement coverage should be 100%, was ' + statementCoverage, statementCoverage, closeTo(100.0, 1.0)) - } -} diff --git a/src/test/groovy/org/scoverage/SimpleReportAcceptanceTest.groovy b/src/test/groovy/org/scoverage/SimpleReportAcceptanceTest.groovy deleted file mode 100644 index 0c2ca6c..0000000 --- a/src/test/groovy/org/scoverage/SimpleReportAcceptanceTest.groovy +++ /dev/null @@ -1,25 +0,0 @@ -package org.scoverage - -import org.junit.Test - -class SimpleReportAcceptanceTest extends AcceptanceTestUtils { - - - @Test - public void testProjectWithCompleteCoverage() throws Exception { - File projectRoot = new File('src/test/happy day') - runBuild(projectRoot, 'clean', 'checkScoverage') - def html = new File(reportDir(projectRoot), 'index.html') - checkFile('an index HTML file', html, true) - def cobertura = new File(reportDir(projectRoot), 'cobertura.xml') - checkFile('a cobertura XML file', cobertura, true) - def scoverageXml = new File(reportDir(projectRoot), 'scoverage.xml') - checkFile('a scoverage XML file', scoverageXml, true) - } - - @Test - public void testRun() throws Exception { - File projectRoot = new File('src/test/runtime') - runBuild(projectRoot, 'clean', 'run') - } -} diff --git a/src/test/happy day/build.gradle b/src/test/happy day/build.gradle deleted file mode 100644 index 17a1522..0000000 --- a/src/test/happy day/build.gradle +++ /dev/null @@ -1,19 +0,0 @@ -plugins { - id 'org.scoverage' -} - -description = 'a project that builds successfully with 100% coverage' - -repositories { - jcenter() -} - -dependencies { - compile 'org.scala-lang:scala-library:2.11.0' - testCompile 'junit:junit:4.11' -} - -checkScoverage { - minimumRate = 1.0 - coverageType = 'Line' -} \ No newline at end of file diff --git a/src/test/happy day/settings.gradle b/src/test/happy day/settings.gradle deleted file mode 100644 index e69de29..0000000 diff --git a/src/test/happy day/src/main/java/old/World.java b/src/test/happy day/src/main/java/old/World.java deleted file mode 100644 index 97f710f..0000000 --- a/src/test/happy day/src/main/java/old/World.java +++ /dev/null @@ -1,7 +0,0 @@ -package old; - -public class World { - public String getMessage() { - return "Hello old boy"; - } -} \ No newline at end of file diff --git a/src/test/happy day/src/main/resources/main.txt b/src/test/happy day/src/main/resources/main.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/test/happy day/src/main/scala/hello/World.scala b/src/test/happy day/src/main/scala/hello/World.scala deleted file mode 100644 index cd1117d..0000000 --- a/src/test/happy day/src/main/scala/hello/World.scala +++ /dev/null @@ -1,8 +0,0 @@ -package hello - -object World { - def say() = { - println(new old.World().getMessage()) - println("ahoy") - } -} \ No newline at end of file diff --git a/src/test/happy day/src/test/resources/test.txt b/src/test/happy day/src/test/resources/test.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/test/happy day/src/test/scala/hello/ResourcesTest.scala b/src/test/happy day/src/test/scala/hello/ResourcesTest.scala deleted file mode 100644 index fd5573b..0000000 --- a/src/test/happy day/src/test/scala/hello/ResourcesTest.scala +++ /dev/null @@ -1,14 +0,0 @@ -package hello - -import org.junit.Test - -class ResourcesTest { - @Test - def mainResourcesAreBuilt() { - assert(getClass.getResource("/main.txt") != null) - } - @Test - def testResourcesAreBuilt() { - assert(getClass.getResource("/test.txt") != null) - } -} \ No newline at end of file diff --git a/src/test/happy day/src/test/scala/hello/WorldTest.scala b/src/test/happy day/src/test/scala/hello/WorldTest.scala deleted file mode 100644 index a087efa..0000000 --- a/src/test/happy day/src/test/scala/hello/WorldTest.scala +++ /dev/null @@ -1,10 +0,0 @@ -package hello - -import org.junit.Test - -class WorldTest { - @Test - def bob() { - World.say() - } -} \ No newline at end of file diff --git a/src/test/resources/cobertura.xml b/src/test/resources/checkTask/cobertura.xml similarity index 100% rename from src/test/resources/cobertura.xml rename to src/test/resources/checkTask/cobertura.xml diff --git a/src/test/resources/scoverage.xml b/src/test/resources/checkTask/scoverage.xml similarity index 100% rename from src/test/resources/scoverage.xml rename to src/test/resources/checkTask/scoverage.xml diff --git a/src/test/runtime/build.gradle b/src/test/runtime/build.gradle deleted file mode 100644 index ec21818..0000000 --- a/src/test/runtime/build.gradle +++ /dev/null @@ -1,20 +0,0 @@ -plugins { - id 'org.scoverage' -} - -description = 'a project that runs an application and captures scoverage' - -repositories { - jcenter() -} - -dependencies { - compile 'org.scala-lang:scala-library:2.11.0' -} - -task run(type: JavaExec) { - classpath = sourceSets.scoverage.runtimeClasspath - main = 'hello.World' -} - -checkScoverage.dependsOn(run) \ No newline at end of file diff --git a/src/test/runtime/settings.gradle b/src/test/runtime/settings.gradle deleted file mode 100644 index e69de29..0000000 diff --git a/src/test/runtime/src/main/scala/hello/World.scala b/src/test/runtime/src/main/scala/hello/World.scala deleted file mode 100644 index d90e2c9..0000000 --- a/src/test/runtime/src/main/scala/hello/World.scala +++ /dev/null @@ -1,5 +0,0 @@ -package hello - -object World extends App { - println("ahoy") -} \ No newline at end of file diff --git a/src/test/separate-tests/a-tests/src/main/scala/hello/BaseTest.scala b/src/test/separate-tests/a-tests/src/main/scala/hello/BaseTest.scala deleted file mode 100644 index 12d82ae..0000000 --- a/src/test/separate-tests/a-tests/src/main/scala/hello/BaseTest.scala +++ /dev/null @@ -1,7 +0,0 @@ -package hello - -class BaseTest { - def beforeTest() = { - println("Running test!") - } -} \ No newline at end of file diff --git a/src/test/separate-tests/a-tests/src/test/scala/hello/HelloTest.scala b/src/test/separate-tests/a-tests/src/test/scala/hello/HelloTest.scala deleted file mode 100644 index 1c7df23..0000000 --- a/src/test/separate-tests/a-tests/src/test/scala/hello/HelloTest.scala +++ /dev/null @@ -1,13 +0,0 @@ -package hello - -import org.junit.Test -import org.junit.Assert.assertEquals - -class HelloTest extends BaseTest { - - @Test def testText() { - beforeTest() - assertEquals("Hello World", new Hello().text) - } - -} diff --git a/src/test/separate-tests/a/src/main/scala/hello/Hello.scala b/src/test/separate-tests/a/src/main/scala/hello/Hello.scala deleted file mode 100644 index eabfc20..0000000 --- a/src/test/separate-tests/a/src/main/scala/hello/Hello.scala +++ /dev/null @@ -1,5 +0,0 @@ -package hello - -class Hello { - def text = "Hello World" -} diff --git a/src/test/separate-tests/build.gradle b/src/test/separate-tests/build.gradle deleted file mode 100644 index 1aeb9b8..0000000 --- a/src/test/separate-tests/build.gradle +++ /dev/null @@ -1,51 +0,0 @@ -plugins { - id 'org.scoverage' -} - -description = 'a multi-project with separate tests setup for gradle-scoverage' - -allprojects { - - repositories { - jcenter() - } -} - -subprojects { - - apply plugin: 'scala' - - dependencies { - compile 'org.scala-lang:scala-library:2.11.4' - - testCompile 'junit:junit:4.11' - } - - testScoverage { - onlyIf { project.name.endsWith('-tests') } - } - - reportScoverage { - onlyIf { project.name.endsWith('-tests') } - } - - checkScoverage { - onlyIf { project.name.endsWith('-tests') } - } - -} - -configure(subprojects.findAll { it.name.endsWith('-tests') }) { - def mainProject = project(":${project.name.minus('-tests')}") - dependencies { - testCompile mainProject.sourceSets.scoverage.output - } - scoverage { - sources = mainProject.extensions.scoverage.sources - dataDir = mainProject.extensions.scoverage.dataDir - reportDir = mainProject.extensions.scoverage.reportDir - } - compileScoverageScala { - onlyIf { false } - } -} \ No newline at end of file diff --git a/src/test/separate-tests/settings.gradle b/src/test/separate-tests/settings.gradle deleted file mode 100644 index 85eeb66..0000000 --- a/src/test/separate-tests/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -include ':a', ':a-tests' diff --git a/src/test/water/bluewhale/src/main/scala/whales/BlueWhale.scala b/src/test/water/bluewhale/src/main/scala/whales/BlueWhale.scala deleted file mode 100644 index 2953e26..0000000 --- a/src/test/water/bluewhale/src/main/scala/whales/BlueWhale.scala +++ /dev/null @@ -1,5 +0,0 @@ -package whales - -class BlueWhale { - def swim(): String = "I'm swimming!" -} \ No newline at end of file diff --git a/src/test/water/bluewhale/src/test/scala/whales/BlueWhaleTest.scala b/src/test/water/bluewhale/src/test/scala/whales/BlueWhaleTest.scala deleted file mode 100644 index 2e3d0be..0000000 --- a/src/test/water/bluewhale/src/test/scala/whales/BlueWhaleTest.scala +++ /dev/null @@ -1,11 +0,0 @@ -package whales - -import org.junit.Test -import org.junit.Assert - -class BlueWhaleTest { - - @Test def bob(): Unit = { - Assert.assertEquals("Whale cannot swim :(", new BlueWhale().swim(), "I'm swimming!") - } -} \ No newline at end of file diff --git a/src/test/water/build.gradle b/src/test/water/build.gradle deleted file mode 100644 index b9bb87c..0000000 --- a/src/test/water/build.gradle +++ /dev/null @@ -1,19 +0,0 @@ -plugins { - id 'org.scoverage' -} - -description = 'a multi-project setup for gradle-scoverage' - -allprojects { - repositories { - jcenter() - } - - apply plugin: 'scala' - - dependencies { - compile 'org.scala-lang:scala-library:2.11.5' - testCompile 'junit:junit:4.11' - } -} - diff --git a/src/test/water/krill/src/main/scala/krills/NorthernKrill.scala b/src/test/water/krill/src/main/scala/krills/NorthernKrill.scala deleted file mode 100644 index 16fdf22..0000000 --- a/src/test/water/krill/src/main/scala/krills/NorthernKrill.scala +++ /dev/null @@ -1,5 +0,0 @@ -package krills - -class NorthernKrill { - def swim(): String = "I can only float :(" -} \ No newline at end of file diff --git a/src/test/water/krill/src/test/scala/krills/NorthernKrillTest.scala b/src/test/water/krill/src/test/scala/krills/NorthernKrillTest.scala deleted file mode 100644 index bcb4dd7..0000000 --- a/src/test/water/krill/src/test/scala/krills/NorthernKrillTest.scala +++ /dev/null @@ -1,11 +0,0 @@ -package krills - -import org.junit.Test -import org.junit.Assert - -class NorthernKrillTest { - - @Test def bob(): Unit = { - Assert.assertEquals("Krill can swim", new NorthernKrill().swim(), "I can only float :(") - } -} \ No newline at end of file diff --git a/src/test/water/settings.gradle b/src/test/water/settings.gradle deleted file mode 100644 index a978eb9..0000000 --- a/src/test/water/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -include 'bluewhale', 'krill' \ No newline at end of file From e11b33181f43d5912b0931d414df210a84ec912d Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Wed, 30 Jan 2019 18:46:26 +0200 Subject: [PATCH 031/167] Remove the "testScoverage" task and make "test" run the coverage (by adding the instrumented classes to its classpath) --- .../org.scoverage/ScalaMultiModuleTest.java | 8 +- .../org.scoverage/ScalaSingleModuleTest.java | 19 +-- .../org/scoverage/ScoveragePlugin.groovy | 149 ++++++++---------- 3 files changed, 75 insertions(+), 101 deletions(-) diff --git a/src/functionalTest/java/org.scoverage/ScalaMultiModuleTest.java b/src/functionalTest/java/org.scoverage/ScalaMultiModuleTest.java index 68d7a92..18b5e0a 100644 --- a/src/functionalTest/java/org.scoverage/ScalaMultiModuleTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaMultiModuleTest.java @@ -116,7 +116,7 @@ public void checkAndAggregateScoverage() throws Exception { public void checkScoverageWithoutCoverageInRoot() throws Exception { AssertableBuildResult result = runAndFail("clean", ScoveragePlugin.getCHECK_NAME(), - ScoveragePlugin.getTEST_NAME(), + "test", "--tests", "org.hello.TestNothingSuite", "--tests", "org.hello.a.WorldASuite", "--tests", "org.hello.b.WorldBSuite"); @@ -131,7 +131,7 @@ public void checkScoverageWithoutCoverageInRoot() throws Exception { public void checkScoverageWithoutCoverageInA() throws Exception { AssertableBuildResult result = runAndFail("clean", ScoveragePlugin.getCHECK_NAME(), - ScoveragePlugin.getTEST_NAME(), + "test", "--tests", "org.hello.a.TestNothingASuite", "--tests", "org.hello.WorldSuite", "--tests", "org.hello.b.WorldBSuite"); @@ -148,7 +148,7 @@ public void checkAndAggregateScoverageWithoutCoverageInRoot() throws Exception { // should pass as the check on the root is for the aggregation (which covers > 50%) AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME(), - ScoveragePlugin.getAGGREGATE_NAME(), ScoveragePlugin.getTEST_NAME(), + ScoveragePlugin.getAGGREGATE_NAME(), "test", "--tests", "org.hello.TestNothingSuite", "--tests", "org.hello.a.WorldASuite", "--tests", "org.hello.b.WorldBSuite"); @@ -169,7 +169,7 @@ public void checkAndAggregateScoverageWithoutCoverageInRoot() throws Exception { public void checkAndAggregateScoverageWithoutCoverageInAll() throws Exception { AssertableBuildResult result = runAndFail("clean", ScoveragePlugin.getCHECK_NAME(), - ScoveragePlugin.getAGGREGATE_NAME(), ScoveragePlugin.getTEST_NAME(), + ScoveragePlugin.getAGGREGATE_NAME(), "test", "--tests", "org.hello.TestNothingSuite", "--tests", "org.hello.a.TestNothingASuite", "--tests", "org.hello.b.TestNothingBSuite"); diff --git a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java index 3734bc8..e69603c 100644 --- a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java @@ -15,7 +15,6 @@ public void test() { AssertableBuildResult result = dryRun("clean", "test"); result.assertTaskDoesntExist(ScoveragePlugin.getCOMPILE_NAME()); - result.assertTaskDoesntExist(ScoveragePlugin.getTEST_NAME()); result.assertTaskDoesntExist(ScoveragePlugin.getREPORT_NAME()); result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); @@ -27,19 +26,6 @@ public void build() { AssertableBuildResult result = dryRun("clean", "build"); result.assertTaskDoesntExist(ScoveragePlugin.getCOMPILE_NAME()); - result.assertTaskDoesntExist(ScoveragePlugin.getTEST_NAME()); - result.assertTaskDoesntExist(ScoveragePlugin.getREPORT_NAME()); - result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); - result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); - } - - @Test - public void testScoverage() { - - AssertableBuildResult result = dryRun("clean", ScoveragePlugin.getTEST_NAME()); - - result.assertTaskExists(ScoveragePlugin.getCOMPILE_NAME()); - result.assertTaskExists(ScoveragePlugin.getTEST_NAME()); result.assertTaskDoesntExist(ScoveragePlugin.getREPORT_NAME()); result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); @@ -51,7 +37,6 @@ public void reportScoverage() { AssertableBuildResult result = dryRun("clean", ScoveragePlugin.getREPORT_NAME()); result.assertTaskExists(ScoveragePlugin.getCOMPILE_NAME()); - result.assertTaskExists(ScoveragePlugin.getTEST_NAME()); result.assertTaskExists(ScoveragePlugin.getREPORT_NAME()); result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); @@ -71,7 +56,6 @@ public void checkScoverage() throws Exception { AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME()); result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); - result.assertTaskSucceeded(ScoveragePlugin.getTEST_NAME()); result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); @@ -84,10 +68,9 @@ public void checkScoverage() throws Exception { public void checkScoverageFails() throws Exception { AssertableBuildResult result = runAndFail("clean", ScoveragePlugin.getCHECK_NAME(), - ScoveragePlugin.getTEST_NAME(), "--tests", "org.hello.TestNothingSuite"); + "test", "--tests", "org.hello.TestNothingSuite"); result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); - result.assertTaskSucceeded(ScoveragePlugin.getTEST_NAME()); result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); result.assertTaskFailed(ScoveragePlugin.getCHECK_NAME()); result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 9afe93c..cce285e 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -1,21 +1,16 @@ package org.scoverage - import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.invocation.Gradle import org.gradle.api.plugins.PluginAware 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 -import java.util.concurrent.Callable - class ScoveragePlugin implements Plugin { static final String CONFIGURATION_NAME = 'scoverage' - static final String TEST_NAME = 'testScoverage' static final String REPORT_NAME = 'reportScoverage' static final String CHECK_NAME = 'checkScoverage' static final String COMPILE_NAME = 'compileScoverageScala' @@ -80,17 +75,12 @@ class ScoveragePlugin implements Plugin { } } - ScoverageRunner scoverageRunner = new ScoverageRunner(project.configurations.scoverage) - - createTasks(project, extension, scoverageRunner) - - project.afterEvaluate { - configureAfterEvaluation(project, extension, scoverageRunner) - } + createTasks(project, extension) } - private void createTasks(Project project, ScoverageExtension extension, ScoverageRunner scoverageRunner) { + private void createTasks(Project project, ScoverageExtension extension) { + ScoverageRunner scoverageRunner = new ScoverageRunner(project.configurations.scoverage) def instrumentedSourceSet = project.sourceSets.create('scoverage') { def original = project.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) @@ -103,8 +93,11 @@ class ScoveragePlugin implements Plugin { runtimeClasspath = it.output + project.configurations.scoverage + original.runtimeClasspath } + def compileTask = project.tasks[instrumentedSourceSet.getCompileTaskName("scala")] + project.test.mustRunAfter(compileTask) + def scoverageJar = project.tasks.create('jarScoverage', Jar.class) { - dependsOn('scoverageClasses') + dependsOn(instrumentedSourceSet.classesTaskName) classifier = CONFIGURATION_NAME from instrumentedSourceSet.output } @@ -112,29 +105,8 @@ class ScoveragePlugin implements Plugin { scoverage scoverageJar } - project.tasks.create(TEST_NAME, Test.class) { - conventionMapping.map("classpath", new Callable() { - Object call() throws Exception { - def testSourceSet = project.sourceSets.getByName(SourceSet.TEST_SOURCE_SET_NAME) - return testSourceSet.output + - instrumentedSourceSet.output + - project.configurations.scoverage + - testSourceSet.runtimeClasspath - } - }) - group = 'verification' - - FilenameFilter measurementFile = new FilenameFilter() { - @Override - boolean accept(File dir, String name) { - return name.startsWith("scoverage.measurements.") - } - } - outputs.upToDateWhen { extension.dataDir.get().listFiles(measurementFile) } - } - - project.tasks.create(REPORT_NAME, ScoverageReport.class) { - dependsOn(project.tasks[TEST_NAME]) + def reportTask = project.tasks.create(REPORT_NAME, ScoverageReport.class) { + dependsOn compileTask, project.test onlyIf { extension.dataDir.get().list() } group = 'verification' runner = scoverageRunner @@ -148,58 +120,77 @@ class ScoveragePlugin implements Plugin { } project.tasks.create(CHECK_NAME, OverallCheckTask.class) { - dependsOn(project.tasks[REPORT_NAME]) + dependsOn(reportTask) group = 'verification' reportDir = extension.reportDir } - } + project.gradle.taskGraph.whenReady { graph -> + if (graph.hasTask(reportTask)) { - private void configureAfterEvaluation(Project project, ScoverageExtension extension, ScoverageRunner scoverageRunner) { - - if (project.childProjects.size() > 0) { - def reportTasks = project.getAllprojects().collect { it.tasks.withType(ScoverageReport) } - def aggregationTask = project.tasks.create(AGGREGATE_NAME, ScoverageAggregate.class) { - dependsOn(reportTasks) - group = 'verification' - runner = scoverageRunner - reportDir = extension.reportDir - deleteReportsOnAggregation = extension.deleteReportsOnAggregation - coverageOutputCobertura = extension.coverageOutputCobertura - coverageOutputXML = extension.coverageOutputXML - coverageOutputHTML = extension.coverageOutputHTML - coverageDebug = extension.coverageDebug + project.test.configure { + project.logger.debug("Adding instrumented classes to '${path}' classpath") + + classpath = project.configurations.scoverage + instrumentedSourceSet.output + classpath + + outputs.upToDateWhen { + extension.dataDir.get().listFiles(new FilenameFilter() { + @Override + boolean accept(File dir, String name) { + return name.startsWith("scoverage.measurements.") + } + }) + } + } } - project.tasks[CHECK_NAME].mustRunAfter(aggregationTask) } - project.tasks[COMPILE_NAME].configure { - File pluginFile = project.configurations[CONFIGURATION_NAME].find { - it.name.startsWith("scalac-scoverage-plugin") - } - List parameters = ['-Xplugin:' + pluginFile.absolutePath] - List existingParameters = scalaCompileOptions.additionalParameters - if (existingParameters) { - parameters.addAll(existingParameters) - } - parameters.add("-P:scoverage:dataDir:${extension.dataDir.get().absolutePath}".toString()) - if (extension.excludedPackages.get()) { - def packages = extension.excludedPackages.get().join(';') - parameters.add("-P:scoverage:excludedPackages:$packages".toString()) - } - if (extension.excludedFiles.get()) { - def packages = extension.excludedFiles.get().join(';') - parameters.add("-P:scoverage:excludedFiles:$packages".toString()) - } - if (extension.highlighting.get()) { - parameters.add('-Yrangepos') + project.afterEvaluate { + + if (project.childProjects.size() > 0) { + def reportTasks = project.getAllprojects().collect { it.tasks.withType(ScoverageReport) } + def aggregationTask = project.tasks.create(AGGREGATE_NAME, ScoverageAggregate.class) { + dependsOn(reportTasks) + group = 'verification' + runner = scoverageRunner + reportDir = extension.reportDir + deleteReportsOnAggregation = extension.deleteReportsOnAggregation + coverageOutputCobertura = extension.coverageOutputCobertura + coverageOutputXML = extension.coverageOutputXML + coverageOutputHTML = extension.coverageOutputHTML + coverageDebug = extension.coverageDebug + } + project.tasks[CHECK_NAME].mustRunAfter(aggregationTask) } - doFirst { - GFileUtils.deleteDirectory(destinationDir) + + compileTask.configure { + File pluginFile = project.configurations[CONFIGURATION_NAME].find { + it.name.startsWith("scalac-scoverage-plugin") + } + List parameters = ['-Xplugin:' + pluginFile.absolutePath] + List existingParameters = scalaCompileOptions.additionalParameters + if (existingParameters) { + parameters.addAll(existingParameters) + } + parameters.add("-P:scoverage:dataDir:${extension.dataDir.get().absolutePath}".toString()) + if (extension.excludedPackages.get()) { + def packages = extension.excludedPackages.get().join(';') + parameters.add("-P:scoverage:excludedPackages:$packages".toString()) + } + if (extension.excludedFiles.get()) { + def packages = extension.excludedFiles.get().join(';') + parameters.add("-P:scoverage:excludedFiles:$packages".toString()) + } + if (extension.highlighting.get()) { + parameters.add('-Yrangepos') + } + doFirst { + GFileUtils.deleteDirectory(destinationDir) + } + scalaCompileOptions.additionalParameters = parameters + // the compile task creates a store of measured statements + outputs.file(new File(extension.dataDir.get(), 'scoverage.coverage.xml')) } - scalaCompileOptions.additionalParameters = parameters - // the compile task creates a store of measured statements - outputs.file(new File(extension.dataDir.get(), 'scoverage.coverage.xml')) } } } \ No newline at end of file From 0a6ec0b977872bc82d224b2983fa4fcc5bbebc29 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Thu, 31 Jan 2019 09:31:18 +0200 Subject: [PATCH 032/167] Make the plugin delete non-instrumented classes from the output directory --- build.gradle | 1 + .../org.scoverage/ScalaSingleModuleTest.java | 18 +++++ .../ScoverageFunctionalTest.java | 12 +++- .../projects/scala-single-module/build.gradle | 6 ++ .../org/scoverage/ScoveragePlugin.groovy | 66 +++++++++++++++---- 5 files changed, 91 insertions(+), 12 deletions(-) diff --git a/build.gradle b/build.gradle index 606cc15..b9fe523 100644 --- a/build.gradle +++ b/build.gradle @@ -49,6 +49,7 @@ targetCompatibility = '1.6' dependencies { compileOnly "org.scoverage:scalac-scoverage-plugin_2.12:1.3.1" + compile group: 'commons-io', name: 'commons-io', version: '2.6' testCompile 'junit:junit:4.12' testCompile 'org.hamcrest:hamcrest-library:1.3' } diff --git a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java index e69603c..c7f9823 100644 --- a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java @@ -79,6 +79,24 @@ public void checkScoverageFails() throws Exception { assertCoverage(0.0); } + @Test + public void reportScoverageWithExcludedClasses() throws Exception { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getREPORT_NAME(), + "-PexcludedFile=.*"); + + result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + + Assert.assertTrue(resolve(reportDir(), "index.html").exists()); + Assert.assertFalse(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + assertCoverage(100.0); // coverage is 100 since no classes are covered + + Assert.assertFalse(resolve(buildDir(), "classes/scala/scoverage/org/hello/World.class").exists()); + } + private void assertReportFilesExist() { Assert.assertTrue(resolve(reportDir(), "index.html").exists()); diff --git a/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java b/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java index a9481fe..27aab49 100644 --- a/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java +++ b/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java @@ -49,6 +49,16 @@ protected File projectDir() { return new File("src/functionalTest/resources/projects/" + projectName); } + protected File buildDir() { + + return buildDir(projectDir()); + } + + protected File buildDir(File projectDir) { + + return projectDir.toPath().resolve("build").toFile(); + } + protected File reportDir() { return reportDir(projectDir()); @@ -56,7 +66,7 @@ protected File reportDir() { protected File reportDir(File projectDir) { - return projectDir.toPath().resolve("build").resolve(ScoveragePlugin.getDEFAULT_REPORT_DIR()).toFile(); + return buildDir(projectDir).toPath().resolve(ScoveragePlugin.getDEFAULT_REPORT_DIR()).toFile(); } protected AssertableBuildResult run(String... arguments) { diff --git a/src/functionalTest/resources/projects/scala-single-module/build.gradle b/src/functionalTest/resources/projects/scala-single-module/build.gradle index b0a4ec6..5ef9ffe 100644 --- a/src/functionalTest/resources/projects/scala-single-module/build.gradle +++ b/src/functionalTest/resources/projects/scala-single-module/build.gradle @@ -26,4 +26,10 @@ test { checkScoverage { minimumRate = 0.5 +} + +if (hasProperty("excludedFile")) { + scoverage { + excludedFiles = [excludedFile] + } } \ No newline at end of file diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index cce285e..cb4eef3 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -1,12 +1,16 @@ package org.scoverage +import org.apache.commons.io.FileUtils import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.invocation.Gradle import org.gradle.api.plugins.PluginAware import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.bundling.Jar -import org.gradle.util.GFileUtils + +import java.nio.file.Files + +import static groovy.io.FileType.FILES class ScoveragePlugin implements Plugin { @@ -82,18 +86,19 @@ class ScoveragePlugin implements Plugin { ScoverageRunner scoverageRunner = new ScoverageRunner(project.configurations.scoverage) + def originalSourceSet = project.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) def instrumentedSourceSet = project.sourceSets.create('scoverage') { - def original = project.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) - resources.source(original.resources) - scala.source(original.java) - scala.source(original.scala) + resources.source(originalSourceSet.resources) + scala.source(originalSourceSet.java) + scala.source(originalSourceSet.scala) - compileClasspath += original.compileClasspath + project.configurations.scoverage - runtimeClasspath = it.output + project.configurations.scoverage + original.runtimeClasspath + compileClasspath += originalSourceSet.compileClasspath + project.configurations.scoverage + runtimeClasspath = it.output + project.configurations.scoverage + originalSourceSet.runtimeClasspath } def compileTask = project.tasks[instrumentedSourceSet.getCompileTaskName("scala")] + compileTask.mustRunAfter(originalSourceSet.getCompileTaskName("scala")) project.test.mustRunAfter(compileTask) def scoverageJar = project.tasks.create('jarScoverage', Jar.class) { @@ -127,7 +132,6 @@ class ScoveragePlugin implements Plugin { project.gradle.taskGraph.whenReady { graph -> if (graph.hasTask(reportTask)) { - project.test.configure { project.logger.debug("Adding instrumented classes to '${path}' classpath") @@ -164,6 +168,10 @@ class ScoveragePlugin implements Plugin { } compileTask.configure { + doFirst { + destinationDir.deleteDir() + } + File pluginFile = project.configurations[CONFIGURATION_NAME].find { it.name.startsWith("scalac-scoverage-plugin") } @@ -184,13 +192,49 @@ class ScoveragePlugin implements Plugin { if (extension.highlighting.get()) { parameters.add('-Yrangepos') } - doFirst { - GFileUtils.deleteDirectory(destinationDir) - } scalaCompileOptions.additionalParameters = parameters // the compile task creates a store of measured statements outputs.file(new File(extension.dataDir.get(), 'scoverage.coverage.xml')) + + doLast { + def originalCompileTaskName = project.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) + .getCompileTaskName("scala") + def originalDestinationDir = project.tasks[originalCompileTaskName].destinationDir + + def findFiles = { File dir, Closure condition = null -> + def files = [] + + if (dir.exists()) { + dir.eachFileRecurse(FILES) { f -> + if (condition == null || condition(f)) { + def relativePath = dir.relativePath(f) + files << relativePath + } + } + } + + return files + } + + def isSameFile = { String relativePath -> + def fileA = new File(originalDestinationDir, relativePath) + def fileB = new File(destinationDir, relativePath) + return FileUtils.contentEquals(fileA, fileB) + } + + def originalClasses = findFiles(originalDestinationDir) + def identicalInstrumentedClasses = findFiles(destinationDir, { f -> + def relativePath = destinationDir.relativePath(f) + return originalClasses.contains(relativePath) && isSameFile(relativePath) + }) + + identicalInstrumentedClasses.each { f -> + Files.deleteIfExists(destinationDir.toPath().resolve(f)) + } + } } } } + + } \ No newline at end of file From ad39e96701b13e822ec9bcc848c28e0c8e02b739 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Thu, 31 Jan 2019 10:58:59 +0200 Subject: [PATCH 033/167] Allow running scoverage without running the normal compilation (only scoverage compilation) --- .../org.scoverage/ScalaSingleModuleTest.java | 38 +++++++- .../projects/scala-single-module/build.gradle | 12 +-- .../src/main/scala/org/hello/World.scala | 3 + .../org/scoverage/ScoverageExtension.groovy | 5 ++ .../org/scoverage/ScoveragePlugin.groovy | 88 ++++++++++--------- 5 files changed, 99 insertions(+), 47 deletions(-) diff --git a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java index c7f9823..081fa9a 100644 --- a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java @@ -61,7 +61,7 @@ public void checkScoverage() throws Exception { result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); assertReportFilesExist(); - assertCoverage(100.0); + assertCoverage(50.0); } @Test @@ -94,6 +94,42 @@ public void reportScoverageWithExcludedClasses() throws Exception { Assert.assertFalse(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); assertCoverage(100.0); // coverage is 100 since no classes are covered + // compiled class should exist in the default classes directory, but not in scoverage + Assert.assertTrue(resolve(buildDir(), "classes/scala/main/org/hello/World.class").exists()); + Assert.assertFalse(resolve(buildDir(), "classes/scala/scoverage/org/hello/World.class").exists()); + } + + @Test + public void reportScoverageWithoutNormalCompilation() throws Exception { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getREPORT_NAME(), + "-PrunNormalCompilation=false"); + + result.assertTaskSkipped("compileScala"); + result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + + assertReportFilesExist(); + assertCoverage(50.0); + + Assert.assertTrue(resolve(buildDir(), "classes/scala/main/org/hello/World.class").exists()); + Assert.assertFalse(resolve(buildDir(), "classes/scala/scoverage/org/hello/World.class").exists()); + } + + @Test + public void reportScoverageWithoutNormalCompilationAndWithExcludedClasses() throws Exception { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getREPORT_NAME(), + "-PrunNormalCompilation=false", "-PexcludedFile=.*"); + + Assert.assertTrue(resolve(reportDir(), "index.html").exists()); + Assert.assertFalse(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + assertCoverage(100.0); // coverage is 100 since no classes are covered + + // compiled class should exist in the default classes directory, but not in scoverage + Assert.assertTrue(resolve(buildDir(), "classes/scala/main/org/hello/World.class").exists()); Assert.assertFalse(resolve(buildDir(), "classes/scala/scoverage/org/hello/World.class").exists()); } diff --git a/src/functionalTest/resources/projects/scala-single-module/build.gradle b/src/functionalTest/resources/projects/scala-single-module/build.gradle index 5ef9ffe..180988a 100644 --- a/src/functionalTest/resources/projects/scala-single-module/build.gradle +++ b/src/functionalTest/resources/projects/scala-single-module/build.gradle @@ -25,11 +25,13 @@ test { } checkScoverage { - minimumRate = 0.5 + minimumRate = 0.3 } if (hasProperty("excludedFile")) { - scoverage { - excludedFiles = [excludedFile] - } -} \ No newline at end of file + scoverage.excludedFiles = [excludedFile] +} +if (hasProperty("runNormalCompilation")) { + scoverage.runNormalCompilation = Boolean.valueOf(runNormalCompilation) +} + diff --git a/src/functionalTest/resources/projects/scala-single-module/src/main/scala/org/hello/World.scala b/src/functionalTest/resources/projects/scala-single-module/src/main/scala/org/hello/World.scala index 27dbe28..270482f 100644 --- a/src/functionalTest/resources/projects/scala-single-module/src/main/scala/org/hello/World.scala +++ b/src/functionalTest/resources/projects/scala-single-module/src/main/scala/org/hello/World.scala @@ -6,4 +6,7 @@ class World { val s = "a" + "b" s } + + // not covered by tests + def bar(): String = "y" } \ No newline at end of file diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index ae99167..f47232d 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -40,6 +40,8 @@ class ScoverageExtension { final Property deleteReportsOnAggregation + final Property runNormalCompilation + ScoverageExtension(Project project) { project.plugins.apply(JavaPlugin.class) @@ -83,5 +85,8 @@ class ScoverageExtension { deleteReportsOnAggregation = project.objects.property(Boolean) deleteReportsOnAggregation.set(false) + + runNormalCompilation = project.objects.property(Boolean) + runNormalCompilation.set(true) } } diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index cb4eef3..51f9b06 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -6,7 +6,6 @@ import org.gradle.api.Project import org.gradle.api.invocation.Gradle import org.gradle.api.plugins.PluginAware import org.gradle.api.tasks.SourceSet -import org.gradle.api.tasks.bundling.Jar import java.nio.file.Files @@ -97,19 +96,13 @@ class ScoveragePlugin implements Plugin { runtimeClasspath = it.output + project.configurations.scoverage + originalSourceSet.runtimeClasspath } + def originalCompileTask = project.tasks[originalSourceSet.getCompileTaskName("scala")] + originalCompileTask.onlyIf { extension.runNormalCompilation.get() } + def compileTask = project.tasks[instrumentedSourceSet.getCompileTaskName("scala")] - compileTask.mustRunAfter(originalSourceSet.getCompileTaskName("scala")) + compileTask.mustRunAfter(originalCompileTask) project.test.mustRunAfter(compileTask) - def scoverageJar = project.tasks.create('jarScoverage', Jar.class) { - dependsOn(instrumentedSourceSet.classesTaskName) - classifier = CONFIGURATION_NAME - from instrumentedSourceSet.output - } - project.artifacts { - scoverage scoverageJar - } - def reportTask = project.tasks.create(REPORT_NAME, ScoverageReport.class) { dependsOn compileTask, project.test onlyIf { extension.dataDir.get().list() } @@ -146,6 +139,12 @@ class ScoveragePlugin implements Plugin { }) } } + + if (!extension.runNormalCompilation.get()) { + project.sourceSets.getByName(SourceSet.TEST_SOURCE_SET_NAME) { + compileClasspath = instrumentedSourceSet.output + compileClasspath + } + } } } @@ -168,8 +167,12 @@ class ScoveragePlugin implements Plugin { } compileTask.configure { - doFirst { - destinationDir.deleteDir() + if (extension.runNormalCompilation.get()) { + doFirst { + destinationDir.deleteDir() + } + } else { + destinationDir = originalCompileTask.destinationDir } File pluginFile = project.configurations[CONFIGURATION_NAME].find { @@ -196,40 +199,43 @@ class ScoveragePlugin implements Plugin { // the compile task creates a store of measured statements outputs.file(new File(extension.dataDir.get(), 'scoverage.coverage.xml')) - doLast { - def originalCompileTaskName = project.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) - .getCompileTaskName("scala") - def originalDestinationDir = project.tasks[originalCompileTaskName].destinationDir - - def findFiles = { File dir, Closure condition = null -> - def files = [] - - if (dir.exists()) { - dir.eachFileRecurse(FILES) { f -> - if (condition == null || condition(f)) { - def relativePath = dir.relativePath(f) - files << relativePath + if (extension.runNormalCompilation.get()) { + // delete non-instrumented classes by comparing normally compiled classes to those compiled with scoverage + doLast { + def originalCompileTaskName = project.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) + .getCompileTaskName("scala") + def originalDestinationDir = project.tasks[originalCompileTaskName].destinationDir + + def findFiles = { File dir, Closure condition = null -> + def files = [] + + if (dir.exists()) { + dir.eachFileRecurse(FILES) { f -> + if (condition == null || condition(f)) { + def relativePath = dir.relativePath(f) + files << relativePath + } } } - } - return files - } + return files + } - def isSameFile = { String relativePath -> - def fileA = new File(originalDestinationDir, relativePath) - def fileB = new File(destinationDir, relativePath) - return FileUtils.contentEquals(fileA, fileB) - } + def isSameFile = { String relativePath -> + def fileA = new File(originalDestinationDir, relativePath) + def fileB = new File(destinationDir, relativePath) + return FileUtils.contentEquals(fileA, fileB) + } - def originalClasses = findFiles(originalDestinationDir) - def identicalInstrumentedClasses = findFiles(destinationDir, { f -> - def relativePath = destinationDir.relativePath(f) - return originalClasses.contains(relativePath) && isSameFile(relativePath) - }) + def originalClasses = findFiles(originalDestinationDir) + def identicalInstrumentedClasses = findFiles(destinationDir, { f -> + def relativePath = destinationDir.relativePath(f) + return originalClasses.contains(relativePath) && isSameFile(relativePath) + }) - identicalInstrumentedClasses.each { f -> - Files.deleteIfExists(destinationDir.toPath().resolve(f)) + identicalInstrumentedClasses.each { f -> + Files.deleteIfExists(destinationDir.toPath().resolve(f)) + } } } } From 7e17f5362ef113292c74d14d8f036577880d6a2f Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Thu, 31 Jan 2019 11:44:24 +0200 Subject: [PATCH 034/167] Make the check-task flags configurable via the extension and not via the task itself --- .../resources/projects/scala-multi-module/build.gradle | 4 ++-- .../resources/projects/scala-single-module/build.gradle | 2 +- src/main/groovy/org/scoverage/OverallCheckTask.groovy | 6 +++--- src/main/groovy/org/scoverage/ScoverageExtension.groovy | 9 +++++++++ src/main/groovy/org/scoverage/ScoveragePlugin.groovy | 2 ++ 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/functionalTest/resources/projects/scala-multi-module/build.gradle b/src/functionalTest/resources/projects/scala-multi-module/build.gradle index 805ce48..7c751a7 100644 --- a/src/functionalTest/resources/projects/scala-multi-module/build.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module/build.gradle @@ -28,11 +28,11 @@ allprojects { useJUnitPlatform() } - checkScoverage { + scoverage { minimumRate = 0.5 } } -checkScoverage { +scoverage { minimumRate = 0.5 } \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-single-module/build.gradle b/src/functionalTest/resources/projects/scala-single-module/build.gradle index 180988a..25a9a4e 100644 --- a/src/functionalTest/resources/projects/scala-single-module/build.gradle +++ b/src/functionalTest/resources/projects/scala-single-module/build.gradle @@ -24,7 +24,7 @@ test { useJUnitPlatform() } -checkScoverage { +scoverage { minimumRate = 0.3 } diff --git a/src/main/groovy/org/scoverage/OverallCheckTask.groovy b/src/main/groovy/org/scoverage/OverallCheckTask.groovy index 810c0ad..e56822a 100644 --- a/src/main/groovy/org/scoverage/OverallCheckTask.groovy +++ b/src/main/groovy/org/scoverage/OverallCheckTask.groovy @@ -44,8 +44,8 @@ enum CoverageType { class OverallCheckTask extends DefaultTask { /** Type of coverage to check. Available options: Line, Statement and Branch */ - CoverageType coverageType = CoverageType.Statement - double minimumRate = 0.75 + final Property coverageType = project.objects.property(CoverageType) + final Property minimumRate = project.objects.property(BigDecimal) final Property reportDir = project.objects.property(File) @@ -56,7 +56,7 @@ class OverallCheckTask extends DefaultTask { void requireLineCoverage() { NumberFormat nf = NumberFormat.getInstance(locale == null ? Locale.getDefault() : locale) - Exception failure = checkLineCoverage(nf, reportDir.get(), coverageType, minimumRate) + Exception failure = checkLineCoverage(nf, reportDir.get(), coverageType.get(), minimumRate.get().doubleValue()) if (failure) throw failure } diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index f47232d..148ea77 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -42,6 +42,9 @@ class ScoverageExtension { final Property runNormalCompilation + final Property coverageType + final Property minimumRate + ScoverageExtension(Project project) { project.plugins.apply(JavaPlugin.class) @@ -88,5 +91,11 @@ class ScoverageExtension { runNormalCompilation = project.objects.property(Boolean) runNormalCompilation.set(true) + + coverageType = project.objects.property(CoverageType) + coverageType.set(CoverageType.Statement) + + minimumRate = project.objects.property(BigDecimal) + minimumRate.set(0.75) } } diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 51f9b06..90afe16 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -120,6 +120,8 @@ class ScoveragePlugin implements Plugin { project.tasks.create(CHECK_NAME, OverallCheckTask.class) { dependsOn(reportTask) group = 'verification' + coverageType = extension.coverageType + minimumRate = extension.minimumRate reportDir = extension.reportDir } From 096d286c8217f5e9fc4c95293d7e55053e6b4cfd Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Thu, 31 Jan 2019 11:54:01 +0200 Subject: [PATCH 035/167] Update README.md with all of the latest changes --- README.md | 99 ++++++++++++++++++++----------------------------------- 1 file changed, 35 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index 696adb5..d6a8c61 100644 --- a/README.md +++ b/README.md @@ -6,90 +6,61 @@ A plugin to enable the use of Scoverage in a gradle Scala project. Getting started --------------- -http://plugins.gradle.org/plugin/org.scoverage - -This creates an additional task `testScoverage` which will run tests against instrumented code. - -A further task `reportScoverage` produces XML and HTML reports for analysing test code coverage. - -You can configure the version of Scoverage that will be used. This plugin should be compatible with all 1+ versions. -```groovy -scoverage { - scoverageVersion = "1.3.1" - scoverageScalaVersion = "2.12" // will be overridden by the 'scala-library' version (if configured) -} -``` - -Then launch command : -`gradle reportScoverage` or `gradle checkScoverage` +http://plugins.gradle.org/plugin/org.scoverage 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. +1. `reportScoverage`: Produces XML and HTML reports for analysing test code coverage. -ReportScoverage ---------------- +2. `aggregateScoverage`: An experimental support for aggregating coverage statistics in composite builds. -You can configure output generated by `gradle reportScoverage` using flags: + When applied on a project with sub-projects, the plugin will create the aggregation task `aggregateScoverage`, which + will first generate reports for each project individually (including the parent project), and will then generate an + aggregated result based on these reports. -| 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. | + The aggregated report will override the parent-project specific report (`parent-project/build/reports/scoverage`). -Aggregating Reports -------------------- + One can still use `reportScoverage` in order to generate a report without aggregation. +3. `checkScoverage`: Validates coverage according status according the generated reports (aggregated or not). -There is now experimental support for aggregating coverage statistics in composite builds. + `gradle checkScoverage` will automatically invoke `reportScoverage` but it won't generate aggregated reports. + In order to check coverage of aggregated reports one should use `gradle checkScoverage aggregateScoverage`. + +Configuration +--------------- -When applied on a project with sub-projects, the plugin will create the aggregation task `aggregateScoverage`, which -will first generate reports for each project individually (including the parent project), and will then generate an -aggregated result based on these reports. +The plugin exposes multiple options that can be configured by setting them in an `scoverage` block within the project's +build script. These options are as follows: -The aggregated report will override the parent-project specific report (`parent-project/build/reports/scoverage`). +You can configure the version of Scoverage that will be used. This plugin should -One can still use `reportScoverage` in order to generate a report without aggregation. +* `scoverageVersion = ` (default `"1.3.1"`): The version of the scoverage scalac plugin. This (gradle) plugin +should be compatible with all 1+ versions. -Aggregation uses same flags as reporting for enabling/disabling different output types. +* `scoverageScalaVersion = ` (default `"2.12"`): The scala version of the scoverage scalac plugin. This will +be overridden by the version of the `scala-library` compile dependency (if the dependency is configured). + +* `coverageOutputCobertura = ` (default `true`): Enables/disables cobertura.xml file generation (for both aggregated and non-aggregated reports). -CheckScoverage --------------- +* `coverageOutputXML = ` (default `true`): Enables/disables scoverage XML output (for both aggregated and non-aggregated reports). -The `checkScoverage` task validates coverage status according the generated reports. +* `coverageOutputHTML = ` (default `true`): Enables/disables scoverage HTML output (for both aggregated and non-aggregated reports). -`gradle checkScoverage` will automatically generate reports via `reportScoverage` but it won't generate aggregated reports. -In order to check coverage of aggregated reports one should use `gradle checkScoverage aggregateScoverage`. +* `coverageDebug = ` (default `false`): Enables/disables scoverage debug output (for both aggregated and non-aggregated reports). -By default, when you launch `gradle checkScoverage` build fail if only 75% of statements in project is covered by tests. +* `minimumRate = ` (default `0.75`): The minimum amount of coverage in decimal proportion (`1.0` == 100%) +required for the validation to pass (otherwise `checkScoverage` will fail the build). -To configure it as you want, add this configuration : -``` -checkScoverage { - minimumRate = 0.5 -} -``` +* `coverageType = <"Statement" | "Branch" | "Line">` (default `"Statement"`): The type of coverage validated by the +`checkScoverage` task. For more information on the different types, please refer to the documentation of the scalac +plugin (https://github.com/scoverage/scalac-scoverage-plugin). -You can also modify type of value to check from `Statement`s to `Line`s or `Branch`es: +* `runNormalCompilation = ` (default `true`): Determines whether both normal scalac compilation (`compileScala`) +and compilation with scoverage (`compileScoverageScala`) should be executed, or if only the scoverage compilation should. +It may be helpful to turn this off so that only the scoverage instrumented classes -- which are not intended for release +-- will be created, thus reducing the build time. -``` -checkScoverage { - coverageType = 'Line' - minimumRate = 0.5 -} -``` -``` -checkScoverage { - coverageType = 'Branch' - minimumRate = 0.5 -} -``` From 1044b8a0dcb828f0749d946cdc09f2615d13f03d Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Fri, 1 Feb 2019 09:42:19 +0200 Subject: [PATCH 036/167] Move all system prints to logger --- .../org/scoverage/ScoverageAggregate.groovy | 2 +- .../org/scoverage/ScoverageReport.groovy | 2 +- .../groovy/org/scoverage/ScoverageWriter.java | 22 +++++++++++++------ 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy index 1e40907..4094476 100644 --- a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy +++ b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy @@ -31,7 +31,7 @@ class ScoverageAggregate extends DefaultTask { reportDir.get().deleteDir() if (coverage.nonEmpty()) { - ScoverageWriter.write( + new ScoverageWriter(project.logger).write( rootDir, reportDir.get(), coverage.get(), diff --git a/src/main/groovy/org/scoverage/ScoverageReport.groovy b/src/main/groovy/org/scoverage/ScoverageReport.groovy index cb9c5d2..ed2d6db 100644 --- a/src/main/groovy/org/scoverage/ScoverageReport.groovy +++ b/src/main/groovy/org/scoverage/ScoverageReport.groovy @@ -50,7 +50,7 @@ class ScoverageReport extends DefaultTask { Set measurements = IOUtils.invoked(measurementFiles) coverage.apply(measurements) - ScoverageWriter.write( + new ScoverageWriter(project.logger).write( sources.get(), reportDir.get(), coverage, diff --git a/src/main/groovy/org/scoverage/ScoverageWriter.java b/src/main/groovy/org/scoverage/ScoverageWriter.java index 0d8ab2f..cf68851 100644 --- a/src/main/groovy/org/scoverage/ScoverageWriter.java +++ b/src/main/groovy/org/scoverage/ScoverageWriter.java @@ -1,5 +1,6 @@ package org.scoverage; +import org.gradle.api.logging.Logger; import scoverage.Constants; import scoverage.Coverage; import scoverage.report.CoberturaXmlWriter; @@ -15,6 +16,13 @@ */ public class ScoverageWriter { + private final Logger logger; + + public ScoverageWriter(Logger logger) { + + this.logger = logger; + } + /** * Generates all reports from given data. * @@ -26,7 +34,7 @@ public class ScoverageWriter { * @param coverageOutputHTML switch for Scoverage HTML output * @param coverageDebug switch for Scoverage Debug output */ - public static void write(File sourceDir, + public void write(File sourceDir, File reportDir, Coverage coverage, Boolean coverageOutputCobertura, @@ -34,13 +42,13 @@ public static void write(File sourceDir, Boolean coverageOutputHTML, Boolean coverageDebug) { - System.out.println("[scoverage] Generating scoverage reports..."); + logger.info("[scoverage] Generating scoverage reports..."); reportDir.mkdirs(); if (coverageOutputCobertura) { new CoberturaXmlWriter(sourceDir, reportDir).write(coverage); - System.out.println("[scoverage] Written Cobertura XML report to " + + logger.info("[scoverage] Written Cobertura XML report to " + reportDir.getAbsolutePath() + File.separator + "cobertura.xml"); @@ -48,13 +56,13 @@ public static void write(File sourceDir, if (coverageOutputXML) { new ScoverageXmlWriter(sourceDir, reportDir, /* debug = */ false).write(coverage); - System.out.println("[scoverage] Written XML report to " + + logger.info("[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 " + + logger.info("[scoverage] Written XML report with debug information to " + reportDir.getAbsolutePath() + File.separator + Constants.XMLReportFilenameWithDebug()); @@ -63,12 +71,12 @@ public static void write(File sourceDir, if (coverageOutputHTML) { new ScoverageHtmlWriter(sourceDir, reportDir).write(coverage); - System.out.println("[scoverage] Written HTML report to " + + logger.info("[scoverage] Written HTML report to " + reportDir.getAbsolutePath() + File.separator + "index.html"); } - System.out.println("[scoverage] Coverage reports completed"); + logger.info("[scoverage] Coverage reports completed"); } } From 67e510629a432df81f441942f37dcac764eaf729 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Fri, 1 Feb 2019 10:42:50 +0200 Subject: [PATCH 037/167] Fix checking without aggregation on multi-module with no source code in the root project --- src/main/groovy/org/scoverage/ScoveragePlugin.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 90afe16..923b65a 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -119,6 +119,7 @@ class ScoveragePlugin implements Plugin { project.tasks.create(CHECK_NAME, OverallCheckTask.class) { dependsOn(reportTask) + onlyIf { extension.reportDir.get().list() } group = 'verification' coverageType = extension.coverageType minimumRate = extension.minimumRate From 269b17c71c3e4c935105b2606272bab878366673 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Fri, 1 Feb 2019 10:45:53 +0200 Subject: [PATCH 038/167] Add a functional test for a multi-module project with multiple scala versions --- .../ScalaMultiModuleCrossVersionTest.java | 59 +++++++++++++++++++ .../2_11/build.gradle | 4 ++ .../src/main/scala/org/hello/World211.scala | 9 +++ .../test/scala/org/hello/World211Suite.scala | 13 ++++ .../2_12/build.gradle | 4 ++ .../src/main/scala/org/hello/World212.scala | 9 +++ .../test/scala/org/hello/World212Suite.scala | 13 ++++ .../build.gradle | 36 +++++++++++ .../settings.gradle | 1 + .../projects/scala-single-module/build.gradle | 2 +- 10 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 src/functionalTest/java/org.scoverage/ScalaMultiModuleCrossVersionTest.java create mode 100644 src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/build.gradle create mode 100644 src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/main/scala/org/hello/World211.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/test/scala/org/hello/World211Suite.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/build.gradle create mode 100644 src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/src/main/scala/org/hello/World212.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/src/test/scala/org/hello/World212Suite.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module-cross-version/build.gradle create mode 100644 src/functionalTest/resources/projects/scala-multi-module-cross-version/settings.gradle diff --git a/src/functionalTest/java/org.scoverage/ScalaMultiModuleCrossVersionTest.java b/src/functionalTest/java/org.scoverage/ScalaMultiModuleCrossVersionTest.java new file mode 100644 index 0000000..224ef34 --- /dev/null +++ b/src/functionalTest/java/org.scoverage/ScalaMultiModuleCrossVersionTest.java @@ -0,0 +1,59 @@ +package org.scoverage; + +import org.junit.Assert; +import org.junit.Test; + +import java.io.File; + +public class ScalaMultiModuleCrossVersionTest extends ScoverageFunctionalTest { + + public ScalaMultiModuleCrossVersionTest() { + super("scala-multi-module-cross-version"); + } + + @Test + public void checkAndAggregateScoverage() throws Exception { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME(), + ScoveragePlugin.getAGGREGATE_NAME()); + + result.assertTaskSkipped(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("2_11:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("2_12:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded("2_11:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded("2_12:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); + + assertAllReportFilesExist(); + assertCoverage(100.0); + } + + private void assertAllReportFilesExist() { + + assert211ReportFilesExist(); + assert212ReportFilesExist(); + assertAggregationFilesExist(); + } + + private void assertAggregationFilesExist() { + + Assert.assertTrue(resolve(reportDir(), "index.html").exists()); + Assert.assertTrue(resolve(reportDir(), "2_11/src/main/scala/org/hello/World211.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "2_12/src/main/scala/org/hello/World212.scala.html").exists()); + } + + private void assert211ReportFilesExist() { + + File reportDir = reportDir(projectDir().toPath().resolve("2_11").toFile()); + Assert.assertTrue(resolve(reportDir, "index.html").exists()); + Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/World211.scala.html").exists()); + } + + private void assert212ReportFilesExist() { + + File reportDir = reportDir(projectDir().toPath().resolve("2_12").toFile()); + Assert.assertTrue(resolve(reportDir, "index.html").exists()); + Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/World212.scala.html").exists()); + } +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/build.gradle new file mode 100644 index 0000000..5421d5a --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/build.gradle @@ -0,0 +1,4 @@ +dependencies { + compile group: 'org.scala-lang', name: 'scala-library', version: "2.11.12" + testCompile group: 'org.scalatest', name: "scalatest_2.11", version: scalatestVersion +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/main/scala/org/hello/World211.scala b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/main/scala/org/hello/World211.scala new file mode 100644 index 0000000..7c7f57b --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/main/scala/org/hello/World211.scala @@ -0,0 +1,9 @@ +package org.hello + +class World211 { + + def foo(): String = { + val s = "2" + "11" + s + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/test/scala/org/hello/World211Suite.scala b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/test/scala/org/hello/World211Suite.scala new file mode 100644 index 0000000..f872840 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/test/scala/org/hello/World211Suite.scala @@ -0,0 +1,13 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class World211Suite extends FunSuite { + + test("foo") { + new World211().foo() + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/build.gradle new file mode 100644 index 0000000..0a8112a --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/build.gradle @@ -0,0 +1,4 @@ +dependencies { + compile group: 'org.scala-lang', name: 'scala-library', version: "2.12.8" + testCompile group: 'org.scalatest', name: "scalatest_2.12", version: scalatestVersion +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/src/main/scala/org/hello/World212.scala b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/src/main/scala/org/hello/World212.scala new file mode 100644 index 0000000..0968efa --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/src/main/scala/org/hello/World212.scala @@ -0,0 +1,9 @@ +package org.hello + +class World212 { + + def foo(): String = { + val s = "2" + "12" + s + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/src/test/scala/org/hello/World212Suite.scala b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/src/test/scala/org/hello/World212Suite.scala new file mode 100644 index 0000000..cd26ad3 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/src/test/scala/org/hello/World212Suite.scala @@ -0,0 +1,13 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class World212Suite extends FunSuite { + + test("foo") { + new World212().foo() + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-cross-version/build.gradle new file mode 100644 index 0000000..4a024a0 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-cross-version/build.gradle @@ -0,0 +1,36 @@ +plugins { + id 'org.scoverage' +} + +allprojects { + repositories { + jcenter() + } +} + +description = 'a multi-module Scala project with multiple Scala versions that builds successfully with 100% coverage' + +allprojects { + + apply plugin: 'java' + apply plugin: 'scala' + + dependencies { + testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + } + + test { + useJUnitPlatform() + } + + scoverage { + minimumRate = 0.5 + } +} + +scoverage { + minimumRate = 0.5 +} + +project(":2_11").tasks.reportScoverage.mustRunAfter(project(":2_12").tasks.reportScoverage) \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/settings.gradle b/src/functionalTest/resources/projects/scala-multi-module-cross-version/settings.gradle new file mode 100644 index 0000000..6d138e6 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-cross-version/settings.gradle @@ -0,0 +1 @@ +include '2_11', '2_12' \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-single-module/build.gradle b/src/functionalTest/resources/projects/scala-single-module/build.gradle index 25a9a4e..fbe8e1e 100644 --- a/src/functionalTest/resources/projects/scala-single-module/build.gradle +++ b/src/functionalTest/resources/projects/scala-single-module/build.gradle @@ -6,7 +6,7 @@ repositories { jcenter() } -description = 'a single-module Scala project that builds successfully with 100% coverage' +description = 'a single-module Scala project that builds successfully with 50% coverage' apply plugin: 'java' apply plugin: 'scala' From 213239b5740c1ec6fac3d25b8cf9ec233f75f27e Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Fri, 1 Feb 2019 12:11:43 +0200 Subject: [PATCH 039/167] Add a functional test for a multi-module project mixed with both scala and java --- .../ScalaJavaMultiModuleTest.java | 62 +++++++++++++++++++ .../scala-java-multi-module/build.gradle | 32 ++++++++++ .../java_only/build.gradle | 6 ++ .../main/java/org/hello/WorldJavaOnly.java | 9 +++ .../java/org/hello/WorldJavaOnlyTest.java | 11 ++++ .../mixed_scala_java/build.gradle | 11 ++++ .../src/main/java/org/hello/WorldJava.java | 9 +++ .../src/main/scala/org/hello/WorldScala.scala | 9 +++ .../test/java/org/hello/WorldJavaTest.java | 11 ++++ .../scala/org/hello/WorldScalaSuite.scala | 13 ++++ .../scala_only/build.gradle | 10 +++ .../main/scala/org/hello/WorldScalaOnly.scala | 9 +++ .../scala/org/hello/WorldScalaOnlySuite.scala | 13 ++++ .../scala-java-multi-module/settings.gradle | 1 + 14 files changed, 206 insertions(+) create mode 100644 src/functionalTest/java/org.scoverage/ScalaJavaMultiModuleTest.java create mode 100644 src/functionalTest/resources/projects/scala-java-multi-module/build.gradle create mode 100644 src/functionalTest/resources/projects/scala-java-multi-module/java_only/build.gradle create mode 100644 src/functionalTest/resources/projects/scala-java-multi-module/java_only/src/main/java/org/hello/WorldJavaOnly.java create mode 100644 src/functionalTest/resources/projects/scala-java-multi-module/java_only/src/test/java/org/hello/WorldJavaOnlyTest.java create mode 100644 src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/build.gradle create mode 100644 src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/src/main/java/org/hello/WorldJava.java create mode 100644 src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/src/main/scala/org/hello/WorldScala.scala create mode 100644 src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/src/test/java/org/hello/WorldJavaTest.java create mode 100644 src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/src/test/scala/org/hello/WorldScalaSuite.scala create mode 100644 src/functionalTest/resources/projects/scala-java-multi-module/scala_only/build.gradle create mode 100644 src/functionalTest/resources/projects/scala-java-multi-module/scala_only/src/main/scala/org/hello/WorldScalaOnly.scala create mode 100644 src/functionalTest/resources/projects/scala-java-multi-module/scala_only/src/test/scala/org/hello/WorldScalaOnlySuite.scala create mode 100644 src/functionalTest/resources/projects/scala-java-multi-module/settings.gradle diff --git a/src/functionalTest/java/org.scoverage/ScalaJavaMultiModuleTest.java b/src/functionalTest/java/org.scoverage/ScalaJavaMultiModuleTest.java new file mode 100644 index 0000000..ccbe91e --- /dev/null +++ b/src/functionalTest/java/org.scoverage/ScalaJavaMultiModuleTest.java @@ -0,0 +1,62 @@ +package org.scoverage; + +import org.junit.Assert; +import org.junit.Test; + +import java.io.File; + +public class ScalaJavaMultiModuleTest extends ScoverageFunctionalTest { + + public ScalaJavaMultiModuleTest() { + super("scala-java-multi-module"); + } + + @Test + public void checkAndAggregateScoverage() throws Exception { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME(), + ScoveragePlugin.getAGGREGATE_NAME()); + + result.assertTaskSkipped(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("scala_only:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("mixed_scala_java:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist("java_only:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded("scala_only:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded("mixed_scala_java:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist("java_only:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); + + assertAllReportFilesExist(); + assertCoverage(100.0); + } + + private void assertAllReportFilesExist() { + + Assert.assertTrue(resolve(reportDir(), "index.html").exists()); + + assertScalaOnlyReportFilesExist(); + assertMixedScalaJavaReportFilesExist(); + assertAggregationFilesExist(); + } + + private void assertAggregationFilesExist() { + + Assert.assertTrue(resolve(reportDir(), "scala_only/src/main/scala/org/hello/WorldScalaOnly.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "mixed_scala_java/src/main/scala/org/hello/WorldScala.scala.html").exists()); + } + + private void assertScalaOnlyReportFilesExist() { + + File reportDir = reportDir(projectDir().toPath().resolve("scala_only").toFile()); + Assert.assertTrue(resolve(reportDir, "index.html").exists()); + Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/WorldScalaOnly.scala.html").exists()); + } + + private void assertMixedScalaJavaReportFilesExist() { + + File reportDir = reportDir(projectDir().toPath().resolve("mixed_scala_java").toFile()); + Assert.assertTrue(resolve(reportDir, "index.html").exists()); + Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/WorldScala.scala.html").exists()); + } +} diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/build.gradle b/src/functionalTest/resources/projects/scala-java-multi-module/build.gradle new file mode 100644 index 0000000..b486ee1 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-multi-module/build.gradle @@ -0,0 +1,32 @@ +plugins { + id 'org.scoverage' apply false +} + +allprojects { + repositories { + jcenter() + } +} + +description = 'a multi-module Scala and Java project that builds successfully with 100% coverage' + +apply plugin: 'org.scoverage' + +allprojects { + + dependencies { + testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + } + + test { + useJUnitPlatform() + } + + scoverage { + minimumRate = 0.5 + } +} + +scoverage { + minimumRate = 0.5 +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/java_only/build.gradle b/src/functionalTest/resources/projects/scala-java-multi-module/java_only/build.gradle new file mode 100644 index 0000000..1cb42eb --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-multi-module/java_only/build.gradle @@ -0,0 +1,6 @@ +apply plugin: 'java' + +dependencies { + + testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion +} diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/java_only/src/main/java/org/hello/WorldJavaOnly.java b/src/functionalTest/resources/projects/scala-java-multi-module/java_only/src/main/java/org/hello/WorldJavaOnly.java new file mode 100644 index 0000000..95c85de --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-multi-module/java_only/src/main/java/org/hello/WorldJavaOnly.java @@ -0,0 +1,9 @@ +package org.hello; + +public class WorldJavaOnly { + + public String foo() { + String s = "java_only" + "a"; + return s; + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/java_only/src/test/java/org/hello/WorldJavaOnlyTest.java b/src/functionalTest/resources/projects/scala-java-multi-module/java_only/src/test/java/org/hello/WorldJavaOnlyTest.java new file mode 100644 index 0000000..68fd33d --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-multi-module/java_only/src/test/java/org/hello/WorldJavaOnlyTest.java @@ -0,0 +1,11 @@ +package org.hello; + +import org.junit.Test; + +public class WorldJavaOnlyTest { + + @Test + public void foo() { + new WorldJavaOnly().foo(); + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/build.gradle b/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/build.gradle new file mode 100644 index 0000000..3aa23b7 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/build.gradle @@ -0,0 +1,11 @@ +apply plugin: 'java' +apply plugin: 'scala' +apply plugin: 'org.scoverage' + +dependencies { + compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + + testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + + testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion +} diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/src/main/java/org/hello/WorldJava.java b/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/src/main/java/org/hello/WorldJava.java new file mode 100644 index 0000000..bcfd8cf --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/src/main/java/org/hello/WorldJava.java @@ -0,0 +1,9 @@ +package org.hello; + +public class WorldJava { + + public String foo() { + String s = "java" + "a"; + return s; + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/src/main/scala/org/hello/WorldScala.scala b/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/src/main/scala/org/hello/WorldScala.scala new file mode 100644 index 0000000..8cdded1 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/src/main/scala/org/hello/WorldScala.scala @@ -0,0 +1,9 @@ +package org.hello + +class WorldScala { + + def foo(): String = { + val s = "scala" + "a" + s + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/src/test/java/org/hello/WorldJavaTest.java b/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/src/test/java/org/hello/WorldJavaTest.java new file mode 100644 index 0000000..a88e452 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/src/test/java/org/hello/WorldJavaTest.java @@ -0,0 +1,11 @@ +package org.hello; + +import org.junit.Test; + +public class WorldJavaTest { + + @Test + public void foo() { + new WorldJava().foo(); + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/src/test/scala/org/hello/WorldScalaSuite.scala b/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/src/test/scala/org/hello/WorldScalaSuite.scala new file mode 100644 index 0000000..4244420 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/src/test/scala/org/hello/WorldScalaSuite.scala @@ -0,0 +1,13 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldScalaSuite extends FunSuite { + + test("foo") { + new WorldScala().foo() + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/scala_only/build.gradle b/src/functionalTest/resources/projects/scala-java-multi-module/scala_only/build.gradle new file mode 100644 index 0000000..97f6ee6 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-multi-module/scala_only/build.gradle @@ -0,0 +1,10 @@ +apply plugin: 'scala' +apply plugin: 'org.scoverage' + +dependencies { + compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + + testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + + testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion +} diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/scala_only/src/main/scala/org/hello/WorldScalaOnly.scala b/src/functionalTest/resources/projects/scala-java-multi-module/scala_only/src/main/scala/org/hello/WorldScalaOnly.scala new file mode 100644 index 0000000..268c5a5 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-multi-module/scala_only/src/main/scala/org/hello/WorldScalaOnly.scala @@ -0,0 +1,9 @@ +package org.hello + +class WorldScalaOnly { + + def foo(): String = { + val s = "scala_only" + "a" + s + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/scala_only/src/test/scala/org/hello/WorldScalaOnlySuite.scala b/src/functionalTest/resources/projects/scala-java-multi-module/scala_only/src/test/scala/org/hello/WorldScalaOnlySuite.scala new file mode 100644 index 0000000..7601021 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-multi-module/scala_only/src/test/scala/org/hello/WorldScalaOnlySuite.scala @@ -0,0 +1,13 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldScalaOnlySuite extends FunSuite { + + test("foo") { + new WorldScalaOnly().foo() + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/settings.gradle b/src/functionalTest/resources/projects/scala-java-multi-module/settings.gradle new file mode 100644 index 0000000..d8268de --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-multi-module/settings.gradle @@ -0,0 +1 @@ +include 'java_only', 'scala_only', 'mixed_scala_java' \ No newline at end of file From 57e6d2771f3d6ad0d3648e4fc8366804509f05a9 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Fri, 1 Feb 2019 13:44:53 +0200 Subject: [PATCH 040/167] Add compatibility with spring's dependency management plugin --- ...laSingleModuleWithDepdencyManagerTest.java | 31 ++++++++++++++ .../build.gradle | 42 +++++++++++++++++++ .../settings.gradle | 0 .../src/main/scala/org/hello/World.scala | 9 ++++ .../src/test/scala/org/hello/WorldSuite.scala | 13 ++++++ .../org/scoverage/ScoveragePlugin.groovy | 14 ++++++- 6 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 src/functionalTest/java/org.scoverage/ScalaSingleModuleWithDepdencyManagerTest.java create mode 100644 src/functionalTest/resources/projects/scala-single-module-dependency-manager/build.gradle create mode 100644 src/functionalTest/resources/projects/scala-single-module-dependency-manager/settings.gradle create mode 100644 src/functionalTest/resources/projects/scala-single-module-dependency-manager/src/main/scala/org/hello/World.scala create mode 100644 src/functionalTest/resources/projects/scala-single-module-dependency-manager/src/test/scala/org/hello/WorldSuite.scala diff --git a/src/functionalTest/java/org.scoverage/ScalaSingleModuleWithDepdencyManagerTest.java b/src/functionalTest/java/org.scoverage/ScalaSingleModuleWithDepdencyManagerTest.java new file mode 100644 index 0000000..f8548fe --- /dev/null +++ b/src/functionalTest/java/org.scoverage/ScalaSingleModuleWithDepdencyManagerTest.java @@ -0,0 +1,31 @@ +package org.scoverage; + +import org.junit.Assert; +import org.junit.Test; + +public class ScalaSingleModuleWithDepdencyManagerTest extends ScoverageFunctionalTest { + + public ScalaSingleModuleWithDepdencyManagerTest() { + super("scala-single-module-dependency-manager"); + } + + @Test + public void checkScoverage() throws Exception { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME()); + + result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + + assertReportFilesExist(); + assertCoverage(100.0); + } + + private void assertReportFilesExist() { + + Assert.assertTrue(resolve(reportDir(), "index.html").exists()); + Assert.assertTrue(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-single-module-dependency-manager/build.gradle b/src/functionalTest/resources/projects/scala-single-module-dependency-manager/build.gradle new file mode 100644 index 0000000..135d248 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-single-module-dependency-manager/build.gradle @@ -0,0 +1,42 @@ +plugins { + id 'io.spring.dependency-management' version "1.0.4.RELEASE" + id 'org.scoverage' +} + +repositories { + jcenter() +} + +description = 'a single-module Scala project with dependency manager that builds successfully with 100% coverage' + +apply plugin: 'java' +apply plugin: 'scala' + + +dependencyManagement { + dependencies { + dependency group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + } +} + +dependencies { + compile group: 'org.scala-lang', name: 'scala-library' + + // scala compilation with the dependency management plugin needs this (otherwise compilation will fail) + zinc group: 'com.typesafe.zinc', name: 'zinc', version: '0.3.15' + zinc group: 'org.scala-lang', name: 'scala-library', version: '2.10.5' + + testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion +} + +test { + useJUnitPlatform() +} + +scoverage { + minimumRate = 0.3 +} + diff --git a/src/functionalTest/resources/projects/scala-single-module-dependency-manager/settings.gradle b/src/functionalTest/resources/projects/scala-single-module-dependency-manager/settings.gradle new file mode 100644 index 0000000..e69de29 diff --git a/src/functionalTest/resources/projects/scala-single-module-dependency-manager/src/main/scala/org/hello/World.scala b/src/functionalTest/resources/projects/scala-single-module-dependency-manager/src/main/scala/org/hello/World.scala new file mode 100644 index 0000000..27dbe28 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-single-module-dependency-manager/src/main/scala/org/hello/World.scala @@ -0,0 +1,9 @@ +package org.hello + +class World { + + def foo(): String = { + val s = "a" + "b" + s + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-single-module-dependency-manager/src/test/scala/org/hello/WorldSuite.scala b/src/functionalTest/resources/projects/scala-single-module-dependency-manager/src/test/scala/org/hello/WorldSuite.scala new file mode 100644 index 0000000..7281a12 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-single-module-dependency-manager/src/test/scala/org/hello/WorldSuite.scala @@ -0,0 +1,13 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldSuite extends FunSuite { + + test("foo") { + new World().foo() + } +} \ No newline at end of file diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 923b65a..6bd42d6 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -57,14 +57,24 @@ class ScoveragePlugin implements Plugin { project.afterEvaluate { def scoverageVersion = project.extensions.scoverage.scoverageVersion.get() - def scalaVersion = project.extensions.scoverage.scoverageScalaVersion.get() + def scalaVersion = null def scalaLibrary = project.configurations.compile.dependencies.find { it.group == "org.scala-lang" && it.name == "scala-library" } if (scalaLibrary != null) { - scalaVersion = scalaLibrary.version.substring(0, scalaLibrary.version.lastIndexOf(".")) + scalaVersion = scalaLibrary.version + } + + if (scalaVersion == null && project.pluginManager.hasPlugin("io.spring.dependency-management")) { + scalaVersion = project.dependencyManagement.compile.managedVersions["org.scala-lang:scala-library"] + } + + if (scalaVersion == null) { + scalaVersion = project.extensions.scoverage.scoverageScalaVersion.get() + } else { + scalaVersion = scalaVersion.substring(0, scalaVersion.lastIndexOf(".")) } def fullScoverageVersion = "$scalaVersion:$scoverageVersion" From ea988ae2dc9432978da0a1df4486af9d563545a6 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Sun, 3 Feb 2019 15:47:54 +0200 Subject: [PATCH 041/167] Change the usage of running without normal compilation and fix it in multi-module projects with inner dependencies --- README.md | 14 +- .../ScalaJavaMultiModuleTest.java | 7 +- .../org.scoverage/ScalaMultiModuleTest.java | 96 ++++++++++-- .../org.scoverage/ScalaSingleModuleTest.java | 4 +- .../ScoverageFunctionalTest.java | 2 +- .../mixed_scala_java/build.gradle | 8 + .../scala-multi-module/a/build.gradle | 3 + .../a/src/main/scala/org/hello/a/WorldA.scala | 4 +- .../scala-multi-module/b/build.gradle | 3 + .../b/src/main/scala/org/hello/b/WorldB.scala | 4 +- .../projects/scala-multi-module/build.gradle | 4 - .../scala/org/hello/common/WorldCommon.scala | 9 ++ .../hello/common/TestNothingCommonSuite.scala | 12 ++ .../org/hello/common/WorldCommonSuite.scala | 13 ++ .../scala-multi-module/settings.gradle | 2 +- .../projects/scala-single-module/build.gradle | 4 - .../org/scoverage/ScoverageExtension.groovy | 5 - .../org/scoverage/ScoveragePlugin.groovy | 146 ++++++++++-------- 18 files changed, 238 insertions(+), 102 deletions(-) create mode 100644 src/functionalTest/resources/projects/scala-multi-module/a/build.gradle create mode 100644 src/functionalTest/resources/projects/scala-multi-module/b/build.gradle create mode 100644 src/functionalTest/resources/projects/scala-multi-module/common/src/main/scala/org/hello/common/WorldCommon.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module/common/src/test/scala/org/hello/common/TestNothingCommonSuite.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module/common/src/test/scala/org/hello/common/WorldCommonSuite.scala diff --git a/README.md b/README.md index d6a8c61..c03c22c 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Available tasks In order to check coverage of aggregated reports one should use `gradle checkScoverage aggregateScoverage`. Configuration ---------------- +------------- The plugin exposes multiple options that can be configured by setting them in an `scoverage` block within the project's build script. These options are as follows: @@ -58,9 +58,13 @@ required for the validation to pass (otherwise `checkScoverage` will fail the bu `checkScoverage` task. For more information on the different types, please refer to the documentation of the scalac plugin (https://github.com/scoverage/scalac-scoverage-plugin). -* `runNormalCompilation = ` (default `true`): Determines whether both normal scalac compilation (`compileScala`) -and compilation with scoverage (`compileScoverageScala`) should be executed, or if only the scoverage compilation should. -It may be helpful to turn this off so that only the scoverage instrumented classes -- which are not intended for release --- will be created, thus reducing the build time. +Run without normal compilation +------------------------------ +By default, running any of the plugin tasks will compile the code both using "normal" compilation (`compileScala`) +and using the scoverage scalac plugin (`compileScoverageScala`). +In cases where you only wish to generate reports / validate coverage, but are not interested in publishing the code, +it is possible to only compile the code with the scoverage scalac plugin, thus reducing build times significantly. +In order to do so, simply add the arguments `-x compileScala` to the gradle execution. +For example: `gradle reportScoverage -x compileScala`. \ No newline at end of file diff --git a/src/functionalTest/java/org.scoverage/ScalaJavaMultiModuleTest.java b/src/functionalTest/java/org.scoverage/ScalaJavaMultiModuleTest.java index ccbe91e..0c6156e 100644 --- a/src/functionalTest/java/org.scoverage/ScalaJavaMultiModuleTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaJavaMultiModuleTest.java @@ -1,5 +1,6 @@ package org.scoverage; +import org.gradle.testkit.runner.TaskOutcome; import org.junit.Assert; import org.junit.Test; @@ -17,14 +18,16 @@ public void checkAndAggregateScoverage() throws Exception { AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME(), ScoveragePlugin.getAGGREGATE_NAME()); + result.assertTaskOutcome("java_only:" + ScoveragePlugin.getCOMPILE_NAME(), TaskOutcome.NO_SOURCE); + result.assertTaskSkipped(ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded("scala_only:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded("mixed_scala_java:" + ScoveragePlugin.getREPORT_NAME()); - result.assertTaskDoesntExist("java_only:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSkipped("java_only:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); result.assertTaskSucceeded("scala_only:" + ScoveragePlugin.getCHECK_NAME()); result.assertTaskSucceeded("mixed_scala_java:" + ScoveragePlugin.getCHECK_NAME()); - result.assertTaskDoesntExist("java_only:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSkipped("java_only:" + ScoveragePlugin.getCHECK_NAME()); result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); assertAllReportFilesExist(); diff --git a/src/functionalTest/java/org.scoverage/ScalaMultiModuleTest.java b/src/functionalTest/java/org.scoverage/ScalaMultiModuleTest.java index 18b5e0a..5818ca5 100644 --- a/src/functionalTest/java/org.scoverage/ScalaMultiModuleTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaMultiModuleTest.java @@ -19,6 +19,7 @@ public void reportScoverage() { result.assertTaskExists(ScoveragePlugin.getREPORT_NAME()); result.assertTaskExists("a:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskExists("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("common:" + ScoveragePlugin.getREPORT_NAME()); } @Test @@ -29,6 +30,7 @@ public void reportScoverageOnlyRoot() { result.assertTaskExists(ScoveragePlugin.getREPORT_NAME()); result.assertTaskDoesntExist("a:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskDoesntExist("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist("common:" + ScoveragePlugin.getREPORT_NAME()); } @Test @@ -39,6 +41,7 @@ public void reportScoverageOnlyA() { result.assertTaskDoesntExist(ScoveragePlugin.getREPORT_NAME()); result.assertTaskExists("a:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskDoesntExist("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist("common:" + ScoveragePlugin.getREPORT_NAME()); } @Test @@ -50,6 +53,7 @@ public void aggregateScoverage() { result.assertTaskExists("a:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskExists("b:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskExists(ScoveragePlugin.getAGGREGATE_NAME()); + result.assertTaskExists("common:" + ScoveragePlugin.getREPORT_NAME()); } @Test @@ -60,9 +64,11 @@ public void checkScoverage() { result.assertTaskExists(ScoveragePlugin.getREPORT_NAME()); result.assertTaskExists("a:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskExists("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("common:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskExists(ScoveragePlugin.getCHECK_NAME()); result.assertTaskExists("a:" + ScoveragePlugin.getCHECK_NAME()); result.assertTaskExists("b:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskExists("common:" + ScoveragePlugin.getCHECK_NAME()); result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); } @@ -88,9 +94,11 @@ public void checkScoverageOnlyA() { result.assertTaskDoesntExist(ScoveragePlugin.getREPORT_NAME()); result.assertTaskExists("a:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskDoesntExist("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist("common:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); result.assertTaskExists("a:" + ScoveragePlugin.getCHECK_NAME()); result.assertTaskDoesntExist("b:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist("common:" + ScoveragePlugin.getCHECK_NAME()); result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); } @@ -103,9 +111,11 @@ public void checkAndAggregateScoverage() throws Exception { result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded("a:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("common:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); result.assertTaskSucceeded("a:" + ScoveragePlugin.getCHECK_NAME()); result.assertTaskSucceeded("b:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded("common:" + ScoveragePlugin.getCHECK_NAME()); result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); assertAllReportFilesExist(); @@ -119,7 +129,8 @@ public void checkScoverageWithoutCoverageInRoot() throws Exception { "test", "--tests", "org.hello.TestNothingSuite", "--tests", "org.hello.a.WorldASuite", - "--tests", "org.hello.b.WorldBSuite"); + "--tests", "org.hello.b.WorldBSuite", + "--tests", "org.hello.common.WorldCommonSuite"); result.assertTaskFailed(ScoveragePlugin.getCHECK_NAME()); @@ -134,7 +145,8 @@ public void checkScoverageWithoutCoverageInA() throws Exception { "test", "--tests", "org.hello.a.TestNothingASuite", "--tests", "org.hello.WorldSuite", - "--tests", "org.hello.b.WorldBSuite"); + "--tests", "org.hello.b.WorldBSuite", + "--tests", "org.hello.common.WorldCommonSuite"); result.assertTaskFailed("a:" + ScoveragePlugin.getCHECK_NAME()); @@ -142,6 +154,21 @@ public void checkScoverageWithoutCoverageInA() throws Exception { assertCoverage(0.0, reportDir(projectDir().toPath().resolve("a").toFile())); } + @Test + public void checkScoverageWithoutNormalCompilationAndWithoutCoverageInCommon() throws Exception { + + AssertableBuildResult result = runAndFail("clean", + ":a:test", + ":common:test", "--tests", "org.hello.common.TestNothingCommonSuite", + "-x", "compileScala", + ScoveragePlugin.getCHECK_NAME()); + + result.assertTaskFailed("common:" + ScoveragePlugin.getCHECK_NAME()); + + assertCommonReportFilesExist(); + assertCoverage(0.0, reportDir(projectDir().toPath().resolve("common").toFile())); + } + @Test public void checkAndAggregateScoverageWithoutCoverageInRoot() throws Exception { @@ -151,18 +178,21 @@ public void checkAndAggregateScoverageWithoutCoverageInRoot() throws Exception { ScoveragePlugin.getAGGREGATE_NAME(), "test", "--tests", "org.hello.TestNothingSuite", "--tests", "org.hello.a.WorldASuite", - "--tests", "org.hello.b.WorldBSuite"); + "--tests", "org.hello.b.WorldBSuite", + "--tests", "org.hello.common.WorldCommonSuite"); result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded("a:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("common:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); result.assertTaskSucceeded("a:" + ScoveragePlugin.getCHECK_NAME()); result.assertTaskSucceeded("b:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded("common:" + ScoveragePlugin.getCHECK_NAME()); result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); assertAllReportFilesExist(); - assertCoverage(66.6); + assertCoverage(87.5); } @Test @@ -172,11 +202,13 @@ public void checkAndAggregateScoverageWithoutCoverageInAll() throws Exception { ScoveragePlugin.getAGGREGATE_NAME(), "test", "--tests", "org.hello.TestNothingSuite", "--tests", "org.hello.a.TestNothingASuite", - "--tests", "org.hello.b.TestNothingBSuite"); + "--tests", "org.hello.b.TestNothingBSuite", + "--tests", "org.hello.common.TestNothingCommonSuite"); result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded("a:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("common:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); result.assertTaskFailed(ScoveragePlugin.getCHECK_NAME()); @@ -184,19 +216,53 @@ public void checkAndAggregateScoverageWithoutCoverageInAll() throws Exception { assertCoverage(0.0); } + @Test + public void aggregateScoverageWithoutNormalCompilation() throws Exception { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getAGGREGATE_NAME(), + "-x", "compileScala"); + + result.assertTaskSkipped("compileScala"); + result.assertTaskSkipped("a:compileScala"); + result.assertTaskSkipped("b:compileScala"); + result.assertTaskSkipped("common:compileScala"); + result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded("a:" + ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded("b:" + ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded("common:" + ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("a:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("common:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); + + assertAllReportFilesExist(); + assertCoverage(100.0); + + Assert.assertTrue(resolve(buildDir(resolve(projectDir(), "a")), "classes/scala/main/org/hello/a/WorldA.class").exists()); + Assert.assertFalse(resolve(buildDir(resolve(projectDir(), "a")), "classes/scala/scoverage/org/hello/a/WorldA.class").exists()); + + Assert.assertTrue(resolve(buildDir(resolve(projectDir(), "b")), "classes/scala/main/org/hello/b/WorldB.class").exists()); + Assert.assertFalse(resolve(buildDir(resolve(projectDir(), "b")), "classes/scala/scoverage/org/hello/b/WorldB.class").exists()); + + Assert.assertTrue(resolve(buildDir(resolve(projectDir(), "common")), "classes/scala/main/org/hello/common/WorldCommon.class").exists()); + Assert.assertFalse(resolve(buildDir(resolve(projectDir(), "common")), "classes/scala/scoverage/org/hello/common/WorldCommon.class").exists()); + } + private void assertAllReportFilesExist() { assertRootReportFilesExist(); assertAReportFilesExist(); assertBReportFilesExist(); + assertCommonReportFilesExist(); assertAggregationFilesExist(); } private void assertAggregationFilesExist() { - assertRootReportFilesExist(); Assert.assertTrue(resolve(reportDir(), "a/src/main/scala/org/hello/a/WorldA.scala.html").exists()); Assert.assertTrue(resolve(reportDir(), "b/src/main/scala/org/hello/b/WorldB.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "common/src/main/scala/org/hello/common/WorldCommon.scala.html").exists()); } private void assertRootReportFilesExist() { @@ -207,16 +273,22 @@ private void assertRootReportFilesExist() { private void assertAReportFilesExist() { - File aReportDir = reportDir(projectDir().toPath().resolve("a").toFile()); - Assert.assertTrue(resolve(aReportDir, "index.html").exists()); - Assert.assertTrue(resolve(aReportDir, "src/main/scala/org/hello/a/WorldA.scala.html").exists()); + File reportDir = reportDir(projectDir().toPath().resolve("a").toFile()); + Assert.assertTrue(resolve(reportDir, "index.html").exists()); + Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/a/WorldA.scala.html").exists()); } private void assertBReportFilesExist() { - File bReportDir = reportDir(projectDir().toPath().resolve("b").toFile()); - Assert.assertTrue(resolve(bReportDir, "index.html").exists()); - Assert.assertTrue(resolve(bReportDir, "src/main/scala/org/hello/b/WorldB.scala.html").exists()); + File reportDir = reportDir(projectDir().toPath().resolve("b").toFile()); + Assert.assertTrue(resolve(reportDir, "index.html").exists()); + Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/b/WorldB.scala.html").exists()); + } + + private void assertCommonReportFilesExist() { + File reportDir = reportDir(projectDir().toPath().resolve("common").toFile()); + Assert.assertTrue(resolve(reportDir, "index.html").exists()); + Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/common/WorldCommon.scala.html").exists()); } } diff --git a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java index 081fa9a..f93e184 100644 --- a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java @@ -103,7 +103,7 @@ public void reportScoverageWithExcludedClasses() throws Exception { public void reportScoverageWithoutNormalCompilation() throws Exception { AssertableBuildResult result = run("clean", ScoveragePlugin.getREPORT_NAME(), - "-PrunNormalCompilation=false"); + "-x", "compileScala"); result.assertTaskSkipped("compileScala"); result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); @@ -122,7 +122,7 @@ public void reportScoverageWithoutNormalCompilation() throws Exception { public void reportScoverageWithoutNormalCompilationAndWithExcludedClasses() throws Exception { AssertableBuildResult result = run("clean", ScoveragePlugin.getREPORT_NAME(), - "-PrunNormalCompilation=false", "-PexcludedFile=.*"); + "-PexcludedFile=.*", "-x", "compileScala"); Assert.assertTrue(resolve(reportDir(), "index.html").exists()); Assert.assertFalse(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); diff --git a/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java b/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java index 27aab49..af14ce5 100644 --- a/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java +++ b/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java @@ -193,7 +193,7 @@ private String fullTaskName(String taskName) { private boolean taskExists(String taskName) { - Pattern regex = Pattern.compile("^" + fullTaskName(taskName), Pattern.MULTILINE); + Pattern regex = Pattern.compile("^(> Task )?" + fullTaskName(taskName), Pattern.MULTILINE); return regex.matcher(result.getOutput()).find(); } } diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/build.gradle b/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/build.gradle index 3aa23b7..9d6a7ab 100644 --- a/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/build.gradle +++ b/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/build.gradle @@ -9,3 +9,11 @@ dependencies { testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion } + +// A common practice in mixed java/scala modules to make Java code able to import Scala code +ext.configureSources = { set, name -> + set.scala.srcDir("src/$name/java") + set.java.srcDirs = [] +} +configureSources(sourceSets.main, 'main') +configureSources(sourceSets.test, 'test') \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/a/build.gradle b/src/functionalTest/resources/projects/scala-multi-module/a/build.gradle new file mode 100644 index 0000000..054045f --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module/a/build.gradle @@ -0,0 +1,3 @@ +dependencies { + compile project(":common") +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/a/src/main/scala/org/hello/a/WorldA.scala b/src/functionalTest/resources/projects/scala-multi-module/a/src/main/scala/org/hello/a/WorldA.scala index 301f445..1d7b2a1 100644 --- a/src/functionalTest/resources/projects/scala-multi-module/a/src/main/scala/org/hello/a/WorldA.scala +++ b/src/functionalTest/resources/projects/scala-multi-module/a/src/main/scala/org/hello/a/WorldA.scala @@ -1,9 +1,11 @@ package org.hello.a +import org.hello.common.WorldCommon + class WorldA { def fooA(): String = { - val s = "a" + "a" + val s = "a" + new WorldCommon().fooCommon() s } } \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/b/build.gradle b/src/functionalTest/resources/projects/scala-multi-module/b/build.gradle new file mode 100644 index 0000000..054045f --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module/b/build.gradle @@ -0,0 +1,3 @@ +dependencies { + compile project(":common") +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/b/src/main/scala/org/hello/b/WorldB.scala b/src/functionalTest/resources/projects/scala-multi-module/b/src/main/scala/org/hello/b/WorldB.scala index bb7a579..5c8bb57 100644 --- a/src/functionalTest/resources/projects/scala-multi-module/b/src/main/scala/org/hello/b/WorldB.scala +++ b/src/functionalTest/resources/projects/scala-multi-module/b/src/main/scala/org/hello/b/WorldB.scala @@ -1,9 +1,11 @@ package org.hello.b +import org.hello.common.WorldCommon + class WorldB { def fooB(): String = { - val s = "b" + "b" + val s = "b" + new WorldCommon().fooCommon() s } } \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/build.gradle b/src/functionalTest/resources/projects/scala-multi-module/build.gradle index 7c751a7..dcfad1a 100644 --- a/src/functionalTest/resources/projects/scala-multi-module/build.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module/build.gradle @@ -31,8 +31,4 @@ allprojects { scoverage { minimumRate = 0.5 } -} - -scoverage { - minimumRate = 0.5 } \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/common/src/main/scala/org/hello/common/WorldCommon.scala b/src/functionalTest/resources/projects/scala-multi-module/common/src/main/scala/org/hello/common/WorldCommon.scala new file mode 100644 index 0000000..494ab34 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module/common/src/main/scala/org/hello/common/WorldCommon.scala @@ -0,0 +1,9 @@ +package org.hello.common + +class WorldCommon { + + def fooCommon(): String = { + val s = "common" + "a" + s + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/common/src/test/scala/org/hello/common/TestNothingCommonSuite.scala b/src/functionalTest/resources/projects/scala-multi-module/common/src/test/scala/org/hello/common/TestNothingCommonSuite.scala new file mode 100644 index 0000000..970cd6c --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module/common/src/test/scala/org/hello/common/TestNothingCommonSuite.scala @@ -0,0 +1,12 @@ +package org.hello.common + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class TestNothingCommonSuite extends FunSuite { + + test("nothing") { + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/common/src/test/scala/org/hello/common/WorldCommonSuite.scala b/src/functionalTest/resources/projects/scala-multi-module/common/src/test/scala/org/hello/common/WorldCommonSuite.scala new file mode 100644 index 0000000..94f8984 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module/common/src/test/scala/org/hello/common/WorldCommonSuite.scala @@ -0,0 +1,13 @@ +package org.hello.common + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldCommonSuite extends FunSuite { + + test("fooCommon") { + new WorldCommon().fooCommon() + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/settings.gradle b/src/functionalTest/resources/projects/scala-multi-module/settings.gradle index dd79722..6eabe3b 100644 --- a/src/functionalTest/resources/projects/scala-multi-module/settings.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module/settings.gradle @@ -1 +1 @@ -include 'a', 'b' \ No newline at end of file +include 'a', 'b', 'common' \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-single-module/build.gradle b/src/functionalTest/resources/projects/scala-single-module/build.gradle index fbe8e1e..6ae71be 100644 --- a/src/functionalTest/resources/projects/scala-single-module/build.gradle +++ b/src/functionalTest/resources/projects/scala-single-module/build.gradle @@ -31,7 +31,3 @@ scoverage { if (hasProperty("excludedFile")) { scoverage.excludedFiles = [excludedFile] } -if (hasProperty("runNormalCompilation")) { - scoverage.runNormalCompilation = Boolean.valueOf(runNormalCompilation) -} - diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index 148ea77..8ee680b 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -40,8 +40,6 @@ class ScoverageExtension { final Property deleteReportsOnAggregation - final Property runNormalCompilation - final Property coverageType final Property minimumRate @@ -89,9 +87,6 @@ class ScoverageExtension { deleteReportsOnAggregation = project.objects.property(Boolean) deleteReportsOnAggregation.set(false) - runNormalCompilation = project.objects.property(Boolean) - runNormalCompilation.set(true) - coverageType = project.objects.property(CoverageType) coverageType.set(CoverageType.Statement) diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 6bd42d6..7c6ac63 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -3,9 +3,11 @@ package org.scoverage import org.apache.commons.io.FileUtils import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.api.Task import org.gradle.api.invocation.Gradle import org.gradle.api.plugins.PluginAware import org.gradle.api.tasks.SourceSet +import org.gradle.api.tasks.scala.ScalaCompile import java.nio.file.Files @@ -99,7 +101,6 @@ class ScoveragePlugin implements Plugin { def instrumentedSourceSet = project.sourceSets.create('scoverage') { resources.source(originalSourceSet.resources) - scala.source(originalSourceSet.java) scala.source(originalSourceSet.scala) compileClasspath += originalSourceSet.compileClasspath + project.configurations.scoverage @@ -107,11 +108,12 @@ class ScoveragePlugin implements Plugin { } def originalCompileTask = project.tasks[originalSourceSet.getCompileTaskName("scala")] - originalCompileTask.onlyIf { extension.runNormalCompilation.get() } + def originalJarTask = project.tasks[originalSourceSet.getJarTaskName()] def compileTask = project.tasks[instrumentedSourceSet.getCompileTaskName("scala")] compileTask.mustRunAfter(originalCompileTask) project.test.mustRunAfter(compileTask) + originalJarTask.mustRunAfter(compileTask) def reportTask = project.tasks.create(REPORT_NAME, ScoverageReport.class) { dependsOn compileTask, project.test @@ -136,33 +138,9 @@ class ScoveragePlugin implements Plugin { reportDir = extension.reportDir } - project.gradle.taskGraph.whenReady { graph -> - if (graph.hasTask(reportTask)) { - project.test.configure { - project.logger.debug("Adding instrumented classes to '${path}' classpath") - - classpath = project.configurations.scoverage + instrumentedSourceSet.output + classpath - - outputs.upToDateWhen { - extension.dataDir.get().listFiles(new FilenameFilter() { - @Override - boolean accept(File dir, String name) { - return name.startsWith("scoverage.measurements.") - } - }) - } - } - - if (!extension.runNormalCompilation.get()) { - project.sourceSets.getByName(SourceSet.TEST_SOURCE_SET_NAME) { - compileClasspath = instrumentedSourceSet.output + compileClasspath - } - } - } - } - project.afterEvaluate { + // define aggregation task if (project.childProjects.size() > 0) { def reportTasks = project.getAllprojects().collect { it.tasks.withType(ScoverageReport) } def aggregationTask = project.tasks.create(AGGREGATE_NAME, ScoverageAggregate.class) { @@ -179,15 +157,23 @@ class ScoveragePlugin implements Plugin { project.tasks[CHECK_NAME].mustRunAfter(aggregationTask) } - compileTask.configure { - if (extension.runNormalCompilation.get()) { - doFirst { - destinationDir.deleteDir() - } - } else { - destinationDir = originalCompileTask.destinationDir + // make this project's scoverage compilation depend on scoverage compilation of any other project + // which this project depends on its normal compilation + // (essential when running without normal compilation on multi-module projects with inner dependencies) + def originalCompilationDependencies = recursiveDependenciesOf(compileTask).findAll { + it instanceof ScalaCompile + } + originalCompilationDependencies.each { + def dependencyProjectCompileTask = it.project.tasks[COMPILE_NAME] + def dependencyProjectReportTask = it.project.tasks[REPORT_NAME] + if (dependencyProjectCompileTask != null) { + compileTask.dependsOn(dependencyProjectCompileTask) + // we don't want this project's test to affect the other project's report + project.test.mustRunAfter(dependencyProjectReportTask) } + } + compileTask.configure { File pluginFile = project.configurations[CONFIGURATION_NAME].find { it.name.startsWith("scalac-scoverage-plugin") } @@ -211,43 +197,70 @@ class ScoveragePlugin implements Plugin { scalaCompileOptions.additionalParameters = parameters // the compile task creates a store of measured statements outputs.file(new File(extension.dataDir.get(), 'scoverage.coverage.xml')) + } + } - if (extension.runNormalCompilation.get()) { - // delete non-instrumented classes by comparing normally compiled classes to those compiled with scoverage - doLast { - def originalCompileTaskName = project.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) - .getCompileTaskName("scala") - def originalDestinationDir = project.tasks[originalCompileTaskName].destinationDir - - def findFiles = { File dir, Closure condition = null -> - def files = [] - - if (dir.exists()) { - dir.eachFileRecurse(FILES) { f -> - if (condition == null || condition(f)) { - def relativePath = dir.relativePath(f) - files << relativePath - } - } + project.gradle.taskGraph.whenReady { graph -> + if (graph.hasTask(reportTask)) { + project.test.configure { + project.logger.debug("Adding instrumented classes to '${path}' classpath") + + classpath = project.configurations.scoverage + instrumentedSourceSet.output + classpath + + outputs.upToDateWhen { + extension.dataDir.get().listFiles(new FilenameFilter() { + @Override + boolean accept(File dir, String name) { + return name.startsWith("scoverage.measurements.") } + }) + } + } - return files + compileTask.configure { + if (!graph.hasTask(originalCompileTask)) { + destinationDir = originalCompileTask.destinationDir + } else { + doFirst { + destinationDir.deleteDir() } - def isSameFile = { String relativePath -> - def fileA = new File(originalDestinationDir, relativePath) - def fileB = new File(destinationDir, relativePath) - return FileUtils.contentEquals(fileA, fileB) - } + // delete non-instrumented classes by comparing normally compiled classes to those compiled with scoverage + doLast { + def originalCompileTaskName = project.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) + .getCompileTaskName("scala") + def originalDestinationDir = project.tasks[originalCompileTaskName].destinationDir + + def findFiles = { File dir, Closure condition = null -> + def files = [] + + if (dir.exists()) { + dir.eachFileRecurse(FILES) { f -> + if (condition == null || condition(f)) { + def relativePath = dir.relativePath(f) + files << relativePath + } + } + } - def originalClasses = findFiles(originalDestinationDir) - def identicalInstrumentedClasses = findFiles(destinationDir, { f -> - def relativePath = destinationDir.relativePath(f) - return originalClasses.contains(relativePath) && isSameFile(relativePath) - }) + return files + } + + def isSameFile = { String relativePath -> + def fileA = new File(originalDestinationDir, relativePath) + def fileB = new File(destinationDir, relativePath) + return FileUtils.contentEquals(fileA, fileB) + } - identicalInstrumentedClasses.each { f -> - Files.deleteIfExists(destinationDir.toPath().resolve(f)) + def originalClasses = findFiles(originalDestinationDir) + def identicalInstrumentedClasses = findFiles(destinationDir, { f -> + def relativePath = destinationDir.relativePath(f) + return originalClasses.contains(relativePath) && isSameFile(relativePath) + }) + + identicalInstrumentedClasses.each { f -> + Files.deleteIfExists(destinationDir.toPath().resolve(f)) + } } } } @@ -255,5 +268,10 @@ class ScoveragePlugin implements Plugin { } } + private Set recursiveDependenciesOf(Task task) { + def directDependencies = task.getTaskDependencies().getDependencies(task) + def nestedDependencies = directDependencies.collect {recursiveDependenciesOf(it) }.flatten() + return directDependencies + nestedDependencies + } } \ No newline at end of file From e5e0e90cdd39756be936e58d3f71517510d0a1cf Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Sun, 3 Feb 2019 16:30:47 +0200 Subject: [PATCH 042/167] Update README.md with release history and instructions on how to migrate to 3.x --- README.md | 63 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index c03c22c..278f371 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,12 @@ gradle-scoverage ================ A plugin to enable the use of Scoverage in a gradle Scala project. -Getting started ---------------- +Usage +----- -http://plugins.gradle.org/plugin/org.scoverage +You can find instructions on how to apply the plugin at: http://plugins.gradle.org/plugin/org.scoverage -Available tasks ---------------- +### Available tasks 1. `reportScoverage`: Produces XML and HTML reports for analysing test code coverage. @@ -29,8 +28,7 @@ Available tasks `gradle checkScoverage` will automatically invoke `reportScoverage` but it won't generate aggregated reports. In order to check coverage of aggregated reports one should use `gradle checkScoverage aggregateScoverage`. -Configuration -------------- +### Configuration The plugin exposes multiple options that can be configured by setting them in an `scoverage` block within the project's build script. These options are as follows: @@ -58,8 +56,7 @@ required for the validation to pass (otherwise `checkScoverage` will fail the bu `checkScoverage` task. For more information on the different types, please refer to the documentation of the scalac plugin (https://github.com/scoverage/scalac-scoverage-plugin). -Run without normal compilation ------------------------------- +### Run without normal compilation By default, running any of the plugin tasks will compile the code both using "normal" compilation (`compileScala`) and using the scoverage scalac plugin (`compileScoverageScala`). @@ -67,4 +64,50 @@ and using the scoverage scalac plugin (`compileScoverageScala`). In cases where you only wish to generate reports / validate coverage, but are not interested in publishing the code, it is possible to only compile the code with the scoverage scalac plugin, thus reducing build times significantly. In order to do so, simply add the arguments `-x compileScala` to the gradle execution. -For example: `gradle reportScoverage -x compileScala`. \ No newline at end of file +For example: `gradle reportScoverage -x compileScala`. + +Migration to 3.x +---------------- + +* No more `testScoverage` task; instead, `test` will run coverage whenever the build is invoked with any of the scoverage tasks. + +* No more need to declare scalac dependencies: +```groovy +// can safely delete this from build scripts +dependencies { + scoverage group: 'org.scoverage', name: 'scalac-scoverage-plugin_2.12', version: '1.3.1' + scoverage group: 'org.scoverage', name: 'scalac-scoverage-runtime_2.12', version: '1.3.1' +} +``` + +* All configurations are configured in `scoverage` block. For instance: +```groovy +// do this +scoverage { + minimumRate = 0.5 +} + +// instead of this +checkScoverage { + minimumRate = 0.5 +} +``` + +* No more need to declare aggregation task: +```groovy +// can safely delete this from build scripts +task aggregateScoverage(type: org.scoverage.ScoverageAggregate) +checkScoverage { + reportDir = file("$buildDir/scoverage-aggregate") +} +``` + +Release history +--------------- + +##### (not released yet) - 3.0.0 + +* Auto resolution of scalac plugin dependencies. +* Aggregation task declared by default. +* Deletion of non-instrumented classes, allowing for better integration with other coverage tools such as cobertura. +* Ability to execute coverage without "normal" compilation, thus reducing build times. \ No newline at end of file From ddf8dc4d94ffad3b32032f676e9b23405cf5ef87 Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 24 Feb 2019 20:08:58 +0000 Subject: [PATCH 043/167] annotate some input properties --- src/main/groovy/org/scoverage/OverallCheckTask.groovy | 4 ++++ src/main/groovy/org/scoverage/ScoverageAggregate.groovy | 6 ++++++ src/main/groovy/org/scoverage/ScoverageReport.groovy | 4 ++++ 3 files changed, 14 insertions(+) diff --git a/src/main/groovy/org/scoverage/OverallCheckTask.groovy b/src/main/groovy/org/scoverage/OverallCheckTask.groovy index e56822a..a9f9cb5 100644 --- a/src/main/groovy/org/scoverage/OverallCheckTask.groovy +++ b/src/main/groovy/org/scoverage/OverallCheckTask.groovy @@ -4,6 +4,7 @@ import org.gradle.api.DefaultTask import org.gradle.api.GradleException import org.gradle.api.provider.Property import org.gradle.api.tasks.CacheableTask +import org.gradle.api.tasks.Input import org.gradle.api.tasks.TaskAction import org.gradle.internal.impldep.com.google.common.annotations.VisibleForTesting @@ -44,9 +45,12 @@ enum CoverageType { class OverallCheckTask extends DefaultTask { /** Type of coverage to check. Available options: Line, Statement and Branch */ + @Input final Property coverageType = project.objects.property(CoverageType) + @Input final Property minimumRate = project.objects.property(BigDecimal) + @Input final Property reportDir = project.objects.property(File) /** Overwrite to test for a specific locale. */ diff --git a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy index 4094476..43abd73 100644 --- a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy +++ b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy @@ -2,6 +2,7 @@ package org.scoverage import org.gradle.api.DefaultTask import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction import scoverage.report.CoverageAggregator @@ -13,12 +14,17 @@ class ScoverageAggregate extends DefaultTask { @OutputDirectory final Property reportDir = project.objects.property(File) + @Input final Property deleteReportsOnAggregation = project.objects.property(Boolean) // TODO - consider separate options for `report` and `aggregate` tasks + @Input final Property coverageOutputCobertura = project.objects.property(Boolean) + @Input final Property coverageOutputXML = project.objects.property(Boolean) + @Input final Property coverageOutputHTML = project.objects.property(Boolean) + @Input final Property coverageDebug = project.objects.property(Boolean) @TaskAction diff --git a/src/main/groovy/org/scoverage/ScoverageReport.groovy b/src/main/groovy/org/scoverage/ScoverageReport.groovy index ed2d6db..e0d1d8b 100644 --- a/src/main/groovy/org/scoverage/ScoverageReport.groovy +++ b/src/main/groovy/org/scoverage/ScoverageReport.groovy @@ -26,9 +26,13 @@ class ScoverageReport extends DefaultTask { @OutputDirectory final Property reportDir = project.objects.property(File) + @Input final Property coverageOutputCobertura = project.objects.property(Boolean) + @Input final Property coverageOutputXML = project.objects.property(Boolean) + @Input final Property coverageOutputHTML = project.objects.property(Boolean) + @Input final Property coverageDebug = project.objects.property(Boolean) @TaskAction From 4bc47412f40a260c3d929935e1626fc9be5d9ea7 Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 24 Feb 2019 20:33:36 +0000 Subject: [PATCH 044/167] make locale an input property --- src/main/groovy/org/scoverage/OverallCheckTask.groovy | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/groovy/org/scoverage/OverallCheckTask.groovy b/src/main/groovy/org/scoverage/OverallCheckTask.groovy index a9f9cb5..6c3687f 100644 --- a/src/main/groovy/org/scoverage/OverallCheckTask.groovy +++ b/src/main/groovy/org/scoverage/OverallCheckTask.groovy @@ -1,5 +1,6 @@ package org.scoverage +import org.apache.tools.ant.taskdefs.Local import org.gradle.api.DefaultTask import org.gradle.api.GradleException import org.gradle.api.provider.Property @@ -54,11 +55,12 @@ class OverallCheckTask extends DefaultTask { final Property reportDir = project.objects.property(File) /** Overwrite to test for a specific locale. */ - Locale locale + @Input + final Property locale = project.objects.property(Locale).value(Locale.getDefault()) @TaskAction void requireLineCoverage() { - NumberFormat nf = NumberFormat.getInstance(locale == null ? Locale.getDefault() : locale) + NumberFormat nf = NumberFormat.getInstance(locale.get()) Exception failure = checkLineCoverage(nf, reportDir.get(), coverageType.get(), minimumRate.get().doubleValue()) From f23360f9a56d36b52a90f2e08df346776e22ea47 Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 24 Feb 2019 21:32:00 +0000 Subject: [PATCH 045/167] bump project version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b9fe523..361e128 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ repositories { group 'org.scoverage' description = 'gradle-scoverage is a Gradle plugin for calculating code coverage using Scoverage' -version = '2.0.0-SNAPSHOT' +version = '3.0.0-SNAPSHOT' ext { website = 'http://scoverage.org' From 0423eaa02dc68f60c5049e35b4d680d6477404ba Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 24 Feb 2019 22:52:22 +0000 Subject: [PATCH 046/167] allow version control from command line --- build.gradle | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 361e128..848d11e 100644 --- a/build.gradle +++ b/build.gradle @@ -10,8 +10,9 @@ repositories { group 'org.scoverage' description = 'gradle-scoverage is a Gradle plugin for calculating code coverage using Scoverage' -version = '3.0.0-SNAPSHOT' - +if (project.version == 'unspecified') { + version = '3.0.0-SNAPSHOT' +} ext { website = 'http://scoverage.org' vcsUrl = 'https://github.com/scoverage/gradle-scoverage.git' From f825409bb41ca1dddb2d350ad6ae12e010d057f6 Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 24 Feb 2019 22:57:22 +0000 Subject: [PATCH 047/167] fix publish configuration --- build.gradle | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 848d11e..56c261c 100644 --- a/build.gradle +++ b/build.gradle @@ -26,6 +26,7 @@ gradlePlugin { gradleScoverage { id = 'org.scoverage' implementationClass = 'org.scoverage.ScoveragePlugin' + displayName = 'Gradle Scoverage plugin' } } } @@ -35,11 +36,6 @@ pluginBundle { vcsUrl = ext.vcsUrl description = project.description tags = ['coverage', 'scala', 'scoverage'] - plugins { - scoveragePlugin { - displayName = 'Gradle Scoverage plugin' - } - } } apply plugin: 'maven' From fbddd9c879679e5b44a36fe9393d077201b1349f Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 24 Feb 2019 22:59:58 +0000 Subject: [PATCH 048/167] release history held on the github releases page --- README.md | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/README.md b/README.md index 278f371..ab37492 100644 --- a/README.md +++ b/README.md @@ -100,14 +100,4 @@ task aggregateScoverage(type: org.scoverage.ScoverageAggregate) checkScoverage { reportDir = file("$buildDir/scoverage-aggregate") } -``` - -Release history ---------------- - -##### (not released yet) - 3.0.0 - -* Auto resolution of scalac plugin dependencies. -* Aggregation task declared by default. -* Deletion of non-instrumented classes, allowing for better integration with other coverage tools such as cobertura. -* Ability to execute coverage without "normal" compilation, thus reducing build times. \ No newline at end of file +``` \ No newline at end of file From b620bb927df04571bdd2b29e2eff232fb8a32833 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Mon, 25 Feb 2019 17:09:32 +0200 Subject: [PATCH 049/167] Fix README typo --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index ab37492..9cd27b1 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ You can find instructions on how to apply the plugin at: http://plugins.gradle. One can still use `reportScoverage` in order to generate a report without aggregation. -3. `checkScoverage`: Validates coverage according status according the generated reports (aggregated or not). +3. `checkScoverage`: Validates coverage status according to generated reports (aggregated or not). `gradle checkScoverage` will automatically invoke `reportScoverage` but it won't generate aggregated reports. In order to check coverage of aggregated reports one should use `gradle checkScoverage aggregateScoverage`. @@ -33,8 +33,6 @@ You can find instructions on how to apply the plugin at: http://plugins.gradle. The plugin exposes multiple options that can be configured by setting them in an `scoverage` block within the project's build script. These options are as follows: -You can configure the version of Scoverage that will be used. This plugin should - * `scoverageVersion = ` (default `"1.3.1"`): The version of the scoverage scalac plugin. This (gradle) plugin should be compatible with all 1+ versions. From 5366cef6221938e739e6ab6c0037c37723314487 Mon Sep 17 00:00:00 2001 From: Stu Date: Tue, 26 Mar 2019 21:35:18 +0000 Subject: [PATCH 050/167] bump to gradle 5.3 --- gradle/wrapper/gradle-wrapper.jar | Bin 51106 -> 55741 bytes gradle/wrapper/gradle-wrapper.properties | 5 +- gradlew | 78 +++++++++++++---------- gradlew.bat | 14 ++-- 4 files changed, 49 insertions(+), 48 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 3c7abdf12790879c06b07176de29647f77aa4129..457aad0d98108420a977756b7145c93c8910b076 100644 GIT binary patch literal 55741 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 O(FVj@M23F*_WuFL)$*MH literal 51106 zcmaI7W0WY}vL#x!ZQHhO+qP}n*k#+cZEKfpo4fG#edqLj{oOwOa^%X9KO#r26&WjH zM$AYBXBtf-10t)!e7Jura6KLkU%-1qtZ3aI`a zDF3^lte~8vn5eP}ovhfS?DUk3G%ei%tTZjv?DSld62mg{-togU?YQKO>ps_JDL96SJbfqAPy~@qd0q#NOS`#@^6`gptnJ#?aZ>H%1m} zkO3id*Me1x+KoO4dNnL}0N;U-jz`c&*alKkva%-&8h)=}7{&3D=Y$t;+NbXI5RyQ6 zuph%n$fuP(ZOXTT)UdOqW$sXd7KfwhPf!C)DKV+T=Mo0_;3_m<}2-cMr z*Y|&DIbQoI4(;#vclfK~|FVVu((=DG_`lTh-)mI%bapYdRdBNZt1K5wQ|G^T9-e}( zE*7SCE|$iIF7{6UQbLKctv!+;f*%@1_}Ichg+Wcq#&0i`<0$(D11!kV;gEE)6|yjR zGiYoM=N@A3=wJRN`Zh(8{QdZ**`Spml8pC!SJSi1bJI;t-u!-kUvT*`V`PgI>GcW> z^{Ioh$d_vphRmU+*E>uNp_^m}4lp*@?L!GZC!o0-rV-pDz+ob^HjrT@o#+v(Jw?KV zyLZBQL~gt`PCo(C^0#9HAr~HqLm%G+N(UD5VY-AVLr&V|yi}|3rq)1@g8_y^l)w4! z;|#VbCf@aWr9~ zaZ5T&YWW^EB_x1fX@2c3;(h|owqva`DzrM_!@GosgW)k=eeXJ8I`yf_0al&L1rTzR zeDGLw74gAX`pOsC0f*6+@g)`(qc>BJ^a;brn~{7IvvT7SBT`knwpU9{NQw+nvRT2r zW71-=`fgL7;vic;rD@LV<1qSGJw>EioF3#a}*Vp!`J)v8ehve6;T z5`cSW?2uB7J?)*atZ&t8ls{pF9>nhM3;lXx~z9Y-m7Z)0VdT z#qhhZ2UQ1uQ7!zP-65k|Ru4;5Cn&PYBvJMY=%3!?^h(3I@~^#Z{vAaB+3qC&m*M@( zszhT4{%$Rpu%GGk6BNX5D7|N+`|c_zU_pf^y*4H`DeemwzASM3{%|Dj6ikSTw9ofP zpKW{qv@`EBF9-;~LTXZ0d5Gk5vQzchUli+x=%MyAj-E`qVDf!rD}?nRx51~?RBkd)urL7%19Lm0!Vq2P{>-kE)z|gPxT%W zE33sZz9(^3-XSIG@!+nBjv4n}=acE_TYi2&AdSJwAjRnkkHS65T*(MZ2m?JaowrB? zv3i32j-Uj99t1B%F(nJxL1{>7m}Kpbmk&WI{f&uQ`;wYGYLyM&b>|8@{&><_QgTBz!S7<(#cC(Gr*Te$; zTnYvdwj3zZm|~f%TXyU4tr_faG<07M(;+I1TFOs1hCSR2*f5bv$11HARw}erzAmwz zSzX(*V?37juFGYQNk_R%S1aH44McN{Sn^NW%(zxtt!#z|t#vE+lB4WW?GvLw!i{KV z$|O}0204v)n&oOU+bUrVzSI zRUXmq%XO(w&{ZDs@Gy_=IN+{#eG(sc>1jQ23OCjJ_gF&)Dc+c?gjlyRglK)fq)0t> z6CU&gIgSZu?Y>fB7BjUBG&_-vya0{@xrgBxH)Gz*qcqzeie9*15mA;&s3RDbgUQ?C z{wRm+p9F*%9KuP-C<_wIi@?z62Kw3w6cYy29C6?zs`vqvJS4b-EO;%+@>(WOEJMC& zXY@B;L0+K(iRECuA;D=0T*8BIV4CTxp+q7uL~0RkF!7SJ1YsSQgGgu;WG|#k7k#y9 zl-fSZ>JX^(`61vH-<->L2$9Y({^2w)gLYS>LQbWsZZGuzG}BE9Q7TX{004!*ag_N# zo2jUWv5l*5lhK&inT+eJ!vD0DhR_U*pGKph-&whzr>tS^&@* zx+5lqw{=>@6AAysOHPvOz=1ym=>+1y9IjxHDyc^)8}a}$A9Pv49n~xcd;&>K4eJrK zSgfXxae6{G2Jpf-Wxxm^Bo!WEFa%A2+>;C}sUV&h+K!d2_}ac6!@|yzgZNc4TQOv{ zr7-jD(PeyT=AR=VxyaNMXT_CMnYaWZ6vtPr$yvrpO^^waYC3 zbA?I~#mcJc3iXzxMh`2k+*#3b6z0X!C49}uf;lHuC01s2`H+qNkqwxmcR)FH6aTtt zRaY<~Zo`_qaP{{6Xi1#565b-VJ&(0$Nt

CflOl1i4(-2^1KXo)&I5QlgjRKFQgM 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 z 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%0DvTus6fLI&f~`9YxjD=W5pR41LBYQt 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 47e24fa..e4eb7ca 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,6 @@ -#Mon Jun 16 21:08:06 BST 2014 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionSha256Sum=f4d820c2a9685710eba5b92f10e0e4fb20e0d6c0dd1f46971e658160f25e7147 +distributionUrl=https\://services.gradle.org/distributions/gradle-5.3-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-5.0-all.zip -distributionSha256Sum=17847c8e12b2bcfce26a79f425f082c31d4ded822f99a66127eee2d96bf18216 \ No newline at end of file diff --git a/gradlew b/gradlew index 91a7e26..af6708f 100755 --- a/gradlew +++ b/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ############################################################################## ## @@ -6,20 +6,38 @@ ## ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m"' + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -30,6 +48,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,31 +59,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -90,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -114,6 +113,7 @@ fi if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` @@ -154,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index aec9973..0f8d593 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,10 +46,9 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windowz variants +@rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. @@ -60,11 +59,6 @@ set _SKIP=2 if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ :execute @rem Setup the command line From 1ae3bc3ab17e9e8b60a57fff682768967ba9a251 Mon Sep 17 00:00:00 2001 From: Todor Petrov Date: Sun, 19 May 2019 00:03:17 +0300 Subject: [PATCH 051/167] Two performance fixes without which the build takes minutes in the configuration phase for multi-module projects with a lot of cross-references. 1. Loads the plugin just one time, instead of loading separately for each module. Debug logging showed that sometimes, this operations takes 10 sec (on some machines at least). 2. The more critical issue was in `recursiveDependenciesOf`. Without caching of the results, the same operations are repeated over and over again and it takes minutes to configure. For a work project I have, with 16 modules, with a lot of cross-references, adding the scoverage plugin without these fixes takes 5-10 mins. The worst of it is that this is the wait time for each change in any build.gradle (e.g. adding a new dependency), which makes the work nearly impossible. After applying the fixes, there is no significant difference with the time taken without the scoverage plugin. --- .../org/scoverage/ScoveragePlugin.groovy | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 7c6ac63..62e3562 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -10,6 +10,7 @@ import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.scala.ScalaCompile import java.nio.file.Files +import java.util.concurrent.ConcurrentHashMap import static groovy.io.FileType.FILES @@ -23,6 +24,9 @@ class ScoveragePlugin implements Plugin { static final String DEFAULT_REPORT_DIR = 'reports' + File.separatorChar + 'scoverage' + private volatile File pluginFile = null + private ConcurrentHashMap> taskDependencies = new ConcurrentHashMap<>(); + @Override void apply(PluginAware pluginAware) { if (pluginAware instanceof Project) { @@ -174,9 +178,12 @@ class ScoveragePlugin implements Plugin { } compileTask.configure { - File pluginFile = project.configurations[CONFIGURATION_NAME].find { - it.name.startsWith("scalac-scoverage-plugin") + if (pluginFile == null) { + pluginFile = project.configurations[CONFIGURATION_NAME].find { + it.name.startsWith("scalac-scoverage-plugin") + } } + List parameters = ['-Xplugin:' + pluginFile.absolutePath] List existingParameters = scalaCompileOptions.additionalParameters if (existingParameters) { @@ -269,9 +276,15 @@ class ScoveragePlugin implements Plugin { } private Set recursiveDependenciesOf(Task task) { + if (!taskDependencies.containsKey(task)) { + def directDependencies = task.getTaskDependencies().getDependencies(task) + def nestedDependencies = directDependencies.collect {recursiveDependenciesOf(it) }.flatten() + def dependencies = directDependencies + nestedDependencies - def directDependencies = task.getTaskDependencies().getDependencies(task) - def nestedDependencies = directDependencies.collect {recursiveDependenciesOf(it) }.flatten() - return directDependencies + nestedDependencies + taskDependencies.put(task, dependencies) + return dependencies + } else { + return taskDependencies.get(task) + } } } \ No newline at end of file From a52ea72ae599c83495e2c8a50a8deac52e96741a Mon Sep 17 00:00:00 2001 From: Oleksii Lisikh Date: Sun, 19 May 2019 16:40:20 +0200 Subject: [PATCH 052/167] Removed choice of which test tasks to include into code coverage --- build.gradle | 4 +- ...SingleModuleWithMultipleTestTasksTest.java | 32 +++ .../build.gradle | 71 +++++++ .../settings.gradle | 0 .../scala/org/hello/WordIntSuite.scala | 13 ++ .../src/main/scala/org/hello/World.scala | 11 ++ .../src/test/scala/org/hello/WorldSuite.scala | 13 ++ .../org/scoverage/OverallCheckTask.groovy | 7 +- .../org/scoverage/ScoveragePlugin.groovy | 184 ++++++++++-------- 9 files changed, 253 insertions(+), 82 deletions(-) create mode 100644 src/functionalTest/java/org.scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java create mode 100644 src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle create mode 100644 src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/settings.gradle create mode 100644 src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/intTest/scala/org/hello/WordIntSuite.scala create mode 100644 src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/main/scala/org/hello/World.scala create mode 100644 src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/test/scala/org/hello/WorldSuite.scala diff --git a/build.gradle b/build.gradle index 56c261c..0cebe0f 100644 --- a/build.gradle +++ b/build.gradle @@ -41,8 +41,8 @@ pluginBundle { apply plugin: 'maven' apply plugin: 'groovy' -sourceCompatibility = '1.6' -targetCompatibility = '1.6' +sourceCompatibility = '1.8' +targetCompatibility = '1.8' dependencies { compileOnly "org.scoverage:scalac-scoverage-plugin_2.12:1.3.1" diff --git a/src/functionalTest/java/org.scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java b/src/functionalTest/java/org.scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java new file mode 100644 index 0000000..40aeeca --- /dev/null +++ b/src/functionalTest/java/org.scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java @@ -0,0 +1,32 @@ +package org.scoverage; + +import org.junit.Assert; +import org.junit.Test; + +public class ScalaSingleModuleWithMultipleTestTasksTest extends ScoverageFunctionalTest { + public ScalaSingleModuleWithMultipleTestTasksTest() { + super("scala-single-module-multiple-test-tasks"); + } + + @Test + public void checkScoverage() throws Exception { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME()); + + result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded("reportTestScoverage"); + result.assertTaskSucceeded("reportIntTestScoverage"); + result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + + assertReportFilesExist(); + assertCoverage(100.0); + } + + private void assertReportFilesExist() { + + Assert.assertTrue(resolve(reportDir(), "index.html").exists()); + Assert.assertTrue(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + } +} diff --git a/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle new file mode 100644 index 0000000..819a07d --- /dev/null +++ b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle @@ -0,0 +1,71 @@ +plugins { + id 'io.spring.dependency-management' version "1.0.4.RELEASE" + id 'org.scoverage' +} + +repositories { + jcenter() +} + +description = 'a single-module Scala project with dependency manager that builds successfully with 100% coverage' + +apply plugin: 'scala' + + +dependencyManagement { + dependencies { + dependency group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + } +} + +dependencies { + compile group: 'org.scala-lang', name: 'scala-library' + + // scala compilation with the dependency management plugin needs this (otherwise compilation will fail) + zinc group: 'com.typesafe.zinc', name: 'zinc', version: '0.3.15' + zinc group: 'org.scala-lang', name: 'scala-library', version: '2.10.5' + + testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion +} + +test { + useJUnitPlatform() +} + + +configurations { + intTestCompile.extendsFrom testCompile + intTestRuntime.extendsFrom testRuntime +} +sourceSets { + intTest { + resources.srcDir file('src/intTest/resources') + scala { + compileClasspath += main.output + test.output + runtimeClasspath += main.output + test.output + srcDir file("${projectDir}/src/intTest/scala") + } + } +} + +test { + maxParallelForks = 1 +} + +task intTest(type: Test) { + testClassesDirs = sourceSets.intTest.output.classesDirs + classpath = sourceSets.intTest.runtimeClasspath + outputs.upToDateWhen { false } + + maxParallelForks = 1 +} +check.dependsOn(intTest) +intTest.mustRunAfter(test) + +scoverage { + minimumRate = 0.3 +} + diff --git a/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/settings.gradle b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/settings.gradle new file mode 100644 index 0000000..e69de29 diff --git a/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/intTest/scala/org/hello/WordIntSuite.scala b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/intTest/scala/org/hello/WordIntSuite.scala new file mode 100644 index 0000000..ebf99bf --- /dev/null +++ b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/intTest/scala/org/hello/WordIntSuite.scala @@ -0,0 +1,13 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldIntSuite extends FunSuite { + + test("bar") { + new World().bar + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/main/scala/org/hello/World.scala b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/main/scala/org/hello/World.scala new file mode 100644 index 0000000..5e75836 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/main/scala/org/hello/World.scala @@ -0,0 +1,11 @@ +package org.hello + +class World { + + def foo: String = { + val s = "a" + "b" + s + } + + def bar: String = "bar" +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/test/scala/org/hello/WorldSuite.scala b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/test/scala/org/hello/WorldSuite.scala new file mode 100644 index 0000000..442f00f --- /dev/null +++ b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/test/scala/org/hello/WorldSuite.scala @@ -0,0 +1,13 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldSuite extends FunSuite { + + test("foo") { + new World().foo + } +} \ No newline at end of file diff --git a/src/main/groovy/org/scoverage/OverallCheckTask.groovy b/src/main/groovy/org/scoverage/OverallCheckTask.groovy index 6c3687f..da83c12 100644 --- a/src/main/groovy/org/scoverage/OverallCheckTask.groovy +++ b/src/main/groovy/org/scoverage/OverallCheckTask.groovy @@ -1,6 +1,5 @@ package org.scoverage -import org.apache.tools.ant.taskdefs.Local import org.gradle.api.DefaultTask import org.gradle.api.GradleException import org.gradle.api.provider.Property @@ -69,12 +68,12 @@ class OverallCheckTask extends DefaultTask { @VisibleForTesting protected static String errorMsg(String actual, String expected, CoverageType type) { - return "Only $actual% of project is covered by tests instead of $expected% (coverageType: $type)" + "Only $actual% of project is covered by tests instead of $expected% (coverageType: $type)" } @VisibleForTesting protected static String fileNotFoundErrorMsg(CoverageType coverageType) { - return "Coverage file (type: $coverageType) not found, check your configuration." + "Coverage file (type: $coverageType) not found, check your configuration." } @VisibleForTesting @@ -100,6 +99,6 @@ class OverallCheckTask extends DefaultTask { } catch (FileNotFoundException fnfe) { return new GradleException(fileNotFoundErrorMsg(coverageType), fnfe) } - return null + null } } diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 7c6ac63..5981f99 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -8,6 +8,7 @@ import org.gradle.api.invocation.Gradle import org.gradle.api.plugins.PluginAware import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.scala.ScalaCompile +import org.gradle.api.tasks.testing.Test import java.nio.file.Files @@ -112,39 +113,66 @@ class ScoveragePlugin implements Plugin { def compileTask = project.tasks[instrumentedSourceSet.getCompileTaskName("scala")] compileTask.mustRunAfter(originalCompileTask) - project.test.mustRunAfter(compileTask) originalJarTask.mustRunAfter(compileTask) - def reportTask = project.tasks.create(REPORT_NAME, ScoverageReport.class) { - dependsOn compileTask, project.test - onlyIf { extension.dataDir.get().list() } - group = 'verification' - runner = scoverageRunner - reportDir = extension.reportDir - sources = extension.sources - dataDir = extension.dataDir - coverageOutputCobertura = extension.coverageOutputCobertura - coverageOutputXML = extension.coverageOutputXML - coverageOutputHTML = extension.coverageOutputHTML - coverageDebug = extension.coverageDebug - } - - project.tasks.create(CHECK_NAME, OverallCheckTask.class) { - dependsOn(reportTask) - onlyIf { extension.reportDir.get().list() } - group = 'verification' - coverageType = extension.coverageType - minimumRate = extension.minimumRate - reportDir = extension.reportDir - } + def globalReportTask = project.tasks.register(REPORT_NAME, ScoverageAggregate) + def globalCheckTask = project.tasks.register(CHECK_NAME, OverallCheckTask) project.afterEvaluate { + List reportTasks = project.tasks.withType(Test).collect { testTask -> + testTask.mustRunAfter(compileTask) + + def reportTaskName = "report${testTask.name.capitalize()}Scoverage" + def taskReportDir = project.file("${project.buildDir}/reports/scoverage${testTask.name.capitalize()}") + + project.tasks.create(reportTaskName, ScoverageReport) { + dependsOn compileTask, testTask + onlyIf { extension.dataDir.get().list() } + group = 'verification' + runner = scoverageRunner + reportDir = taskReportDir + sources = extension.sources + dataDir = extension.dataDir + coverageOutputCobertura = extension.coverageOutputCobertura + coverageOutputXML = extension.coverageOutputXML + coverageOutputHTML = extension.coverageOutputHTML + coverageDebug = extension.coverageDebug + } + } + + globalReportTask.configure { + dependsOn reportTasks + onlyIf { reportTasks.any { it.reportDir.get().list() } } + group = 'verification' + runner = scoverageRunner + reportDir = extension.reportDir + deleteReportsOnAggregation = extension.deleteReportsOnAggregation + coverageOutputCobertura = extension.coverageOutputCobertura + coverageOutputXML = extension.coverageOutputXML + coverageOutputHTML = extension.coverageOutputHTML + coverageDebug = extension.coverageDebug + } + + + globalCheckTask.configure { + dependsOn globalReportTask + + onlyIf { extension.reportDir.get().list() } + group = 'verification' + coverageType = extension.coverageType + minimumRate = extension.minimumRate + reportDir = extension.reportDir + } // define aggregation task if (project.childProjects.size() > 0) { - def reportTasks = project.getAllprojects().collect { it.tasks.withType(ScoverageReport) } + def allReportTasks = project.getAllprojects().findResults { + it.tasks.find { task -> + task.name == REPORT_NAME && task instanceof ScoverageAggregate + } + } def aggregationTask = project.tasks.create(AGGREGATE_NAME, ScoverageAggregate.class) { - dependsOn(reportTasks) + dependsOn(allReportTasks) group = 'verification' runner = scoverageRunner reportDir = extension.reportDir @@ -198,68 +226,72 @@ class ScoveragePlugin implements Plugin { // the compile task creates a store of measured statements outputs.file(new File(extension.dataDir.get(), 'scoverage.coverage.xml')) } - } - project.gradle.taskGraph.whenReady { graph -> - if (graph.hasTask(reportTask)) { - project.test.configure { - project.logger.debug("Adding instrumented classes to '${path}' classpath") + project.gradle.taskGraph.whenReady { graph -> + def hasAnyReportTask = reportTasks.any { graph.hasTask(it) } - classpath = project.configurations.scoverage + instrumentedSourceSet.output + classpath + if (hasAnyReportTask) { + project.tasks.withType(Test).each { testTask -> + testTask.configure { + project.logger.info("Adding instrumented classes to '${path}' classpath") - outputs.upToDateWhen { - extension.dataDir.get().listFiles(new FilenameFilter() { - @Override - boolean accept(File dir, String name) { - return name.startsWith("scoverage.measurements.") - } - }) - } - } + classpath = project.configurations.scoverage + instrumentedSourceSet.output + classpath - compileTask.configure { - if (!graph.hasTask(originalCompileTask)) { - destinationDir = originalCompileTask.destinationDir - } else { - doFirst { - destinationDir.deleteDir() + outputs.upToDateWhen { + extension.dataDir.get().listFiles(new FilenameFilter() { + @Override + boolean accept(File dir, String name) { + name.startsWith("scoverage.measurements.") + } + }) + } } + } - // delete non-instrumented classes by comparing normally compiled classes to those compiled with scoverage - doLast { - def originalCompileTaskName = project.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) - .getCompileTaskName("scala") - def originalDestinationDir = project.tasks[originalCompileTaskName].destinationDir - - def findFiles = { File dir, Closure condition = null -> - def files = [] + compileTask.configure { + if (!graph.hasTask(originalCompileTask)) { + destinationDir = originalCompileTask.destinationDir + } else { + doFirst { + destinationDir.deleteDir() + } - if (dir.exists()) { - dir.eachFileRecurse(FILES) { f -> - if (condition == null || condition(f)) { - def relativePath = dir.relativePath(f) - files << relativePath + // delete non-instrumented classes by comparing normally compiled classes to those compiled with scoverage + doLast { + def originalCompileTaskName = project.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) + .getCompileTaskName("scala") + def originalDestinationDir = project.tasks[originalCompileTaskName].destinationDir + + def findFiles = { File dir, Closure condition = null -> + def files = [] + + if (dir.exists()) { + dir.eachFileRecurse(FILES) { f -> + if (condition == null || condition(f)) { + def relativePath = dir.relativePath(f) + files << relativePath + } } } - } - return files - } + files + } - def isSameFile = { String relativePath -> - def fileA = new File(originalDestinationDir, relativePath) - def fileB = new File(destinationDir, relativePath) - return FileUtils.contentEquals(fileA, fileB) - } + def isSameFile = { String relativePath -> + def fileA = new File(originalDestinationDir, relativePath) + def fileB = new File(destinationDir, relativePath) + FileUtils.contentEquals(fileA, fileB) + } - def originalClasses = findFiles(originalDestinationDir) - def identicalInstrumentedClasses = findFiles(destinationDir, { f -> - def relativePath = destinationDir.relativePath(f) - return originalClasses.contains(relativePath) && isSameFile(relativePath) - }) + def originalClasses = findFiles(originalDestinationDir) + def identicalInstrumentedClasses = findFiles(destinationDir, { f -> + def relativePath = destinationDir.relativePath(f) + originalClasses.contains(relativePath) && isSameFile(relativePath) + }) - identicalInstrumentedClasses.each { f -> - Files.deleteIfExists(destinationDir.toPath().resolve(f)) + identicalInstrumentedClasses.each { f -> + Files.deleteIfExists(destinationDir.toPath().resolve(f)) + } } } } @@ -271,7 +303,7 @@ class ScoveragePlugin implements Plugin { private Set recursiveDependenciesOf(Task task) { def directDependencies = task.getTaskDependencies().getDependencies(task) - def nestedDependencies = directDependencies.collect {recursiveDependenciesOf(it) }.flatten() - return directDependencies + nestedDependencies + def nestedDependencies = directDependencies.collect { recursiveDependenciesOf(it) }.flatten() + directDependencies + nestedDependencies } } \ No newline at end of file From 7e7e792a84920473292c8a0b9197ea16aa7f4eea Mon Sep 17 00:00:00 2001 From: Todor Petrov Date: Mon, 20 May 2019 12:56:00 +0300 Subject: [PATCH 053/167] Made the task dependencies cache final. --- src/main/groovy/org/scoverage/ScoveragePlugin.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 62e3562..b72a130 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -25,7 +25,7 @@ class ScoveragePlugin implements Plugin { static final String DEFAULT_REPORT_DIR = 'reports' + File.separatorChar + 'scoverage' private volatile File pluginFile = null - private ConcurrentHashMap> taskDependencies = new ConcurrentHashMap<>(); + private final ConcurrentHashMap> taskDependencies = new ConcurrentHashMap<>(); @Override void apply(PluginAware pluginAware) { From 0484592adccff206dd6ca32d9bd7990eb10449cd Mon Sep 17 00:00:00 2001 From: Oleksii Lisikh Date: Tue, 21 May 2019 23:01:26 +0200 Subject: [PATCH 054/167] Fixed cross-project dependencies between compilation task and test tasks --- .../groovy/org/scoverage/ScoveragePlugin.groovy | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 5981f99..f01043a 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -119,7 +119,9 @@ class ScoveragePlugin implements Plugin { def globalCheckTask = project.tasks.register(CHECK_NAME, OverallCheckTask) project.afterEvaluate { - List reportTasks = project.tasks.withType(Test).collect { testTask -> + def testTasks = project.tasks.withType(Test) + + List reportTasks = testTasks.collect { testTask -> testTask.mustRunAfter(compileTask) def reportTaskName = "report${testTask.name.capitalize()}Scoverage" @@ -171,7 +173,8 @@ class ScoveragePlugin implements Plugin { task.name == REPORT_NAME && task instanceof ScoverageAggregate } } - def aggregationTask = project.tasks.create(AGGREGATE_NAME, ScoverageAggregate.class) { + + def aggregationTask = project.tasks.create(AGGREGATE_NAME, ScoverageAggregate) { dependsOn(allReportTasks) group = 'verification' runner = scoverageRunner @@ -196,8 +199,10 @@ class ScoveragePlugin implements Plugin { def dependencyProjectReportTask = it.project.tasks[REPORT_NAME] if (dependencyProjectCompileTask != null) { compileTask.dependsOn(dependencyProjectCompileTask) - // we don't want this project's test to affect the other project's report - project.test.mustRunAfter(dependencyProjectReportTask) + // we don't want this project's tests to affect the other project's report + testTasks.each { + it.mustRunAfter(dependencyProjectReportTask) + } } } From 0e75f253a6958173a65f0da1e16a93d4a8068c7e Mon Sep 17 00:00:00 2001 From: Oleksii Lisikh Date: Wed, 22 May 2019 00:00:39 +0200 Subject: [PATCH 055/167] Fixed issue when reports were aggregated improperly --- .../org/scoverage/ScoverageAggregate.groovy | 20 ++++++++++++++++++- .../org/scoverage/ScoveragePlugin.groovy | 8 ++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy index 43abd73..89de7de 100644 --- a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy +++ b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy @@ -1,10 +1,13 @@ package org.scoverage import org.gradle.api.DefaultTask +import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.Input import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction +import scala.collection.JavaConverters +import scoverage.IOUtils import scoverage.report.CoverageAggregator class ScoverageAggregate extends DefaultTask { @@ -14,6 +17,9 @@ class ScoverageAggregate extends DefaultTask { @OutputDirectory final Property reportDir = project.objects.property(File) + @Input + final ListProperty dirsToAggregateFrom = project.objects.listProperty(File) + @Input final Property deleteReportsOnAggregation = project.objects.property(Boolean) @@ -27,12 +33,24 @@ class ScoverageAggregate extends DefaultTask { @Input final Property coverageDebug = project.objects.property(Boolean) + ScoverageAggregate() { + dirsToAggregateFrom.set([]) + } + @TaskAction def aggregate() { runner.run { def rootDir = project.projectDir - def coverage = CoverageAggregator.aggregate(rootDir, deleteReportsOnAggregation.get()) + def coverage + if (dirsToAggregateFrom.get().isEmpty()) { + coverage = CoverageAggregator.aggregate(rootDir, deleteReportsOnAggregation.get()) + } else { + def reportFiles = dirsToAggregateFrom.get().collectMany { + JavaConverters.seqAsJavaList(IOUtils.reportFileSearch(it, IOUtils.isReportFile())) + } + coverage = CoverageAggregator.aggregate(JavaConverters.asScalaBuffer(reportFiles), deleteReportsOnAggregation.get()) + } reportDir.get().deleteDir() diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index f01043a..6f04391 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -143,12 +143,16 @@ class ScoveragePlugin implements Plugin { } globalReportTask.configure { + def reportDirs = reportTasks.findResults { it.reportDir.get() } + dependsOn reportTasks - onlyIf { reportTasks.any { it.reportDir.get().list() } } + onlyIf { reportDirs.any { it.list() } } + group = 'verification' runner = scoverageRunner reportDir = extension.reportDir - deleteReportsOnAggregation = extension.deleteReportsOnAggregation + dirsToAggregateFrom = reportDirs + deleteReportsOnAggregation = false coverageOutputCobertura = extension.coverageOutputCobertura coverageOutputXML = extension.coverageOutputXML coverageOutputHTML = extension.coverageOutputHTML From b1a637874d6350230eff9cb2fbcb59ae88736294 Mon Sep 17 00:00:00 2001 From: Oleksii Lisikh Date: Wed, 22 May 2019 00:24:12 +0200 Subject: [PATCH 056/167] More tests for the project with multiple test tasks --- ...SingleModuleWithMultipleTestTasksTest.java | 128 ++++++++++++++++++ .../build.gradle | 5 +- .../scala/org/hello/TestNothingSuite.scala | 12 ++ ...WordIntSuite.scala => WorldIntSuite.scala} | 2 +- .../src/main/scala/org/hello/World.scala | 4 +- .../src/test/scala/org/hello/WorldSuite.scala | 2 +- .../org/scoverage/ScoverageReport.groovy | 4 +- 7 files changed, 150 insertions(+), 7 deletions(-) create mode 100644 src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/intTest/scala/org/hello/TestNothingSuite.scala rename src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/intTest/scala/org/hello/{WordIntSuite.scala => WorldIntSuite.scala} (90%) diff --git a/src/functionalTest/java/org.scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java b/src/functionalTest/java/org.scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java index 40aeeca..3d09d61 100644 --- a/src/functionalTest/java/org.scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java @@ -8,6 +8,48 @@ public ScalaSingleModuleWithMultipleTestTasksTest() { super("scala-single-module-multiple-test-tasks"); } + @Test + public void test() { + + AssertableBuildResult result = dryRun("clean", "test"); + + result.assertTaskDoesntExist(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); + } + + @Test + public void build() { + + AssertableBuildResult result = dryRun("clean", "build"); + + result.assertTaskDoesntExist(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); + } + + @Test + public void reportScoverage() { + + AssertableBuildResult result = dryRun("clean", ScoveragePlugin.getREPORT_NAME()); + + result.assertTaskExists(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskExists(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); + } + + @Test + public void aggregateScoverage() { + + AssertableBuildResult result = runAndFail("clean", ScoveragePlugin.getAGGREGATE_NAME()); + + result.assertNoTasks(); + } + + @Test public void checkScoverage() throws Exception { @@ -24,6 +66,92 @@ public void checkScoverage() throws Exception { assertCoverage(100.0); } + @Test + public void checkScoverageIntTest() throws Exception { + AssertableBuildResult result = runAndFail("clean", "-x", "reportTestScoverage", ScoveragePlugin.getCHECK_NAME()); + + result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskDoesntExist("reportTestScoverage"); + result.assertTaskSucceeded("reportIntTestScoverage"); + result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskFailed(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + + assertReportFilesExist(); + assertCoverage(50.0); + } + + + @Test + public void checkScoverageFails() throws Exception { + + AssertableBuildResult result = runAndFail("clean", ScoveragePlugin.getCHECK_NAME(), + "intTest", "--tests", "org.hello.TestNothingSuite", + "-x", "test"); + + result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskFailed(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + + assertReportFilesExist(); + assertCoverage(0.0); + } + + @Test + public void reportScoverageWithExcludedClasses() throws Exception { + + AssertableBuildResult result = run("clean", "-PexcludedFile=.*", ScoveragePlugin.getREPORT_NAME()); + + result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + + Assert.assertTrue(resolve(reportDir(), "index.html").exists()); + Assert.assertFalse(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + assertCoverage(100.0); // coverage is 100 since no classes are covered + + // compiled class should exist in the default classes directory, but not in scoverage + Assert.assertTrue(resolve(buildDir(), "classes/scala/main/org/hello/World.class").exists()); + Assert.assertFalse(resolve(buildDir(), "classes/scala/scoverage/org/hello/World.class").exists()); + } + + @Test + public void reportScoverageWithoutNormalCompilation() throws Exception { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getREPORT_NAME(), + "-x", "compileScala"); + + result.assertTaskSkipped("compileScala"); + result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + + assertReportFilesExist(); + assertCoverage(100.0); + + Assert.assertTrue(resolve(buildDir(), "classes/scala/main/org/hello/World.class").exists()); + Assert.assertFalse(resolve(buildDir(), "classes/scala/scoverage/org/hello/World.class").exists()); + } + + @Test + public void reportScoverageWithoutNormalCompilationAndWithExcludedClasses() throws Exception { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getREPORT_NAME(), + "-PexcludedFile=.*", "-x", "compileScala"); + + Assert.assertTrue(resolve(reportDir(), "index.html").exists()); + Assert.assertFalse(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + assertCoverage(100.0); // coverage is 100 since no classes are covered + + // compiled class should exist in the default classes directory, but not in scoverage + Assert.assertTrue(resolve(buildDir(), "classes/scala/main/org/hello/World.class").exists()); + Assert.assertFalse(resolve(buildDir(), "classes/scala/scoverage/org/hello/World.class").exists()); + } + + private void assertReportFilesExist() { Assert.assertTrue(resolve(reportDir(), "index.html").exists()); diff --git a/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle index 819a07d..c0e0e6d 100644 --- a/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle +++ b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle @@ -66,6 +66,9 @@ check.dependsOn(intTest) intTest.mustRunAfter(test) scoverage { - minimumRate = 0.3 + minimumRate = 0.6 } +if (hasProperty("excludedFile")) { + scoverage.excludedFiles = [excludedFile] +} diff --git a/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/intTest/scala/org/hello/TestNothingSuite.scala b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/intTest/scala/org/hello/TestNothingSuite.scala new file mode 100644 index 0000000..1ac25b5 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/intTest/scala/org/hello/TestNothingSuite.scala @@ -0,0 +1,12 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class TestNothingSuite extends FunSuite { + + test("nothing") { + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/intTest/scala/org/hello/WordIntSuite.scala b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/intTest/scala/org/hello/WorldIntSuite.scala similarity index 90% rename from src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/intTest/scala/org/hello/WordIntSuite.scala rename to src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/intTest/scala/org/hello/WorldIntSuite.scala index ebf99bf..31458d8 100644 --- a/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/intTest/scala/org/hello/WordIntSuite.scala +++ b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/intTest/scala/org/hello/WorldIntSuite.scala @@ -8,6 +8,6 @@ import org.scalatest.junit.JUnitRunner class WorldIntSuite extends FunSuite { test("bar") { - new World().bar + new World().bar() } } \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/main/scala/org/hello/World.scala b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/main/scala/org/hello/World.scala index 5e75836..c9edf98 100644 --- a/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/main/scala/org/hello/World.scala +++ b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/main/scala/org/hello/World.scala @@ -2,10 +2,10 @@ package org.hello class World { - def foo: String = { + def foo(): String = { val s = "a" + "b" s } - def bar: String = "bar" + def bar(): String = "bar" } \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/test/scala/org/hello/WorldSuite.scala b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/test/scala/org/hello/WorldSuite.scala index 442f00f..7281a12 100644 --- a/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/test/scala/org/hello/WorldSuite.scala +++ b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/test/scala/org/hello/WorldSuite.scala @@ -8,6 +8,6 @@ import org.scalatest.junit.JUnitRunner class WorldSuite extends FunSuite { test("foo") { - new World().foo + new World().foo() } } \ No newline at end of file diff --git a/src/main/groovy/org/scoverage/ScoverageReport.groovy b/src/main/groovy/org/scoverage/ScoverageReport.groovy index e0d1d8b..252cd59 100644 --- a/src/main/groovy/org/scoverage/ScoverageReport.groovy +++ b/src/main/groovy/org/scoverage/ScoverageReport.groovy @@ -6,6 +6,7 @@ import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.Input import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction +import scala.collection.JavaConverters import scala.collection.Seq import scala.collection.Set import scoverage.Coverage @@ -46,8 +47,7 @@ class ScoverageReport extends DefaultTask { project.logger.info("[scoverage] Could not find coverage file, skipping...") } else { File[] array = IOUtils.findMeasurementFiles(dataDir.get()) - // TODO: patch scoverage core to use a consistent collection type? - Seq measurementFiles = scala.collection.JavaConversions.asScalaBuffer(Arrays.asList(array)) + Seq measurementFiles = JavaConverters.asScalaBuffer(Arrays.asList(array)) Coverage coverage = Serializer.deserialize(coverageFile) From 6120627f35418f0a4d9b98e4538b834a5c1c4863 Mon Sep 17 00:00:00 2001 From: Stu Date: Wed, 22 May 2019 21:46:52 +0100 Subject: [PATCH 057/167] remove duplicate signing --- build.gradle | 3 --- 1 file changed, 3 deletions(-) diff --git a/build.gradle b/build.gradle index 0cebe0f..320937c 100644 --- a/build.gradle +++ b/build.gradle @@ -92,9 +92,6 @@ artifacts { if (project.properties.containsKey('signing.keyId')) { apply plugin: 'signing' - signing { - sign configurations.archives - } } uploadArchives { From 3bfe9e9d042e53e46db1f8e5c4be796475ae0b0b Mon Sep 17 00:00:00 2001 From: Stu Date: Thu, 23 May 2019 20:45:03 +0100 Subject: [PATCH 058/167] Revert "remove duplicate signing" This reverts commit 6120627f --- build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.gradle b/build.gradle index 320937c..0cebe0f 100644 --- a/build.gradle +++ b/build.gradle @@ -92,6 +92,9 @@ artifacts { if (project.properties.containsKey('signing.keyId')) { apply plugin: 'signing' + signing { + sign configurations.archives + } } uploadArchives { From 5cf9e027eab08306ea1c510bdd4a52c277c5efa1 Mon Sep 17 00:00:00 2001 From: Stu Date: Thu, 23 May 2019 20:45:23 +0100 Subject: [PATCH 059/167] jar is already added to archives --- build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0cebe0f..e70daea 100644 --- a/build.gradle +++ b/build.gradle @@ -85,7 +85,6 @@ task sourcesJar(type: Jar) { } artifacts { - archives jar archives groovydocJar archives sourcesJar } From dc47aa6f7f5d9737b593d9d8cfd532879cffad1b Mon Sep 17 00:00:00 2001 From: Oleksii Lisikh Date: Fri, 24 May 2019 19:52:07 +0200 Subject: [PATCH 060/167] Fixed bug: ConcurrentModificationException during project evaluation --- ...aMultiModuleWithMultipleTestTasksTest.java | 328 ++++++++++++++++++ .../a/build.gradle | 3 + .../scala/org/hello/a/WorldAIntSuite.scala | 13 + .../a/src/main/scala/org/hello/a/WorldA.scala | 16 + .../scala/org/hello/a/TestNothingASuite.scala | 12 + .../test/scala/org/hello/a/WorldASuite.scala | 13 + .../b/build.gradle | 3 + .../scala/org/hello/b/WorldBIntSuite.scala | 13 + .../b/src/main/scala/org/hello/b/WorldB.scala | 16 + .../scala/org/hello/b/TestNothingBSuite.scala | 12 + .../test/scala/org/hello/b/WorldBSuite.scala | 13 + .../build.gradle | 61 ++++ .../scala/org/hello/common/WorldCommon.scala | 9 + .../hello/common/TestNothingCommonSuite.scala | 12 + .../org/hello/common/WorldCommonSuite.scala | 13 + .../settings.gradle | 1 + .../scala/org/hello/TestNothingSuite.scala | 12 + .../scala/org/hello/WorldIntSuite.scala | 13 + .../src/main/scala/org/hello/World.scala | 11 + .../scala/org/hello/TestNothingSuite.scala | 12 + .../src/test/scala/org/hello/WorldSuite.scala | 13 + .../org/scoverage/ScoveragePlugin.groovy | 8 +- 22 files changed, 604 insertions(+), 3 deletions(-) create mode 100644 src/functionalTest/java/org.scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java create mode 100644 src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/build.gradle create mode 100644 src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/src/intTest/scala/org/hello/a/WorldAIntSuite.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/src/main/scala/org/hello/a/WorldA.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/src/test/scala/org/hello/a/TestNothingASuite.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/src/test/scala/org/hello/a/WorldASuite.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/build.gradle create mode 100644 src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/src/intTest/scala/org/hello/b/WorldBIntSuite.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/src/main/scala/org/hello/b/WorldB.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/src/test/scala/org/hello/b/TestNothingBSuite.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/src/test/scala/org/hello/b/WorldBSuite.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle create mode 100644 src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/common/src/main/scala/org/hello/common/WorldCommon.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/common/src/test/scala/org/hello/common/TestNothingCommonSuite.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/common/src/test/scala/org/hello/common/WorldCommonSuite.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/settings.gradle create mode 100644 src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/src/intTest/scala/org/hello/TestNothingSuite.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/src/intTest/scala/org/hello/WorldIntSuite.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/src/main/scala/org/hello/World.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/src/test/scala/org/hello/TestNothingSuite.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/src/test/scala/org/hello/WorldSuite.scala diff --git a/src/functionalTest/java/org.scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java b/src/functionalTest/java/org.scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java new file mode 100644 index 0000000..1905a1c --- /dev/null +++ b/src/functionalTest/java/org.scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java @@ -0,0 +1,328 @@ +package org.scoverage; + +import org.junit.Assert; +import org.junit.Test; + + +import java.io.File; + + +public class ScalaMultiModuleWithMultipleTestTasksTest extends ScoverageFunctionalTest { + + + public ScalaMultiModuleWithMultipleTestTasksTest() { + super("scala-multi-module-multiple-test-tasks"); + } + + @Test + public void reportScoverage() { + + AssertableBuildResult result = dryRun("clean", ScoveragePlugin.getREPORT_NAME()); + + result.assertTaskExists(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("a:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("common:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("intTest"); + result.assertTaskExists("reportIntTestScoverage"); + result.assertTaskExists("a:intTest"); + result.assertTaskExists("b:intTest"); + result.assertTaskExists("common:intTest"); + result.assertTaskExists("a:reportIntTestScoverage"); + result.assertTaskExists("b:reportIntTestScoverage"); + result.assertTaskExists("common:reportIntTestScoverage"); + result.assertTaskExists(ScoveragePlugin.getREPORT_NAME()); + } + + @Test + public void reportScoverageOnlyRoot() { + + AssertableBuildResult result = dryRun("clean", ":" + ScoveragePlugin.getREPORT_NAME()); + + result.assertTaskExists(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist("a:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist("common:" + ScoveragePlugin.getREPORT_NAME()); + } + + @Test + public void reportScoverageOnlyA() { + + AssertableBuildResult result = dryRun("clean", ":a:" + ScoveragePlugin.getREPORT_NAME()); + + result.assertTaskDoesntExist(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("a:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist("common:" + ScoveragePlugin.getREPORT_NAME()); + } + + @Test + public void aggregateScoverage() { + + AssertableBuildResult result = dryRun("clean", ScoveragePlugin.getAGGREGATE_NAME()); + + result.assertTaskExists(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("a:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists(ScoveragePlugin.getAGGREGATE_NAME()); + result.assertTaskExists("common:" + ScoveragePlugin.getREPORT_NAME()); + } + + @Test + public void checkScoverage() { + + AssertableBuildResult result = dryRun("clean", ScoveragePlugin.getCHECK_NAME()); + + result.assertTaskExists(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("a:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("common:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskExists("a:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskExists("b:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskExists("common:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + } + + @Test + public void checkScoverageOnlyRoot() { + + AssertableBuildResult result = dryRun("clean", ":" + ScoveragePlugin.getCHECK_NAME()); + + result.assertTaskExists(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist("a:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist("a:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist("b:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + } + + @Test + public void checkScoverageOnlyA() { + + AssertableBuildResult result = dryRun("clean", ":a:" + ScoveragePlugin.getCHECK_NAME()); + + result.assertTaskDoesntExist(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("a:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist("common:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskExists("a:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist("b:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist("common:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + } + + @Test + public void checkScoverageWithoutIntTests() { + AssertableBuildResult result = dryRun("clean", ScoveragePlugin.getCHECK_NAME(), + "-x", "intTest"); + + result.assertTaskExists(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("a:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("common:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist("intTest"); + result.assertTaskExists("reportIntTestScoverage"); + result.assertTaskDoesntExist("a:intTest"); + result.assertTaskDoesntExist("b:intTest"); + result.assertTaskDoesntExist("common:intTest"); + result.assertTaskExists("a:reportIntTestScoverage"); + result.assertTaskExists("b:reportIntTestScoverage"); + result.assertTaskExists("common:reportIntTestScoverage"); + } + + @Test + public void checkAndAggregateScoverage() throws Exception { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME(), + ScoveragePlugin.getAGGREGATE_NAME()); + + result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("a:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("common:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded("a:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded("b:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded("common:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); + + assertAllReportFilesExist(); + assertCoverage(100.0); + } + + @Test + public void checkScoverageWithoutCoverageInRoot() throws Exception { + + AssertableBuildResult result = runAndFail("clean", ScoveragePlugin.getCHECK_NAME(), + "test", + "--tests", "org.hello.TestNothingSuite", + "--tests", "org.hello.a.WorldASuite", + "--tests", "org.hello.b.WorldBSuite", + "--tests", "org.hello.common.WorldCommonSuite", + "-x", "intTest"); + + result.assertTaskFailed(ScoveragePlugin.getCHECK_NAME()); + + assertRootReportFilesExist(); + assertCoverage(0.0); + } + + @Test + public void checkScoverageWithoutCoverageInA() throws Exception { + + AssertableBuildResult result = runAndFail("clean", ScoveragePlugin.getCHECK_NAME(), + "test", + "--tests", "org.hello.a.TestNothingASuite", + "--tests", "org.hello.WorldSuite", + "--tests", "org.hello.b.WorldBSuite", + "--tests", "org.hello.common.WorldCommonSuite", + "-x", ":a:intTest"); + + result.assertTaskFailed("a:" + ScoveragePlugin.getCHECK_NAME()); + + assertAReportFilesExist(); + assertCoverage(0.0, reportDir(projectDir().toPath().resolve("a").toFile())); + } + + @Test + public void checkScoverageWithoutNormalCompilationAndWithoutCoverageInCommon() throws Exception { + + AssertableBuildResult result = runAndFail("clean", + ":a:test", + ":common:test", "--tests", "org.hello.common.TestNothingCommonSuite", + "-x", "compileScala", + ScoveragePlugin.getCHECK_NAME()); + + result.assertTaskFailed("common:" + ScoveragePlugin.getCHECK_NAME()); + + assertCommonReportFilesExist(); + assertCoverage(0.0, reportDir(projectDir().toPath().resolve("common").toFile())); + } + + @Test + public void checkAndAggregateScoverageWithoutCoverageInRoot() throws Exception { + + // should pass as the check on the root is for the aggregation (which covers > 50%) + + AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME(), + ScoveragePlugin.getAGGREGATE_NAME(), "test", + "--tests", "org.hello.TestNothingSuite", + "--tests", "org.hello.a.WorldASuite", + "--tests", "org.hello.b.WorldBSuite", + "--tests", "org.hello.common.WorldCommonSuite"); + + result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("a:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("common:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded("a:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded("b:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded("common:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); + + assertAllReportFilesExist(); + assertCoverage(93.33); + } + + @Test + public void checkAndAggregateScoverageWithoutCoverageInAll() throws Exception { + + AssertableBuildResult result = runAndFail("clean", ScoveragePlugin.getCHECK_NAME(), + ScoveragePlugin.getAGGREGATE_NAME(), "test", + "--tests", "org.hello.TestNothingSuite", + "--tests", "org.hello.a.TestNothingASuite", + "--tests", "org.hello.b.TestNothingBSuite", + "--tests", "org.hello.common.TestNothingCommonSuite", + "-x", "intTest"); + + result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("a:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("common:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); + result.assertTaskFailed(ScoveragePlugin.getCHECK_NAME()); + + assertAllReportFilesExist(); + assertCoverage(0.0); + } + + @Test + public void aggregateScoverageWithoutNormalCompilation() throws Exception { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getAGGREGATE_NAME(), + "-x", "compileScala"); + + result.assertTaskSkipped("compileScala"); + result.assertTaskSkipped("a:compileScala"); + result.assertTaskSkipped("b:compileScala"); + result.assertTaskSkipped("common:compileScala"); + result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded("a:" + ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded("b:" + ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded("common:" + ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("a:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("common:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); + + assertAllReportFilesExist(); + assertCoverage(100.0); + + Assert.assertTrue(resolve(buildDir(resolve(projectDir(), "a")), "classes/scala/main/org/hello/a/WorldA.class").exists()); + Assert.assertFalse(resolve(buildDir(resolve(projectDir(), "a")), "classes/scala/scoverage/org/hello/a/WorldA.class").exists()); + + Assert.assertTrue(resolve(buildDir(resolve(projectDir(), "b")), "classes/scala/main/org/hello/b/WorldB.class").exists()); + Assert.assertFalse(resolve(buildDir(resolve(projectDir(), "b")), "classes/scala/scoverage/org/hello/b/WorldB.class").exists()); + + Assert.assertTrue(resolve(buildDir(resolve(projectDir(), "common")), "classes/scala/main/org/hello/common/WorldCommon.class").exists()); + Assert.assertFalse(resolve(buildDir(resolve(projectDir(), "common")), "classes/scala/scoverage/org/hello/common/WorldCommon.class").exists()); + } + + private void assertAllReportFilesExist() { + + assertRootReportFilesExist(); + assertAReportFilesExist(); + assertBReportFilesExist(); + assertCommonReportFilesExist(); + assertAggregationFilesExist(); + } + + private void assertAggregationFilesExist() { + + Assert.assertTrue(resolve(reportDir(), "a/src/main/scala/org/hello/a/WorldA.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "b/src/main/scala/org/hello/b/WorldB.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "common/src/main/scala/org/hello/common/WorldCommon.scala.html").exists()); + } + + private void assertRootReportFilesExist() { + + Assert.assertTrue(resolve(reportDir(), "index.html").exists()); + Assert.assertTrue(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + } + + private void assertAReportFilesExist() { + + File reportDir = reportDir(projectDir().toPath().resolve("a").toFile()); + Assert.assertTrue(resolve(reportDir, "index.html").exists()); + Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/a/WorldA.scala.html").exists()); + } + + private void assertBReportFilesExist() { + + File reportDir = reportDir(projectDir().toPath().resolve("b").toFile()); + Assert.assertTrue(resolve(reportDir, "index.html").exists()); + Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/b/WorldB.scala.html").exists()); + } + + private void assertCommonReportFilesExist() { + + File reportDir = reportDir(projectDir().toPath().resolve("common").toFile()); + Assert.assertTrue(resolve(reportDir, "index.html").exists()); + Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/common/WorldCommon.scala.html").exists()); + } +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/build.gradle new file mode 100644 index 0000000..368d0bc --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/build.gradle @@ -0,0 +1,3 @@ +dependencies { + compile project(":common") +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/src/intTest/scala/org/hello/a/WorldAIntSuite.scala b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/src/intTest/scala/org/hello/a/WorldAIntSuite.scala new file mode 100644 index 0000000..2abf597 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/src/intTest/scala/org/hello/a/WorldAIntSuite.scala @@ -0,0 +1,13 @@ +package org.hello.a + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldAIntSuite extends FunSuite { + + test("barA") { + new WorldA().barA() + } +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/src/main/scala/org/hello/a/WorldA.scala b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/src/main/scala/org/hello/a/WorldA.scala new file mode 100644 index 0000000..a564416 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/src/main/scala/org/hello/a/WorldA.scala @@ -0,0 +1,16 @@ +package org.hello.a + +import org.hello.common.WorldCommon + +class WorldA { + + def fooA(): String = { + val s = "a" + new WorldCommon().fooCommon() + s + } + + def barA(): String = { + val s = "a" + new WorldCommon().fooCommon() + s + } +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/src/test/scala/org/hello/a/TestNothingASuite.scala b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/src/test/scala/org/hello/a/TestNothingASuite.scala new file mode 100644 index 0000000..ad764b7 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/src/test/scala/org/hello/a/TestNothingASuite.scala @@ -0,0 +1,12 @@ +package org.hello.a + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class TestNothingASuite extends FunSuite { + + test("nothing") { + } +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/src/test/scala/org/hello/a/WorldASuite.scala b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/src/test/scala/org/hello/a/WorldASuite.scala new file mode 100644 index 0000000..727de09 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/src/test/scala/org/hello/a/WorldASuite.scala @@ -0,0 +1,13 @@ +package org.hello.a + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldASuite extends FunSuite { + + test("fooA") { + new WorldA().fooA() + } +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/build.gradle new file mode 100644 index 0000000..368d0bc --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/build.gradle @@ -0,0 +1,3 @@ +dependencies { + compile project(":common") +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/src/intTest/scala/org/hello/b/WorldBIntSuite.scala b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/src/intTest/scala/org/hello/b/WorldBIntSuite.scala new file mode 100644 index 0000000..a4c8ddf --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/src/intTest/scala/org/hello/b/WorldBIntSuite.scala @@ -0,0 +1,13 @@ +package org.hello.b + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldBIntSuite extends FunSuite { + + test("barB") { + new WorldB().barB() + } +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/src/main/scala/org/hello/b/WorldB.scala b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/src/main/scala/org/hello/b/WorldB.scala new file mode 100644 index 0000000..67f27cd --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/src/main/scala/org/hello/b/WorldB.scala @@ -0,0 +1,16 @@ +package org.hello.b + +import org.hello.common.WorldCommon + +class WorldB { + + def fooB(): String = { + val s = "b" + new WorldCommon().fooCommon() + s + } + + def barB(): String = { + val s = "b" + new WorldCommon().fooCommon() + s + } +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/src/test/scala/org/hello/b/TestNothingBSuite.scala b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/src/test/scala/org/hello/b/TestNothingBSuite.scala new file mode 100644 index 0000000..502fc77 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/src/test/scala/org/hello/b/TestNothingBSuite.scala @@ -0,0 +1,12 @@ +package org.hello.b + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class TestNothingBSuite extends FunSuite { + + test("nothing") { + } +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/src/test/scala/org/hello/b/WorldBSuite.scala b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/src/test/scala/org/hello/b/WorldBSuite.scala new file mode 100644 index 0000000..f32f22f --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/src/test/scala/org/hello/b/WorldBSuite.scala @@ -0,0 +1,13 @@ +package org.hello.b + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldBSuite extends FunSuite { + + test("fooB") { + new WorldB().fooB() + } +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle new file mode 100644 index 0000000..af0a9b3 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle @@ -0,0 +1,61 @@ +plugins { + id 'org.scoverage' +} + +allprojects { + repositories { + jcenter() + } +} + +description = 'a multi-module Scala project that builds successfully with 100% coverage' + +allprojects { + + apply plugin: 'java' + apply plugin: 'scala' + + dependencies { + compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + + testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion + } + + test { + useJUnitPlatform() + maxParallelForks = 1 + } + + configurations { + intTestCompile.extendsFrom testCompile + intTestRuntime.extendsFrom testRuntime + } + sourceSets { + intTest { + resources.srcDir file('src/intTest/resources') + scala { + compileClasspath += main.output + test.output + runtimeClasspath += main.output + test.output + srcDir file("${projectDir}/src/intTest/scala") + } + } + } + + + task intTest(type: Test) { + testClassesDirs = sourceSets.intTest.output.classesDirs + classpath = sourceSets.intTest.runtimeClasspath + outputs.upToDateWhen { false } + + maxParallelForks = 1 + } + check.dependsOn(intTest) + intTest.mustRunAfter(test) + + scoverage { + minimumRate = 0.5 + } +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/common/src/main/scala/org/hello/common/WorldCommon.scala b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/common/src/main/scala/org/hello/common/WorldCommon.scala new file mode 100644 index 0000000..5fe6c6e --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/common/src/main/scala/org/hello/common/WorldCommon.scala @@ -0,0 +1,9 @@ +package org.hello.common + +class WorldCommon { + + def fooCommon(): String = { + val s = "common" + "a" + s + } +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/common/src/test/scala/org/hello/common/TestNothingCommonSuite.scala b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/common/src/test/scala/org/hello/common/TestNothingCommonSuite.scala new file mode 100644 index 0000000..9e74f75 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/common/src/test/scala/org/hello/common/TestNothingCommonSuite.scala @@ -0,0 +1,12 @@ +package org.hello.common + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class TestNothingCommonSuite extends FunSuite { + + test("nothing") { + } +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/common/src/test/scala/org/hello/common/WorldCommonSuite.scala b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/common/src/test/scala/org/hello/common/WorldCommonSuite.scala new file mode 100644 index 0000000..d906699 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/common/src/test/scala/org/hello/common/WorldCommonSuite.scala @@ -0,0 +1,13 @@ +package org.hello.common + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldCommonSuite extends FunSuite { + + test("fooCommon") { + new WorldCommon().fooCommon() + } +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/settings.gradle b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/settings.gradle new file mode 100644 index 0000000..46ba372 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/settings.gradle @@ -0,0 +1 @@ +include 'a', 'b', 'common' diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/src/intTest/scala/org/hello/TestNothingSuite.scala b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/src/intTest/scala/org/hello/TestNothingSuite.scala new file mode 100644 index 0000000..b8599be --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/src/intTest/scala/org/hello/TestNothingSuite.scala @@ -0,0 +1,12 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class TestNothingSuite extends FunSuite { + + test("nothing") { + } +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/src/intTest/scala/org/hello/WorldIntSuite.scala b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/src/intTest/scala/org/hello/WorldIntSuite.scala new file mode 100644 index 0000000..f884b8b --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/src/intTest/scala/org/hello/WorldIntSuite.scala @@ -0,0 +1,13 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldIntSuite extends FunSuite { + + test("bar") { + new World().bar() + } +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/src/main/scala/org/hello/World.scala b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/src/main/scala/org/hello/World.scala new file mode 100644 index 0000000..f07b25e --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/src/main/scala/org/hello/World.scala @@ -0,0 +1,11 @@ +package org.hello + +class World { + + def foo(): String = { + val s = "a" + "b" + s + } + + def bar(): String = "bar" +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/src/test/scala/org/hello/TestNothingSuite.scala b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/src/test/scala/org/hello/TestNothingSuite.scala new file mode 100644 index 0000000..b8599be --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/src/test/scala/org/hello/TestNothingSuite.scala @@ -0,0 +1,12 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class TestNothingSuite extends FunSuite { + + test("nothing") { + } +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/src/test/scala/org/hello/WorldSuite.scala b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/src/test/scala/org/hello/WorldSuite.scala new file mode 100644 index 0000000..1aa434c --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/src/test/scala/org/hello/WorldSuite.scala @@ -0,0 +1,13 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldSuite extends FunSuite { + + test("foo") { + new World().foo() + } +} diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index c0492a9..1a4e6c4 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -123,7 +123,9 @@ class ScoveragePlugin implements Plugin { def globalCheckTask = project.tasks.register(CHECK_NAME, OverallCheckTask) project.afterEvaluate { - def testTasks = project.tasks.withType(Test) + // calling toList() on TaskCollection is required + // to avoid potential ConcurrentModificationException in multi-project builds + def testTasks = project.tasks.withType(Test).toList() List reportTasks = testTasks.collect { testTask -> testTask.mustRunAfter(compileTask) @@ -319,7 +321,7 @@ class ScoveragePlugin implements Plugin { private Set recursiveDependenciesOf(Task task) { if (!taskDependencies.containsKey(task)) { def directDependencies = task.getTaskDependencies().getDependencies(task) - def nestedDependencies = directDependencies.collect {recursiveDependenciesOf(it) }.flatten() + def nestedDependencies = directDependencies.collect { recursiveDependenciesOf(it) }.flatten() def dependencies = directDependencies + nestedDependencies taskDependencies.put(task, dependencies) @@ -328,4 +330,4 @@ class ScoveragePlugin implements Plugin { return taskDependencies.get(task) } } -} \ No newline at end of file +} From d6f8cc546bbaed7b08fe9e2a4b3e02fcb8e01f8c Mon Sep 17 00:00:00 2001 From: Oleksii Lisikh Date: Fri, 31 May 2019 18:24:36 +0200 Subject: [PATCH 061/167] Issue #102: Honor java sources when running compileScoverageScala --- .../ScalaSingleMultiLangModuleTest.java | 145 ++++++++++++++++++ .../build.gradle | 33 ++++ .../settings.gradle | 0 .../src/main/java/org/hello/JavaWorld.java | 7 + .../src/main/scala/org/hello/World.scala | 14 ++ .../scala/org/hello/TestNothingSuite.scala | 12 ++ .../src/test/scala/org/hello/WorldSuite.scala | 17 ++ .../org/scoverage/ScoveragePlugin.groovy | 1 + 8 files changed, 229 insertions(+) create mode 100644 src/functionalTest/java/org.scoverage/ScalaSingleMultiLangModuleTest.java create mode 100644 src/functionalTest/resources/projects/scala-single-multi-lang-module/build.gradle create mode 100644 src/functionalTest/resources/projects/scala-single-multi-lang-module/settings.gradle create mode 100644 src/functionalTest/resources/projects/scala-single-multi-lang-module/src/main/java/org/hello/JavaWorld.java create mode 100644 src/functionalTest/resources/projects/scala-single-multi-lang-module/src/main/scala/org/hello/World.scala create mode 100644 src/functionalTest/resources/projects/scala-single-multi-lang-module/src/test/scala/org/hello/TestNothingSuite.scala create mode 100644 src/functionalTest/resources/projects/scala-single-multi-lang-module/src/test/scala/org/hello/WorldSuite.scala diff --git a/src/functionalTest/java/org.scoverage/ScalaSingleMultiLangModuleTest.java b/src/functionalTest/java/org.scoverage/ScalaSingleMultiLangModuleTest.java new file mode 100644 index 0000000..3f8dd76 --- /dev/null +++ b/src/functionalTest/java/org.scoverage/ScalaSingleMultiLangModuleTest.java @@ -0,0 +1,145 @@ +package org.scoverage; + +import org.junit.Assert; +import org.junit.Test; + +public class ScalaSingleMultiLangModuleTest extends ScoverageFunctionalTest { + + public ScalaSingleMultiLangModuleTest() { super("scala-single-multi-lang-module"); } + + @Test + public void test() { + + AssertableBuildResult result = dryRun("clean", "test"); + + result.assertTaskDoesntExist(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); + } + + @Test + public void build() { + + AssertableBuildResult result = dryRun("clean", "build"); + + result.assertTaskDoesntExist(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); + } + + @Test + public void reportScoverage() { + + AssertableBuildResult result = dryRun("clean", ScoveragePlugin.getREPORT_NAME()); + + result.assertTaskExists(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskExists(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); + } + + @Test + public void aggregateScoverage() { + + AssertableBuildResult result = runAndFail("clean", ScoveragePlugin.getAGGREGATE_NAME()); + + result.assertNoTasks(); + } + + @Test + public void checkScoverage() throws Exception { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME()); + + result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + + assertReportFilesExist(); + assertCoverage(66.7); + } + + @Test + public void checkScoverageFails() throws Exception { + + AssertableBuildResult result = runAndFail("clean", ScoveragePlugin.getCHECK_NAME(), + "test", "--tests", "org.hello.TestNothingSuite"); + + result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskFailed(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + + assertReportFilesExist(); + assertCoverage(0.0); + } + + @Test + public void reportScoverageWithExcludedClasses() throws Exception { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getREPORT_NAME(), + "-PexcludedFile=.*"); + + result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + + Assert.assertTrue(resolve(reportDir(), "index.html").exists()); + Assert.assertFalse(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + assertCoverage(100.0); // coverage is 100 since no classes are covered + + // compiled class should exist in the default classes directory, but not in scoverage + Assert.assertTrue(resolve(buildDir(), "classes/scala/main/org/hello/World.class").exists()); + Assert.assertFalse(resolve(buildDir(), "classes/scala/scoverage/org/hello/World.class").exists()); + } + + @Test + public void reportScoverageWithoutNormalCompilation() throws Exception { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getREPORT_NAME(), + "-x", "compileScala"); + + result.assertTaskSkipped("compileScala"); + result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + + assertReportFilesExist(); + assertCoverage(66.7); + + Assert.assertTrue(resolve(reportDir(), "index.html").exists()); + Assert.assertTrue(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + Assert.assertFalse(resolve(reportDir(), "src/main/java/org/hello/JavaWorld.java.html").exists()); + + Assert.assertTrue(resolve(buildDir(), "classes/java/main/org/hello/JavaWorld.class").exists()); + Assert.assertTrue(resolve(buildDir(), "classes/java/scoverage/org/hello/JavaWorld.class").exists()); + Assert.assertTrue(resolve(buildDir(), "classes/scala/main/org/hello/World.class").exists()); + Assert.assertFalse(resolve(buildDir(), "classes/scala/scoverage/org/hello/World.class").exists()); + } + + @Test + public void reportScoverageWithoutNormalCompilationAndWithExcludedClasses() throws Exception { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getREPORT_NAME(), + "-PexcludedFile=.*", "-x", "compileScala"); + + Assert.assertTrue(resolve(reportDir(), "index.html").exists()); + Assert.assertFalse(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + assertCoverage(100.0); // coverage is 100 since no classes are covered + + // compiled class should exist in the default classes directory, but not in scoverage + Assert.assertTrue(resolve(buildDir(), "classes/scala/main/org/hello/World.class").exists()); + Assert.assertFalse(resolve(buildDir(), "classes/scala/scoverage/org/hello/World.class").exists()); + } + + + private void assertReportFilesExist() { + Assert.assertTrue(resolve(reportDir(), "index.html").exists()); + Assert.assertTrue(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + } +} diff --git a/src/functionalTest/resources/projects/scala-single-multi-lang-module/build.gradle b/src/functionalTest/resources/projects/scala-single-multi-lang-module/build.gradle new file mode 100644 index 0000000..c7ebff2 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-single-multi-lang-module/build.gradle @@ -0,0 +1,33 @@ +plugins { + id 'org.scoverage' +} + +repositories { + jcenter() +} + +description = 'a single-module Scala project with java and scala sources' + +apply plugin: 'java' +apply plugin: 'scala' + +dependencies { + compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + + testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion +} + +test { + useJUnitPlatform() +} + +scoverage { + minimumRate = 0.3 +} + +if (hasProperty("excludedFile")) { + scoverage.excludedFiles = [excludedFile] +} diff --git a/src/functionalTest/resources/projects/scala-single-multi-lang-module/settings.gradle b/src/functionalTest/resources/projects/scala-single-multi-lang-module/settings.gradle new file mode 100644 index 0000000..e69de29 diff --git a/src/functionalTest/resources/projects/scala-single-multi-lang-module/src/main/java/org/hello/JavaWorld.java b/src/functionalTest/resources/projects/scala-single-multi-lang-module/src/main/java/org/hello/JavaWorld.java new file mode 100644 index 0000000..2f199c5 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-single-multi-lang-module/src/main/java/org/hello/JavaWorld.java @@ -0,0 +1,7 @@ +package org.hello; + +public class JavaWorld { + public static void hello() { + System.out.println("Hello, World!"); + } +} diff --git a/src/functionalTest/resources/projects/scala-single-multi-lang-module/src/main/scala/org/hello/World.scala b/src/functionalTest/resources/projects/scala-single-multi-lang-module/src/main/scala/org/hello/World.scala new file mode 100644 index 0000000..b7090dc --- /dev/null +++ b/src/functionalTest/resources/projects/scala-single-multi-lang-module/src/main/scala/org/hello/World.scala @@ -0,0 +1,14 @@ +package org.hello + +class World { + + def foo(): String = { + val s = "a" + "b" + s + } + + // not covered by tests + def bar(): String = "y" + + def helloFromJava(): Unit = JavaWorld.hello() +} diff --git a/src/functionalTest/resources/projects/scala-single-multi-lang-module/src/test/scala/org/hello/TestNothingSuite.scala b/src/functionalTest/resources/projects/scala-single-multi-lang-module/src/test/scala/org/hello/TestNothingSuite.scala new file mode 100644 index 0000000..b8599be --- /dev/null +++ b/src/functionalTest/resources/projects/scala-single-multi-lang-module/src/test/scala/org/hello/TestNothingSuite.scala @@ -0,0 +1,12 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class TestNothingSuite extends FunSuite { + + test("nothing") { + } +} diff --git a/src/functionalTest/resources/projects/scala-single-multi-lang-module/src/test/scala/org/hello/WorldSuite.scala b/src/functionalTest/resources/projects/scala-single-multi-lang-module/src/test/scala/org/hello/WorldSuite.scala new file mode 100644 index 0000000..2e90b74 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-single-multi-lang-module/src/test/scala/org/hello/WorldSuite.scala @@ -0,0 +1,17 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldSuite extends FunSuite { + + test("foo") { + new World().foo() + } + + test("helloFromJava") { + new World().helloFromJava() + } +} diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 1a4e6c4..af6dc80 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -106,6 +106,7 @@ class ScoveragePlugin implements Plugin { def instrumentedSourceSet = project.sourceSets.create('scoverage') { resources.source(originalSourceSet.resources) + java.source(originalSourceSet.java) scala.source(originalSourceSet.scala) compileClasspath += originalSourceSet.compileClasspath + project.configurations.scoverage From c3dc6bbff8050401fa13cdb9efdd942cfb56f962 Mon Sep 17 00:00:00 2001 From: Stu Date: Sat, 1 Jun 2019 20:39:01 +0100 Subject: [PATCH 062/167] bump to gradle 5.4.1 --- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e4eb7ca..9c80f8b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=f4d820c2a9685710eba5b92f10e0e4fb20e0d6c0dd1f46971e658160f25e7147 -distributionUrl=https\://services.gradle.org/distributions/gradle-5.3-all.zip +distributionSha256Sum=14cd15fc8cc8705bd69dcfa3c8fefb27eb7027f5de4b47a8b279218f76895a91 +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 80b126a317d086289fc278090e79efdfca30b6d4 Mon Sep 17 00:00:00 2001 From: Cosmin Stroe Date: Thu, 6 Jun 2019 11:30:37 -0500 Subject: [PATCH 063/167] Mention the individual tasks that are automatically created. --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 9cd27b1..0d01c1b 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,11 @@ You can find instructions on how to apply the plugin at: http://plugins.gradle. 1. `reportScoverage`: Produces XML and HTML reports for analysing test code coverage. + The plugin automatically creates a `report{Task name}Scoverage` task for each test task in your + Gradle build. The `reportScoverage` task will run all test tasks and you can use the individual + tasks to run only the desired tests. For example, to run only the unit tests and no other test + tasks (e.g., integration tests), you can run `reportTestScoverage`. + 2. `aggregateScoverage`: An experimental support for aggregating coverage statistics in composite builds. When applied on a project with sub-projects, the plugin will create the aggregation task `aggregateScoverage`, which From 5ae6b7611053d98dfafcacf4c5a22d7a5657b7ea Mon Sep 17 00:00:00 2001 From: Stu Date: Fri, 14 Jun 2019 18:57:06 +0100 Subject: [PATCH 064/167] revert change to JavaConverions (it is not compatible with 2.11) --- src/main/groovy/org/scoverage/ScoverageReport.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/groovy/org/scoverage/ScoverageReport.groovy b/src/main/groovy/org/scoverage/ScoverageReport.groovy index 252cd59..37195b0 100644 --- a/src/main/groovy/org/scoverage/ScoverageReport.groovy +++ b/src/main/groovy/org/scoverage/ScoverageReport.groovy @@ -6,7 +6,7 @@ import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.Input import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction -import scala.collection.JavaConverters +import scala.collection.JavaConversions import scala.collection.Seq import scala.collection.Set import scoverage.Coverage @@ -47,7 +47,7 @@ class ScoverageReport extends DefaultTask { project.logger.info("[scoverage] Could not find coverage file, skipping...") } else { File[] array = IOUtils.findMeasurementFiles(dataDir.get()) - Seq measurementFiles = JavaConverters.asScalaBuffer(Arrays.asList(array)) + Seq measurementFiles = JavaConversions.asScalaBuffer(Arrays.asList(array)) Coverage coverage = Serializer.deserialize(coverageFile) From e51a7a9d643ed53ba0763d11e85f28619e6e590c Mon Sep 17 00:00:00 2001 From: Oleksii Lisikh Date: Wed, 19 Jun 2019 20:34:36 +0200 Subject: [PATCH 065/167] Issue #102: Use deprecated JavaConversions to maintain backward compatibility with Scala 2.11 --- src/main/groovy/org/scoverage/ScoverageAggregate.groovy | 7 ++++--- src/main/groovy/org/scoverage/ScoverageReport.groovy | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy index 89de7de..e41d16b 100644 --- a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy +++ b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy @@ -6,7 +6,8 @@ import org.gradle.api.provider.Property import org.gradle.api.tasks.Input import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction -import scala.collection.JavaConverters +// don't use scala.collection.JavaConverters as it breaks backward compatibility with scala 2.11 +import scala.collection.JavaConversions import scoverage.IOUtils import scoverage.report.CoverageAggregator @@ -47,9 +48,9 @@ class ScoverageAggregate extends DefaultTask { coverage = CoverageAggregator.aggregate(rootDir, deleteReportsOnAggregation.get()) } else { def reportFiles = dirsToAggregateFrom.get().collectMany { - JavaConverters.seqAsJavaList(IOUtils.reportFileSearch(it, IOUtils.isReportFile())) + JavaConversions.seqAsJavaList(IOUtils.reportFileSearch(it, IOUtils.isReportFile())) } - coverage = CoverageAggregator.aggregate(JavaConverters.asScalaBuffer(reportFiles), deleteReportsOnAggregation.get()) + coverage = CoverageAggregator.aggregate(JavaConversions.asScalaBuffer(reportFiles), deleteReportsOnAggregation.get()) } reportDir.get().deleteDir() diff --git a/src/main/groovy/org/scoverage/ScoverageReport.groovy b/src/main/groovy/org/scoverage/ScoverageReport.groovy index 37195b0..d5c5691 100644 --- a/src/main/groovy/org/scoverage/ScoverageReport.groovy +++ b/src/main/groovy/org/scoverage/ScoverageReport.groovy @@ -6,6 +6,7 @@ import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.Input import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction +// don't use scala.collection.JavaConverters as it breaks backward compatibility with scala 2.11 import scala.collection.JavaConversions import scala.collection.Seq import scala.collection.Set From 56f0d58027740efeddcf847e537ea2c3e2a69fbd Mon Sep 17 00:00:00 2001 From: Oleksii Lisikh Date: Wed, 19 Jun 2019 20:43:43 +0200 Subject: [PATCH 066/167] Issue #102: Show stdout of functional tests --- build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.gradle b/build.gradle index e70daea..1c7fb4d 100644 --- a/build.gradle +++ b/build.gradle @@ -65,6 +65,9 @@ task functionalTest(type: Test) { group = 'verification' testClassesDirs = sourceSets.functionalTest.output.classesDirs classpath = sourceSets.functionalTest.runtimeClasspath + + testLogging.showStandardStreams = true + mustRunAfter test } From e1c5acbfc87725b4cf12bde0d7c4a9b50720dbe0 Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 23 Jun 2019 20:51:27 +0100 Subject: [PATCH 067/167] add a test for running the plugin under 2.11 --- .../java/org.scoverage/ScalaSingleModuleTest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java index f93e184..d53881b 100644 --- a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java @@ -133,6 +133,15 @@ public void reportScoverageWithoutNormalCompilationAndWithExcludedClasses() thro Assert.assertFalse(resolve(buildDir(), "classes/scala/scoverage/org/hello/World.class").exists()); } + @Test + public void reportScoverageUnder2_11() throws Exception { + run("clean", ScoveragePlugin.getREPORT_NAME(), + "-PscalaVersionMinor=11", + "-PscalaVersionBuild=8", + "-Pscoverage.scoverageScalaVersion=2_11"); + assertReportFilesExist(); + } + private void assertReportFilesExist() { Assert.assertTrue(resolve(reportDir(), "index.html").exists()); From f05db1eb98f3cb5323f7d97c8e2b416bd2e319bf Mon Sep 17 00:00:00 2001 From: Stu Date: Sat, 13 Jul 2019 21:28:58 +0100 Subject: [PATCH 068/167] build with scala 2.12 and scoverage 1.4.0 --- build.gradle | 2 +- .../java/org.scoverage/ScoverageFunctionalTest.java | 2 +- src/main/groovy/org/scoverage/ScoverageExtension.groovy | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 1c7fb4d..2346e1b 100644 --- a/build.gradle +++ b/build.gradle @@ -45,7 +45,7 @@ sourceCompatibility = '1.8' targetCompatibility = '1.8' dependencies { - compileOnly "org.scoverage:scalac-scoverage-plugin_2.12:1.3.1" + compileOnly "org.scoverage:scalac-scoverage-plugin_2.12:1.4.0" compile group: 'commons-io', name: 'commons-io', version: '2.6' testCompile 'junit:junit:4.12' testCompile 'org.hamcrest:hamcrest-library:1.3' diff --git a/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java b/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java index af14ce5..7535319 100644 --- a/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java +++ b/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java @@ -122,7 +122,7 @@ private void configureArguments(String... arguments) { fullArguments.add("-PscalaVersionBuild=8"); fullArguments.add("-PjunitVersion=5.3.2"); fullArguments.add("-PjunitPlatformVersion=1.3.2"); - fullArguments.add("-PscalatestVersion=3.0.5"); + fullArguments.add("-PscalatestVersion=3.0.8"); fullArguments.addAll(Arrays.asList(arguments)); runner.withArguments(fullArguments); diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index 8ee680b..8e45a7e 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -49,7 +49,7 @@ class ScoverageExtension { project.plugins.apply(ScalaPlugin.class) scoverageVersion = project.objects.property(String) - scoverageVersion.set('1.3.1') + scoverageVersion.set('1.4.0') scoverageScalaVersion = project.objects.property(String) scoverageScalaVersion.set('2.12') From 4e49a1bf76306f628d64613c6e81f76a89901553 Mon Sep 17 00:00:00 2001 From: Stu Date: Mon, 22 Jul 2019 22:08:26 +0100 Subject: [PATCH 069/167] scoverage 1.4 aggregates from the data directories --- .../org/scoverage/ScoverageAggregate.groovy | 20 +++++------------- .../org/scoverage/ScoveragePlugin.groovy | 9 +++++--- .../org/scoverage/ScoverageReport.groovy | 21 +++++-------------- 3 files changed, 16 insertions(+), 34 deletions(-) diff --git a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy index e41d16b..9505a4d 100644 --- a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy +++ b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy @@ -8,7 +8,6 @@ import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction // don't use scala.collection.JavaConverters as it breaks backward compatibility with scala 2.11 import scala.collection.JavaConversions -import scoverage.IOUtils import scoverage.report.CoverageAggregator class ScoverageAggregate extends DefaultTask { @@ -35,29 +34,20 @@ class ScoverageAggregate extends DefaultTask { final Property coverageDebug = project.objects.property(Boolean) ScoverageAggregate() { - dirsToAggregateFrom.set([]) + dirsToAggregateFrom.set([project.extensions.scoverage.dataDir.get()]) } @TaskAction def aggregate() { runner.run { - def rootDir = project.projectDir - - def coverage - if (dirsToAggregateFrom.get().isEmpty()) { - coverage = CoverageAggregator.aggregate(rootDir, deleteReportsOnAggregation.get()) - } else { - def reportFiles = dirsToAggregateFrom.get().collectMany { - JavaConversions.seqAsJavaList(IOUtils.reportFileSearch(it, IOUtils.isReportFile())) - } - coverage = CoverageAggregator.aggregate(JavaConversions.asScalaBuffer(reportFiles), deleteReportsOnAggregation.get()) - } - reportDir.get().deleteDir() + reportDir.get().mkdirs() + + def coverage = CoverageAggregator.aggregate(JavaConversions.asScalaBuffer(dirsToAggregateFrom.get())) if (coverage.nonEmpty()) { new ScoverageWriter(project.logger).write( - rootDir, + project.projectDir, reportDir.get(), coverage.get(), coverageOutputCobertura.get(), diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index af6dc80..b2388bf 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -150,15 +150,15 @@ class ScoveragePlugin implements Plugin { } globalReportTask.configure { - def reportDirs = reportTasks.findResults { it.reportDir.get() } + def dataDirs = reportTasks.findResults { it.dataDir.get() } dependsOn reportTasks - onlyIf { reportDirs.any { it.list() } } + onlyIf { dataDirs.any { it.list() } } group = 'verification' runner = scoverageRunner reportDir = extension.reportDir - dirsToAggregateFrom = reportDirs + dirsToAggregateFrom = dataDirs deleteReportsOnAggregation = false coverageOutputCobertura = extension.coverageOutputCobertura coverageOutputXML = extension.coverageOutputXML @@ -186,10 +186,13 @@ class ScoveragePlugin implements Plugin { } def aggregationTask = project.tasks.create(AGGREGATE_NAME, ScoverageAggregate) { + def dataDirs = allReportTasks.findResults { it.dirsToAggregateFrom.get() }.flatten() + dependsOn(allReportTasks) group = 'verification' runner = scoverageRunner reportDir = extension.reportDir + dirsToAggregateFrom = dataDirs deleteReportsOnAggregation = extension.deleteReportsOnAggregation coverageOutputCobertura = extension.coverageOutputCobertura coverageOutputXML = extension.coverageOutputXML diff --git a/src/main/groovy/org/scoverage/ScoverageReport.groovy b/src/main/groovy/org/scoverage/ScoverageReport.groovy index d5c5691..5dc395b 100644 --- a/src/main/groovy/org/scoverage/ScoverageReport.groovy +++ b/src/main/groovy/org/scoverage/ScoverageReport.groovy @@ -8,11 +8,7 @@ import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction // don't use scala.collection.JavaConverters as it breaks backward compatibility with scala 2.11 import scala.collection.JavaConversions -import scala.collection.Seq -import scala.collection.Set -import scoverage.Coverage -import scoverage.IOUtils -import scoverage.Serializer +import scoverage.report.CoverageAggregator @CacheableTask class ScoverageReport extends DefaultTask { @@ -40,25 +36,18 @@ class ScoverageReport extends DefaultTask { @TaskAction def report() { runner.run { + reportDir.get().delete() reportDir.get().mkdirs() - File coverageFile = Serializer.coverageFile(dataDir.get()) + def coverage = CoverageAggregator.aggregate(JavaConversions.asScalaBuffer(Arrays.asList(dataDir.get()))) - if (!coverageFile.exists()) { + if (coverage.isEmpty()) { project.logger.info("[scoverage] Could not find coverage file, skipping...") } else { - File[] array = IOUtils.findMeasurementFiles(dataDir.get()) - Seq measurementFiles = JavaConversions.asScalaBuffer(Arrays.asList(array)) - - Coverage coverage = Serializer.deserialize(coverageFile) - - Set measurements = IOUtils.invoked(measurementFiles) - coverage.apply(measurements) - new ScoverageWriter(project.logger).write( sources.get(), reportDir.get(), - coverage, + coverage.get(), coverageOutputCobertura.get(), coverageOutputXML.get(), coverageOutputHTML.get(), From cc1c43fb85874f70976eff43df48ed1f44d4c4e9 Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 28 Jul 2019 13:39:18 +0100 Subject: [PATCH 070/167] statement count appears to fixed in 1.4 --- .../ScalaMultiModuleWithMultipleTestTasksTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/functionalTest/java/org.scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java b/src/functionalTest/java/org.scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java index 1905a1c..66863c4 100644 --- a/src/functionalTest/java/org.scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java @@ -225,7 +225,7 @@ public void checkAndAggregateScoverageWithoutCoverageInRoot() throws Exception { result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); assertAllReportFilesExist(); - assertCoverage(93.33); + assertCoverage(88.24); } @Test From 3f8e297051a9fee069cee10909af600f1dfb7bbc Mon Sep 17 00:00:00 2001 From: Stu Date: Wed, 7 Aug 2019 09:40:15 +0100 Subject: [PATCH 071/167] use the new aggregation function which supports arrays --- src/main/groovy/org/scoverage/ScoverageAggregate.groovy | 2 +- src/main/groovy/org/scoverage/ScoverageReport.groovy | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy index 9505a4d..1ba9b85 100644 --- a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy +++ b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy @@ -43,7 +43,7 @@ class ScoverageAggregate extends DefaultTask { reportDir.get().deleteDir() reportDir.get().mkdirs() - def coverage = CoverageAggregator.aggregate(JavaConversions.asScalaBuffer(dirsToAggregateFrom.get())) + def coverage = CoverageAggregator.aggregate(dirsToAggregateFrom.get() as File[]) if (coverage.nonEmpty()) { new ScoverageWriter(project.logger).write( diff --git a/src/main/groovy/org/scoverage/ScoverageReport.groovy b/src/main/groovy/org/scoverage/ScoverageReport.groovy index 5dc395b..6f5e3ee 100644 --- a/src/main/groovy/org/scoverage/ScoverageReport.groovy +++ b/src/main/groovy/org/scoverage/ScoverageReport.groovy @@ -39,7 +39,7 @@ class ScoverageReport extends DefaultTask { reportDir.get().delete() reportDir.get().mkdirs() - def coverage = CoverageAggregator.aggregate(JavaConversions.asScalaBuffer(Arrays.asList(dataDir.get()))) + def coverage = CoverageAggregator.aggregate([dataDir.get()] as File[]) if (coverage.isEmpty()) { project.logger.info("[scoverage] Could not find coverage file, skipping...") From 89e09f087b42747cb2b789fe66067a86294feee1 Mon Sep 17 00:00:00 2001 From: Stu Date: Thu, 8 Aug 2019 21:32:18 +0100 Subject: [PATCH 072/167] add a test for 2.13 --- .../java/org.scoverage/ScalaSingleModuleTest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java index d53881b..b06278d 100644 --- a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java @@ -142,6 +142,15 @@ public void reportScoverageUnder2_11() throws Exception { assertReportFilesExist(); } + @Test + public void reportScoverageUnder2_13() throws Exception { + run("clean", ScoveragePlugin.getREPORT_NAME(), + "-PscalaVersionMinor=13", + "-PscalaVersionBuild=0", + "-Pscoverage.scoverageScalaVersion=2_13"); + assertReportFilesExist(); + } + private void assertReportFilesExist() { Assert.assertTrue(resolve(reportDir(), "index.html").exists()); From 433b79c147c0f02d1e2ce1ce4a6a6cf47222bcf6 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Tue, 10 Sep 2019 10:04:20 +0300 Subject: [PATCH 073/167] Fix #112 - report on specific module in a multi-module project without normal compilation fails --- .../org.scoverage/ScalaMultiModuleTest.java | 30 +++++++- .../org/scoverage/ScoveragePlugin.groovy | 76 ++++++++++--------- 2 files changed, 67 insertions(+), 39 deletions(-) diff --git a/src/functionalTest/java/org.scoverage/ScalaMultiModuleTest.java b/src/functionalTest/java/org.scoverage/ScalaMultiModuleTest.java index 5818ca5..6442b1b 100644 --- a/src/functionalTest/java/org.scoverage/ScalaMultiModuleTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaMultiModuleTest.java @@ -36,12 +36,38 @@ public void reportScoverageOnlyRoot() { @Test public void reportScoverageOnlyA() { - AssertableBuildResult result = dryRun("clean", ":a:" + ScoveragePlugin.getREPORT_NAME()); + AssertableBuildResult result = run("clean", ":a:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskDoesntExist(ScoveragePlugin.getREPORT_NAME()); - result.assertTaskExists("a:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskDoesntExist("b:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskDoesntExist("common:" + ScoveragePlugin.getREPORT_NAME()); + + result.assertTaskSucceeded("a:" + ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded("a:" + ScoveragePlugin.getREPORT_NAME()); + + assertAReportFilesExist(); + } + + @Test + public void reportScoverageOnlyAWithoutNormalCompilation() { + + AssertableBuildResult result = run("clean", ":a:" + ScoveragePlugin.getREPORT_NAME(), + "-x", "compileScala"); + + result.assertTaskSkipped("compileScala"); + result.assertTaskSkipped("a:compileScala"); + result.assertTaskSkipped("common:compileScala"); + result.assertTaskSucceeded("common:" + ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded("a:" + ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded("a:" + ScoveragePlugin.getREPORT_NAME()); + + assertAReportFilesExist(); + + Assert.assertTrue(resolve(buildDir(resolve(projectDir(), "a")), "classes/scala/main/org/hello/a/WorldA.class").exists()); + Assert.assertFalse(resolve(buildDir(resolve(projectDir(), "a")), "classes/scala/scoverage/org/hello/a/WorldA.class").exists()); + + Assert.assertTrue(resolve(buildDir(resolve(projectDir(), "common")), "classes/scala/main/org/hello/common/WorldCommon.class").exists()); + Assert.assertFalse(resolve(buildDir(resolve(projectDir(), "common")), "classes/scala/scoverage/org/hello/common/WorldCommon.class").exists()); } @Test diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index af6dc80..86c2180 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -266,51 +266,53 @@ class ScoveragePlugin implements Plugin { } } } + } - compileTask.configure { - if (!graph.hasTask(originalCompileTask)) { - destinationDir = originalCompileTask.destinationDir - } else { - doFirst { - destinationDir.deleteDir() - } + compileTask.configure { + if (!graph.hasTask(originalCompileTask)) { + project.logger.info("Making scoverage compilation the primary compilation task (instead of compileScala)") + destinationDir = originalCompileTask.destinationDir + } else { + doFirst { + destinationDir.deleteDir() + } - // delete non-instrumented classes by comparing normally compiled classes to those compiled with scoverage - doLast { - def originalCompileTaskName = project.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) - .getCompileTaskName("scala") - def originalDestinationDir = project.tasks[originalCompileTaskName].destinationDir - - def findFiles = { File dir, Closure condition = null -> - def files = [] - - if (dir.exists()) { - dir.eachFileRecurse(FILES) { f -> - if (condition == null || condition(f)) { - def relativePath = dir.relativePath(f) - files << relativePath - } + // delete non-instrumented classes by comparing normally compiled classes to those compiled with scoverage + doLast { + project.logger.info("Deleting classes compiled by scoverage but non-instrumented (identical to normal compilation)") + def originalCompileTaskName = project.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) + .getCompileTaskName("scala") + def originalDestinationDir = project.tasks[originalCompileTaskName].destinationDir + + def findFiles = { File dir, Closure condition = null -> + def files = [] + + if (dir.exists()) { + dir.eachFileRecurse(FILES) { f -> + if (condition == null || condition(f)) { + def relativePath = dir.relativePath(f) + files << relativePath } } - - files } - def isSameFile = { String relativePath -> - def fileA = new File(originalDestinationDir, relativePath) - def fileB = new File(destinationDir, relativePath) - FileUtils.contentEquals(fileA, fileB) - } + files + } - def originalClasses = findFiles(originalDestinationDir) - def identicalInstrumentedClasses = findFiles(destinationDir, { f -> - def relativePath = destinationDir.relativePath(f) - originalClasses.contains(relativePath) && isSameFile(relativePath) - }) + def isSameFile = { String relativePath -> + def fileA = new File(originalDestinationDir, relativePath) + def fileB = new File(destinationDir, relativePath) + FileUtils.contentEquals(fileA, fileB) + } - identicalInstrumentedClasses.each { f -> - Files.deleteIfExists(destinationDir.toPath().resolve(f)) - } + def originalClasses = findFiles(originalDestinationDir) + def identicalInstrumentedClasses = findFiles(destinationDir, { f -> + def relativePath = destinationDir.relativePath(f) + originalClasses.contains(relativePath) && isSameFile(relativePath) + }) + + identicalInstrumentedClasses.each { f -> + Files.deleteIfExists(destinationDir.toPath().resolve(f)) } } } From 86fe8d22cbf44605e000eee97a0fa21e61ed3310 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Tue, 10 Sep 2019 11:10:14 +0300 Subject: [PATCH 074/167] Remove redundant functional test for Scala 2.11 (which is also failing Travis CI build) --- .../java/org.scoverage/ScalaSingleModuleTest.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java index d53881b..f93e184 100644 --- a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java @@ -133,15 +133,6 @@ public void reportScoverageWithoutNormalCompilationAndWithExcludedClasses() thro Assert.assertFalse(resolve(buildDir(), "classes/scala/scoverage/org/hello/World.class").exists()); } - @Test - public void reportScoverageUnder2_11() throws Exception { - run("clean", ScoveragePlugin.getREPORT_NAME(), - "-PscalaVersionMinor=11", - "-PscalaVersionBuild=8", - "-Pscoverage.scoverageScalaVersion=2_11"); - assertReportFilesExist(); - } - private void assertReportFilesExist() { Assert.assertTrue(resolve(reportDir(), "index.html").exists()); From 1c4ea7f7015c5e1477dd84d7b7f5b0a4c5293245 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Sat, 14 Sep 2019 16:15:16 +0300 Subject: [PATCH 075/167] Add detection of scala version via 'implementation' and 'compileOnly' configurations --- .../org.scoverage/DetectScalaLibraryTest.java | 43 +++++++++++++++ .../ScoverageFunctionalTest.java | 22 ++++---- .../detect-scala-library/compile/build.gradle | 9 ++++ .../compile/settings.gradle | 0 .../compileOnly/build.gradle | 9 ++++ .../compileOnly/settings.gradle | 0 .../dependency-management/build.gradle | 16 ++++++ .../dependency-management/settings.gradle | 0 .../implementation/build.gradle | 9 ++++ .../implementation/settings.gradle | 0 .../org/scoverage/ScoveragePlugin.groovy | 54 ++++++++++++------- 11 files changed, 133 insertions(+), 29 deletions(-) create mode 100644 src/functionalTest/java/org.scoverage/DetectScalaLibraryTest.java create mode 100644 src/functionalTest/resources/projects/detect-scala-library/compile/build.gradle create mode 100644 src/functionalTest/resources/projects/detect-scala-library/compile/settings.gradle create mode 100644 src/functionalTest/resources/projects/detect-scala-library/compileOnly/build.gradle create mode 100644 src/functionalTest/resources/projects/detect-scala-library/compileOnly/settings.gradle create mode 100644 src/functionalTest/resources/projects/detect-scala-library/dependency-management/build.gradle create mode 100644 src/functionalTest/resources/projects/detect-scala-library/dependency-management/settings.gradle create mode 100644 src/functionalTest/resources/projects/detect-scala-library/implementation/build.gradle create mode 100644 src/functionalTest/resources/projects/detect-scala-library/implementation/settings.gradle diff --git a/src/functionalTest/java/org.scoverage/DetectScalaLibraryTest.java b/src/functionalTest/java/org.scoverage/DetectScalaLibraryTest.java new file mode 100644 index 0000000..1c60a1c --- /dev/null +++ b/src/functionalTest/java/org.scoverage/DetectScalaLibraryTest.java @@ -0,0 +1,43 @@ +package org.scoverage; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.Arrays; +import java.util.Collection; + +@RunWith(Parameterized.class) +public class DetectScalaLibraryTest extends ScoverageFunctionalTest { + + private static final String SCALA_VERSION = "0.0"; + private static final String SCALA_LIBRARY_PARAMETER = "-PdetectedScalaLibraryVersion=" + SCALA_VERSION + ".0"; + private static final String EXPECTED_OUTPUT = "Using scoverage scalac plugin version '" + SCALA_VERSION; + + @Parameterized.Parameter(0) + public String projectDir; + + @Parameterized.Parameters(name = "{index}: Project {0} ") + public static Collection data() { + Object[][] data = new Object[][]{{"/compile"}, {"/compileOnly"}, {"/implementation"}, {"/dependency-management"}}; + return Arrays.asList(data); + } + + public DetectScalaLibraryTest() { + super(null); + } + + @Test + public void test() { + setProjectName("detect-scala-library" + projectDir); + + // build supposed to fail since repositories are not configured + AssertableBuildResult result = runAndFail("clean", SCALA_LIBRARY_PARAMETER, "--info"); + + // all we want to know is that the plugin detected our configured library version + String output = result.getResult().getOutput(); + Assert.assertTrue(output.contains(EXPECTED_OUTPUT)); + } + +} \ No newline at end of file diff --git a/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java b/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java index af14ce5..c60f8d2 100644 --- a/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java +++ b/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java @@ -23,18 +23,12 @@ public abstract class ScoverageFunctionalTest { - private final String projectName; - private final GradleRunner runner; + private String projectName; + private GradleRunner runner; private final XmlParser parser; protected ScoverageFunctionalTest(String projectName) { - - this.projectName = projectName; - this.runner = GradleRunner.create() - .withProjectDir(projectDir()) - .withPluginClasspath() - .forwardOutput(); - + setProjectName(projectName); try { this.parser = new XmlParser(); parser.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false); @@ -44,6 +38,16 @@ protected ScoverageFunctionalTest(String projectName) { } } + protected void setProjectName(String projectName) { + if (projectName != null) { + this.projectName = projectName; + this.runner = GradleRunner.create() + .withProjectDir(projectDir()) + .withPluginClasspath() + .forwardOutput(); + } + } + protected File projectDir() { return new File("src/functionalTest/resources/projects/" + projectName); diff --git a/src/functionalTest/resources/projects/detect-scala-library/compile/build.gradle b/src/functionalTest/resources/projects/detect-scala-library/compile/build.gradle new file mode 100644 index 0000000..cf21671 --- /dev/null +++ b/src/functionalTest/resources/projects/detect-scala-library/compile/build.gradle @@ -0,0 +1,9 @@ +plugins { + id 'org.scoverage' +} + +description = 'defines scala library using the "compile" configuration' + +dependencies { + compile group: 'org.scala-lang', name: 'scala-library', version: "${detectedScalaLibraryVersion}" +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/detect-scala-library/compile/settings.gradle b/src/functionalTest/resources/projects/detect-scala-library/compile/settings.gradle new file mode 100644 index 0000000..e69de29 diff --git a/src/functionalTest/resources/projects/detect-scala-library/compileOnly/build.gradle b/src/functionalTest/resources/projects/detect-scala-library/compileOnly/build.gradle new file mode 100644 index 0000000..67ec586 --- /dev/null +++ b/src/functionalTest/resources/projects/detect-scala-library/compileOnly/build.gradle @@ -0,0 +1,9 @@ +plugins { + id 'org.scoverage' +} + +description = 'defines scala library using the "compileOnly" configuration' + +dependencies { + compileOnly group: 'org.scala-lang', name: 'scala-library', version: "${detectedScalaLibraryVersion}" +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/detect-scala-library/compileOnly/settings.gradle b/src/functionalTest/resources/projects/detect-scala-library/compileOnly/settings.gradle new file mode 100644 index 0000000..e69de29 diff --git a/src/functionalTest/resources/projects/detect-scala-library/dependency-management/build.gradle b/src/functionalTest/resources/projects/detect-scala-library/dependency-management/build.gradle new file mode 100644 index 0000000..6f48d15 --- /dev/null +++ b/src/functionalTest/resources/projects/detect-scala-library/dependency-management/build.gradle @@ -0,0 +1,16 @@ +plugins { + id 'io.spring.dependency-management' version "1.0.4.RELEASE" + id 'org.scoverage' +} + +description = 'defines scala library using the "implementation" configuration and the dependency-management plugin' + +dependencyManagement { + dependencies { + dependency group: 'org.scala-lang', name: 'scala-library', version: "${detectedScalaLibraryVersion}" + } +} + +dependencies { + implementation group: 'org.scala-lang', name: 'scala-library' +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/detect-scala-library/dependency-management/settings.gradle b/src/functionalTest/resources/projects/detect-scala-library/dependency-management/settings.gradle new file mode 100644 index 0000000..e69de29 diff --git a/src/functionalTest/resources/projects/detect-scala-library/implementation/build.gradle b/src/functionalTest/resources/projects/detect-scala-library/implementation/build.gradle new file mode 100644 index 0000000..67460ad --- /dev/null +++ b/src/functionalTest/resources/projects/detect-scala-library/implementation/build.gradle @@ -0,0 +1,9 @@ +plugins { + id 'org.scoverage' +} + +description = 'defines scala library using the "implementation" configuration' + +dependencies { + implementation group: 'org.scala-lang', name: 'scala-library', version: "${detectedScalaLibraryVersion}" +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/detect-scala-library/implementation/settings.gradle b/src/functionalTest/resources/projects/detect-scala-library/implementation/settings.gradle new file mode 100644 index 0000000..e69de29 diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index af6dc80..4b1db20 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -63,27 +63,8 @@ class ScoveragePlugin implements Plugin { } project.afterEvaluate { + def scalaVersion = resolveScalaVersion(project) def scoverageVersion = project.extensions.scoverage.scoverageVersion.get() - def scalaVersion = null - - def scalaLibrary = project.configurations.compile.dependencies.find { - it.group == "org.scala-lang" && it.name == "scala-library" - } - - if (scalaLibrary != null) { - scalaVersion = scalaLibrary.version - } - - if (scalaVersion == null && project.pluginManager.hasPlugin("io.spring.dependency-management")) { - scalaVersion = project.dependencyManagement.compile.managedVersions["org.scala-lang:scala-library"] - } - - if (scalaVersion == null) { - scalaVersion = project.extensions.scoverage.scoverageScalaVersion.get() - } else { - scalaVersion = scalaVersion.substring(0, scalaVersion.lastIndexOf(".")) - } - def fullScoverageVersion = "$scalaVersion:$scoverageVersion" project.logger.info("Using scoverage scalac plugin version '$fullScoverageVersion'") @@ -319,6 +300,39 @@ class ScoveragePlugin implements Plugin { } } + private String resolveScalaVersion(Project project) { + def scalaVersion = null + + def configurations = [ + project.configurations.compile, + project.configurations.compileOnly, + project.configurations.implementation + ] + def dependencies = configurations.collectMany { it.dependencies } + + def scalaLibrary = dependencies.find { + it.group == "org.scala-lang" && it.name == "scala-library" + } + + if (scalaLibrary != null) { + scalaVersion = scalaLibrary.version + } + + if (scalaVersion == null && project.pluginManager.hasPlugin("io.spring.dependency-management")) { + scalaVersion = project.dependencyManagement.compile.managedVersions["org.scala-lang:scala-library"] + } + + if (scalaVersion == null) { + project.logger.info("No scala library detected. Using property 'scoverageScalaVersion'") + scalaVersion = project.extensions.scoverage.scoverageScalaVersion.get() + } else { + project.logger.info("Detected scala library in compilation classpath") + scalaVersion = scalaVersion.substring(0, scalaVersion.lastIndexOf(".")) + } + + return scalaVersion + } + private Set recursiveDependenciesOf(Task task) { if (!taskDependencies.containsKey(task)) { def directDependencies = task.getTaskDependencies().getDependencies(task) From b0c01a7b891a2ccac2d48dfbebe81aefafb0e4c2 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Tue, 10 Sep 2019 11:10:14 +0300 Subject: [PATCH 076/167] Remove redundant functional test for Scala 2.11 (which is also failing Travis CI build) --- .../java/org.scoverage/ScalaSingleModuleTest.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java index d53881b..f93e184 100644 --- a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java @@ -133,15 +133,6 @@ public void reportScoverageWithoutNormalCompilationAndWithExcludedClasses() thro Assert.assertFalse(resolve(buildDir(), "classes/scala/scoverage/org/hello/World.class").exists()); } - @Test - public void reportScoverageUnder2_11() throws Exception { - run("clean", ScoveragePlugin.getREPORT_NAME(), - "-PscalaVersionMinor=11", - "-PscalaVersionBuild=8", - "-Pscoverage.scoverageScalaVersion=2_11"); - assertReportFilesExist(); - } - private void assertReportFilesExist() { Assert.assertTrue(resolve(reportDir(), "index.html").exists()); From 0c01830c752bdff87d54c70b25ce37bc405535df Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Sat, 14 Sep 2019 19:47:19 +0300 Subject: [PATCH 077/167] Resolve scala library version according to the resolved compilation classpath This commit adds support for any plugin which manipulates the configuration via resolution strategy. --- .../org.scoverage/DetectScalaLibraryTest.java | 20 ++++++++----- .../detect-scala-library/compile/build.gradle | 4 +++ .../compileOnly/build.gradle | 4 +++ .../dependency-management/build.gradle | 4 +++ .../implementation/build.gradle | 4 +++ .../org/scoverage/ScoveragePlugin.groovy | 29 +++++-------------- 6 files changed, 35 insertions(+), 30 deletions(-) diff --git a/src/functionalTest/java/org.scoverage/DetectScalaLibraryTest.java b/src/functionalTest/java/org.scoverage/DetectScalaLibraryTest.java index 1c60a1c..9b2d163 100644 --- a/src/functionalTest/java/org.scoverage/DetectScalaLibraryTest.java +++ b/src/functionalTest/java/org.scoverage/DetectScalaLibraryTest.java @@ -11,9 +11,11 @@ @RunWith(Parameterized.class) public class DetectScalaLibraryTest extends ScoverageFunctionalTest { - private static final String SCALA_VERSION = "0.0"; - private static final String SCALA_LIBRARY_PARAMETER = "-PdetectedScalaLibraryVersion=" + SCALA_VERSION + ".0"; - private static final String EXPECTED_OUTPUT = "Using scoverage scalac plugin version '" + SCALA_VERSION; + private static final String SCALA_VERSION = "2.12"; + private static final String SCALA_LIBRARY_PARAMETER = "-PdetectedScalaLibraryVersion="; + + private static final String EXPECTED_OUTPUT_A = "Detected scala library in compilation classpath"; + private static final String EXPECTED_OUTPUT_B = "Using scoverage scalac plugin version '" + SCALA_VERSION; @Parameterized.Parameter(0) public String projectDir; @@ -31,13 +33,15 @@ public DetectScalaLibraryTest() { @Test public void test() { setProjectName("detect-scala-library" + projectDir); + testWithParameter(SCALA_LIBRARY_PARAMETER + SCALA_VERSION + ".0"); + testWithParameter(SCALA_LIBRARY_PARAMETER + SCALA_VERSION + ".+"); + } - // build supposed to fail since repositories are not configured - AssertableBuildResult result = runAndFail("clean", SCALA_LIBRARY_PARAMETER, "--info"); - - // all we want to know is that the plugin detected our configured library version + private void testWithParameter(String parameter) { + AssertableBuildResult result = dryRun("clean", parameter, "--info"); String output = result.getResult().getOutput(); - Assert.assertTrue(output.contains(EXPECTED_OUTPUT)); + Assert.assertTrue(output.contains(EXPECTED_OUTPUT_A)); + Assert.assertTrue(output.contains(EXPECTED_OUTPUT_B)); } } \ No newline at end of file diff --git a/src/functionalTest/resources/projects/detect-scala-library/compile/build.gradle b/src/functionalTest/resources/projects/detect-scala-library/compile/build.gradle index cf21671..8201e48 100644 --- a/src/functionalTest/resources/projects/detect-scala-library/compile/build.gradle +++ b/src/functionalTest/resources/projects/detect-scala-library/compile/build.gradle @@ -2,6 +2,10 @@ plugins { id 'org.scoverage' } +repositories { + jcenter() +} + description = 'defines scala library using the "compile" configuration' dependencies { diff --git a/src/functionalTest/resources/projects/detect-scala-library/compileOnly/build.gradle b/src/functionalTest/resources/projects/detect-scala-library/compileOnly/build.gradle index 67ec586..4dd36e8 100644 --- a/src/functionalTest/resources/projects/detect-scala-library/compileOnly/build.gradle +++ b/src/functionalTest/resources/projects/detect-scala-library/compileOnly/build.gradle @@ -2,6 +2,10 @@ plugins { id 'org.scoverage' } +repositories { + jcenter() +} + description = 'defines scala library using the "compileOnly" configuration' dependencies { diff --git a/src/functionalTest/resources/projects/detect-scala-library/dependency-management/build.gradle b/src/functionalTest/resources/projects/detect-scala-library/dependency-management/build.gradle index 6f48d15..c4de0c2 100644 --- a/src/functionalTest/resources/projects/detect-scala-library/dependency-management/build.gradle +++ b/src/functionalTest/resources/projects/detect-scala-library/dependency-management/build.gradle @@ -3,6 +3,10 @@ plugins { id 'org.scoverage' } +repositories { + jcenter() +} + description = 'defines scala library using the "implementation" configuration and the dependency-management plugin' dependencyManagement { diff --git a/src/functionalTest/resources/projects/detect-scala-library/implementation/build.gradle b/src/functionalTest/resources/projects/detect-scala-library/implementation/build.gradle index 67460ad..be9936b 100644 --- a/src/functionalTest/resources/projects/detect-scala-library/implementation/build.gradle +++ b/src/functionalTest/resources/projects/detect-scala-library/implementation/build.gradle @@ -2,6 +2,10 @@ plugins { id 'org.scoverage' } +repositories { + jcenter() +} + description = 'defines scala library using the "implementation" configuration' dependencies { diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 4b1db20..5c0e20c 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -301,36 +301,21 @@ class ScoveragePlugin implements Plugin { } private String resolveScalaVersion(Project project) { - def scalaVersion = null - def configurations = [ - project.configurations.compile, - project.configurations.compileOnly, - project.configurations.implementation - ] - def dependencies = configurations.collectMany { it.dependencies } + def resolvedDependencies = project.configurations.compileClasspath.resolvedConfiguration.firstLevelModuleDependencies - def scalaLibrary = dependencies.find { - it.group == "org.scala-lang" && it.name == "scala-library" + def scalaLibrary = resolvedDependencies.find { + it.moduleGroup == "org.scala-lang" && it.moduleName == "scala-library" } - if (scalaLibrary != null) { - scalaVersion = scalaLibrary.version - } - - if (scalaVersion == null && project.pluginManager.hasPlugin("io.spring.dependency-management")) { - scalaVersion = project.dependencyManagement.compile.managedVersions["org.scala-lang:scala-library"] - } - - if (scalaVersion == null) { + if (scalaLibrary == null) { project.logger.info("No scala library detected. Using property 'scoverageScalaVersion'") - scalaVersion = project.extensions.scoverage.scoverageScalaVersion.get() + return project.extensions.scoverage.scoverageScalaVersion.get() } else { project.logger.info("Detected scala library in compilation classpath") - scalaVersion = scalaVersion.substring(0, scalaVersion.lastIndexOf(".")) + def fullScalaVersion = scalaLibrary.moduleVersion + return fullScalaVersion.substring(0, fullScalaVersion.lastIndexOf(".")) } - - return scalaVersion } private Set recursiveDependenciesOf(Task task) { From d5078807a19e7b4b34b9485d3eb7da172a020f0f Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Mon, 16 Sep 2019 21:47:14 +0300 Subject: [PATCH 078/167] Fix incorrect reading of source files when generating an HTML report (#68) --- .../groovy/org/scoverage/ScoverageAggregate.groovy | 4 ++++ src/main/groovy/org/scoverage/ScoveragePlugin.groovy | 9 +++++++++ src/main/groovy/org/scoverage/ScoverageReport.groovy | 4 ++++ src/main/groovy/org/scoverage/ScoverageWriter.java | 10 +++++++++- 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy index e41d16b..08d5eac 100644 --- a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy +++ b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy @@ -24,6 +24,9 @@ class ScoverageAggregate extends DefaultTask { @Input final Property deleteReportsOnAggregation = project.objects.property(Boolean) + @Input + final Property sourceEncoding = project.objects.property(String) + // TODO - consider separate options for `report` and `aggregate` tasks @Input final Property coverageOutputCobertura = project.objects.property(Boolean) @@ -60,6 +63,7 @@ class ScoverageAggregate extends DefaultTask { rootDir, reportDir.get(), coverage.get(), + sourceEncoding.get(), coverageOutputCobertura.get(), coverageOutputXML.get(), coverageOutputHTML.get(), diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 8be36fb..4666a6c 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -104,7 +104,13 @@ class ScoveragePlugin implements Plugin { def globalReportTask = project.tasks.register(REPORT_NAME, ScoverageAggregate) def globalCheckTask = project.tasks.register(CHECK_NAME, OverallCheckTask) + project.afterEvaluate { + def detectedSourceEncoding = compileTask.scalaCompileOptions.encoding + if (detectedSourceEncoding == null) { + detectedSourceEncoding = "UTF-8" + } + // calling toList() on TaskCollection is required // to avoid potential ConcurrentModificationException in multi-project builds def testTasks = project.tasks.withType(Test).toList() @@ -123,6 +129,7 @@ class ScoveragePlugin implements Plugin { reportDir = taskReportDir sources = extension.sources dataDir = extension.dataDir + sourceEncoding.set(detectedSourceEncoding) coverageOutputCobertura = extension.coverageOutputCobertura coverageOutputXML = extension.coverageOutputXML coverageOutputHTML = extension.coverageOutputHTML @@ -139,6 +146,7 @@ class ScoveragePlugin implements Plugin { group = 'verification' runner = scoverageRunner reportDir = extension.reportDir + sourceEncoding.set(detectedSourceEncoding) dirsToAggregateFrom = reportDirs deleteReportsOnAggregation = false coverageOutputCobertura = extension.coverageOutputCobertura @@ -171,6 +179,7 @@ class ScoveragePlugin implements Plugin { group = 'verification' runner = scoverageRunner reportDir = extension.reportDir + sourceEncoding.set(detectedSourceEncoding) deleteReportsOnAggregation = extension.deleteReportsOnAggregation coverageOutputCobertura = extension.coverageOutputCobertura coverageOutputXML = extension.coverageOutputXML diff --git a/src/main/groovy/org/scoverage/ScoverageReport.groovy b/src/main/groovy/org/scoverage/ScoverageReport.groovy index d5c5691..784213d 100644 --- a/src/main/groovy/org/scoverage/ScoverageReport.groovy +++ b/src/main/groovy/org/scoverage/ScoverageReport.groovy @@ -28,6 +28,9 @@ class ScoverageReport extends DefaultTask { @OutputDirectory final Property reportDir = project.objects.property(File) + @Input + final Property sourceEncoding = project.objects.property(String) + @Input final Property coverageOutputCobertura = project.objects.property(Boolean) @Input @@ -59,6 +62,7 @@ class ScoverageReport extends DefaultTask { sources.get(), reportDir.get(), coverage, + sourceEncoding.get(), coverageOutputCobertura.get(), coverageOutputXML.get(), coverageOutputHTML.get(), diff --git a/src/main/groovy/org/scoverage/ScoverageWriter.java b/src/main/groovy/org/scoverage/ScoverageWriter.java index cf68851..a4c7ecf 100644 --- a/src/main/groovy/org/scoverage/ScoverageWriter.java +++ b/src/main/groovy/org/scoverage/ScoverageWriter.java @@ -1,6 +1,9 @@ package org.scoverage; import org.gradle.api.logging.Logger; +import scala.Some; +import scala.collection.JavaConverters; +import scala.collection.mutable.Buffer; import scoverage.Constants; import scoverage.Coverage; import scoverage.report.CoberturaXmlWriter; @@ -8,6 +11,8 @@ import scoverage.report.ScoverageXmlWriter; import java.io.File; +import java.nio.charset.Charset; +import java.util.Arrays; /** * Util for generating and saving coverage files. @@ -29,6 +34,7 @@ public ScoverageWriter(Logger logger) { * @param sourceDir directory with project sources * @param reportDir directory for generate reports * @param coverage coverage data + * @param sourceEncoding the encoding of the source files * @param coverageOutputCobertura switch for Cobertura output * @param coverageOutputXML switch for Scoverage XML output * @param coverageOutputHTML switch for Scoverage HTML output @@ -37,6 +43,7 @@ public ScoverageWriter(Logger logger) { public void write(File sourceDir, File reportDir, Coverage coverage, + String sourceEncoding, Boolean coverageOutputCobertura, Boolean coverageOutputXML, Boolean coverageOutputHTML, @@ -70,7 +77,8 @@ public void write(File sourceDir, } if (coverageOutputHTML) { - new ScoverageHtmlWriter(sourceDir, reportDir).write(coverage); + Buffer sources = JavaConverters.asScalaBuffer(Arrays.asList(sourceDir)); + new ScoverageHtmlWriter(sources, reportDir, new Some<>(sourceEncoding)).write(coverage); logger.info("[scoverage] Written HTML report to " + reportDir.getAbsolutePath() + File.separator + From e856e030490807ec2ea407c9f74bcf9eabb2d299 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Sun, 15 Sep 2019 17:52:37 +0300 Subject: [PATCH 079/167] Add support for configuring multiple check tasks (#93) --- build.gradle | 12 +- .../org.scoverage/MultipleCheckTasksTest.java | 91 +++++++++++++ .../multiple-checks/build.gradle | 40 ++++++ .../multiple-checks/settings.gradle | 0 .../src/main/scala/org/hello/World.scala | 8 ++ .../src/test/scala/org/hello/WorldSuite.scala | 13 ++ .../no-check/build.gradle | 25 ++++ .../no-check/settings.gradle | 0 .../src/main/scala/org/hello/World.scala | 8 ++ .../src/test/scala/org/hello/WorldSuite.scala | 13 ++ .../old-and-new-syntax/build.gradle | 38 ++++++ .../old-and-new-syntax/settings.gradle | 0 .../src/main/scala/org/hello/World.scala | 8 ++ .../src/test/scala/org/hello/WorldSuite.scala | 13 ++ .../single-check-new-syntax/build.gradle | 32 +++++ .../single-check-new-syntax/settings.gradle | 0 .../src/main/scala/org/hello/World.scala | 8 ++ .../src/test/scala/org/hello/WorldSuite.scala | 13 ++ .../single-check-old-syntax/build.gradle | 30 +++++ .../single-check-old-syntax/settings.gradle | 0 .../src/main/scala/org/hello/World.scala | 8 ++ .../src/test/scala/org/hello/WorldSuite.scala | 13 ++ ...heckTask.groovy => CoverageChecker.groovy} | 61 ++++----- .../org/scoverage/ScoverageExtension.groovy | 24 +++- .../org/scoverage/ScoveragePlugin.groovy | 45 +++++-- .../org/scoverage/CoverageCheckerTest.groovy | 122 +++++++++++++++++ .../org/scoverage/OverallCheckTaskTest.groovy | 126 ------------------ 27 files changed, 569 insertions(+), 182 deletions(-) create mode 100644 src/functionalTest/java/org.scoverage/MultipleCheckTasksTest.java create mode 100644 src/functionalTest/resources/projects/multiple-check-tasks/multiple-checks/build.gradle create mode 100644 src/functionalTest/resources/projects/multiple-check-tasks/multiple-checks/settings.gradle create mode 100644 src/functionalTest/resources/projects/multiple-check-tasks/multiple-checks/src/main/scala/org/hello/World.scala create mode 100644 src/functionalTest/resources/projects/multiple-check-tasks/multiple-checks/src/test/scala/org/hello/WorldSuite.scala create mode 100644 src/functionalTest/resources/projects/multiple-check-tasks/no-check/build.gradle create mode 100644 src/functionalTest/resources/projects/multiple-check-tasks/no-check/settings.gradle create mode 100644 src/functionalTest/resources/projects/multiple-check-tasks/no-check/src/main/scala/org/hello/World.scala create mode 100644 src/functionalTest/resources/projects/multiple-check-tasks/no-check/src/test/scala/org/hello/WorldSuite.scala create mode 100644 src/functionalTest/resources/projects/multiple-check-tasks/old-and-new-syntax/build.gradle create mode 100644 src/functionalTest/resources/projects/multiple-check-tasks/old-and-new-syntax/settings.gradle create mode 100644 src/functionalTest/resources/projects/multiple-check-tasks/old-and-new-syntax/src/main/scala/org/hello/World.scala create mode 100644 src/functionalTest/resources/projects/multiple-check-tasks/old-and-new-syntax/src/test/scala/org/hello/WorldSuite.scala create mode 100644 src/functionalTest/resources/projects/multiple-check-tasks/single-check-new-syntax/build.gradle create mode 100644 src/functionalTest/resources/projects/multiple-check-tasks/single-check-new-syntax/settings.gradle create mode 100644 src/functionalTest/resources/projects/multiple-check-tasks/single-check-new-syntax/src/main/scala/org/hello/World.scala create mode 100644 src/functionalTest/resources/projects/multiple-check-tasks/single-check-new-syntax/src/test/scala/org/hello/WorldSuite.scala create mode 100644 src/functionalTest/resources/projects/multiple-check-tasks/single-check-old-syntax/build.gradle create mode 100644 src/functionalTest/resources/projects/multiple-check-tasks/single-check-old-syntax/settings.gradle create mode 100644 src/functionalTest/resources/projects/multiple-check-tasks/single-check-old-syntax/src/main/scala/org/hello/World.scala create mode 100644 src/functionalTest/resources/projects/multiple-check-tasks/single-check-old-syntax/src/test/scala/org/hello/WorldSuite.scala rename src/main/groovy/org/scoverage/{OverallCheckTask.groovy => CoverageChecker.groovy} (63%) create mode 100644 src/test/groovy/org/scoverage/CoverageCheckerTest.groovy delete mode 100644 src/test/groovy/org/scoverage/OverallCheckTaskTest.groovy diff --git a/build.gradle b/build.gradle index 1c7fb4d..f6b566d 100644 --- a/build.gradle +++ b/build.gradle @@ -46,16 +46,20 @@ targetCompatibility = '1.8' dependencies { compileOnly "org.scoverage:scalac-scoverage-plugin_2.12:1.3.1" - compile group: 'commons-io', name: 'commons-io', version: '2.6' - testCompile 'junit:junit:4.12' - testCompile 'org.hamcrest:hamcrest-library:1.3' + implementation group: 'commons-io', name: 'commons-io', version: '2.6' + + testImplementation 'junit:junit:4.12' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.5.2' + testRuntimeOnly 'org.junit.vintage:junit-vintage-engine:5.5.2' + + testImplementation 'org.hamcrest:hamcrest-library:1.3' } sourceSets { functionalTest { java.srcDir file('src/functionalTest/java') resources.srcDir file('src/functionalTest/resources') - compileClasspath += sourceSets.main.output + configurations.testRuntime + compileClasspath += sourceSets.main.output + configurations.testRuntimeClasspath runtimeClasspath += output + compileClasspath } } diff --git a/src/functionalTest/java/org.scoverage/MultipleCheckTasksTest.java b/src/functionalTest/java/org.scoverage/MultipleCheckTasksTest.java new file mode 100644 index 0000000..0980c4e --- /dev/null +++ b/src/functionalTest/java/org.scoverage/MultipleCheckTasksTest.java @@ -0,0 +1,91 @@ +package org.scoverage; + +import org.junit.Assert; +import org.junit.Test; + +public abstract class MultipleCheckTasksTest extends ScoverageFunctionalTest { + + /* --- Abstract Test ---- */ + + private final boolean shouldSucceed; + + public MultipleCheckTasksTest(String projectDir, boolean shouldSucceed) { + super("multiple-check-tasks/" + projectDir); + this.shouldSucceed = shouldSucceed; + } + + @Test + public void test() { + assertResult(run()); + } + + protected abstract void assertResult(AssertableBuildResult result); + + protected void assertOutput(AssertableBuildResult result, CoverageType type, double minimumRate) { + String expectedMessage = String.format("Checking coverage. Type: %s. Minimum rate: %s", type, minimumRate); + Assert.assertTrue(result.getResult().getOutput().contains(expectedMessage)); + } + + private AssertableBuildResult run() { + if (shouldSucceed) { + return run("clean", ScoveragePlugin.getCHECK_NAME(), "--info"); + } else { + return runAndFail(ScoveragePlugin.getCHECK_NAME(), "--info"); + } + } + + /* --- Test Classes ---- */ + + public static class MultipleChecks extends MultipleCheckTasksTest { + public MultipleChecks() { + super("multiple-checks", true); + } + @Override + protected void assertResult(AssertableBuildResult result) { + + result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); + assertOutput(result, CoverageType.Line, 0.3); + assertOutput(result, CoverageType.Branch, 0.1); + assertOutput(result, CoverageType.Statement, 0.6); + + } + } + public static class SingleCheckNewSyntax extends MultipleCheckTasksTest { + public SingleCheckNewSyntax() { + super("single-check-new-syntax", true); + } + @Override + protected void assertResult(AssertableBuildResult result) { + result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); + assertOutput(result, CoverageType.Line, 0.3); + } + } + public static class SingleCheckOldSyntax extends MultipleCheckTasksTest { + public SingleCheckOldSyntax() { + super("single-check-old-syntax", true); + } + @Override + protected void assertResult(AssertableBuildResult result) { + result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); + assertOutput(result, CoverageType.Line, 0.3); + } + } + public static class OldAndNewSyntax extends MultipleCheckTasksTest { + public OldAndNewSyntax() { + super("old-and-new-syntax", false); + } + @Override + protected void assertResult(AssertableBuildResult result) { + } + } + public static class NoCheck extends MultipleCheckTasksTest { + public NoCheck() { + super("no-check", true); + } + @Override + protected void assertResult(AssertableBuildResult result) { + result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); + assertOutput(result, ScoverageExtension.DEFAULT_COVERAGE_TYPE, ScoverageExtension.DEFAULT_MINIMUM_RATE); + } + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/multiple-checks/build.gradle b/src/functionalTest/resources/projects/multiple-check-tasks/multiple-checks/build.gradle new file mode 100644 index 0000000..01abbe0 --- /dev/null +++ b/src/functionalTest/resources/projects/multiple-check-tasks/multiple-checks/build.gradle @@ -0,0 +1,40 @@ +plugins { + id 'org.scoverage' +} + +repositories { + jcenter() +} + +description = 'a single-module Scala project that has multiple check configurations' + +apply plugin: 'java' +apply plugin: 'scala' + +dependencies { + compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + + testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion +} + +test { + useJUnitPlatform() +} + +scoverage { + check { + minimumRate = 0.3 + coverageType = org.scoverage.CoverageType.Line + } + check { + minimumRate = 0.1 + coverageType = org.scoverage.CoverageType.Branch + } + check { + minimumRate = 0.6 + coverageType = org.scoverage.CoverageType.Statement + } +} diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/multiple-checks/settings.gradle b/src/functionalTest/resources/projects/multiple-check-tasks/multiple-checks/settings.gradle new file mode 100644 index 0000000..e69de29 diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/multiple-checks/src/main/scala/org/hello/World.scala b/src/functionalTest/resources/projects/multiple-check-tasks/multiple-checks/src/main/scala/org/hello/World.scala new file mode 100644 index 0000000..94be85c --- /dev/null +++ b/src/functionalTest/resources/projects/multiple-check-tasks/multiple-checks/src/main/scala/org/hello/World.scala @@ -0,0 +1,8 @@ +package org.hello + +class World { + + def foo(): String = { + "a" + "b" + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/multiple-checks/src/test/scala/org/hello/WorldSuite.scala b/src/functionalTest/resources/projects/multiple-check-tasks/multiple-checks/src/test/scala/org/hello/WorldSuite.scala new file mode 100644 index 0000000..7281a12 --- /dev/null +++ b/src/functionalTest/resources/projects/multiple-check-tasks/multiple-checks/src/test/scala/org/hello/WorldSuite.scala @@ -0,0 +1,13 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldSuite extends FunSuite { + + test("foo") { + new World().foo() + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/no-check/build.gradle b/src/functionalTest/resources/projects/multiple-check-tasks/no-check/build.gradle new file mode 100644 index 0000000..07ca734 --- /dev/null +++ b/src/functionalTest/resources/projects/multiple-check-tasks/no-check/build.gradle @@ -0,0 +1,25 @@ +plugins { + id 'org.scoverage' +} + +repositories { + jcenter() +} + +description = 'a single-module Scala project with no check configured' + +apply plugin: 'java' +apply plugin: 'scala' + +dependencies { + compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + + testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/no-check/settings.gradle b/src/functionalTest/resources/projects/multiple-check-tasks/no-check/settings.gradle new file mode 100644 index 0000000..e69de29 diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/no-check/src/main/scala/org/hello/World.scala b/src/functionalTest/resources/projects/multiple-check-tasks/no-check/src/main/scala/org/hello/World.scala new file mode 100644 index 0000000..94be85c --- /dev/null +++ b/src/functionalTest/resources/projects/multiple-check-tasks/no-check/src/main/scala/org/hello/World.scala @@ -0,0 +1,8 @@ +package org.hello + +class World { + + def foo(): String = { + "a" + "b" + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/no-check/src/test/scala/org/hello/WorldSuite.scala b/src/functionalTest/resources/projects/multiple-check-tasks/no-check/src/test/scala/org/hello/WorldSuite.scala new file mode 100644 index 0000000..7281a12 --- /dev/null +++ b/src/functionalTest/resources/projects/multiple-check-tasks/no-check/src/test/scala/org/hello/WorldSuite.scala @@ -0,0 +1,13 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldSuite extends FunSuite { + + test("foo") { + new World().foo() + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/old-and-new-syntax/build.gradle b/src/functionalTest/resources/projects/multiple-check-tasks/old-and-new-syntax/build.gradle new file mode 100644 index 0000000..a672629 --- /dev/null +++ b/src/functionalTest/resources/projects/multiple-check-tasks/old-and-new-syntax/build.gradle @@ -0,0 +1,38 @@ +plugins { + id 'org.scoverage' +} + +repositories { + jcenter() +} + +description = 'a single-module Scala project that has multiple check configurations - some new syntax, some old' + +apply plugin: 'java' +apply plugin: 'scala' + +dependencies { + compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + + testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion +} + +test { + useJUnitPlatform() +} + +scoverage { + minimumRate = 0.3 + coverageType = org.scoverage.CoverageType.Line + check { + minimumRate = 0.1 + coverageType = org.scoverage.CoverageType.Branch + } + check { + minimumRate = 0.6 + coverageType = org.scoverage.CoverageType.Statement + } +} diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/old-and-new-syntax/settings.gradle b/src/functionalTest/resources/projects/multiple-check-tasks/old-and-new-syntax/settings.gradle new file mode 100644 index 0000000..e69de29 diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/old-and-new-syntax/src/main/scala/org/hello/World.scala b/src/functionalTest/resources/projects/multiple-check-tasks/old-and-new-syntax/src/main/scala/org/hello/World.scala new file mode 100644 index 0000000..94be85c --- /dev/null +++ b/src/functionalTest/resources/projects/multiple-check-tasks/old-and-new-syntax/src/main/scala/org/hello/World.scala @@ -0,0 +1,8 @@ +package org.hello + +class World { + + def foo(): String = { + "a" + "b" + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/old-and-new-syntax/src/test/scala/org/hello/WorldSuite.scala b/src/functionalTest/resources/projects/multiple-check-tasks/old-and-new-syntax/src/test/scala/org/hello/WorldSuite.scala new file mode 100644 index 0000000..7281a12 --- /dev/null +++ b/src/functionalTest/resources/projects/multiple-check-tasks/old-and-new-syntax/src/test/scala/org/hello/WorldSuite.scala @@ -0,0 +1,13 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldSuite extends FunSuite { + + test("foo") { + new World().foo() + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/single-check-new-syntax/build.gradle b/src/functionalTest/resources/projects/multiple-check-tasks/single-check-new-syntax/build.gradle new file mode 100644 index 0000000..4967ad1 --- /dev/null +++ b/src/functionalTest/resources/projects/multiple-check-tasks/single-check-new-syntax/build.gradle @@ -0,0 +1,32 @@ +plugins { + id 'org.scoverage' +} + +repositories { + jcenter() +} + +description = 'a single-module Scala project that has a single check configurations (with the new syntax)' + +apply plugin: 'java' +apply plugin: 'scala' + +dependencies { + compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + + testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion +} + +test { + useJUnitPlatform() +} + +scoverage { + check { + minimumRate = 0.3 + coverageType = org.scoverage.CoverageType.Line + } +} diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/single-check-new-syntax/settings.gradle b/src/functionalTest/resources/projects/multiple-check-tasks/single-check-new-syntax/settings.gradle new file mode 100644 index 0000000..e69de29 diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/single-check-new-syntax/src/main/scala/org/hello/World.scala b/src/functionalTest/resources/projects/multiple-check-tasks/single-check-new-syntax/src/main/scala/org/hello/World.scala new file mode 100644 index 0000000..94be85c --- /dev/null +++ b/src/functionalTest/resources/projects/multiple-check-tasks/single-check-new-syntax/src/main/scala/org/hello/World.scala @@ -0,0 +1,8 @@ +package org.hello + +class World { + + def foo(): String = { + "a" + "b" + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/single-check-new-syntax/src/test/scala/org/hello/WorldSuite.scala b/src/functionalTest/resources/projects/multiple-check-tasks/single-check-new-syntax/src/test/scala/org/hello/WorldSuite.scala new file mode 100644 index 0000000..7281a12 --- /dev/null +++ b/src/functionalTest/resources/projects/multiple-check-tasks/single-check-new-syntax/src/test/scala/org/hello/WorldSuite.scala @@ -0,0 +1,13 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldSuite extends FunSuite { + + test("foo") { + new World().foo() + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/single-check-old-syntax/build.gradle b/src/functionalTest/resources/projects/multiple-check-tasks/single-check-old-syntax/build.gradle new file mode 100644 index 0000000..93fa3a8 --- /dev/null +++ b/src/functionalTest/resources/projects/multiple-check-tasks/single-check-old-syntax/build.gradle @@ -0,0 +1,30 @@ +plugins { + id 'org.scoverage' +} + +repositories { + jcenter() +} + +description = 'a single-module Scala project that has a single check configurations (with the old syntax)' + +apply plugin: 'java' +apply plugin: 'scala' + +dependencies { + compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + + testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion +} + +test { + useJUnitPlatform() +} + +scoverage { + minimumRate = 0.3 + coverageType = org.scoverage.CoverageType.Line +} diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/single-check-old-syntax/settings.gradle b/src/functionalTest/resources/projects/multiple-check-tasks/single-check-old-syntax/settings.gradle new file mode 100644 index 0000000..e69de29 diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/single-check-old-syntax/src/main/scala/org/hello/World.scala b/src/functionalTest/resources/projects/multiple-check-tasks/single-check-old-syntax/src/main/scala/org/hello/World.scala new file mode 100644 index 0000000..94be85c --- /dev/null +++ b/src/functionalTest/resources/projects/multiple-check-tasks/single-check-old-syntax/src/main/scala/org/hello/World.scala @@ -0,0 +1,8 @@ +package org.hello + +class World { + + def foo(): String = { + "a" + "b" + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/single-check-old-syntax/src/test/scala/org/hello/WorldSuite.scala b/src/functionalTest/resources/projects/multiple-check-tasks/single-check-old-syntax/src/test/scala/org/hello/WorldSuite.scala new file mode 100644 index 0000000..7281a12 --- /dev/null +++ b/src/functionalTest/resources/projects/multiple-check-tasks/single-check-old-syntax/src/test/scala/org/hello/WorldSuite.scala @@ -0,0 +1,13 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldSuite extends FunSuite { + + test("foo") { + new World().foo() + } +} \ No newline at end of file diff --git a/src/main/groovy/org/scoverage/OverallCheckTask.groovy b/src/main/groovy/org/scoverage/CoverageChecker.groovy similarity index 63% rename from src/main/groovy/org/scoverage/OverallCheckTask.groovy rename to src/main/groovy/org/scoverage/CoverageChecker.groovy index da83c12..595dbd0 100644 --- a/src/main/groovy/org/scoverage/OverallCheckTask.groovy +++ b/src/main/groovy/org/scoverage/CoverageChecker.groovy @@ -1,11 +1,8 @@ package org.scoverage -import org.gradle.api.DefaultTask + import org.gradle.api.GradleException -import org.gradle.api.provider.Property -import org.gradle.api.tasks.CacheableTask -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.TaskAction +import org.gradle.api.logging.Logger import org.gradle.internal.impldep.com.google.common.annotations.VisibleForTesting import java.text.DecimalFormat @@ -41,43 +38,22 @@ enum CoverageType { /** * Throws a GradleException if overall coverage dips below the configured percentage. */ -@CacheableTask -class OverallCheckTask extends DefaultTask { - - /** Type of coverage to check. Available options: Line, Statement and Branch */ - @Input - final Property coverageType = project.objects.property(CoverageType) - @Input - final Property minimumRate = project.objects.property(BigDecimal) - - @Input - final Property reportDir = project.objects.property(File) +class CoverageChecker { - /** Overwrite to test for a specific locale. */ - @Input - final Property locale = project.objects.property(Locale).value(Locale.getDefault()) + final Logger logger - @TaskAction - void requireLineCoverage() { - NumberFormat nf = NumberFormat.getInstance(locale.get()) - - Exception failure = checkLineCoverage(nf, reportDir.get(), coverageType.get(), minimumRate.get().doubleValue()) - - if (failure) throw failure + CoverageChecker(Logger logger) { + this.logger = logger } - @VisibleForTesting - protected static String errorMsg(String actual, String expected, CoverageType type) { - "Only $actual% of project is covered by tests instead of $expected% (coverageType: $type)" + public void checkLineCoverage(File reportDir, CoverageType coverageType, double minimumRate) throws GradleException { + NumberFormat defaultNf = NumberFormat.getInstance(Locale.getDefault()) + checkLineCoverage(reportDir, coverageType, minimumRate, defaultNf) } - @VisibleForTesting - protected static String fileNotFoundErrorMsg(CoverageType coverageType) { - "Coverage file (type: $coverageType) not found, check your configuration." - } + public void checkLineCoverage(File reportDir, CoverageType coverageType, double minimumRate, NumberFormat nf) throws GradleException { + logger.info("Checking coverage. Type: {}. Minimum rate: {}", coverageType, minimumRate) - @VisibleForTesting - protected static Exception checkLineCoverage(NumberFormat nf, File reportDir, CoverageType coverageType, double minimumRate) { XmlParser 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) @@ -94,11 +70,20 @@ class OverallCheckTask extends DefaultTask { if (difference > 1e-7) { String is = df.format(overallRate * 100) String needed = df.format(minimumRate * 100) - return new GradleException(errorMsg(is, needed, coverageType)) + throw new GradleException(errorMsg(is, needed, coverageType)) } } catch (FileNotFoundException fnfe) { - return new GradleException(fileNotFoundErrorMsg(coverageType), fnfe) + throw new GradleException(fileNotFoundErrorMsg(coverageType), fnfe) } - null + } + + @VisibleForTesting + protected static String errorMsg(String actual, String expected, CoverageType type) { + "Only $actual% of project is covered by tests instead of $expected% (coverageType: $type)" + } + + @VisibleForTesting + protected static String fileNotFoundErrorMsg(CoverageType coverageType) { + "Coverage file (type: $coverageType) not found, check your configuration." } } diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index 8ee680b..7b9649d 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -13,6 +13,11 @@ import org.gradle.api.provider.Property */ class ScoverageExtension { + public static final CoverageType DEFAULT_COVERAGE_TYPE = CoverageType.Statement + public static final double DEFAULT_MINIMUM_RATE = 0.75 + + final Project project + /** Version of scoverage to use for the scalac plugin */ final Property scoverageVersion @@ -40,11 +45,14 @@ class ScoverageExtension { final Property deleteReportsOnAggregation + final List checks = new ArrayList<>() + final Property coverageType final Property minimumRate ScoverageExtension(Project project) { + this.project = project project.plugins.apply(JavaPlugin.class) project.plugins.apply(ScalaPlugin.class) @@ -88,9 +96,19 @@ class ScoverageExtension { deleteReportsOnAggregation.set(false) coverageType = project.objects.property(CoverageType) - coverageType.set(CoverageType.Statement) - minimumRate = project.objects.property(BigDecimal) - minimumRate.set(0.75) + } + + void check(Closure closure) { + CheckConfig check = new CheckConfig() + project.configure(check, closure) + checks.add(check) + } + + static class CheckConfig { + CoverageType coverageType + BigDecimal minimumRate + CheckConfig() { + } } } diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 8be36fb..d302edb 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -1,12 +1,14 @@ package org.scoverage import org.apache.commons.io.FileUtils +import org.gradle.api.GradleException import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.Task import org.gradle.api.invocation.Gradle import org.gradle.api.plugins.PluginAware import org.gradle.api.tasks.SourceSet +import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.scala.ScalaCompile import org.gradle.api.tasks.testing.Test @@ -102,7 +104,7 @@ class ScoveragePlugin implements Plugin { originalJarTask.mustRunAfter(compileTask) def globalReportTask = project.tasks.register(REPORT_NAME, ScoverageAggregate) - def globalCheckTask = project.tasks.register(CHECK_NAME, OverallCheckTask) + def globalCheckTask = project.tasks.register(CHECK_NAME) project.afterEvaluate { // calling toList() on TaskCollection is required @@ -147,16 +149,7 @@ class ScoveragePlugin implements Plugin { coverageDebug = extension.coverageDebug } - - globalCheckTask.configure { - dependsOn globalReportTask - - onlyIf { extension.reportDir.get().list() } - group = 'verification' - coverageType = extension.coverageType - minimumRate = extension.minimumRate - reportDir = extension.reportDir - } + configureCheckTask(project, extension, globalCheckTask, globalReportTask) // define aggregation task if (project.childProjects.size() > 0) { @@ -302,6 +295,36 @@ class ScoveragePlugin implements Plugin { } } + private void configureCheckTask(Project project, ScoverageExtension extension, + TaskProvider globalCheckTask, + TaskProvider globalReportTask) { + + if (extension.checks.isEmpty()) { + extension.check { + minimumRate = extension.minimumRate.getOrElse(BigDecimal.valueOf(ScoverageExtension.DEFAULT_MINIMUM_RATE)) + coverageType = extension.coverageType.getOrElse(ScoverageExtension.DEFAULT_COVERAGE_TYPE) + } + } else if (extension.minimumRate.isPresent() || extension.coverageType.isPresent()) { + throw new IllegalArgumentException("Check configuration should be defined in either the new or the old syntax exclusively, not together") + } + + def checker = new CoverageChecker(project.logger) + + globalCheckTask.configure { + group = 'verification' + dependsOn globalReportTask + onlyIf { extension.reportDir.get().list() } + } + + extension.checks.each { config -> + globalCheckTask.configure { + doLast { + checker.checkLineCoverage(extension.reportDir.get(), config.coverageType, config.minimumRate.doubleValue()) + } + } + } + } + private String resolveScalaVersion(Project project) { def resolvedDependencies = project.configurations.compileClasspath.resolvedConfiguration.firstLevelModuleDependencies diff --git a/src/test/groovy/org/scoverage/CoverageCheckerTest.groovy b/src/test/groovy/org/scoverage/CoverageCheckerTest.groovy new file mode 100644 index 0000000..04c695a --- /dev/null +++ b/src/test/groovy/org/scoverage/CoverageCheckerTest.groovy @@ -0,0 +1,122 @@ +package org.scoverage + +import org.gradle.api.GradleException +import org.hamcrest.Description +import org.hamcrest.TypeSafeMatcher +import org.junit.Rule +import org.junit.Test +import org.junit.jupiter.api.function.Executable +import org.junit.rules.TemporaryFolder +import org.slf4j.LoggerFactory + +import java.nio.file.Paths +import java.text.NumberFormat + +import static org.junit.Assert.assertThat +import static org.junit.jupiter.api.Assertions.assertThrows + +class CoverageCheckerTest { + + private NumberFormat numberFormat = NumberFormat.getInstance(Locale.US) + + private File reportDir = Paths.get(getClass().getClassLoader().getResource("checkTask").toURI()).toFile() + + private CoverageChecker checker = new CoverageChecker(LoggerFactory.getLogger(CoverageCheckerTest.class)) + + @Rule + public TemporaryFolder tempDir = new TemporaryFolder() + + // error when report file is not there + + @Test + void failsWhenReportFileIsNotFound() { + assertFailure(CoverageChecker.fileNotFoundErrorMsg(CoverageType.Line), { + checker.checkLineCoverage(tempDir.getRoot(), CoverageType.Line, 0.0, numberFormat) + }) + } + + // line coverage + + @Test + void failsWhenLineRateIsBelowTarget() { + assertFailure(CoverageChecker.errorMsg("66", "100", CoverageType.Line), { + checker.checkLineCoverage(reportDir, CoverageType.Line, 1.0, numberFormat) + }) + } + + @Test + void doesNotFailWhenLineRateIsAtTarget() { + checker.checkLineCoverage(reportDir, CoverageType.Line, 0.66, numberFormat) + } + + @Test + void doesNotFailWhenLineRateIsAboveTarget() { + checker.checkLineCoverage(reportDir, CoverageType.Line, 0.6, numberFormat) + } + + // Statement coverage + + @Test + void failsWhenStatementRateIsBelowTarget() { + assertFailure(CoverageChecker.errorMsg(numberFormat.format(new Double(33.33)), "100", CoverageType.Statement), { + checker.checkLineCoverage(reportDir, CoverageType.Statement, 1.0, numberFormat) + }) + } + + @Test + void doesNotFailWhenStatementRateIsAtTarget() { + checker.checkLineCoverage(reportDir, CoverageType.Statement, 0.33, numberFormat) + } + + @Test + void doesNotFailWhenStatementRateIsAboveTarget() { + checker.checkLineCoverage(reportDir, CoverageType.Statement, 0.3, numberFormat) + } + + // Branch coverage + + @Test + void failsWhenBranchRateIsBelowTarget() { + assertFailure(CoverageChecker.errorMsg("50", "100", CoverageType.Branch), { + checker.checkLineCoverage(reportDir, CoverageType.Branch, 1.0, numberFormat) + }) + } + + @Test + void doesNotFailWhenBranchRateIsAtTarget() { + checker.checkLineCoverage(reportDir, CoverageType.Branch, 0.5, numberFormat) + } + + @Test + void doesNotFailWhenBranchRateIsAboveTarget() { + checker.checkLineCoverage(reportDir, CoverageType.Branch, 0.45, numberFormat) + } + + private void assertFailure(String message, Executable executable) { + GradleException e = assertThrows(GradleException.class, executable) + assertThat(e, new CauseMatcher(message)) + } +} + +/** + * Copied from the Internet, just to check if we have correct exception thrown. + */ +class CauseMatcher extends TypeSafeMatcher { + + private final String expectedMessage + + CauseMatcher(String expectedMessage) { + this.expectedMessage = expectedMessage + } + + @Override + protected boolean matchesSafely(GradleException item) { + return item.getMessage().contains(expectedMessage) + } + + @Override + void describeTo(Description description) { + description.appendText("expects message ") + .appendValue(expectedMessage) + } +} \ No newline at end of file diff --git a/src/test/groovy/org/scoverage/OverallCheckTaskTest.groovy b/src/test/groovy/org/scoverage/OverallCheckTaskTest.groovy deleted file mode 100644 index 27c68dc..0000000 --- a/src/test/groovy/org/scoverage/OverallCheckTaskTest.groovy +++ /dev/null @@ -1,126 +0,0 @@ -package org.scoverage - -import org.gradle.api.GradleException -import org.hamcrest.Description -import org.hamcrest.Matcher -import org.hamcrest.TypeSafeMatcher -import org.junit.Rule -import org.junit.Test -import org.junit.rules.TemporaryFolder - -import java.nio.file.Paths -import java.text.NumberFormat - -import static org.junit.Assert.assertNull -import static org.junit.Assert.assertThat -import static org.scoverage.OverallCheckTask.checkLineCoverage - -/** - * Copied from the Internet, just to check if we have correct exception thrown. - */ -class CauseMatcher extends TypeSafeMatcher { - - private final Class type - private final String expectedMessage - - CauseMatcher(Class type, String expectedMessage) { - this.type = type - this.expectedMessage = expectedMessage - } - - @Override - protected boolean matchesSafely(Throwable item) { - return item.getClass().isAssignableFrom(type) && item.getMessage().contains(expectedMessage) - } - - @Override - void describeTo(Description description) { - description.appendText("expects type ") - .appendValue(type) - .appendText(" and a message ") - .appendValue(expectedMessage) - } -} - -class OverallCheckTaskTest { - - private NumberFormat numberFormat = NumberFormat.getInstance(Locale.US) - - private File reportDir = Paths.get(getClass().getClassLoader().getResource("checkTask").toURI()).toFile() - - @Rule - public TemporaryFolder tempDir = new TemporaryFolder() - - private static Matcher failsWith(String message) { - return new CauseMatcher( - GradleException.class, - message - ) - } - - // error when report file is not there - - @Test - void failsWhenReportFileIsNotFound() { - assertThat( - checkLineCoverage(numberFormat, tempDir.getRoot(), CoverageType.Line, 0.0), - failsWith(OverallCheckTask.fileNotFoundErrorMsg(CoverageType.Line))) - } - - // line coverage - - @Test - void failsWhenLineRateIsBelowTarget() { - assertThat( - checkLineCoverage(numberFormat, reportDir, CoverageType.Line, 1.0), - failsWith(OverallCheckTask.errorMsg("66", "100", CoverageType.Line))) - } - - @Test - void doesNotFailWhenLineRateIsAtTarget() { - assertNull(checkLineCoverage(numberFormat, reportDir, CoverageType.Line, 0.66)) - } - - @Test - void doesNotFailWhenLineRateIsAboveTarget() { - assertNull(checkLineCoverage(numberFormat, reportDir, CoverageType.Line, 0.6)) - } - - // Statement coverage - - @Test - void failsWhenStatementRateIsBelowTarget() { - assertThat( - checkLineCoverage(numberFormat, reportDir, CoverageType.Statement, 1.0), - failsWith(OverallCheckTask.errorMsg(numberFormat.format(new Double(33.33)), "100", CoverageType.Statement))) - } - - @Test - void doesNotFailWhenStatementRateIsAtTarget() { - assertNull(checkLineCoverage(numberFormat, reportDir, CoverageType.Statement, 0.33)) - } - - @Test - void doesNotFailWhenStatementRateIsAboveTarget() { - assertNull(checkLineCoverage(numberFormat, reportDir, CoverageType.Statement, 0.3)) - } - - // Branch coverage - - @Test - void failsWhenBranchRateIsBelowTarget() { - assertThat( - checkLineCoverage(numberFormat, reportDir, CoverageType.Branch, 1.0), - failsWith(OverallCheckTask.errorMsg("50", "100", CoverageType.Branch))) - } - - @Test - void doesNotFailWhenBranchRateIsAtTarget() { - assertNull(checkLineCoverage(numberFormat, reportDir, CoverageType.Branch, 0.5)) - } - - @Test - void doesNotFailWhenBranchRateIsAboveTarget() { - assertNull(checkLineCoverage(numberFormat, reportDir, CoverageType.Branch, 0.45)) - } -} From d3663ca33de63d36fb56fa9b9cfd831999c0ae7d Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Sun, 15 Sep 2019 18:00:52 +0300 Subject: [PATCH 080/167] Update README with instructions on the new multiple-checks support --- README.md | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0d01c1b..806bedd 100644 --- a/README.md +++ b/README.md @@ -55,10 +55,51 @@ be overridden by the version of the `scala-library` compile dependency (if the d * `minimumRate = ` (default `0.75`): The minimum amount of coverage in decimal proportion (`1.0` == 100%) required for the validation to pass (otherwise `checkScoverage` will fail the build). -* `coverageType = <"Statement" | "Branch" | "Line">` (default `"Statement"`): The type of coverage validated by the +* `coverageType = ` (default `CoverageType.Statement`): The type of coverage validated by the `checkScoverage` task. For more information on the different types, please refer to the documentation of the scalac plugin (https://github.com/scoverage/scalac-scoverage-plugin). +#### Multiple check tasks + +It is possible to configure multiple checks; for instance, one check for a statement rate and another for a branch rate: +``` +scoverage { + check { + minimumRate = 0.5 + coverageType = CoverageType.Statement + } + check { + minimumRate = 0.8 + coverageType = CoverageType.Branch + } +} +``` + +Note that you cannot mix multiple-checks syntax with plain check configuration: +``` +// ok +scoverage { + check { + minimumRate = 0.5 + coverageType = CoverageType.Statement + } +} + +// ok +scoverage { + minimumRate = 0.2 +} + +// NOT ok +scoverage { + minimumRate = 0.2 + check { + minimumRate = 0.5 + coverageType = CoverageType.Statement + } +} +``` + ### Run without normal compilation By default, running any of the plugin tasks will compile the code both using "normal" compilation (`compileScala`) From 308fdddf7b18220b82b0f8681cc0f63b658b66d5 Mon Sep 17 00:00:00 2001 From: Stu Date: Wed, 18 Sep 2019 20:22:21 +0100 Subject: [PATCH 081/167] move 2.13 to the multi-module test --- .../ScalaMultiModuleCrossVersionTest.java | 8 ++++++++ .../java/org.scoverage/ScalaSingleModuleTest.java | 9 --------- .../2_13/build.gradle | 4 ++++ .../2_13/src/main/scala/org/hello/World213.scala | 9 +++++++++ .../src/test/scala/org/hello/World213Suite.scala | 13 +++++++++++++ .../scala-multi-module-cross-version/build.gradle | 4 +++- .../settings.gradle | 2 +- 7 files changed, 38 insertions(+), 11 deletions(-) create mode 100644 src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/build.gradle create mode 100644 src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/src/main/scala/org/hello/World213.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/src/test/scala/org/hello/World213Suite.scala diff --git a/src/functionalTest/java/org.scoverage/ScalaMultiModuleCrossVersionTest.java b/src/functionalTest/java/org.scoverage/ScalaMultiModuleCrossVersionTest.java index 224ef34..401149a 100644 --- a/src/functionalTest/java/org.scoverage/ScalaMultiModuleCrossVersionTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaMultiModuleCrossVersionTest.java @@ -33,6 +33,7 @@ private void assertAllReportFilesExist() { assert211ReportFilesExist(); assert212ReportFilesExist(); + assert213ReportFilesExist(); assertAggregationFilesExist(); } @@ -56,4 +57,11 @@ private void assert212ReportFilesExist() { Assert.assertTrue(resolve(reportDir, "index.html").exists()); Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/World212.scala.html").exists()); } + + private void assert213ReportFilesExist() { + + File reportDir = reportDir(projectDir().toPath().resolve("2_13").toFile()); + Assert.assertTrue(resolve(reportDir, "index.html").exists()); + Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/World213.scala.html").exists()); + } } diff --git a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java index d9fb4e0..f93e184 100644 --- a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java @@ -133,15 +133,6 @@ public void reportScoverageWithoutNormalCompilationAndWithExcludedClasses() thro Assert.assertFalse(resolve(buildDir(), "classes/scala/scoverage/org/hello/World.class").exists()); } - @Test - public void reportScoverageUnder2_13() throws Exception { - run("clean", ScoveragePlugin.getREPORT_NAME(), - "-PscalaVersionMinor=13", - "-PscalaVersionBuild=0", - "-Pscoverage.scoverageScalaVersion=2_13"); - assertReportFilesExist(); - } - private void assertReportFilesExist() { Assert.assertTrue(resolve(reportDir(), "index.html").exists()); diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/build.gradle new file mode 100644 index 0000000..6db22d2 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/build.gradle @@ -0,0 +1,4 @@ +dependencies { + compile group: 'org.scala-lang', name: 'scala-library', version: "2.13.0" + testCompile group: 'org.scalatest', name: "scalatest_2.13", version: scalatestVersion +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/src/main/scala/org/hello/World213.scala b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/src/main/scala/org/hello/World213.scala new file mode 100644 index 0000000..b5fc8fb --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/src/main/scala/org/hello/World213.scala @@ -0,0 +1,9 @@ +package org.hello + +class World213 { + + def foo(): String = { + val s = "2" + "12" + s + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/src/test/scala/org/hello/World213Suite.scala b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/src/test/scala/org/hello/World213Suite.scala new file mode 100644 index 0000000..ad43f08 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/src/test/scala/org/hello/World213Suite.scala @@ -0,0 +1,13 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class World212Suite extends FunSuite { + + test("foo") { + new World213().foo() + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-cross-version/build.gradle index 4a024a0..279410b 100644 --- a/src/functionalTest/resources/projects/scala-multi-module-cross-version/build.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module-cross-version/build.gradle @@ -33,4 +33,6 @@ scoverage { minimumRate = 0.5 } -project(":2_11").tasks.reportScoverage.mustRunAfter(project(":2_12").tasks.reportScoverage) \ No newline at end of file +project(":2_11").tasks.reportScoverage + .mustRunAfter(project(":2_12").tasks.reportScoverage) + .mustRunAfter(project(":2_13").tasks.reportScoverage) \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/settings.gradle b/src/functionalTest/resources/projects/scala-multi-module-cross-version/settings.gradle index 6d138e6..174d3b1 100644 --- a/src/functionalTest/resources/projects/scala-multi-module-cross-version/settings.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module-cross-version/settings.gradle @@ -1 +1 @@ -include '2_11', '2_12' \ No newline at end of file +include '2_11', '2_12', '2_13' \ No newline at end of file From 11d50275757bb0718458a2bb046d6e25fc02db89 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Mon, 28 Oct 2019 11:00:17 +0200 Subject: [PATCH 082/167] (#121) Make the plugin compatible with `java-platform` plugin by removing auto-apply on subprojects --- .../ScalaJavaMultiModuleTest.java | 4 +- .../scala-java-multi-module/build.gradle | 14 ++--- .../java_only/build.gradle | 3 -- .../mixed_scala_java/build.gradle | 9 ++-- .../scala_only/build.gradle | 6 ++- .../build.gradle | 3 +- .../build.gradle | 3 +- .../projects/scala-multi-module/build.gradle | 40 +++++++------- .../dependencies/build.gradle | 14 +++++ .../scala-multi-module/settings.gradle | 2 +- .../org/scoverage/ScoveragePlugin.groovy | 53 +++++++++---------- 11 files changed, 83 insertions(+), 68 deletions(-) create mode 100644 src/functionalTest/resources/projects/scala-multi-module/dependencies/build.gradle diff --git a/src/functionalTest/java/org.scoverage/ScalaJavaMultiModuleTest.java b/src/functionalTest/java/org.scoverage/ScalaJavaMultiModuleTest.java index 0c6156e..6f094bf 100644 --- a/src/functionalTest/java/org.scoverage/ScalaJavaMultiModuleTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaJavaMultiModuleTest.java @@ -18,16 +18,18 @@ public void checkAndAggregateScoverage() throws Exception { AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME(), ScoveragePlugin.getAGGREGATE_NAME()); - result.assertTaskOutcome("java_only:" + ScoveragePlugin.getCOMPILE_NAME(), TaskOutcome.NO_SOURCE); + result.assertTaskSkipped("java_only:" + ScoveragePlugin.getCOMPILE_NAME()); result.assertTaskSkipped(ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded("scala_only:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded("mixed_scala_java:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskSkipped("java_only:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); result.assertTaskSucceeded("scala_only:" + ScoveragePlugin.getCHECK_NAME()); result.assertTaskSucceeded("mixed_scala_java:" + ScoveragePlugin.getCHECK_NAME()); result.assertTaskSkipped("java_only:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); assertAllReportFilesExist(); diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/build.gradle b/src/functionalTest/resources/projects/scala-java-multi-module/build.gradle index b486ee1..27246b6 100644 --- a/src/functionalTest/resources/projects/scala-java-multi-module/build.gradle +++ b/src/functionalTest/resources/projects/scala-java-multi-module/build.gradle @@ -2,17 +2,16 @@ plugins { id 'org.scoverage' apply false } +description = 'a multi-module Scala and Java project that builds successfully with 100% coverage' + allprojects { repositories { jcenter() } } -description = 'a multi-module Scala and Java project that builds successfully with 100% coverage' - -apply plugin: 'org.scoverage' - -allprojects { +subprojects { + apply plugin: 'java' dependencies { testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion @@ -21,12 +20,9 @@ allprojects { test { useJUnitPlatform() } - - scoverage { - minimumRate = 0.5 - } } +apply plugin: 'org.scoverage' scoverage { minimumRate = 0.5 } \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/java_only/build.gradle b/src/functionalTest/resources/projects/scala-java-multi-module/java_only/build.gradle index 1cb42eb..c2060d5 100644 --- a/src/functionalTest/resources/projects/scala-java-multi-module/java_only/build.gradle +++ b/src/functionalTest/resources/projects/scala-java-multi-module/java_only/build.gradle @@ -1,6 +1,3 @@ -apply plugin: 'java' - dependencies { - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion } diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/build.gradle b/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/build.gradle index 9d6a7ab..c107f19 100644 --- a/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/build.gradle +++ b/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/build.gradle @@ -1,6 +1,4 @@ -apply plugin: 'java' apply plugin: 'scala' -apply plugin: 'org.scoverage' dependencies { compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" @@ -16,4 +14,9 @@ ext.configureSources = { set, name -> set.java.srcDirs = [] } configureSources(sourceSets.main, 'main') -configureSources(sourceSets.test, 'test') \ No newline at end of file +configureSources(sourceSets.test, 'test') + +apply plugin: 'org.scoverage' +scoverage { + minimumRate = 0.5 +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/scala_only/build.gradle b/src/functionalTest/resources/projects/scala-java-multi-module/scala_only/build.gradle index 97f6ee6..abca859 100644 --- a/src/functionalTest/resources/projects/scala-java-multi-module/scala_only/build.gradle +++ b/src/functionalTest/resources/projects/scala-java-multi-module/scala_only/build.gradle @@ -1,5 +1,4 @@ apply plugin: 'scala' -apply plugin: 'org.scoverage' dependencies { compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" @@ -8,3 +7,8 @@ dependencies { testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion } + +apply plugin: 'org.scoverage' +scoverage { + minimumRate = 0.5 +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-cross-version/build.gradle index 4a024a0..d70523d 100644 --- a/src/functionalTest/resources/projects/scala-multi-module-cross-version/build.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module-cross-version/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'org.scoverage' + id 'org.scoverage' apply false } allprojects { @@ -14,6 +14,7 @@ allprojects { apply plugin: 'java' apply plugin: 'scala' + apply plugin: 'org.scoverage' dependencies { testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle index af0a9b3..310e1da 100644 --- a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'org.scoverage' + id 'org.scoverage' apply false } allprojects { @@ -14,6 +14,7 @@ allprojects { apply plugin: 'java' apply plugin: 'scala' + apply plugin: 'org.scoverage' dependencies { compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" diff --git a/src/functionalTest/resources/projects/scala-multi-module/build.gradle b/src/functionalTest/resources/projects/scala-multi-module/build.gradle index dcfad1a..3f10c36 100644 --- a/src/functionalTest/resources/projects/scala-multi-module/build.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module/build.gradle @@ -1,34 +1,36 @@ plugins { - id 'org.scoverage' + id 'org.scoverage' apply false } -allprojects { +description = 'a multi-module Scala project that builds successfully with 100% coverage' + +allprojects { p -> repositories { jcenter() } -} -description = 'a multi-module Scala project that builds successfully with 100% coverage' + if (p.name != 'dependencies') { + apply plugin: 'java' + apply plugin: 'scala' + apply plugin: 'org.scoverage' -allprojects { + dependencies { + implementation platform(project(':dependencies')) - apply plugin: 'java' - apply plugin: 'scala' + compile group: 'org.scala-lang', name: 'scala-library' - dependencies { - compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine' + testCompile group: 'org.junit.platform', name: 'junit-platform-runner' - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion - testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}" + } - testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion - } - - test { - useJUnitPlatform() - } + test { + useJUnitPlatform() + } - scoverage { - minimumRate = 0.5 + scoverage { + minimumRate = 0.5 + } } } \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/dependencies/build.gradle b/src/functionalTest/resources/projects/scala-multi-module/dependencies/build.gradle new file mode 100644 index 0000000..3ac33f7 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module/dependencies/build.gradle @@ -0,0 +1,14 @@ +plugins { + id 'java-platform' +} + +dependencies { + constraints { + api group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + + api group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + api group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + api group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/settings.gradle b/src/functionalTest/resources/projects/scala-multi-module/settings.gradle index 6eabe3b..084ba0c 100644 --- a/src/functionalTest/resources/projects/scala-multi-module/settings.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module/settings.gradle @@ -1 +1 @@ -include 'a', 'b', 'common' \ No newline at end of file +include 'dependencies', 'a', 'b', 'common' \ No newline at end of file diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 4666a6c..009a0cd 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -32,11 +32,6 @@ class ScoveragePlugin implements Plugin { void apply(PluginAware pluginAware) { if (pluginAware instanceof Project) { applyProject(pluginAware) - if (pluginAware == pluginAware.rootProject) { - pluginAware.subprojects { p -> - p.plugins.apply(ScoveragePlugin) - } - } } else if (pluginAware instanceof Gradle) { pluginAware.allprojects { p -> p.plugins.apply(ScoveragePlugin) @@ -104,7 +99,6 @@ class ScoveragePlugin implements Plugin { def globalReportTask = project.tasks.register(REPORT_NAME, ScoverageAggregate) def globalCheckTask = project.tasks.register(CHECK_NAME, OverallCheckTask) - project.afterEvaluate { def detectedSourceEncoding = compileTask.scalaCompileOptions.encoding if (detectedSourceEncoding == null) { @@ -166,29 +160,6 @@ class ScoveragePlugin implements Plugin { reportDir = extension.reportDir } - // define aggregation task - if (project.childProjects.size() > 0) { - def allReportTasks = project.getAllprojects().findResults { - it.tasks.find { task -> - task.name == REPORT_NAME && task instanceof ScoverageAggregate - } - } - - def aggregationTask = project.tasks.create(AGGREGATE_NAME, ScoverageAggregate) { - dependsOn(allReportTasks) - group = 'verification' - runner = scoverageRunner - reportDir = extension.reportDir - sourceEncoding.set(detectedSourceEncoding) - deleteReportsOnAggregation = extension.deleteReportsOnAggregation - coverageOutputCobertura = extension.coverageOutputCobertura - coverageOutputXML = extension.coverageOutputXML - coverageOutputHTML = extension.coverageOutputHTML - coverageDebug = extension.coverageDebug - } - project.tasks[CHECK_NAME].mustRunAfter(aggregationTask) - } - // make this project's scoverage compilation depend on scoverage compilation of any other project // which this project depends on its normal compilation // (essential when running without normal compilation on multi-module projects with inner dependencies) @@ -308,6 +279,30 @@ class ScoveragePlugin implements Plugin { } } } + + // define aggregation task + if (project.childProjects.size() > 0) { + project.gradle.projectsEvaluated { + def allReportTasks = project.getAllprojects().findResults { + it.tasks.find { task -> + task.name == REPORT_NAME && task instanceof ScoverageAggregate + } + } + def aggregationTask = project.tasks.create(AGGREGATE_NAME, ScoverageAggregate) { + dependsOn(allReportTasks) + group = 'verification' + runner = scoverageRunner + reportDir = extension.reportDir + sourceEncoding.set(detectedSourceEncoding) + deleteReportsOnAggregation = extension.deleteReportsOnAggregation + coverageOutputCobertura = extension.coverageOutputCobertura + coverageOutputXML = extension.coverageOutputXML + coverageOutputHTML = extension.coverageOutputHTML + coverageDebug = extension.coverageDebug + } + project.tasks[CHECK_NAME].mustRunAfter(aggregationTask) + } + } } } From 7547f04879b75d2f273e9a968df74da712d6c636 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Mon, 28 Oct 2019 12:00:07 +0200 Subject: [PATCH 083/167] (#121) Add a warning when scala subprojects don't have scoverage applied to them (and the parent does) --- ...ModulePluginNotConfiguredForScalaTest.java | 38 +++++++++++++++++++ .../build.gradle | 30 +++++++++++++++ .../dependencies/build.gradle | 14 +++++++ .../java_only/build.gradle | 3 ++ .../main/java/org/hello/WorldJavaOnly.java | 9 +++++ .../java/org/hello/WorldJavaOnlyTest.java | 11 ++++++ .../scala_only/build.gradle | 9 +++++ .../main/scala/org/hello/WorldScalaOnly.scala | 9 +++++ .../scala/org/hello/WorldScalaOnlySuite.scala | 13 +++++++ .../settings.gradle | 1 + .../org/scoverage/ScoveragePlugin.groovy | 14 ++++++- 11 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 src/functionalTest/java/org.scoverage/MultiModulePluginNotConfiguredForScalaTest.java create mode 100644 src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/build.gradle create mode 100644 src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/dependencies/build.gradle create mode 100644 src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/build.gradle create mode 100644 src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/src/main/java/org/hello/WorldJavaOnly.java create mode 100644 src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/src/test/java/org/hello/WorldJavaOnlyTest.java create mode 100644 src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/build.gradle create mode 100644 src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/src/main/scala/org/hello/WorldScalaOnly.scala create mode 100644 src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/src/test/scala/org/hello/WorldScalaOnlySuite.scala create mode 100644 src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/settings.gradle diff --git a/src/functionalTest/java/org.scoverage/MultiModulePluginNotConfiguredForScalaTest.java b/src/functionalTest/java/org.scoverage/MultiModulePluginNotConfiguredForScalaTest.java new file mode 100644 index 0000000..c3fdffa --- /dev/null +++ b/src/functionalTest/java/org.scoverage/MultiModulePluginNotConfiguredForScalaTest.java @@ -0,0 +1,38 @@ +package org.scoverage; + +import org.junit.Assert; +import org.junit.Test; + +public class MultiModulePluginNotConfiguredForScalaTest extends ScoverageFunctionalTest { + + public MultiModulePluginNotConfiguredForScalaTest() { + super("multi-module-plugin-not-configured-for-scala"); + } + + @Test + public void checkAndAggregateScoverage() throws Exception { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME(), + ScoveragePlugin.getAGGREGATE_NAME()); + + result.assertTaskSkipped(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSkipped("scala_only:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSkipped("java_only:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSkipped(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSkipped("scala_only:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSkipped("java_only:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSkipped(ScoveragePlugin.getAGGREGATE_NAME()); + + assertReportDirsEmpty(); + + Assert.assertTrue(result.getResult().getOutput().contains("Scala sub-project 'scala_only' doesn't have Scoverage applied")); + Assert.assertFalse(result.getResult().getOutput().contains("Scala sub-project 'java_only' doesn't have Scoverage applied")); + } + + private void assertReportDirsEmpty() { + + Assert.assertFalse(reportDir().exists()); + Assert.assertFalse(reportDir(projectDir().toPath().resolve("scala_only").toFile()).exists()); + Assert.assertFalse(reportDir(projectDir().toPath().resolve("java_only").toFile()).exists()); + } +} diff --git a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/build.gradle b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/build.gradle new file mode 100644 index 0000000..450d3e7 --- /dev/null +++ b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/build.gradle @@ -0,0 +1,30 @@ +plugins { + id 'org.scoverage' apply false +} + +description = 'a multi-module Scala and Java project that defines scoverage only on root but not on subprojects' + +allprojects { + repositories { + jcenter() + } +} + +subprojects { p -> + if (p.name != 'dependencies') { + apply plugin: 'java' + dependencies { + implementation platform(project(':dependencies')) + testCompile group: 'org.junit.platform', name: 'junit-platform-runner' + } + + test { + useJUnitPlatform() + } + } +} + +apply plugin: 'org.scoverage' +scoverage { + minimumRate = 0.5 +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/dependencies/build.gradle b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/dependencies/build.gradle new file mode 100644 index 0000000..3ac33f7 --- /dev/null +++ b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/dependencies/build.gradle @@ -0,0 +1,14 @@ +plugins { + id 'java-platform' +} + +dependencies { + constraints { + api group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + + api group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + api group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + api group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/build.gradle b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/build.gradle new file mode 100644 index 0000000..bbcd2f4 --- /dev/null +++ b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/build.gradle @@ -0,0 +1,3 @@ +dependencies { + testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine' +} diff --git a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/src/main/java/org/hello/WorldJavaOnly.java b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/src/main/java/org/hello/WorldJavaOnly.java new file mode 100644 index 0000000..95c85de --- /dev/null +++ b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/src/main/java/org/hello/WorldJavaOnly.java @@ -0,0 +1,9 @@ +package org.hello; + +public class WorldJavaOnly { + + public String foo() { + String s = "java_only" + "a"; + return s; + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/src/test/java/org/hello/WorldJavaOnlyTest.java b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/src/test/java/org/hello/WorldJavaOnlyTest.java new file mode 100644 index 0000000..68fd33d --- /dev/null +++ b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/src/test/java/org/hello/WorldJavaOnlyTest.java @@ -0,0 +1,11 @@ +package org.hello; + +import org.junit.Test; + +public class WorldJavaOnlyTest { + + @Test + public void foo() { + new WorldJavaOnly().foo(); + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/build.gradle b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/build.gradle new file mode 100644 index 0000000..28ca396 --- /dev/null +++ b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/build.gradle @@ -0,0 +1,9 @@ +apply plugin: 'scala' +// apply plugin: 'org.scoverage' // Oops forgot to configure scoverage + +dependencies { + compile group: 'org.scala-lang', name: 'scala-library' + + testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine' + testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}" +} diff --git a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/src/main/scala/org/hello/WorldScalaOnly.scala b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/src/main/scala/org/hello/WorldScalaOnly.scala new file mode 100644 index 0000000..268c5a5 --- /dev/null +++ b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/src/main/scala/org/hello/WorldScalaOnly.scala @@ -0,0 +1,9 @@ +package org.hello + +class WorldScalaOnly { + + def foo(): String = { + val s = "scala_only" + "a" + s + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/src/test/scala/org/hello/WorldScalaOnlySuite.scala b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/src/test/scala/org/hello/WorldScalaOnlySuite.scala new file mode 100644 index 0000000..7601021 --- /dev/null +++ b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/src/test/scala/org/hello/WorldScalaOnlySuite.scala @@ -0,0 +1,13 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldScalaOnlySuite extends FunSuite { + + test("foo") { + new WorldScalaOnly().foo() + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/settings.gradle b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/settings.gradle new file mode 100644 index 0000000..0f44066 --- /dev/null +++ b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/settings.gradle @@ -0,0 +1 @@ +include 'dependencies', 'java_only', 'scala_only' \ No newline at end of file diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 009a0cd..3dcf232 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -6,6 +6,7 @@ import org.gradle.api.Project import org.gradle.api.Task import org.gradle.api.invocation.Gradle import org.gradle.api.plugins.PluginAware +import org.gradle.api.plugins.scala.ScalaPlugin import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.scala.ScalaCompile import org.gradle.api.tasks.testing.Test @@ -281,14 +282,23 @@ class ScoveragePlugin implements Plugin { } // define aggregation task - if (project.childProjects.size() > 0) { + if (!project.subprojects.empty) { project.gradle.projectsEvaluated { - def allReportTasks = project.getAllprojects().findResults { + project.subprojects.each { + if (it.plugins.hasPlugin(ScalaPlugin) && !it.plugins.hasPlugin(ScoveragePlugin)) { + it.logger.warn("Scala sub-project '${it.name}' doesn't have Scoverage applied and will be ignored in parent project aggregation") + } + } + def childReportTasks = project.subprojects.findResults { it.tasks.find { task -> task.name == REPORT_NAME && task instanceof ScoverageAggregate } } + def allReportTasks = childReportTasks + globalReportTask def aggregationTask = project.tasks.create(AGGREGATE_NAME, ScoverageAggregate) { + onlyIf { + !childReportTasks.empty + } dependsOn(allReportTasks) group = 'verification' runner = scoverageRunner From 7c003ce1819c0c185d64dddc331b4ec98e32ebc2 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Mon, 28 Oct 2019 12:05:23 +0200 Subject: [PATCH 084/167] (#121) Update README regarding the change in (not) automatically applying the plugin on sub-projects --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 0d01c1b..5d0e083 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,9 @@ You can find instructions on how to apply the plugin at: http://plugins.gradle. When applied on a project with sub-projects, the plugin will create the aggregation task `aggregateScoverage`, which will first generate reports for each project individually (including the parent project), and will then generate an aggregated result based on these reports. + + The plugin must be applied on a sub-project for it to be included in the aggregated; applying the plugin on a + project _does not_ automatically apply it on sub-projects. The aggregated report will override the parent-project specific report (`parent-project/build/reports/scoverage`). From 5233c8ec2dec8e0fb5d312e6ac40aac0a6de3ea6 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Tue, 29 Oct 2019 16:51:07 +0200 Subject: [PATCH 085/167] (#120) Fix configuration of coverage type check --- .../projects/scala-single-module/build.gradle | 1 + .../org/scoverage/OverallCheckTask.groovy | 25 ++++++++++++++----- .../org/scoverage/ScoverageExtension.groovy | 6 ++--- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/functionalTest/resources/projects/scala-single-module/build.gradle b/src/functionalTest/resources/projects/scala-single-module/build.gradle index 6ae71be..c9856a8 100644 --- a/src/functionalTest/resources/projects/scala-single-module/build.gradle +++ b/src/functionalTest/resources/projects/scala-single-module/build.gradle @@ -26,6 +26,7 @@ test { scoverage { minimumRate = 0.3 + coverageType = "Line" } if (hasProperty("excludedFile")) { diff --git a/src/main/groovy/org/scoverage/OverallCheckTask.groovy b/src/main/groovy/org/scoverage/OverallCheckTask.groovy index da83c12..4d7eaf5 100644 --- a/src/main/groovy/org/scoverage/OverallCheckTask.groovy +++ b/src/main/groovy/org/scoverage/OverallCheckTask.groovy @@ -15,10 +15,12 @@ import java.text.NumberFormat * Handles different types of coverage Scoverage can measure. */ enum CoverageType { - Line('cobertura.xml', 'line-rate', 1.0), - Statement('scoverage.xml', 'statement-rate', 100.0), - Branch('scoverage.xml', 'branch-rate', 100.0) + Line('Line', 'cobertura.xml', 'line-rate', 1.0), + Statement('Statement', 'scoverage.xml', 'statement-rate', 100.0), + Branch('Branch', 'scoverage.xml', 'branch-rate', 100.0) + /** Name of enum option the way it appears in the build configuration */ + String configurationName /** Name of file with coverage data */ String fileName /** Name of param in XML file with coverage value */ @@ -26,7 +28,8 @@ enum CoverageType { /** Used to normalize coverage value */ private double factor - private CoverageType(String fileName, String paramName, double factor) { + private CoverageType(String configurationName, String fileName, String paramName, double factor) { + this.configurationName = configurationName this.fileName = fileName this.paramName = paramName this.factor = factor @@ -36,6 +39,12 @@ enum CoverageType { Double normalize(Double value) { return value / factor } + + static CoverageType find(String configurationName) { + CoverageType.values().find { + it.configurationName.toLowerCase() == configurationName.toLowerCase() + } + } } /** @@ -46,7 +55,7 @@ class OverallCheckTask extends DefaultTask { /** Type of coverage to check. Available options: Line, Statement and Branch */ @Input - final Property coverageType = project.objects.property(CoverageType) + final Property coverageType = project.objects.property(String) @Input final Property minimumRate = project.objects.property(BigDecimal) @@ -61,7 +70,11 @@ class OverallCheckTask extends DefaultTask { void requireLineCoverage() { NumberFormat nf = NumberFormat.getInstance(locale.get()) - Exception failure = checkLineCoverage(nf, reportDir.get(), coverageType.get(), minimumRate.get().doubleValue()) + CoverageType coverageType = CoverageType.find(this.coverageType.get()) + if (coverageType == null) { + throw new GradleException("Unknown coverage type ${this.coverageType.get()}") + } + Exception failure = checkLineCoverage(nf, reportDir.get(), coverageType, minimumRate.get().doubleValue()) if (failure) throw failure } diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index 8ee680b..372b3dd 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -40,7 +40,7 @@ class ScoverageExtension { final Property deleteReportsOnAggregation - final Property coverageType + final Property coverageType final Property minimumRate ScoverageExtension(Project project) { @@ -87,8 +87,8 @@ class ScoverageExtension { deleteReportsOnAggregation = project.objects.property(Boolean) deleteReportsOnAggregation.set(false) - coverageType = project.objects.property(CoverageType) - coverageType.set(CoverageType.Statement) + coverageType = project.objects.property(String) + coverageType.set(CoverageType.Statement.configurationName) minimumRate = project.objects.property(BigDecimal) minimumRate.set(0.75) From f45a5d0deeb9118019ec9f7031728f047a43d9c7 Mon Sep 17 00:00:00 2001 From: Stu Date: Tue, 19 Nov 2019 19:55:21 +0000 Subject: [PATCH 086/167] bump scoverage to 1.4.1 --- src/main/groovy/org/scoverage/ScoverageExtension.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index 8e45a7e..f7b87ec 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -49,7 +49,7 @@ class ScoverageExtension { project.plugins.apply(ScalaPlugin.class) scoverageVersion = project.objects.property(String) - scoverageVersion.set('1.4.0') + scoverageVersion.set('1.4.1') scoverageScalaVersion = project.objects.property(String) scoverageScalaVersion.set('2.12') From a67eabdafe0feb876a67df6f48a227607edd8a15 Mon Sep 17 00:00:00 2001 From: Stu Date: Tue, 19 Nov 2019 20:16:05 +0000 Subject: [PATCH 087/167] scoverage 1.4.1 requires scala 2.13.1 --- .../projects/scala-multi-module-cross-version/2_13/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/build.gradle index 6db22d2..8be20a7 100644 --- a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/build.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/build.gradle @@ -1,4 +1,4 @@ dependencies { - compile group: 'org.scala-lang', name: 'scala-library', version: "2.13.0" + compile group: 'org.scala-lang', name: 'scala-library', version: "2.13.1" testCompile group: 'org.scalatest', name: "scalatest_2.13", version: scalatestVersion } From ddbe15228564cc0c8451e2a903f818a9b30d3d47 Mon Sep 17 00:00:00 2001 From: Stu Date: Wed, 20 Nov 2019 18:53:12 +0000 Subject: [PATCH 088/167] remove ScalaSingleMultiLangModuleTest (restore https://github.com/scoverage/gradle-scoverage/commit/64ad30efbe4d99e2624c64ee6ed56bfcf077fbc4) --- .../ScalaSingleMultiLangModuleTest.java | 145 ------------------ .../build.gradle | 33 ---- .../settings.gradle | 0 .../src/main/java/org/hello/JavaWorld.java | 7 - .../src/main/scala/org/hello/World.scala | 14 -- .../scala/org/hello/TestNothingSuite.scala | 12 -- .../src/test/scala/org/hello/WorldSuite.scala | 17 -- 7 files changed, 228 deletions(-) delete mode 100644 src/functionalTest/java/org.scoverage/ScalaSingleMultiLangModuleTest.java delete mode 100644 src/functionalTest/resources/projects/scala-single-multi-lang-module/build.gradle delete mode 100644 src/functionalTest/resources/projects/scala-single-multi-lang-module/settings.gradle delete mode 100644 src/functionalTest/resources/projects/scala-single-multi-lang-module/src/main/java/org/hello/JavaWorld.java delete mode 100644 src/functionalTest/resources/projects/scala-single-multi-lang-module/src/main/scala/org/hello/World.scala delete mode 100644 src/functionalTest/resources/projects/scala-single-multi-lang-module/src/test/scala/org/hello/TestNothingSuite.scala delete mode 100644 src/functionalTest/resources/projects/scala-single-multi-lang-module/src/test/scala/org/hello/WorldSuite.scala diff --git a/src/functionalTest/java/org.scoverage/ScalaSingleMultiLangModuleTest.java b/src/functionalTest/java/org.scoverage/ScalaSingleMultiLangModuleTest.java deleted file mode 100644 index 3f8dd76..0000000 --- a/src/functionalTest/java/org.scoverage/ScalaSingleMultiLangModuleTest.java +++ /dev/null @@ -1,145 +0,0 @@ -package org.scoverage; - -import org.junit.Assert; -import org.junit.Test; - -public class ScalaSingleMultiLangModuleTest extends ScoverageFunctionalTest { - - public ScalaSingleMultiLangModuleTest() { super("scala-single-multi-lang-module"); } - - @Test - public void test() { - - AssertableBuildResult result = dryRun("clean", "test"); - - result.assertTaskDoesntExist(ScoveragePlugin.getCOMPILE_NAME()); - result.assertTaskDoesntExist(ScoveragePlugin.getREPORT_NAME()); - result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); - result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); - } - - @Test - public void build() { - - AssertableBuildResult result = dryRun("clean", "build"); - - result.assertTaskDoesntExist(ScoveragePlugin.getCOMPILE_NAME()); - result.assertTaskDoesntExist(ScoveragePlugin.getREPORT_NAME()); - result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); - result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); - } - - @Test - public void reportScoverage() { - - AssertableBuildResult result = dryRun("clean", ScoveragePlugin.getREPORT_NAME()); - - result.assertTaskExists(ScoveragePlugin.getCOMPILE_NAME()); - result.assertTaskExists(ScoveragePlugin.getREPORT_NAME()); - result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); - result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); - } - - @Test - public void aggregateScoverage() { - - AssertableBuildResult result = runAndFail("clean", ScoveragePlugin.getAGGREGATE_NAME()); - - result.assertNoTasks(); - } - - @Test - public void checkScoverage() throws Exception { - - AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME()); - - result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); - result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); - result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); - result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); - - assertReportFilesExist(); - assertCoverage(66.7); - } - - @Test - public void checkScoverageFails() throws Exception { - - AssertableBuildResult result = runAndFail("clean", ScoveragePlugin.getCHECK_NAME(), - "test", "--tests", "org.hello.TestNothingSuite"); - - result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); - result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); - result.assertTaskFailed(ScoveragePlugin.getCHECK_NAME()); - result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); - - assertReportFilesExist(); - assertCoverage(0.0); - } - - @Test - public void reportScoverageWithExcludedClasses() throws Exception { - - AssertableBuildResult result = run("clean", ScoveragePlugin.getREPORT_NAME(), - "-PexcludedFile=.*"); - - result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); - result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); - result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); - result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); - - Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertFalse(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); - assertCoverage(100.0); // coverage is 100 since no classes are covered - - // compiled class should exist in the default classes directory, but not in scoverage - Assert.assertTrue(resolve(buildDir(), "classes/scala/main/org/hello/World.class").exists()); - Assert.assertFalse(resolve(buildDir(), "classes/scala/scoverage/org/hello/World.class").exists()); - } - - @Test - public void reportScoverageWithoutNormalCompilation() throws Exception { - - AssertableBuildResult result = run("clean", ScoveragePlugin.getREPORT_NAME(), - "-x", "compileScala"); - - result.assertTaskSkipped("compileScala"); - result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); - result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); - result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); - result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); - - assertReportFilesExist(); - assertCoverage(66.7); - - Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertTrue(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); - Assert.assertFalse(resolve(reportDir(), "src/main/java/org/hello/JavaWorld.java.html").exists()); - - Assert.assertTrue(resolve(buildDir(), "classes/java/main/org/hello/JavaWorld.class").exists()); - Assert.assertTrue(resolve(buildDir(), "classes/java/scoverage/org/hello/JavaWorld.class").exists()); - Assert.assertTrue(resolve(buildDir(), "classes/scala/main/org/hello/World.class").exists()); - Assert.assertFalse(resolve(buildDir(), "classes/scala/scoverage/org/hello/World.class").exists()); - } - - @Test - public void reportScoverageWithoutNormalCompilationAndWithExcludedClasses() throws Exception { - - AssertableBuildResult result = run("clean", ScoveragePlugin.getREPORT_NAME(), - "-PexcludedFile=.*", "-x", "compileScala"); - - Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertFalse(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); - assertCoverage(100.0); // coverage is 100 since no classes are covered - - // compiled class should exist in the default classes directory, but not in scoverage - Assert.assertTrue(resolve(buildDir(), "classes/scala/main/org/hello/World.class").exists()); - Assert.assertFalse(resolve(buildDir(), "classes/scala/scoverage/org/hello/World.class").exists()); - } - - - private void assertReportFilesExist() { - Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertTrue(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); - } -} diff --git a/src/functionalTest/resources/projects/scala-single-multi-lang-module/build.gradle b/src/functionalTest/resources/projects/scala-single-multi-lang-module/build.gradle deleted file mode 100644 index c7ebff2..0000000 --- a/src/functionalTest/resources/projects/scala-single-multi-lang-module/build.gradle +++ /dev/null @@ -1,33 +0,0 @@ -plugins { - id 'org.scoverage' -} - -repositories { - jcenter() -} - -description = 'a single-module Scala project with java and scala sources' - -apply plugin: 'java' -apply plugin: 'scala' - -dependencies { - compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" - - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion - testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion - - testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion -} - -test { - useJUnitPlatform() -} - -scoverage { - minimumRate = 0.3 -} - -if (hasProperty("excludedFile")) { - scoverage.excludedFiles = [excludedFile] -} diff --git a/src/functionalTest/resources/projects/scala-single-multi-lang-module/settings.gradle b/src/functionalTest/resources/projects/scala-single-multi-lang-module/settings.gradle deleted file mode 100644 index e69de29..0000000 diff --git a/src/functionalTest/resources/projects/scala-single-multi-lang-module/src/main/java/org/hello/JavaWorld.java b/src/functionalTest/resources/projects/scala-single-multi-lang-module/src/main/java/org/hello/JavaWorld.java deleted file mode 100644 index 2f199c5..0000000 --- a/src/functionalTest/resources/projects/scala-single-multi-lang-module/src/main/java/org/hello/JavaWorld.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.hello; - -public class JavaWorld { - public static void hello() { - System.out.println("Hello, World!"); - } -} diff --git a/src/functionalTest/resources/projects/scala-single-multi-lang-module/src/main/scala/org/hello/World.scala b/src/functionalTest/resources/projects/scala-single-multi-lang-module/src/main/scala/org/hello/World.scala deleted file mode 100644 index b7090dc..0000000 --- a/src/functionalTest/resources/projects/scala-single-multi-lang-module/src/main/scala/org/hello/World.scala +++ /dev/null @@ -1,14 +0,0 @@ -package org.hello - -class World { - - def foo(): String = { - val s = "a" + "b" - s - } - - // not covered by tests - def bar(): String = "y" - - def helloFromJava(): Unit = JavaWorld.hello() -} diff --git a/src/functionalTest/resources/projects/scala-single-multi-lang-module/src/test/scala/org/hello/TestNothingSuite.scala b/src/functionalTest/resources/projects/scala-single-multi-lang-module/src/test/scala/org/hello/TestNothingSuite.scala deleted file mode 100644 index b8599be..0000000 --- a/src/functionalTest/resources/projects/scala-single-multi-lang-module/src/test/scala/org/hello/TestNothingSuite.scala +++ /dev/null @@ -1,12 +0,0 @@ -package org.hello - -import org.junit.runner.RunWith -import org.scalatest.FunSuite -import org.scalatest.junit.JUnitRunner - -@RunWith(classOf[JUnitRunner]) -class TestNothingSuite extends FunSuite { - - test("nothing") { - } -} diff --git a/src/functionalTest/resources/projects/scala-single-multi-lang-module/src/test/scala/org/hello/WorldSuite.scala b/src/functionalTest/resources/projects/scala-single-multi-lang-module/src/test/scala/org/hello/WorldSuite.scala deleted file mode 100644 index 2e90b74..0000000 --- a/src/functionalTest/resources/projects/scala-single-multi-lang-module/src/test/scala/org/hello/WorldSuite.scala +++ /dev/null @@ -1,17 +0,0 @@ -package org.hello - -import org.junit.runner.RunWith -import org.scalatest.FunSuite -import org.scalatest.junit.JUnitRunner - -@RunWith(classOf[JUnitRunner]) -class WorldSuite extends FunSuite { - - test("foo") { - new World().foo() - } - - test("helloFromJava") { - new World().helloFromJava() - } -} From 40f939ff746e3295a70cf28df403f6e32d8978e3 Mon Sep 17 00:00:00 2001 From: Stu Date: Wed, 20 Nov 2019 19:34:47 +0000 Subject: [PATCH 089/167] Revert "statement count appears to fixed in 1.4" This reverts commit cc1c43fb --- .../ScalaMultiModuleWithMultipleTestTasksTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/functionalTest/java/org.scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java b/src/functionalTest/java/org.scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java index 66863c4..1905a1c 100644 --- a/src/functionalTest/java/org.scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java @@ -225,7 +225,7 @@ public void checkAndAggregateScoverageWithoutCoverageInRoot() throws Exception { result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); assertAllReportFilesExist(); - assertCoverage(88.24); + assertCoverage(93.33); } @Test From 72bdc5a04b35a85657e54bb219cdb18e18097d45 Mon Sep 17 00:00:00 2001 From: Stu Date: Wed, 20 Nov 2019 20:50:28 +0000 Subject: [PATCH 090/167] update README for next release --- README.md | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e9b8dc4..53b93a1 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ A plugin to enable the use of Scoverage in a gradle Scala project. Usage ----- -You can find instructions on how to apply the plugin at: http://plugins.gradle.org/plugin/org.scoverage +You can find instructions on how to apply the plugin at http://plugins.gradle.org/plugin/org.scoverage ### Available tasks @@ -18,7 +18,7 @@ You can find instructions on how to apply the plugin at: http://plugins.gradle. tasks to run only the desired tests. For example, to run only the unit tests and no other test tasks (e.g., integration tests), you can run `reportTestScoverage`. -2. `aggregateScoverage`: An experimental support for aggregating coverage statistics in composite builds. +2. `aggregateScoverage`: Aggregates coverage statistics in composite builds. When applied on a project with sub-projects, the plugin will create the aggregation task `aggregateScoverage`, which will first generate reports for each project individually (including the parent project), and will then generate an @@ -41,7 +41,7 @@ You can find instructions on how to apply the plugin at: http://plugins.gradle. The plugin exposes multiple options that can be configured by setting them in an `scoverage` block within the project's build script. These options are as follows: -* `scoverageVersion = ` (default `"1.3.1"`): The version of the scoverage scalac plugin. This (gradle) plugin +* `scoverageVersion = ` (default `"1.4.1"`): The version of the scoverage scalac plugin. This (gradle) plugin should be compatible with all 1+ versions. * `scoverageScalaVersion = ` (default `"2.12"`): The scala version of the scoverage scalac plugin. This will @@ -113,6 +113,21 @@ it is possible to only compile the code with the scoverage scalac plugin, thus r In order to do so, simply add the arguments `-x compileScala` to the gradle execution. For example: `gradle reportScoverage -x compileScala`. +Migration to 4.x +---------------- + +* Requires scoverage 1.4.1 or higher (and uses this version by default) +* Requires application of the plugin to appropriate subprojects. A multi-module project might apply it to all. + +```groovy +plugins { + id 'org.scoverage' version '4.0.0' apply false +} +allprojects { + apply plugin: 'org.scoverage' +} +``` + Migration to 3.x ---------------- From 544ef784e2b738da9711ce2e5da87e7c20cc72b3 Mon Sep 17 00:00:00 2001 From: chengpan Date: Wed, 27 Nov 2019 12:11:24 +0800 Subject: [PATCH 091/167] (#125) fix compatibility with scala 2.11 --- src/main/groovy/org/scoverage/ScoverageWriter.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/groovy/org/scoverage/ScoverageWriter.java b/src/main/groovy/org/scoverage/ScoverageWriter.java index a4c7ecf..47572c1 100644 --- a/src/main/groovy/org/scoverage/ScoverageWriter.java +++ b/src/main/groovy/org/scoverage/ScoverageWriter.java @@ -11,7 +11,6 @@ import scoverage.report.ScoverageXmlWriter; import java.io.File; -import java.nio.charset.Charset; import java.util.Arrays; /** @@ -77,7 +76,7 @@ public void write(File sourceDir, } if (coverageOutputHTML) { - Buffer sources = JavaConverters.asScalaBuffer(Arrays.asList(sourceDir)); + Buffer sources = JavaConverters.asScalaBufferConverter(Arrays.asList(sourceDir)).asScala(); new ScoverageHtmlWriter(sources, reportDir, new Some<>(sourceEncoding)).write(coverage); logger.info("[scoverage] Written HTML report to " + reportDir.getAbsolutePath() + From f9e7137c0b83e5aac0690ebc96dbf4dc3023cd62 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Wed, 27 Nov 2019 17:27:54 +0200 Subject: [PATCH 092/167] Fix the cross (scala) version test by adding individual test cases for each version --- .../ScalaMultiModuleCrossVersionTest.java | 33 ++++++++++++++++++- .../build.gradle | 6 +--- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/functionalTest/java/org.scoverage/ScalaMultiModuleCrossVersionTest.java b/src/functionalTest/java/org.scoverage/ScalaMultiModuleCrossVersionTest.java index 401149a..22ef656 100644 --- a/src/functionalTest/java/org.scoverage/ScalaMultiModuleCrossVersionTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaMultiModuleCrossVersionTest.java @@ -5,6 +5,10 @@ import java.io.File; +/** + * Note that it is important to test the case of all of the modules together, + * along with the cases of each module individually, as they behave differently. + */ public class ScalaMultiModuleCrossVersionTest extends ScoverageFunctionalTest { public ScalaMultiModuleCrossVersionTest() { @@ -12,7 +16,7 @@ public ScalaMultiModuleCrossVersionTest() { } @Test - public void checkAndAggregateScoverage() throws Exception { + public void checkAndAggregateAll() throws Exception { AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME(), ScoveragePlugin.getAGGREGATE_NAME()); @@ -20,15 +24,41 @@ public void checkAndAggregateScoverage() throws Exception { result.assertTaskSkipped(ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded("2_11:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded("2_12:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("2_13:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); result.assertTaskSucceeded("2_11:" + ScoveragePlugin.getCHECK_NAME()); result.assertTaskSucceeded("2_12:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded("2_13:" + ScoveragePlugin.getCHECK_NAME()); result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); assertAllReportFilesExist(); assertCoverage(100.0); } + @Test + public void report211() throws Exception { + + AssertableBuildResult result = run("clean", ":2_11:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("2_11:" + ScoveragePlugin.getREPORT_NAME()); + assert211ReportFilesExist(); + } + + @Test + public void report212() throws Exception { + + AssertableBuildResult result = run("clean", ":2_12:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("2_12:" + ScoveragePlugin.getREPORT_NAME()); + assert212ReportFilesExist(); + } + + @Test + public void report213() throws Exception { + + AssertableBuildResult result = run("clean", ":2_13:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("2_13:" + ScoveragePlugin.getREPORT_NAME()); + assert213ReportFilesExist(); + } + private void assertAllReportFilesExist() { assert211ReportFilesExist(); @@ -42,6 +72,7 @@ private void assertAggregationFilesExist() { Assert.assertTrue(resolve(reportDir(), "index.html").exists()); Assert.assertTrue(resolve(reportDir(), "2_11/src/main/scala/org/hello/World211.scala.html").exists()); Assert.assertTrue(resolve(reportDir(), "2_12/src/main/scala/org/hello/World212.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "2_13/src/main/scala/org/hello/World213.scala.html").exists()); } private void assert211ReportFilesExist() { diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-cross-version/build.gradle index 6f7d74c..8577cf5 100644 --- a/src/functionalTest/resources/projects/scala-multi-module-cross-version/build.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module-cross-version/build.gradle @@ -32,8 +32,4 @@ allprojects { scoverage { minimumRate = 0.5 -} - -project(":2_11").tasks.reportScoverage - .mustRunAfter(project(":2_12").tasks.reportScoverage) - .mustRunAfter(project(":2_13").tasks.reportScoverage) \ No newline at end of file +} \ No newline at end of file From 53a2d0d19662f664731be4e72abe633ab54c9a78 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Sun, 1 Dec 2019 14:58:56 +0200 Subject: [PATCH 093/167] Fix the cross (scala) version test by making sure to run the test before all other functional tests --- build.gradle | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 5502a69..bafe5e9 100644 --- a/build.gradle +++ b/build.gradle @@ -64,17 +64,29 @@ sourceSets { } } -task functionalTest(type: Test) { - description = 'Runs the functional tests.' +task crossScalaVersionFunctionalTest(type: Test) { + description = 'Runs the cross scala version functional test.' group = 'verification' testClassesDirs = sourceSets.functionalTest.output.classesDirs classpath = sourceSets.functionalTest.runtimeClasspath + include "**/ScalaMultiModuleCrossVersionTest.*" testLogging.showStandardStreams = true mustRunAfter test } +task functionalTest(type: Test) { + description = 'Runs the functional tests.' + group = 'verification' + testClassesDirs = sourceSets.functionalTest.output.classesDirs + classpath = sourceSets.functionalTest.runtimeClasspath + exclude "**/ScalaMultiModuleCrossVersionTest.*" + + testLogging.showStandardStreams = true + + dependsOn crossScalaVersionFunctionalTest +} check.dependsOn functionalTest gradlePlugin { From 25ada508b050f7a4309d42a32e59866a6cb85d22 Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 1 Dec 2019 09:43:11 +0000 Subject: [PATCH 094/167] attempt to deduplicate the coverage files being aggregated --- src/main/groovy/org/scoverage/ScoverageAggregate.groovy | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy index 8a7fa3b..1cffc13 100644 --- a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy +++ b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy @@ -46,7 +46,9 @@ class ScoverageAggregate extends DefaultTask { reportDir.get().deleteDir() reportDir.get().mkdirs() - def coverage = CoverageAggregator.aggregate(dirsToAggregateFrom.get() as File[]) + def dirs = [] + dirs.addAll(dirsToAggregateFrom.get()) + def coverage = CoverageAggregator.aggregate(dirs.unique() as File[]) if (coverage.nonEmpty()) { new ScoverageWriter(project.logger).write( From dbea830974191371b9a2570990bf18a4ea725f38 Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 1 Dec 2019 17:47:58 +0000 Subject: [PATCH 095/167] show applying to subprojects in the README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 53b93a1..20d82f9 100644 --- a/README.md +++ b/README.md @@ -121,9 +121,9 @@ Migration to 4.x ```groovy plugins { - id 'org.scoverage' version '4.0.0' apply false + id 'org.scoverage' version '4.0.0' } -allprojects { +subprojects { apply plugin: 'org.scoverage' } ``` From ba8d7604f5fc8dc77bef7e034caf3e3cd941b6f0 Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 1 Dec 2019 17:51:05 +0000 Subject: [PATCH 096/167] update to gradle 6.0.1 --- gradle/wrapper/gradle-wrapper.jar | Bin 55741 -> 55616 bytes gradle/wrapper/gradle-wrapper.properties | 3 +-- gradlew | 18 +++++++++++++++++- gradlew.bat | 18 +++++++++++++++++- ...ingleModuleWithDependencyManagerTest.java} | 4 ++-- .../build.gradle | 4 ---- .../build.gradle | 4 ---- .../org/scoverage/ScoverageAggregate.groovy | 4 ++-- .../org/scoverage/ScoverageReport.groovy | 2 ++ .../org/scoverage/ScoverageRunner.groovy | 4 +++- 10 files changed, 44 insertions(+), 17 deletions(-) rename src/functionalTest/java/org.scoverage/{ScalaSingleModuleWithDepdencyManagerTest.java => ScalaSingleModuleWithDependencyManagerTest.java} (85%) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 457aad0d98108420a977756b7145c93c8910b076..5c2d1cf016b3885f6930543d57b744ea8c220a1a 100644 GIT binary patch delta 19567 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 PFlPAY0appj7IgMMQM_1| diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9c80f8b..9492014 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=14cd15fc8cc8705bd69dcfa3c8fefb27eb7027f5de4b47a8b279218f76895a91 -distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index af6708f..b0d6d0a 100755 --- a/gradlew +++ b/gradlew @@ -1,5 +1,21 @@ #!/usr/bin/env sh +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + ############################################################################## ## ## Gradle start up script for UN*X @@ -28,7 +44,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m"' +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" diff --git a/gradlew.bat b/gradlew.bat index 0f8d593..15e1ee3 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome diff --git a/src/functionalTest/java/org.scoverage/ScalaSingleModuleWithDepdencyManagerTest.java b/src/functionalTest/java/org.scoverage/ScalaSingleModuleWithDependencyManagerTest.java similarity index 85% rename from src/functionalTest/java/org.scoverage/ScalaSingleModuleWithDepdencyManagerTest.java rename to src/functionalTest/java/org.scoverage/ScalaSingleModuleWithDependencyManagerTest.java index f8548fe..e7f701a 100644 --- a/src/functionalTest/java/org.scoverage/ScalaSingleModuleWithDepdencyManagerTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaSingleModuleWithDependencyManagerTest.java @@ -3,9 +3,9 @@ import org.junit.Assert; import org.junit.Test; -public class ScalaSingleModuleWithDepdencyManagerTest extends ScoverageFunctionalTest { +public class ScalaSingleModuleWithDependencyManagerTest extends ScoverageFunctionalTest { - public ScalaSingleModuleWithDepdencyManagerTest() { + public ScalaSingleModuleWithDependencyManagerTest() { super("scala-single-module-dependency-manager"); } diff --git a/src/functionalTest/resources/projects/scala-single-module-dependency-manager/build.gradle b/src/functionalTest/resources/projects/scala-single-module-dependency-manager/build.gradle index 135d248..8d36fb3 100644 --- a/src/functionalTest/resources/projects/scala-single-module-dependency-manager/build.gradle +++ b/src/functionalTest/resources/projects/scala-single-module-dependency-manager/build.gradle @@ -22,10 +22,6 @@ dependencyManagement { dependencies { compile group: 'org.scala-lang', name: 'scala-library' - // scala compilation with the dependency management plugin needs this (otherwise compilation will fail) - zinc group: 'com.typesafe.zinc', name: 'zinc', version: '0.3.15' - zinc group: 'org.scala-lang', name: 'scala-library', version: '2.10.5' - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion diff --git a/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle index c0e0e6d..b26ba4f 100644 --- a/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle +++ b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle @@ -21,10 +21,6 @@ dependencyManagement { dependencies { compile group: 'org.scala-lang', name: 'scala-library' - // scala compilation with the dependency management plugin needs this (otherwise compilation will fail) - zinc group: 'com.typesafe.zinc', name: 'zinc', version: '0.3.15' - zinc group: 'org.scala-lang', name: 'scala-library', version: '2.10.5' - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion diff --git a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy index 1cffc13..b445e29 100644 --- a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy +++ b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy @@ -4,14 +4,14 @@ import org.gradle.api.DefaultTask import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Nested import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction -// don't use scala.collection.JavaConverters as it breaks backward compatibility with scala 2.11 -import scala.collection.JavaConversions import scoverage.report.CoverageAggregator class ScoverageAggregate extends DefaultTask { + @Nested ScoverageRunner runner @OutputDirectory diff --git a/src/main/groovy/org/scoverage/ScoverageReport.groovy b/src/main/groovy/org/scoverage/ScoverageReport.groovy index 55cd701..ca8ceb2 100644 --- a/src/main/groovy/org/scoverage/ScoverageReport.groovy +++ b/src/main/groovy/org/scoverage/ScoverageReport.groovy @@ -4,6 +4,7 @@ import org.gradle.api.DefaultTask import org.gradle.api.provider.Property import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Nested import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction import scoverage.report.CoverageAggregator @@ -11,6 +12,7 @@ import scoverage.report.CoverageAggregator @CacheableTask class ScoverageReport extends DefaultTask { + @Nested ScoverageRunner runner @Input diff --git a/src/main/groovy/org/scoverage/ScoverageRunner.groovy b/src/main/groovy/org/scoverage/ScoverageRunner.groovy index 48889e7..713b9e4 100644 --- a/src/main/groovy/org/scoverage/ScoverageRunner.groovy +++ b/src/main/groovy/org/scoverage/ScoverageRunner.groovy @@ -1,12 +1,14 @@ package org.scoverage import org.gradle.api.file.FileCollection +import org.gradle.api.tasks.Classpath import java.lang.reflect.Method class ScoverageRunner { - private FileCollection runtimeClasspath + @Classpath + final FileCollection runtimeClasspath ScoverageRunner(FileCollection runtimeClasspath) { From 4e08a800ded85e084266df0d5ef23fcce87efd90 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Sun, 22 Dec 2019 13:36:10 +0200 Subject: [PATCH 097/167] Fix the cross (scala) version test (again) by making sure to run each test in a separate JVM process --- build.gradle | 7 +- .../ScalaMultiModuleCrossVersionTest.java | 98 ------------------- .../scoverage/crossversion/Scala211Test.java | 7 ++ .../scoverage/crossversion/Scala212Test.java | 7 ++ .../scoverage/crossversion/Scala213Test.java | 7 ++ .../ScalaCrossVersionAggregationTest.java | 46 +++++++++ .../crossversion/ScalaVersionTest.java | 35 +++++++ .../hello/{World211.scala => World2_11.scala} | 2 +- .../scala/org/hello/World2_11Suite.scala} | 4 +- .../src/main/scala/org/hello/World2_12.scala} | 2 +- .../scala/org/hello/World2_12Suite.scala} | 4 +- .../src/main/scala/org/hello/World2_13.scala} | 2 +- .../scala/org/hello/World2_13Suite.scala} | 2 +- 13 files changed, 113 insertions(+), 110 deletions(-) delete mode 100644 src/functionalTest/java/org.scoverage/ScalaMultiModuleCrossVersionTest.java create mode 100644 src/functionalTest/java/org/scoverage/crossversion/Scala211Test.java create mode 100644 src/functionalTest/java/org/scoverage/crossversion/Scala212Test.java create mode 100644 src/functionalTest/java/org/scoverage/crossversion/Scala213Test.java create mode 100644 src/functionalTest/java/org/scoverage/crossversion/ScalaCrossVersionAggregationTest.java create mode 100644 src/functionalTest/java/org/scoverage/crossversion/ScalaVersionTest.java rename src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/main/scala/org/hello/{World211.scala => World2_11.scala} (81%) rename src/functionalTest/resources/projects/scala-multi-module-cross-version/{2_13/src/test/scala/org/hello/World213Suite.scala => 2_11/src/test/scala/org/hello/World2_11Suite.scala} (72%) rename src/functionalTest/resources/projects/scala-multi-module-cross-version/{2_13/src/main/scala/org/hello/World213.scala => 2_12/src/main/scala/org/hello/World2_12.scala} (81%) rename src/functionalTest/resources/projects/scala-multi-module-cross-version/{2_11/src/test/scala/org/hello/World211Suite.scala => 2_12/src/test/scala/org/hello/World2_12Suite.scala} (72%) rename src/functionalTest/resources/projects/scala-multi-module-cross-version/{2_12/src/main/scala/org/hello/World212.scala => 2_13/src/main/scala/org/hello/World2_13.scala} (81%) rename src/functionalTest/resources/projects/scala-multi-module-cross-version/{2_12/src/test/scala/org/hello/World212Suite.scala => 2_13/src/test/scala/org/hello/World2_13Suite.scala} (89%) diff --git a/build.gradle b/build.gradle index bafe5e9..c6f706d 100644 --- a/build.gradle +++ b/build.gradle @@ -69,7 +69,8 @@ task crossScalaVersionFunctionalTest(type: Test) { group = 'verification' testClassesDirs = sourceSets.functionalTest.output.classesDirs classpath = sourceSets.functionalTest.runtimeClasspath - include "**/ScalaMultiModuleCrossVersionTest.*" + include '**/crossversion/*' + forkEvery = 1 // crucial to run every test in its own JVM testLogging.showStandardStreams = true @@ -81,9 +82,7 @@ task functionalTest(type: Test) { group = 'verification' testClassesDirs = sourceSets.functionalTest.output.classesDirs classpath = sourceSets.functionalTest.runtimeClasspath - exclude "**/ScalaMultiModuleCrossVersionTest.*" - - testLogging.showStandardStreams = true + exclude '**/crossversion/*' dependsOn crossScalaVersionFunctionalTest } diff --git a/src/functionalTest/java/org.scoverage/ScalaMultiModuleCrossVersionTest.java b/src/functionalTest/java/org.scoverage/ScalaMultiModuleCrossVersionTest.java deleted file mode 100644 index 22ef656..0000000 --- a/src/functionalTest/java/org.scoverage/ScalaMultiModuleCrossVersionTest.java +++ /dev/null @@ -1,98 +0,0 @@ -package org.scoverage; - -import org.junit.Assert; -import org.junit.Test; - -import java.io.File; - -/** - * Note that it is important to test the case of all of the modules together, - * along with the cases of each module individually, as they behave differently. - */ -public class ScalaMultiModuleCrossVersionTest extends ScoverageFunctionalTest { - - public ScalaMultiModuleCrossVersionTest() { - super("scala-multi-module-cross-version"); - } - - @Test - public void checkAndAggregateAll() throws Exception { - - AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME(), - ScoveragePlugin.getAGGREGATE_NAME()); - - result.assertTaskSkipped(ScoveragePlugin.getREPORT_NAME()); - result.assertTaskSucceeded("2_11:" + ScoveragePlugin.getREPORT_NAME()); - result.assertTaskSucceeded("2_12:" + ScoveragePlugin.getREPORT_NAME()); - result.assertTaskSucceeded("2_13:" + ScoveragePlugin.getREPORT_NAME()); - result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); - result.assertTaskSucceeded("2_11:" + ScoveragePlugin.getCHECK_NAME()); - result.assertTaskSucceeded("2_12:" + ScoveragePlugin.getCHECK_NAME()); - result.assertTaskSucceeded("2_13:" + ScoveragePlugin.getCHECK_NAME()); - result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); - - assertAllReportFilesExist(); - assertCoverage(100.0); - } - - @Test - public void report211() throws Exception { - - AssertableBuildResult result = run("clean", ":2_11:" + ScoveragePlugin.getREPORT_NAME()); - result.assertTaskSucceeded("2_11:" + ScoveragePlugin.getREPORT_NAME()); - assert211ReportFilesExist(); - } - - @Test - public void report212() throws Exception { - - AssertableBuildResult result = run("clean", ":2_12:" + ScoveragePlugin.getREPORT_NAME()); - result.assertTaskSucceeded("2_12:" + ScoveragePlugin.getREPORT_NAME()); - assert212ReportFilesExist(); - } - - @Test - public void report213() throws Exception { - - AssertableBuildResult result = run("clean", ":2_13:" + ScoveragePlugin.getREPORT_NAME()); - result.assertTaskSucceeded("2_13:" + ScoveragePlugin.getREPORT_NAME()); - assert213ReportFilesExist(); - } - - private void assertAllReportFilesExist() { - - assert211ReportFilesExist(); - assert212ReportFilesExist(); - assert213ReportFilesExist(); - assertAggregationFilesExist(); - } - - private void assertAggregationFilesExist() { - - Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertTrue(resolve(reportDir(), "2_11/src/main/scala/org/hello/World211.scala.html").exists()); - Assert.assertTrue(resolve(reportDir(), "2_12/src/main/scala/org/hello/World212.scala.html").exists()); - Assert.assertTrue(resolve(reportDir(), "2_13/src/main/scala/org/hello/World213.scala.html").exists()); - } - - private void assert211ReportFilesExist() { - - File reportDir = reportDir(projectDir().toPath().resolve("2_11").toFile()); - Assert.assertTrue(resolve(reportDir, "index.html").exists()); - Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/World211.scala.html").exists()); - } - - private void assert212ReportFilesExist() { - - File reportDir = reportDir(projectDir().toPath().resolve("2_12").toFile()); - Assert.assertTrue(resolve(reportDir, "index.html").exists()); - Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/World212.scala.html").exists()); - } - - private void assert213ReportFilesExist() { - - File reportDir = reportDir(projectDir().toPath().resolve("2_13").toFile()); - Assert.assertTrue(resolve(reportDir, "index.html").exists()); - Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/World213.scala.html").exists()); - } -} diff --git a/src/functionalTest/java/org/scoverage/crossversion/Scala211Test.java b/src/functionalTest/java/org/scoverage/crossversion/Scala211Test.java new file mode 100644 index 0000000..e8dfcaa --- /dev/null +++ b/src/functionalTest/java/org/scoverage/crossversion/Scala211Test.java @@ -0,0 +1,7 @@ +package org.scoverage.crossversion; + +public class Scala211Test extends ScalaVersionTest { + public Scala211Test() { + super("2_11"); + } +} \ No newline at end of file diff --git a/src/functionalTest/java/org/scoverage/crossversion/Scala212Test.java b/src/functionalTest/java/org/scoverage/crossversion/Scala212Test.java new file mode 100644 index 0000000..ee34a21 --- /dev/null +++ b/src/functionalTest/java/org/scoverage/crossversion/Scala212Test.java @@ -0,0 +1,7 @@ +package org.scoverage.crossversion; + +public class Scala212Test extends ScalaVersionTest { + public Scala212Test() { + super("2_12"); + } +} \ No newline at end of file diff --git a/src/functionalTest/java/org/scoverage/crossversion/Scala213Test.java b/src/functionalTest/java/org/scoverage/crossversion/Scala213Test.java new file mode 100644 index 0000000..f6a6043 --- /dev/null +++ b/src/functionalTest/java/org/scoverage/crossversion/Scala213Test.java @@ -0,0 +1,7 @@ +package org.scoverage.crossversion; + +public class Scala213Test extends ScalaVersionTest { + public Scala213Test() { + super("2_13"); + } +} \ No newline at end of file diff --git a/src/functionalTest/java/org/scoverage/crossversion/ScalaCrossVersionAggregationTest.java b/src/functionalTest/java/org/scoverage/crossversion/ScalaCrossVersionAggregationTest.java new file mode 100644 index 0000000..a086188 --- /dev/null +++ b/src/functionalTest/java/org/scoverage/crossversion/ScalaCrossVersionAggregationTest.java @@ -0,0 +1,46 @@ +package org.scoverage.crossversion; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.jupiter.api.Tag; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.scoverage.ScoverageFunctionalTest; +import org.scoverage.ScoveragePlugin; + +import java.io.File; + +public class ScalaCrossVersionAggregationTest extends ScoverageFunctionalTest { + + public ScalaCrossVersionAggregationTest() { + super("scala-multi-module-cross-version"); + } + + @Test + public void checkAndAggregateAll() throws Exception { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME(), + ScoveragePlugin.getAGGREGATE_NAME()); + + result.assertTaskSkipped(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("2_11:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("2_12:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("2_13:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded("2_11:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded("2_12:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded("2_13:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); + + assertAggregationFilesExist(); + assertCoverage(100.0); + } + + private void assertAggregationFilesExist() { + + Assert.assertTrue(resolve(reportDir(), "index.html").exists()); + Assert.assertTrue(resolve(reportDir(), "2_11/src/main/scala/org/hello/World2_11.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "2_12/src/main/scala/org/hello/World2_12.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "2_13/src/main/scala/org/hello/World2_13.scala.html").exists()); + } +} diff --git a/src/functionalTest/java/org/scoverage/crossversion/ScalaVersionTest.java b/src/functionalTest/java/org/scoverage/crossversion/ScalaVersionTest.java new file mode 100644 index 0000000..e5ac15f --- /dev/null +++ b/src/functionalTest/java/org/scoverage/crossversion/ScalaVersionTest.java @@ -0,0 +1,35 @@ +package org.scoverage.crossversion; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.jupiter.api.Tag; +import org.scoverage.ScoverageFunctionalTest; +import org.scoverage.ScoveragePlugin; + +import java.io.File; + +/** + * This abstract class is used to test each scala version in an individual class. + * It is crucial that each test will be separated into its own class, + * as this is the only way to run these tests in separate JVM processes (via `forkEvery` gradle configuration). + */ +public abstract class ScalaVersionTest extends ScoverageFunctionalTest { + + private final String scalaVersion; + + public ScalaVersionTest(String scalaVersion) { + super("scala-multi-module-cross-version"); + this.scalaVersion = scalaVersion; + } + + @Test + public void report() throws Exception { + + AssertableBuildResult result = run("clean", ":" + scalaVersion + ":" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded(scalaVersion + ":" + ScoveragePlugin.getREPORT_NAME()); + + File reportDir = reportDir(projectDir().toPath().resolve(scalaVersion).toFile()); + Assert.assertTrue(resolve(reportDir, "index.html").exists()); + Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/World" + scalaVersion + ".scala.html").exists()); + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/main/scala/org/hello/World211.scala b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/main/scala/org/hello/World2_11.scala similarity index 81% rename from src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/main/scala/org/hello/World211.scala rename to src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/main/scala/org/hello/World2_11.scala index 7c7f57b..cab6958 100644 --- a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/main/scala/org/hello/World211.scala +++ b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/main/scala/org/hello/World2_11.scala @@ -1,6 +1,6 @@ package org.hello -class World211 { +class World2_11 { def foo(): String = { val s = "2" + "11" diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/src/test/scala/org/hello/World213Suite.scala b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/test/scala/org/hello/World2_11Suite.scala similarity index 72% rename from src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/src/test/scala/org/hello/World213Suite.scala rename to src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/test/scala/org/hello/World2_11Suite.scala index ad43f08..2d99209 100644 --- a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/src/test/scala/org/hello/World213Suite.scala +++ b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/test/scala/org/hello/World2_11Suite.scala @@ -5,9 +5,9 @@ import org.scalatest.FunSuite import org.scalatest.junit.JUnitRunner @RunWith(classOf[JUnitRunner]) -class World212Suite extends FunSuite { +class World2_11Suite extends FunSuite { test("foo") { - new World213().foo() + new World2_11().foo() } } \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/src/main/scala/org/hello/World213.scala b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/src/main/scala/org/hello/World2_12.scala similarity index 81% rename from src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/src/main/scala/org/hello/World213.scala rename to src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/src/main/scala/org/hello/World2_12.scala index b5fc8fb..c0cc10b 100644 --- a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/src/main/scala/org/hello/World213.scala +++ b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/src/main/scala/org/hello/World2_12.scala @@ -1,6 +1,6 @@ package org.hello -class World213 { +class World2_12 { def foo(): String = { val s = "2" + "12" diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/test/scala/org/hello/World211Suite.scala b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/src/test/scala/org/hello/World2_12Suite.scala similarity index 72% rename from src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/test/scala/org/hello/World211Suite.scala rename to src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/src/test/scala/org/hello/World2_12Suite.scala index f872840..23e5b04 100644 --- a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/test/scala/org/hello/World211Suite.scala +++ b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/src/test/scala/org/hello/World2_12Suite.scala @@ -5,9 +5,9 @@ import org.scalatest.FunSuite import org.scalatest.junit.JUnitRunner @RunWith(classOf[JUnitRunner]) -class World211Suite extends FunSuite { +class World2_12Suite extends FunSuite { test("foo") { - new World211().foo() + new World2_12().foo() } } \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/src/main/scala/org/hello/World212.scala b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/src/main/scala/org/hello/World2_13.scala similarity index 81% rename from src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/src/main/scala/org/hello/World212.scala rename to src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/src/main/scala/org/hello/World2_13.scala index 0968efa..d18034b 100644 --- a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/src/main/scala/org/hello/World212.scala +++ b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/src/main/scala/org/hello/World2_13.scala @@ -1,6 +1,6 @@ package org.hello -class World212 { +class World2_13 { def foo(): String = { val s = "2" + "12" diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/src/test/scala/org/hello/World212Suite.scala b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/src/test/scala/org/hello/World2_13Suite.scala similarity index 89% rename from src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/src/test/scala/org/hello/World212Suite.scala rename to src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/src/test/scala/org/hello/World2_13Suite.scala index cd26ad3..0628dc4 100644 --- a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/src/test/scala/org/hello/World212Suite.scala +++ b/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/src/test/scala/org/hello/World2_13Suite.scala @@ -8,6 +8,6 @@ import org.scalatest.junit.JUnitRunner class World212Suite extends FunSuite { test("foo") { - new World212().foo() + new World2_13().foo() } } \ No newline at end of file From d754ede393839c21dbb8241d065057b7cb613f4d Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Sun, 22 Dec 2019 18:14:57 +0200 Subject: [PATCH 098/167] Add an ignored test-case for composite build (ignored since it isn't supported yet) --- .../org.scoverage/CompositeBuildTest.java | 46 +++++++++++++++++++ .../composite-build/proj1/build.gradle | 32 +++++++++++++ .../composite-build/proj1/settings.gradle | 0 .../main/scala/org/composite/proj1/Foo.scala | 7 +++ .../scala/org/composite/proj1/FooSuite.scala | 14 ++++++ .../composite-build/proj2/build.gradle | 30 ++++++++++++ .../scala/org/composite/proj2/Reporter.scala | 19 ++++++++ .../org/composite/proj2/ReporterSuite.scala | 16 +++++++ 8 files changed, 164 insertions(+) create mode 100644 src/functionalTest/java/org.scoverage/CompositeBuildTest.java create mode 100644 src/functionalTest/resources/projects/composite-build/proj1/build.gradle create mode 100644 src/functionalTest/resources/projects/composite-build/proj1/settings.gradle create mode 100644 src/functionalTest/resources/projects/composite-build/proj1/src/main/scala/org/composite/proj1/Foo.scala create mode 100644 src/functionalTest/resources/projects/composite-build/proj1/src/test/scala/org/composite/proj1/FooSuite.scala create mode 100644 src/functionalTest/resources/projects/composite-build/proj2/build.gradle create mode 100644 src/functionalTest/resources/projects/composite-build/proj2/src/main/scala/org/composite/proj2/Reporter.scala create mode 100644 src/functionalTest/resources/projects/composite-build/proj2/src/test/scala/org/composite/proj2/ReporterSuite.scala diff --git a/src/functionalTest/java/org.scoverage/CompositeBuildTest.java b/src/functionalTest/java/org.scoverage/CompositeBuildTest.java new file mode 100644 index 0000000..86dd695 --- /dev/null +++ b/src/functionalTest/java/org.scoverage/CompositeBuildTest.java @@ -0,0 +1,46 @@ +package org.scoverage; + +import org.junit.Ignore; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Tests are currently ignored as composite builds are not supported yet. + * + * See https://github.com/scoverage/gradle-scoverage/issues/98 + */ +public class CompositeBuildTest extends ScoverageFunctionalTest { + + public CompositeBuildTest() { + super("composite-build"); + } + + @Ignore + @Test + public void buildComposite() { + + runComposite("clean", "build"); + } + + @Ignore + @Test + public void reportComposite() { + + runComposite("clean", ScoveragePlugin.getREPORT_NAME()); + } + + private AssertableBuildResult runComposite(String... arguments) { + + List fullArguments = new ArrayList(); + fullArguments.add("-p"); + fullArguments.add("proj1"); + fullArguments.add("--include-build"); + fullArguments.add("../proj2"); + fullArguments.addAll(Arrays.asList(arguments)); + + return run(fullArguments.toArray(new String[0])); + } +} diff --git a/src/functionalTest/resources/projects/composite-build/proj1/build.gradle b/src/functionalTest/resources/projects/composite-build/proj1/build.gradle new file mode 100644 index 0000000..d0e32d3 --- /dev/null +++ b/src/functionalTest/resources/projects/composite-build/proj1/build.gradle @@ -0,0 +1,32 @@ +plugins { + id 'org.scoverage' +} + +repositories { + jcenter() +} + +description = 'a single-module Scala project taking part in a composite build (1)' + +apply plugin: 'java' +apply plugin: 'scala' + + +group "org.composite" +version '1.0' + +dependencies { + compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + + testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion + + compile "org.composite:proj2:1.0" +} + +test { + useJUnitPlatform() +} + diff --git a/src/functionalTest/resources/projects/composite-build/proj1/settings.gradle b/src/functionalTest/resources/projects/composite-build/proj1/settings.gradle new file mode 100644 index 0000000..e69de29 diff --git a/src/functionalTest/resources/projects/composite-build/proj1/src/main/scala/org/composite/proj1/Foo.scala b/src/functionalTest/resources/projects/composite-build/proj1/src/main/scala/org/composite/proj1/Foo.scala new file mode 100644 index 0000000..cc5333e --- /dev/null +++ b/src/functionalTest/resources/projects/composite-build/proj1/src/main/scala/org/composite/proj1/Foo.scala @@ -0,0 +1,7 @@ +package org.composite.proj1 + +import org.composite.proj2.Reporter + +class Foo { + def bar(): String = "bar" +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/composite-build/proj1/src/test/scala/org/composite/proj1/FooSuite.scala b/src/functionalTest/resources/projects/composite-build/proj1/src/test/scala/org/composite/proj1/FooSuite.scala new file mode 100644 index 0000000..370252a --- /dev/null +++ b/src/functionalTest/resources/projects/composite-build/proj1/src/test/scala/org/composite/proj1/FooSuite.scala @@ -0,0 +1,14 @@ +package org.composite.proj1 + +import org.scalatest.FunSuite +import org.junit.runner.RunWith +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class FooSuite extends FunSuite { + + test("bar"){ + + new Foo().bar() + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/composite-build/proj2/build.gradle b/src/functionalTest/resources/projects/composite-build/proj2/build.gradle new file mode 100644 index 0000000..b86570e --- /dev/null +++ b/src/functionalTest/resources/projects/composite-build/proj2/build.gradle @@ -0,0 +1,30 @@ +plugins { + id 'org.scoverage' +} + +repositories { + jcenter() +} + +description = 'a single-module Scala project taking part in a composite build (2)' + +apply plugin: 'java' +apply plugin: 'scala' + + +group "org.composite" +version '1.0' + +dependencies { + compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + + testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion +} + +test { + useJUnitPlatform() +} + diff --git a/src/functionalTest/resources/projects/composite-build/proj2/src/main/scala/org/composite/proj2/Reporter.scala b/src/functionalTest/resources/projects/composite-build/proj2/src/main/scala/org/composite/proj2/Reporter.scala new file mode 100644 index 0000000..11ef036 --- /dev/null +++ b/src/functionalTest/resources/projects/composite-build/proj2/src/main/scala/org/composite/proj2/Reporter.scala @@ -0,0 +1,19 @@ +package org.composite.proj2 + +class Reporter { + + def report(rawData: String): Report = { + Report(1,2) + } + + class InnerReporter { + + def lala(): Unit = { + + val x = 1 + 1 + x + } + } +} + +case class Report(id: Long, count: Int) \ No newline at end of file diff --git a/src/functionalTest/resources/projects/composite-build/proj2/src/test/scala/org/composite/proj2/ReporterSuite.scala b/src/functionalTest/resources/projects/composite-build/proj2/src/test/scala/org/composite/proj2/ReporterSuite.scala new file mode 100644 index 0000000..89de304 --- /dev/null +++ b/src/functionalTest/resources/projects/composite-build/proj2/src/test/scala/org/composite/proj2/ReporterSuite.scala @@ -0,0 +1,16 @@ +package org.composite.proj2 + +import org.scalatest.FunSuite +import org.junit.runner.RunWith +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class ReporterSuite extends FunSuite { + + test("report"){ + + val report = new Reporter().report("x") + + assertResult(Report(1, 2))(report) + } +} From 161bad9c26347fa43e89fec52f4c17f03339930a Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Sun, 22 Dec 2019 18:15:19 +0200 Subject: [PATCH 099/167] Update README to mention that composite builds are not currently supported --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 20d82f9..4e09b2c 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,8 @@ You can find instructions on how to apply the plugin at http://plugins.gradle.or `gradle checkScoverage` will automatically invoke `reportScoverage` but it won't generate aggregated reports. In order to check coverage of aggregated reports one should use `gradle checkScoverage aggregateScoverage`. + +**Note:** The plugin is not compatible with composite builds. For more information, see [the relevant issue](https://github.com/scoverage/gradle-scoverage/issues/98). ### Configuration From e7fc279a51984448a75a37996f22264676d53f56 Mon Sep 17 00:00:00 2001 From: Jozef Vilcek Date: Fri, 17 Apr 2020 13:11:30 +0200 Subject: [PATCH 100/167] Allow dependency project not to use scoverage --- ...ultiModuleWithPartialScoverageUseTest.java | 20 ++++++++++++ .../a/build.gradle | 0 .../a/src/main/scala/org/hello/a/WorldA.scala | 8 +++++ .../b/build.gradle | 0 .../b/src/main/scala/org/hello/b/WorldB.scala | 8 +++++ .../build.gradle | 32 +++++++++++++++++++ .../settings.gradle | 1 + .../src/main/scala/org/hello/World.scala | 11 +++++++ .../org/scoverage/ScoveragePlugin.groovy | 4 +-- 9 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 src/functionalTest/java/org.scoverage/ScalaMultiModuleWithPartialScoverageUseTest.java create mode 100644 src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/a/build.gradle create mode 100644 src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/a/src/main/scala/org/hello/a/WorldA.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/b/build.gradle create mode 100644 src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/b/src/main/scala/org/hello/b/WorldB.scala create mode 100644 src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/build.gradle create mode 100644 src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/settings.gradle create mode 100644 src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/src/main/scala/org/hello/World.scala diff --git a/src/functionalTest/java/org.scoverage/ScalaMultiModuleWithPartialScoverageUseTest.java b/src/functionalTest/java/org.scoverage/ScalaMultiModuleWithPartialScoverageUseTest.java new file mode 100644 index 0000000..53d469f --- /dev/null +++ b/src/functionalTest/java/org.scoverage/ScalaMultiModuleWithPartialScoverageUseTest.java @@ -0,0 +1,20 @@ +package org.scoverage; + +import org.junit.Test; + +public class ScalaMultiModuleWithPartialScoverageUseTest extends ScoverageFunctionalTest { + + public ScalaMultiModuleWithPartialScoverageUseTest() { + super("scala-multi-module-with-partial-scoverage-use"); + } + + @Test + public void reportScoverage() { + + AssertableBuildResult result = dryRun("clean", ScoveragePlugin.getREPORT_NAME()); + + result.assertTaskExists(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("b:" + ScoveragePlugin.getREPORT_NAME()); + } + +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/a/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/a/build.gradle new file mode 100644 index 0000000..e69de29 diff --git a/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/a/src/main/scala/org/hello/a/WorldA.scala b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/a/src/main/scala/org/hello/a/WorldA.scala new file mode 100644 index 0000000..c07f298 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/a/src/main/scala/org/hello/a/WorldA.scala @@ -0,0 +1,8 @@ +package org.hello.a + +class WorldA { + + def fooA(): String = { + "a" + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/b/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/b/build.gradle new file mode 100644 index 0000000..e69de29 diff --git a/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/b/src/main/scala/org/hello/b/WorldB.scala b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/b/src/main/scala/org/hello/b/WorldB.scala new file mode 100644 index 0000000..83a8f32 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/b/src/main/scala/org/hello/b/WorldB.scala @@ -0,0 +1,8 @@ +package org.hello.b + +class WorldB { + + def fooB(): String = { + "b" + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/build.gradle new file mode 100644 index 0000000..ea5f8aa --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/build.gradle @@ -0,0 +1,32 @@ +plugins { + id 'org.scoverage' apply false +} + +description = 'a multi-module Scala project that builds successfully and has modules which does not use scoverate plugin' + +allprojects { p -> + repositories { + jcenter() + } + + apply plugin: 'java' + apply plugin: 'scala' + + if (p.name != 'a') { + apply plugin: 'org.scoverage' + } + + dependencies { + + compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + + testCompile group: 'org.junit.platform', name: 'junit-platform-runner' + + testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}" + } +} + +dependencies { + compile project(':a') + compile project(':b') +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/settings.gradle b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/settings.gradle new file mode 100644 index 0000000..dd79722 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/settings.gradle @@ -0,0 +1 @@ +include 'a', 'b' \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/src/main/scala/org/hello/World.scala b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/src/main/scala/org/hello/World.scala new file mode 100644 index 0000000..bf64f3e --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/src/main/scala/org/hello/World.scala @@ -0,0 +1,11 @@ +package org.hello + +import org.hello.a.WorldA +import org.hello.a.WorldB + +class World { + + def foo(): String = { + WorldA.foo() + WorldB.foo() + } +} \ No newline at end of file diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index a6f46a9..d1e47ca 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -161,8 +161,8 @@ class ScoveragePlugin implements Plugin { it instanceof ScalaCompile } originalCompilationDependencies.each { - def dependencyProjectCompileTask = it.project.tasks[COMPILE_NAME] - def dependencyProjectReportTask = it.project.tasks[REPORT_NAME] + def dependencyProjectCompileTask = it.project.tasks.findByName(COMPILE_NAME) + def dependencyProjectReportTask = it.project.tasks.findByName(REPORT_NAME) if (dependencyProjectCompileTask != null) { compileTask.dependsOn(dependencyProjectCompileTask) // we don't want this project's tests to affect the other project's report From 3dc9d5bcae6b9113fe83f9d52fdc46b6690fc1b5 Mon Sep 17 00:00:00 2001 From: cristian-garcia Date: Thu, 28 May 2020 17:12:46 +0200 Subject: [PATCH 101/167] Fix: ScoverageReport task inputs declaration --- src/main/groovy/org/scoverage/ScoverageReport.groovy | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/groovy/org/scoverage/ScoverageReport.groovy b/src/main/groovy/org/scoverage/ScoverageReport.groovy index ca8ceb2..e95f547 100644 --- a/src/main/groovy/org/scoverage/ScoverageReport.groovy +++ b/src/main/groovy/org/scoverage/ScoverageReport.groovy @@ -4,21 +4,27 @@ import org.gradle.api.DefaultTask import org.gradle.api.provider.Property import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputDirectory import org.gradle.api.tasks.Nested import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.PathSensitive import org.gradle.api.tasks.TaskAction import scoverage.report.CoverageAggregator +import static org.gradle.api.tasks.PathSensitivity.RELATIVE + @CacheableTask class ScoverageReport extends DefaultTask { @Nested ScoverageRunner runner - @Input + @InputDirectory + @PathSensitive(RELATIVE) final Property dataDir = project.objects.property(File) - @Input + @InputDirectory + @PathSensitive(RELATIVE) final Property sources = project.objects.property(File) @OutputDirectory From 154abb1d978de7748946c5b66d57ae72af51fa7e Mon Sep 17 00:00:00 2001 From: Stu Date: Tue, 9 Jun 2020 21:58:20 +0100 Subject: [PATCH 102/167] upgrade publish plugin --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index bafe5e9..745d7dd 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java-gradle-plugin' - id "com.gradle.plugin-publish" version "0.10.0" + id "com.gradle.plugin-publish" version "0.12.0" id "org.jetbrains.gradle.plugin.idea-ext" version "0.4.2" } From cfb3963dea27ad26065c34f6433a0b860d19d1b0 Mon Sep 17 00:00:00 2001 From: Stu Date: Tue, 9 Jun 2020 22:14:00 +0100 Subject: [PATCH 103/167] bump to gradle 6.4.1 --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9492014..a4f0001 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.4.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 0c08012c28d7aa228f510364a8329a273b8630e2 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Fri, 19 Jun 2020 19:38:14 +0300 Subject: [PATCH 104/167] #140 Add functional test for compatibility with 'palantir/gradle-consistent-versions' plugin (test currently fails) --- .../org.scoverage/DetectScalaLibraryTest.java | 28 ++++++++++++++++--- .../gradle-consistent-versions/build.gradle | 14 ++++++++++ .../settings.gradle | 0 .../gradle-consistent-versions/versions.lock | 2 ++ .../gradle-consistent-versions/versions.props | 1 + .../org/scoverage/ScoveragePlugin.groovy | 9 +++--- 6 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/build.gradle create mode 100644 src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/settings.gradle create mode 100644 src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/versions.lock create mode 100644 src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/versions.props diff --git a/src/functionalTest/java/org.scoverage/DetectScalaLibraryTest.java b/src/functionalTest/java/org.scoverage/DetectScalaLibraryTest.java index 9b2d163..dd9cf8a 100644 --- a/src/functionalTest/java/org.scoverage/DetectScalaLibraryTest.java +++ b/src/functionalTest/java/org.scoverage/DetectScalaLibraryTest.java @@ -7,6 +7,8 @@ import java.util.Arrays; import java.util.Collection; +import java.util.List; +import java.util.stream.Stream; @RunWith(Parameterized.class) public class DetectScalaLibraryTest extends ScoverageFunctionalTest { @@ -20,9 +22,21 @@ public class DetectScalaLibraryTest extends ScoverageFunctionalTest { @Parameterized.Parameter(0) public String projectDir; + @Parameterized.Parameter(1) + public String[] subVersions; + + @Parameterized.Parameter(2) + public String[] additionalParameters; + @Parameterized.Parameters(name = "{index}: Project {0} ") public static Collection data() { - Object[][] data = new Object[][]{{"/compile"}, {"/compileOnly"}, {"/implementation"}, {"/dependency-management"}}; + Object[][] data = new Object[][]{ + {"/compile", new String[] {".0", ".+"}, new String[0]}, + {"/compileOnly", new String[] {".0", ".+"}, new String[0]}, + {"/implementation", new String[] {".0", ".+"}, new String[0]}, + {"/dependency-management", new String[] {".0", ".+"}, new String[0]}, + {"/gradle-consistent-versions", new String[] {"ignored"}, new String[] {"--write-locks"}}, + }; return Arrays.asList(data); } @@ -33,12 +47,18 @@ public DetectScalaLibraryTest() { @Test public void test() { setProjectName("detect-scala-library" + projectDir); - testWithParameter(SCALA_LIBRARY_PARAMETER + SCALA_VERSION + ".0"); - testWithParameter(SCALA_LIBRARY_PARAMETER + SCALA_VERSION + ".+"); + for (String subVersion : subVersions) { + testWithParameter(SCALA_LIBRARY_PARAMETER + SCALA_VERSION + subVersion); + } } private void testWithParameter(String parameter) { - AssertableBuildResult result = dryRun("clean", parameter, "--info"); + + String[] basicParameters = {"clean", parameter, "--info"}; + String[] parameters = Stream.concat(Arrays.stream(basicParameters), Arrays.stream(additionalParameters)) + .toArray(String[]::new); + AssertableBuildResult result = dryRun(parameters); + String output = result.getResult().getOutput(); Assert.assertTrue(output.contains(EXPECTED_OUTPUT_A)); Assert.assertTrue(output.contains(EXPECTED_OUTPUT_B)); diff --git a/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/build.gradle b/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/build.gradle new file mode 100644 index 0000000..b59158b --- /dev/null +++ b/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/build.gradle @@ -0,0 +1,14 @@ +plugins { + id "com.palantir.consistent-versions" version "1.16.0" + id 'org.scoverage' +} + +repositories { + jcenter() +} + +description = 'defines scala library using the "implementation" configuration and the gradle-consistent-versions plugin' + +dependencies { + implementation group: 'org.scala-lang', name: 'scala-library' +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/settings.gradle b/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/settings.gradle new file mode 100644 index 0000000..e69de29 diff --git a/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/versions.lock b/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/versions.lock new file mode 100644 index 0000000..97decdb --- /dev/null +++ b/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/versions.lock @@ -0,0 +1,2 @@ +# Run ./gradlew --write-locks to regenerate this file +org.scala-lang:scala-library:2.12.0 (1 constraints: 3705353b) diff --git a/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/versions.props b/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/versions.props new file mode 100644 index 0000000..4da792e --- /dev/null +++ b/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/versions.props @@ -0,0 +1 @@ +org.scala-lang:scala-library = 2.12.0 \ No newline at end of file diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index d1e47ca..0bcb565 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -1,7 +1,6 @@ package org.scoverage import org.apache.commons.io.FileUtils -import org.gradle.api.GradleException import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.Task @@ -343,10 +342,10 @@ class ScoveragePlugin implements Plugin { private String resolveScalaVersion(Project project) { - def resolvedDependencies = project.configurations.compileClasspath.resolvedConfiguration.firstLevelModuleDependencies + def components = project.configurations.compileClasspath.incoming.resolutionResult.getAllComponents() - def scalaLibrary = resolvedDependencies.find { - it.moduleGroup == "org.scala-lang" && it.moduleName == "scala-library" + def scalaLibrary = components.find { + it.moduleVersion.group == "org.scala-lang" && it.moduleVersion.name == "scala-library" } if (scalaLibrary == null) { @@ -354,7 +353,7 @@ class ScoveragePlugin implements Plugin { return project.extensions.scoverage.scoverageScalaVersion.get() } else { project.logger.info("Detected scala library in compilation classpath") - def fullScalaVersion = scalaLibrary.moduleVersion + def fullScalaVersion = scalaLibrary.moduleVersion.version return fullScalaVersion.substring(0, fullScalaVersion.lastIndexOf(".")) } } From 2df5448d3dd268bed7c8158d9dd623ebca2f5787 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Sat, 20 Jun 2020 18:48:16 +0300 Subject: [PATCH 105/167] Fix location of the functional tests ('org.scoverage' -> 'org/scoverage') and separate the cross-version tests to a separate source set --- build.gradle | 36 +++++++++++++------ .../java/org/scoverage}/Scala211Test.java | 2 +- .../java/org/scoverage}/Scala212Test.java | 2 +- .../java/org/scoverage}/Scala213Test.java | 2 +- .../ScalaCrossVersionAggregationTest.java | 2 +- .../java/org/scoverage}/ScalaVersionTest.java | 2 +- .../2_11/build.gradle | 0 .../src/main/scala/org/hello/World2_11.scala | 0 .../test/scala/org/hello/World2_11Suite.scala | 0 .../2_12/build.gradle | 0 .../src/main/scala/org/hello/World2_12.scala | 0 .../test/scala/org/hello/World2_12Suite.scala | 0 .../2_13/build.gradle | 0 .../src/main/scala/org/hello/World2_13.scala | 0 .../test/scala/org/hello/World2_13Suite.scala | 0 .../build.gradle | 0 .../settings.gradle | 0 .../scoverage}/CompositeBuildTest.java | 0 .../scoverage}/DetectScalaLibraryTest.java | 0 ...ModulePluginNotConfiguredForScalaTest.java | 0 .../scoverage}/MultipleCheckTasksTest.java | 0 .../scoverage}/ScalaJavaMultiModuleTest.java | 0 .../scoverage}/ScalaMultiModuleTest.java | 0 ...aMultiModuleWithMultipleTestTasksTest.java | 0 ...ultiModuleWithPartialScoverageUseTest.java | 0 .../scoverage}/ScalaSingleModuleTest.java | 0 ...SingleModuleWithDependencyManagerTest.java | 0 ...SingleModuleWithMultipleTestTasksTest.java | 0 .../scoverage}/ScoverageFunctionalTest.java | 2 +- 29 files changed, 31 insertions(+), 17 deletions(-) rename src/{functionalTest/java/org/scoverage/crossversion => crossScalaVersionTest/java/org/scoverage}/Scala211Test.java (75%) rename src/{functionalTest/java/org/scoverage/crossversion => crossScalaVersionTest/java/org/scoverage}/Scala212Test.java (75%) rename src/{functionalTest/java/org/scoverage/crossversion => crossScalaVersionTest/java/org/scoverage}/Scala213Test.java (75%) rename src/{functionalTest/java/org/scoverage/crossversion => crossScalaVersionTest/java/org/scoverage}/ScalaCrossVersionAggregationTest.java (98%) rename src/{functionalTest/java/org/scoverage/crossversion => crossScalaVersionTest/java/org/scoverage}/ScalaVersionTest.java (97%) rename src/{functionalTest => crossScalaVersionTest}/resources/projects/scala-multi-module-cross-version/2_11/build.gradle (100%) rename src/{functionalTest => crossScalaVersionTest}/resources/projects/scala-multi-module-cross-version/2_11/src/main/scala/org/hello/World2_11.scala (100%) rename src/{functionalTest => crossScalaVersionTest}/resources/projects/scala-multi-module-cross-version/2_11/src/test/scala/org/hello/World2_11Suite.scala (100%) rename src/{functionalTest => crossScalaVersionTest}/resources/projects/scala-multi-module-cross-version/2_12/build.gradle (100%) rename src/{functionalTest => crossScalaVersionTest}/resources/projects/scala-multi-module-cross-version/2_12/src/main/scala/org/hello/World2_12.scala (100%) rename src/{functionalTest => crossScalaVersionTest}/resources/projects/scala-multi-module-cross-version/2_12/src/test/scala/org/hello/World2_12Suite.scala (100%) rename src/{functionalTest => crossScalaVersionTest}/resources/projects/scala-multi-module-cross-version/2_13/build.gradle (100%) rename src/{functionalTest => crossScalaVersionTest}/resources/projects/scala-multi-module-cross-version/2_13/src/main/scala/org/hello/World2_13.scala (100%) rename src/{functionalTest => crossScalaVersionTest}/resources/projects/scala-multi-module-cross-version/2_13/src/test/scala/org/hello/World2_13Suite.scala (100%) rename src/{functionalTest => crossScalaVersionTest}/resources/projects/scala-multi-module-cross-version/build.gradle (100%) rename src/{functionalTest => crossScalaVersionTest}/resources/projects/scala-multi-module-cross-version/settings.gradle (100%) rename src/functionalTest/java/{org.scoverage => org/scoverage}/CompositeBuildTest.java (100%) rename src/functionalTest/java/{org.scoverage => org/scoverage}/DetectScalaLibraryTest.java (100%) rename src/functionalTest/java/{org.scoverage => org/scoverage}/MultiModulePluginNotConfiguredForScalaTest.java (100%) rename src/functionalTest/java/{org.scoverage => org/scoverage}/MultipleCheckTasksTest.java (100%) rename src/functionalTest/java/{org.scoverage => org/scoverage}/ScalaJavaMultiModuleTest.java (100%) rename src/functionalTest/java/{org.scoverage => org/scoverage}/ScalaMultiModuleTest.java (100%) rename src/functionalTest/java/{org.scoverage => org/scoverage}/ScalaMultiModuleWithMultipleTestTasksTest.java (100%) rename src/functionalTest/java/{org.scoverage => org/scoverage}/ScalaMultiModuleWithPartialScoverageUseTest.java (100%) rename src/functionalTest/java/{org.scoverage => org/scoverage}/ScalaSingleModuleTest.java (100%) rename src/functionalTest/java/{org.scoverage => org/scoverage}/ScalaSingleModuleWithDependencyManagerTest.java (100%) rename src/functionalTest/java/{org.scoverage => org/scoverage}/ScalaSingleModuleWithMultipleTestTasksTest.java (100%) rename src/functionalTest/java/{org.scoverage => org/scoverage}/ScoverageFunctionalTest.java (98%) diff --git a/build.gradle b/build.gradle index 03d4b54..268de3e 100644 --- a/build.gradle +++ b/build.gradle @@ -44,6 +44,7 @@ apply plugin: 'groovy' sourceCompatibility = '1.8' targetCompatibility = '1.8' + dependencies { compileOnly "org.scoverage:scalac-scoverage-plugin_2.12:1.4.1" implementation group: 'commons-io', name: 'commons-io', version: '2.6' @@ -58,38 +59,51 @@ dependencies { sourceSets { functionalTest { java.srcDir file('src/functionalTest/java') - resources.srcDir file('src/functionalTest/resources') - compileClasspath += sourceSets.main.output + configurations.testRuntimeClasspath - runtimeClasspath += output + compileClasspath + compileClasspath += sourceSets.main.output + runtimeClasspath += sourceSets.main.output + } + crossScalaVersionTest { + java.srcDir file('src/crossScalaVersionTest/java') + compileClasspath += sourceSets.main.output + sourceSets.functionalTest.output + runtimeClasspath += sourceSets.main.output + sourceSets.functionalTest.output } } -task crossScalaVersionFunctionalTest(type: Test) { +configurations { + functionalTestImplementation.extendsFrom testImplementation + functionalTestRuntimeOnly.extendsFrom testRuntimeOnly + + crossScalaVersionTestImplementation.extendsFrom testImplementation + crossScalaVersionTestRuntimeOnly.extendsFrom testRuntimeOnly +} + +task crossScalaVersionTest(type: Test) { description = 'Runs the cross scala version functional test.' group = 'verification' - testClassesDirs = sourceSets.functionalTest.output.classesDirs - classpath = sourceSets.functionalTest.runtimeClasspath - include '**/crossversion/*' + testClassesDirs = sourceSets.crossScalaVersionTest.output + classpath = sourceSets.crossScalaVersionTest.runtimeClasspath forkEvery = 1 // crucial to run every test in its own JVM testLogging.showStandardStreams = true mustRunAfter test } +check.dependsOn crossScalaVersionTest task functionalTest(type: Test) { description = 'Runs the functional tests.' group = 'verification' - testClassesDirs = sourceSets.functionalTest.output.classesDirs + testClassesDirs = sourceSets.functionalTest.output classpath = sourceSets.functionalTest.runtimeClasspath - exclude '**/crossversion/*' - dependsOn crossScalaVersionFunctionalTest + testLogging.showStandardStreams = true + + mustRunAfter crossScalaVersionTest } check.dependsOn functionalTest gradlePlugin { - testSourceSets sourceSets.functionalTest + testSourceSets sourceSets.functionalTest, sourceSets.crossScalaVersionTest } task groovydocJar(type: Jar, dependsOn: groovydoc) { diff --git a/src/functionalTest/java/org/scoverage/crossversion/Scala211Test.java b/src/crossScalaVersionTest/java/org/scoverage/Scala211Test.java similarity index 75% rename from src/functionalTest/java/org/scoverage/crossversion/Scala211Test.java rename to src/crossScalaVersionTest/java/org/scoverage/Scala211Test.java index e8dfcaa..ac06067 100644 --- a/src/functionalTest/java/org/scoverage/crossversion/Scala211Test.java +++ b/src/crossScalaVersionTest/java/org/scoverage/Scala211Test.java @@ -1,4 +1,4 @@ -package org.scoverage.crossversion; +package org.scoverage; public class Scala211Test extends ScalaVersionTest { public Scala211Test() { diff --git a/src/functionalTest/java/org/scoverage/crossversion/Scala212Test.java b/src/crossScalaVersionTest/java/org/scoverage/Scala212Test.java similarity index 75% rename from src/functionalTest/java/org/scoverage/crossversion/Scala212Test.java rename to src/crossScalaVersionTest/java/org/scoverage/Scala212Test.java index ee34a21..2c538ae 100644 --- a/src/functionalTest/java/org/scoverage/crossversion/Scala212Test.java +++ b/src/crossScalaVersionTest/java/org/scoverage/Scala212Test.java @@ -1,4 +1,4 @@ -package org.scoverage.crossversion; +package org.scoverage; public class Scala212Test extends ScalaVersionTest { public Scala212Test() { diff --git a/src/functionalTest/java/org/scoverage/crossversion/Scala213Test.java b/src/crossScalaVersionTest/java/org/scoverage/Scala213Test.java similarity index 75% rename from src/functionalTest/java/org/scoverage/crossversion/Scala213Test.java rename to src/crossScalaVersionTest/java/org/scoverage/Scala213Test.java index f6a6043..31d9a38 100644 --- a/src/functionalTest/java/org/scoverage/crossversion/Scala213Test.java +++ b/src/crossScalaVersionTest/java/org/scoverage/Scala213Test.java @@ -1,4 +1,4 @@ -package org.scoverage.crossversion; +package org.scoverage; public class Scala213Test extends ScalaVersionTest { public Scala213Test() { diff --git a/src/functionalTest/java/org/scoverage/crossversion/ScalaCrossVersionAggregationTest.java b/src/crossScalaVersionTest/java/org/scoverage/ScalaCrossVersionAggregationTest.java similarity index 98% rename from src/functionalTest/java/org/scoverage/crossversion/ScalaCrossVersionAggregationTest.java rename to src/crossScalaVersionTest/java/org/scoverage/ScalaCrossVersionAggregationTest.java index a086188..d3b66ae 100644 --- a/src/functionalTest/java/org/scoverage/crossversion/ScalaCrossVersionAggregationTest.java +++ b/src/crossScalaVersionTest/java/org/scoverage/ScalaCrossVersionAggregationTest.java @@ -1,4 +1,4 @@ -package org.scoverage.crossversion; +package org.scoverage; import org.junit.Assert; import org.junit.Test; diff --git a/src/functionalTest/java/org/scoverage/crossversion/ScalaVersionTest.java b/src/crossScalaVersionTest/java/org/scoverage/ScalaVersionTest.java similarity index 97% rename from src/functionalTest/java/org/scoverage/crossversion/ScalaVersionTest.java rename to src/crossScalaVersionTest/java/org/scoverage/ScalaVersionTest.java index e5ac15f..59160f3 100644 --- a/src/functionalTest/java/org/scoverage/crossversion/ScalaVersionTest.java +++ b/src/crossScalaVersionTest/java/org/scoverage/ScalaVersionTest.java @@ -1,4 +1,4 @@ -package org.scoverage.crossversion; +package org.scoverage; import org.junit.Assert; import org.junit.Test; diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/build.gradle b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_11/build.gradle similarity index 100% rename from src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/build.gradle rename to src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_11/build.gradle diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/main/scala/org/hello/World2_11.scala b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_11/src/main/scala/org/hello/World2_11.scala similarity index 100% rename from src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/main/scala/org/hello/World2_11.scala rename to src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_11/src/main/scala/org/hello/World2_11.scala diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/test/scala/org/hello/World2_11Suite.scala b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_11/src/test/scala/org/hello/World2_11Suite.scala similarity index 100% rename from src/functionalTest/resources/projects/scala-multi-module-cross-version/2_11/src/test/scala/org/hello/World2_11Suite.scala rename to src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_11/src/test/scala/org/hello/World2_11Suite.scala diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/build.gradle b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_12/build.gradle similarity index 100% rename from src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/build.gradle rename to src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_12/build.gradle diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/src/main/scala/org/hello/World2_12.scala b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_12/src/main/scala/org/hello/World2_12.scala similarity index 100% rename from src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/src/main/scala/org/hello/World2_12.scala rename to src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_12/src/main/scala/org/hello/World2_12.scala diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/src/test/scala/org/hello/World2_12Suite.scala b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_12/src/test/scala/org/hello/World2_12Suite.scala similarity index 100% rename from src/functionalTest/resources/projects/scala-multi-module-cross-version/2_12/src/test/scala/org/hello/World2_12Suite.scala rename to src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_12/src/test/scala/org/hello/World2_12Suite.scala diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/build.gradle b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_13/build.gradle similarity index 100% rename from src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/build.gradle rename to src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_13/build.gradle diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/src/main/scala/org/hello/World2_13.scala b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_13/src/main/scala/org/hello/World2_13.scala similarity index 100% rename from src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/src/main/scala/org/hello/World2_13.scala rename to src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_13/src/main/scala/org/hello/World2_13.scala diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/src/test/scala/org/hello/World2_13Suite.scala b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_13/src/test/scala/org/hello/World2_13Suite.scala similarity index 100% rename from src/functionalTest/resources/projects/scala-multi-module-cross-version/2_13/src/test/scala/org/hello/World2_13Suite.scala rename to src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_13/src/test/scala/org/hello/World2_13Suite.scala diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/build.gradle b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/build.gradle similarity index 100% rename from src/functionalTest/resources/projects/scala-multi-module-cross-version/build.gradle rename to src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/build.gradle diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/settings.gradle b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/settings.gradle similarity index 100% rename from src/functionalTest/resources/projects/scala-multi-module-cross-version/settings.gradle rename to src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/settings.gradle diff --git a/src/functionalTest/java/org.scoverage/CompositeBuildTest.java b/src/functionalTest/java/org/scoverage/CompositeBuildTest.java similarity index 100% rename from src/functionalTest/java/org.scoverage/CompositeBuildTest.java rename to src/functionalTest/java/org/scoverage/CompositeBuildTest.java diff --git a/src/functionalTest/java/org.scoverage/DetectScalaLibraryTest.java b/src/functionalTest/java/org/scoverage/DetectScalaLibraryTest.java similarity index 100% rename from src/functionalTest/java/org.scoverage/DetectScalaLibraryTest.java rename to src/functionalTest/java/org/scoverage/DetectScalaLibraryTest.java diff --git a/src/functionalTest/java/org.scoverage/MultiModulePluginNotConfiguredForScalaTest.java b/src/functionalTest/java/org/scoverage/MultiModulePluginNotConfiguredForScalaTest.java similarity index 100% rename from src/functionalTest/java/org.scoverage/MultiModulePluginNotConfiguredForScalaTest.java rename to src/functionalTest/java/org/scoverage/MultiModulePluginNotConfiguredForScalaTest.java diff --git a/src/functionalTest/java/org.scoverage/MultipleCheckTasksTest.java b/src/functionalTest/java/org/scoverage/MultipleCheckTasksTest.java similarity index 100% rename from src/functionalTest/java/org.scoverage/MultipleCheckTasksTest.java rename to src/functionalTest/java/org/scoverage/MultipleCheckTasksTest.java diff --git a/src/functionalTest/java/org.scoverage/ScalaJavaMultiModuleTest.java b/src/functionalTest/java/org/scoverage/ScalaJavaMultiModuleTest.java similarity index 100% rename from src/functionalTest/java/org.scoverage/ScalaJavaMultiModuleTest.java rename to src/functionalTest/java/org/scoverage/ScalaJavaMultiModuleTest.java diff --git a/src/functionalTest/java/org.scoverage/ScalaMultiModuleTest.java b/src/functionalTest/java/org/scoverage/ScalaMultiModuleTest.java similarity index 100% rename from src/functionalTest/java/org.scoverage/ScalaMultiModuleTest.java rename to src/functionalTest/java/org/scoverage/ScalaMultiModuleTest.java diff --git a/src/functionalTest/java/org.scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java b/src/functionalTest/java/org/scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java similarity index 100% rename from src/functionalTest/java/org.scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java rename to src/functionalTest/java/org/scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java diff --git a/src/functionalTest/java/org.scoverage/ScalaMultiModuleWithPartialScoverageUseTest.java b/src/functionalTest/java/org/scoverage/ScalaMultiModuleWithPartialScoverageUseTest.java similarity index 100% rename from src/functionalTest/java/org.scoverage/ScalaMultiModuleWithPartialScoverageUseTest.java rename to src/functionalTest/java/org/scoverage/ScalaMultiModuleWithPartialScoverageUseTest.java diff --git a/src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java b/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java similarity index 100% rename from src/functionalTest/java/org.scoverage/ScalaSingleModuleTest.java rename to src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java diff --git a/src/functionalTest/java/org.scoverage/ScalaSingleModuleWithDependencyManagerTest.java b/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithDependencyManagerTest.java similarity index 100% rename from src/functionalTest/java/org.scoverage/ScalaSingleModuleWithDependencyManagerTest.java rename to src/functionalTest/java/org/scoverage/ScalaSingleModuleWithDependencyManagerTest.java diff --git a/src/functionalTest/java/org.scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java b/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java similarity index 100% rename from src/functionalTest/java/org.scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java rename to src/functionalTest/java/org/scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java diff --git a/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java b/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java similarity index 98% rename from src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java rename to src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java index 0341cc2..c1bd0b1 100644 --- a/src/functionalTest/java/org.scoverage/ScoverageFunctionalTest.java +++ b/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java @@ -50,7 +50,7 @@ protected void setProjectName(String projectName) { protected File projectDir() { - return new File("src/functionalTest/resources/projects/" + projectName); + return new File(getClass().getClassLoader().getResource("projects/" + projectName).getFile()); } protected File buildDir() { From 69bb994e28f4959c46618f211b4ac980595f43d9 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Sat, 20 Jun 2020 18:57:42 +0300 Subject: [PATCH 106/167] Ignore the functional test for Scala 2.13 until it is supported (#106) --- .../java/org/scoverage/Scala213Test.java | 8 ++++++++ .../java/org/scoverage/CompositeBuildTest.java | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/crossScalaVersionTest/java/org/scoverage/Scala213Test.java b/src/crossScalaVersionTest/java/org/scoverage/Scala213Test.java index 31d9a38..0f6ed71 100644 --- a/src/crossScalaVersionTest/java/org/scoverage/Scala213Test.java +++ b/src/crossScalaVersionTest/java/org/scoverage/Scala213Test.java @@ -1,5 +1,13 @@ package org.scoverage; +import org.junit.Ignore; + +/** + * Tests is currently ignored as support for Scala 2.13 is not available yet. + * + * @see Issue #106. + */ +@Ignore public class Scala213Test extends ScalaVersionTest { public Scala213Test() { super("2_13"); diff --git a/src/functionalTest/java/org/scoverage/CompositeBuildTest.java b/src/functionalTest/java/org/scoverage/CompositeBuildTest.java index 86dd695..98a9ee8 100644 --- a/src/functionalTest/java/org/scoverage/CompositeBuildTest.java +++ b/src/functionalTest/java/org/scoverage/CompositeBuildTest.java @@ -10,7 +10,7 @@ /** * Tests are currently ignored as composite builds are not supported yet. * - * See https://github.com/scoverage/gradle-scoverage/issues/98 + * @see Issue #94. */ public class CompositeBuildTest extends ScoverageFunctionalTest { From 57a036aeee6b0df8fb158fae272fec3b79c715f3 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Sun, 16 Aug 2020 18:25:22 +0300 Subject: [PATCH 107/167] #140 Resolve scalac plugin file at execution time instead of configuration time --- .../org/scoverage/ScoveragePlugin.groovy | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 0bcb565..d0c589c 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -27,7 +27,6 @@ class ScoveragePlugin implements Plugin { static final String DEFAULT_REPORT_DIR = 'reports' + File.separatorChar + 'scoverage' - private volatile File pluginFile = null private final ConcurrentHashMap> taskDependencies = new ConcurrentHashMap<>(); @Override @@ -172,13 +171,7 @@ class ScoveragePlugin implements Plugin { } compileTask.configure { - if (pluginFile == null) { - pluginFile = project.configurations[CONFIGURATION_NAME].find { - it.name.startsWith("scalac-scoverage-plugin") - } - } - - List parameters = ['-Xplugin:' + pluginFile.absolutePath] + List parameters = [] List existingParameters = scalaCompileOptions.additionalParameters if (existingParameters) { parameters.addAll(existingParameters) @@ -198,6 +191,18 @@ class ScoveragePlugin implements Plugin { scalaCompileOptions.additionalParameters = parameters // the compile task creates a store of measured statements outputs.file(new File(extension.dataDir.get(), 'scoverage.coverage.xml')) + + dependsOn project.configurations[CONFIGURATION_NAME] + doFirst { + /* + It is crucial that this would run in `doFirst`, as this resolves the (dependencies of the) + configuration, which we do not want to do at configuration time (but only at execution time). + */ + def pluginFile = project.configurations[CONFIGURATION_NAME].find { + it.name.startsWith("scalac-scoverage-plugin") + } + scalaCompileOptions.additionalParameters.add('-Xplugin:' + pluginFile.absolutePath) + } } project.gradle.taskGraph.whenReady { graph -> From cc9bdaab7fa8191889c373308891d54c6bf31254 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Sun, 16 Aug 2020 18:58:07 +0300 Subject: [PATCH 108/167] #140 Only attempt to detect Scala version if it isn't already configured by the `scoverageScalaVersion` option --- README.md | 11 +++++-- .../org/scoverage/DetectScalaLibraryTest.java | 30 ++++++++++------- .../gradle-consistent-versions/build.gradle | 5 +++ .../org/scoverage/ScoverageExtension.groovy | 1 - .../org/scoverage/ScoveragePlugin.groovy | 32 ++++++++++++------- 5 files changed, 53 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 4e09b2c..98f0543 100644 --- a/README.md +++ b/README.md @@ -46,8 +46,8 @@ build script. These options are as follows: * `scoverageVersion = ` (default `"1.4.1"`): The version of the scoverage scalac plugin. This (gradle) plugin should be compatible with all 1+ versions. -* `scoverageScalaVersion = ` (default `"2.12"`): The scala version of the scoverage scalac plugin. This will -be overridden by the version of the `scala-library` compile dependency (if the dependency is configured). +* `scoverageScalaVersion = ` (default `"2.12"`): The scala version of the scoverage scalac plugin. This +overrides the version of the `scala-library` compile dependency (if the dependency is configured). * `coverageOutputCobertura = ` (default `true`): Enables/disables cobertura.xml file generation (for both aggregated and non-aggregated reports). @@ -115,6 +115,13 @@ it is possible to only compile the code with the scoverage scalac plugin, thus r In order to do so, simply add the arguments `-x compileScala` to the gradle execution. For example: `gradle reportScoverage -x compileScala`. + +### Compatibility with Consistent Versions Plugin + +In order for the plugin to work alongside [Palantir's consistent versions plugin](https://github.com/palantir/gradle-consistent-versions), +the Scala version must be manually configured (via `scoverageScalaVersion`); otherwise, the plugin will attempt to +resolve the compilation classpath, which is prohibited by the versions plugin. + Migration to 4.x ---------------- diff --git a/src/functionalTest/java/org/scoverage/DetectScalaLibraryTest.java b/src/functionalTest/java/org/scoverage/DetectScalaLibraryTest.java index dd9cf8a..bcda654 100644 --- a/src/functionalTest/java/org/scoverage/DetectScalaLibraryTest.java +++ b/src/functionalTest/java/org/scoverage/DetectScalaLibraryTest.java @@ -16,8 +16,9 @@ public class DetectScalaLibraryTest extends ScoverageFunctionalTest { private static final String SCALA_VERSION = "2.12"; private static final String SCALA_LIBRARY_PARAMETER = "-PdetectedScalaLibraryVersion="; - private static final String EXPECTED_OUTPUT_A = "Detected scala library in compilation classpath"; - private static final String EXPECTED_OUTPUT_B = "Using scoverage scalac plugin version '" + SCALA_VERSION; + private static final String EXPECTED_OUTPUT_CONFIGURED_VERSION = "Using configured Scala version"; + private static final String EXPECTED_OUTPUT_DETECTED_VERSION = "Detected scala library in compilation classpath"; + private static final String EXPECTED_OUTPUT_USING = "Using scoverage scalac plugin version '" + SCALA_VERSION; @Parameterized.Parameter(0) public String projectDir; @@ -26,16 +27,19 @@ public class DetectScalaLibraryTest extends ScoverageFunctionalTest { public String[] subVersions; @Parameterized.Parameter(2) + public boolean detect; + + @Parameterized.Parameter(3) public String[] additionalParameters; @Parameterized.Parameters(name = "{index}: Project {0} ") public static Collection data() { Object[][] data = new Object[][]{ - {"/compile", new String[] {".0", ".+"}, new String[0]}, - {"/compileOnly", new String[] {".0", ".+"}, new String[0]}, - {"/implementation", new String[] {".0", ".+"}, new String[0]}, - {"/dependency-management", new String[] {".0", ".+"}, new String[0]}, - {"/gradle-consistent-versions", new String[] {"ignored"}, new String[] {"--write-locks"}}, + {"/compile", new String[] {".0", ".+"}, true, new String[0]}, + {"/compileOnly", new String[] {".0", ".+"}, true, new String[0]}, + {"/implementation", new String[] {".0", ".+"}, true, new String[0]}, + {"/dependency-management", new String[] {".0", ".+"}, true, new String[0]}, + {"/gradle-consistent-versions", new String[] {"ignored"}, false, new String[] {"--write-locks"}}, }; return Arrays.asList(data); } @@ -48,11 +52,11 @@ public DetectScalaLibraryTest() { public void test() { setProjectName("detect-scala-library" + projectDir); for (String subVersion : subVersions) { - testWithParameter(SCALA_LIBRARY_PARAMETER + SCALA_VERSION + subVersion); + testWithParameter(SCALA_LIBRARY_PARAMETER + SCALA_VERSION + subVersion, detect); } } - private void testWithParameter(String parameter) { + private void testWithParameter(String parameter, Boolean detect) { String[] basicParameters = {"clean", parameter, "--info"}; String[] parameters = Stream.concat(Arrays.stream(basicParameters), Arrays.stream(additionalParameters)) @@ -60,8 +64,12 @@ private void testWithParameter(String parameter) { AssertableBuildResult result = dryRun(parameters); String output = result.getResult().getOutput(); - Assert.assertTrue(output.contains(EXPECTED_OUTPUT_A)); - Assert.assertTrue(output.contains(EXPECTED_OUTPUT_B)); + if (detect) { + Assert.assertTrue(output.contains(EXPECTED_OUTPUT_DETECTED_VERSION)); + } else { + Assert.assertTrue(output.contains(EXPECTED_OUTPUT_CONFIGURED_VERSION)); + } + Assert.assertTrue(output.contains(EXPECTED_OUTPUT_USING)); } } \ No newline at end of file diff --git a/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/build.gradle b/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/build.gradle index b59158b..030a1c1 100644 --- a/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/build.gradle +++ b/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/build.gradle @@ -11,4 +11,9 @@ description = 'defines scala library using the "implementation" configuration an dependencies { implementation group: 'org.scala-lang', name: 'scala-library' +} + +scoverage { + // 'detectedScalaLibraryVersion' is set by the test `DetectScalaLibraryTest.java` + scoverageScalaVersion = detectedScalaLibraryVersion } \ No newline at end of file diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index a65b8aa..9de93c5 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -60,7 +60,6 @@ class ScoverageExtension { scoverageVersion.set('1.4.1') scoverageScalaVersion = project.objects.property(String) - scoverageScalaVersion.set('2.12') sources = project.objects.property(File) sources.set(project.projectDir) diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index d0c589c..ab5f4d2 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -24,6 +24,7 @@ class ScoveragePlugin implements Plugin { static final String CHECK_NAME = 'checkScoverage' static final String COMPILE_NAME = 'compileScoverageScala' static final String AGGREGATE_NAME = 'aggregateScoverage' + static final String DEFAULT_SCALA_VERSION = '2.12' static final String DEFAULT_REPORT_DIR = 'reports' + File.separatorChar + 'scoverage' @@ -347,19 +348,26 @@ class ScoveragePlugin implements Plugin { private String resolveScalaVersion(Project project) { - def components = project.configurations.compileClasspath.incoming.resolutionResult.getAllComponents() - - def scalaLibrary = components.find { - it.moduleVersion.group == "org.scala-lang" && it.moduleVersion.name == "scala-library" - } - - if (scalaLibrary == null) { - project.logger.info("No scala library detected. Using property 'scoverageScalaVersion'") - return project.extensions.scoverage.scoverageScalaVersion.get() + def scalaVersionProperty = project.extensions.scoverage.scoverageScalaVersion + if (scalaVersionProperty.isPresent()) { + def configuredScalaVersion = scalaVersionProperty.get() + project.logger.info("Using configured Scala version: $configuredScalaVersion") + return configuredScalaVersion } else { - project.logger.info("Detected scala library in compilation classpath") - def fullScalaVersion = scalaLibrary.moduleVersion.version - return fullScalaVersion.substring(0, fullScalaVersion.lastIndexOf(".")) + project.logger.info("No Scala version configured. Detecting scala library...") + def components = project.configurations.compileClasspath.incoming.resolutionResult.getAllComponents() + def scalaLibrary = components.find { + it.moduleVersion.group == "org.scala-lang" && it.moduleVersion.name == "scala-library" + } + if (scalaLibrary != null) { + def fullScalaVersion = scalaLibrary.moduleVersion.version + def scalaVersion = fullScalaVersion.substring(0, fullScalaVersion.lastIndexOf(".")) + project.logger.info("Detected scala library in compilation classpath. Scala version: $scalaVersion") + return scalaVersion + } else { + project.logger.info("No scala library detected. Using default Scala version: $DEFAULT_SCALA_VERSION") + return DEFAULT_SCALA_VERSION + } } } From 2d525194be4f3af59f9519d3b403ac9949cc1e97 Mon Sep 17 00:00:00 2001 From: Stu Date: Wed, 16 Sep 2020 22:08:55 +0100 Subject: [PATCH 109/167] bump to gradle 6.6.1 --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a4f0001..12d38de 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.4.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 8333ee393d8ccc37f366dbdb49fcf87fc0773459 Mon Sep 17 00:00:00 2001 From: Stu Date: Mon, 16 Nov 2020 21:54:59 +0000 Subject: [PATCH 110/167] upgrade to scoverage 1.4.2 (dropping support for 2.11 as it is gone upstream) --- build.gradle | 2 +- .../java/org/scoverage/Scala211Test.java | 7 ------- .../java/org/scoverage/Scala213Test.java | 8 -------- .../scoverage/ScalaCrossVersionAggregationTest.java | 3 --- .../java/org/scoverage/ScalaVersionTest.java | 3 --- .../2_11/build.gradle | 4 ---- .../2_11/src/main/scala/org/hello/World2_11.scala | 9 --------- .../src/test/scala/org/hello/World2_11Suite.scala | 13 ------------- .../settings.gradle | 2 +- .../groovy/org/scoverage/ScoverageExtension.groovy | 2 +- src/main/groovy/org/scoverage/ScoverageWriter.java | 6 +----- 11 files changed, 4 insertions(+), 55 deletions(-) delete mode 100644 src/crossScalaVersionTest/java/org/scoverage/Scala211Test.java delete mode 100644 src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_11/build.gradle delete mode 100644 src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_11/src/main/scala/org/hello/World2_11.scala delete mode 100644 src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_11/src/test/scala/org/hello/World2_11Suite.scala diff --git a/build.gradle b/build.gradle index 268de3e..ea6cb92 100644 --- a/build.gradle +++ b/build.gradle @@ -46,7 +46,7 @@ targetCompatibility = '1.8' dependencies { - compileOnly "org.scoverage:scalac-scoverage-plugin_2.12:1.4.1" + compileOnly "org.scoverage:scalac-scoverage-plugin_2.13:1.4.2" implementation group: 'commons-io', name: 'commons-io', version: '2.6' testImplementation 'junit:junit:4.12' diff --git a/src/crossScalaVersionTest/java/org/scoverage/Scala211Test.java b/src/crossScalaVersionTest/java/org/scoverage/Scala211Test.java deleted file mode 100644 index ac06067..0000000 --- a/src/crossScalaVersionTest/java/org/scoverage/Scala211Test.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.scoverage; - -public class Scala211Test extends ScalaVersionTest { - public Scala211Test() { - super("2_11"); - } -} \ No newline at end of file diff --git a/src/crossScalaVersionTest/java/org/scoverage/Scala213Test.java b/src/crossScalaVersionTest/java/org/scoverage/Scala213Test.java index 0f6ed71..31d9a38 100644 --- a/src/crossScalaVersionTest/java/org/scoverage/Scala213Test.java +++ b/src/crossScalaVersionTest/java/org/scoverage/Scala213Test.java @@ -1,13 +1,5 @@ package org.scoverage; -import org.junit.Ignore; - -/** - * Tests is currently ignored as support for Scala 2.13 is not available yet. - * - * @see Issue #106. - */ -@Ignore public class Scala213Test extends ScalaVersionTest { public Scala213Test() { super("2_13"); diff --git a/src/crossScalaVersionTest/java/org/scoverage/ScalaCrossVersionAggregationTest.java b/src/crossScalaVersionTest/java/org/scoverage/ScalaCrossVersionAggregationTest.java index d3b66ae..62850aa 100644 --- a/src/crossScalaVersionTest/java/org/scoverage/ScalaCrossVersionAggregationTest.java +++ b/src/crossScalaVersionTest/java/org/scoverage/ScalaCrossVersionAggregationTest.java @@ -23,11 +23,9 @@ public void checkAndAggregateAll() throws Exception { ScoveragePlugin.getAGGREGATE_NAME()); result.assertTaskSkipped(ScoveragePlugin.getREPORT_NAME()); - result.assertTaskSucceeded("2_11:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded("2_12:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded("2_13:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); - result.assertTaskSucceeded("2_11:" + ScoveragePlugin.getCHECK_NAME()); result.assertTaskSucceeded("2_12:" + ScoveragePlugin.getCHECK_NAME()); result.assertTaskSucceeded("2_13:" + ScoveragePlugin.getCHECK_NAME()); result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); @@ -39,7 +37,6 @@ public void checkAndAggregateAll() throws Exception { private void assertAggregationFilesExist() { Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertTrue(resolve(reportDir(), "2_11/src/main/scala/org/hello/World2_11.scala.html").exists()); Assert.assertTrue(resolve(reportDir(), "2_12/src/main/scala/org/hello/World2_12.scala.html").exists()); Assert.assertTrue(resolve(reportDir(), "2_13/src/main/scala/org/hello/World2_13.scala.html").exists()); } diff --git a/src/crossScalaVersionTest/java/org/scoverage/ScalaVersionTest.java b/src/crossScalaVersionTest/java/org/scoverage/ScalaVersionTest.java index 59160f3..55a15c8 100644 --- a/src/crossScalaVersionTest/java/org/scoverage/ScalaVersionTest.java +++ b/src/crossScalaVersionTest/java/org/scoverage/ScalaVersionTest.java @@ -2,9 +2,6 @@ import org.junit.Assert; import org.junit.Test; -import org.junit.jupiter.api.Tag; -import org.scoverage.ScoverageFunctionalTest; -import org.scoverage.ScoveragePlugin; import java.io.File; diff --git a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_11/build.gradle b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_11/build.gradle deleted file mode 100644 index 5421d5a..0000000 --- a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_11/build.gradle +++ /dev/null @@ -1,4 +0,0 @@ -dependencies { - compile group: 'org.scala-lang', name: 'scala-library', version: "2.11.12" - testCompile group: 'org.scalatest', name: "scalatest_2.11", version: scalatestVersion -} diff --git a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_11/src/main/scala/org/hello/World2_11.scala b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_11/src/main/scala/org/hello/World2_11.scala deleted file mode 100644 index cab6958..0000000 --- a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_11/src/main/scala/org/hello/World2_11.scala +++ /dev/null @@ -1,9 +0,0 @@ -package org.hello - -class World2_11 { - - def foo(): String = { - val s = "2" + "11" - s - } -} \ No newline at end of file diff --git a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_11/src/test/scala/org/hello/World2_11Suite.scala b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_11/src/test/scala/org/hello/World2_11Suite.scala deleted file mode 100644 index 2d99209..0000000 --- a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_11/src/test/scala/org/hello/World2_11Suite.scala +++ /dev/null @@ -1,13 +0,0 @@ -package org.hello - -import org.junit.runner.RunWith -import org.scalatest.FunSuite -import org.scalatest.junit.JUnitRunner - -@RunWith(classOf[JUnitRunner]) -class World2_11Suite extends FunSuite { - - test("foo") { - new World2_11().foo() - } -} \ No newline at end of file diff --git a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/settings.gradle b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/settings.gradle index 174d3b1..f294f6a 100644 --- a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/settings.gradle +++ b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/settings.gradle @@ -1 +1 @@ -include '2_11', '2_12', '2_13' \ No newline at end of file +include '2_12', '2_13' \ No newline at end of file diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index 9de93c5..06d22ba 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -57,7 +57,7 @@ class ScoverageExtension { project.plugins.apply(ScalaPlugin.class) scoverageVersion = project.objects.property(String) - scoverageVersion.set('1.4.1') + scoverageVersion.set('1.4.2') scoverageScalaVersion = project.objects.property(String) diff --git a/src/main/groovy/org/scoverage/ScoverageWriter.java b/src/main/groovy/org/scoverage/ScoverageWriter.java index 47572c1..bf0e2df 100644 --- a/src/main/groovy/org/scoverage/ScoverageWriter.java +++ b/src/main/groovy/org/scoverage/ScoverageWriter.java @@ -2,8 +2,6 @@ import org.gradle.api.logging.Logger; import scala.Some; -import scala.collection.JavaConverters; -import scala.collection.mutable.Buffer; import scoverage.Constants; import scoverage.Coverage; import scoverage.report.CoberturaXmlWriter; @@ -11,7 +9,6 @@ import scoverage.report.ScoverageXmlWriter; import java.io.File; -import java.util.Arrays; /** * Util for generating and saving coverage files. @@ -76,8 +73,7 @@ public void write(File sourceDir, } if (coverageOutputHTML) { - Buffer sources = JavaConverters.asScalaBufferConverter(Arrays.asList(sourceDir)).asScala(); - new ScoverageHtmlWriter(sources, reportDir, new Some<>(sourceEncoding)).write(coverage); + new ScoverageHtmlWriter(new File[]{sourceDir}, reportDir, new Some<>(sourceEncoding)).write(coverage); logger.info("[scoverage] Written HTML report to " + reportDir.getAbsolutePath() + File.separator + From ecbddddd51b25b908d4ad8e39cefc375b119f142 Mon Sep 17 00:00:00 2001 From: Cristian Garcia Date: Tue, 17 Nov 2020 09:50:44 +0100 Subject: [PATCH 111/167] Fix CoverageFileName fixes #135 This issue is making builds using the Gradle BuildCache to report 0% coverage. Gradle caches the .xml file that doesn't exist from the compile task and then the report task doesn't see anything, now it will cache the right file fixing the builds. --- src/main/groovy/org/scoverage/ScoveragePlugin.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index ab5f4d2..aa21566 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -191,7 +191,7 @@ class ScoveragePlugin implements Plugin { } scalaCompileOptions.additionalParameters = parameters // the compile task creates a store of measured statements - outputs.file(new File(extension.dataDir.get(), 'scoverage.coverage.xml')) + outputs.file(new File(extension.dataDir.get(), 'scoverage.coverage')) dependsOn project.configurations[CONFIGURATION_NAME] doFirst { From 051134b06acb117c67d69c0a5af1dd39d68e533b Mon Sep 17 00:00:00 2001 From: Stu Date: Tue, 17 Nov 2020 08:52:17 +0000 Subject: [PATCH 112/167] update README with details of v5 --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 98f0543..bf3c548 100644 --- a/README.md +++ b/README.md @@ -43,10 +43,10 @@ You can find instructions on how to apply the plugin at http://plugins.gradle.or The plugin exposes multiple options that can be configured by setting them in an `scoverage` block within the project's build script. These options are as follows: -* `scoverageVersion = ` (default `"1.4.1"`): The version of the scoverage scalac plugin. This (gradle) plugin +* `scoverageVersion = ` (default `"1.4.2`): The version of the scoverage scalac plugin. This (gradle) plugin should be compatible with all 1+ versions. -* `scoverageScalaVersion = ` (default `"2.12"`): The scala version of the scoverage scalac plugin. This +* `scoverageScalaVersion = ` (default `detected`): The scala version of the scoverage scalac plugin. This overrides the version of the `scala-library` compile dependency (if the dependency is configured). * `coverageOutputCobertura = ` (default `true`): Enables/disables cobertura.xml file generation (for both aggregated and non-aggregated reports). @@ -122,6 +122,13 @@ In order for the plugin to work alongside [Palantir's consistent versions plugin the Scala version must be manually configured (via `scoverageScalaVersion`); otherwise, the plugin will attempt to resolve the compilation classpath, which is prohibited by the versions plugin. +Migration to 5.x +---------------- + +* Requires scoverage 1.4.2 or higher (and uses this version by default) +* Adds support for Scala 2.13 +* Drops support for Scala 2.11 + Migration to 4.x ---------------- From 78080ffad938bfd3e693b6fade0d79e9b4d5fd43 Mon Sep 17 00:00:00 2001 From: Stu Date: Sat, 1 May 2021 16:18:41 +0100 Subject: [PATCH 113/167] move to maven-publish --- build.gradle | 81 +++++++++++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/build.gradle b/build.gradle index ea6cb92..622ab99 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ plugins { id 'java-gradle-plugin' id "com.gradle.plugin-publish" version "0.12.0" - id "org.jetbrains.gradle.plugin.idea-ext" version "0.4.2" + id "org.jetbrains.gradle.plugin.idea-ext" version "1.0" } repositories { @@ -38,7 +38,7 @@ pluginBundle { tags = ['coverage', 'scala', 'scoverage'] } -apply plugin: 'maven' +apply plugin: 'maven-publish' apply plugin: 'groovy' sourceCompatibility = '1.8' @@ -107,79 +107,82 @@ gradlePlugin { } task groovydocJar(type: Jar, dependsOn: groovydoc) { - classifier = 'groovydoc' from "$buildDir/docs/groovydoc" + classifier 'groovydoc' } task sourcesJar(type: Jar) { from sourceSets.main.allSource - classifier = 'sources' + classifier 'sources' } -artifacts { - archives groovydocJar - archives sourcesJar -} - -if (project.properties.containsKey('signing.keyId')) { - apply plugin: 'signing' - signing { - sign configurations.archives +def propOrDefault(String property) { + if (project.hasProperty(property)) { + return project.getProperty(property) + } else { + return '' } } -uploadArchives { +publishing { repositories { - mavenDeployer { - if (project.properties.containsKey('signing.keyId')) { - beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } - } - - snapshotRepository(url: 'https://oss.sonatype.org/content/repositories/snapshots') { - authentication(userName: sonatypeUser, password: sonatypePass) - } - - repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { - authentication(userName: sonatypeUser, password: sonatypePass) + maven { + url = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" + credentials(PasswordCredentials) { + username = propOrDefault('sonatypeUser') + password = propOrDefault('sonatypePass') } - - pom.project { - name 'GradleScoverage' - description project.description - url project.website + } + } + publications { + mavenJava(MavenPublication) { + pom { + name = 'GradleScoverage' + description = project.description + url = project.website scm { - url scmUrl - developerConnection scmUrl + url = scmUrl + developerConnection = scmUrl } licenses { license { - name 'The Apache Software License, Version 2.0' - url 'http://www.apache.org/licenses/LICENSE-2.0.txt' - distribution 'repo' + name = 'The Apache Software License, Version 2.0' + url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' + distribution = 'repo' } } developers { developer { - id 'maiflai' + id = 'maiflai' } developer { - id 'ubourdon' + id = 'ubourdon' } developer { - id 'D-Roch' + id = 'D-Roch' } developer { - id 'eyalroth' + id = 'eyalroth' } } } + from components.java + artifact groovydocJar + artifact sourcesJar } } } +if (project.properties.containsKey('signing.keyId')) { + apply plugin: 'signing' + signing { + sign publishing.publications.mavenJava + } +} + // see https://stackoverflow.com/questions/44679007 task fixIdeaPluginClasspath { doFirst { From 2843f9e4a8cb4e263d2a5cc3c898814ec6ce78c5 Mon Sep 17 00:00:00 2001 From: Stu Date: Sat, 1 May 2021 16:19:02 +0100 Subject: [PATCH 114/167] remove unnecessary file --- .../resources/META-INF/gradle-plugins/org.scoverage.properties | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/main/resources/META-INF/gradle-plugins/org.scoverage.properties diff --git a/src/main/resources/META-INF/gradle-plugins/org.scoverage.properties b/src/main/resources/META-INF/gradle-plugins/org.scoverage.properties deleted file mode 100644 index 4490e61..0000000 --- a/src/main/resources/META-INF/gradle-plugins/org.scoverage.properties +++ /dev/null @@ -1 +0,0 @@ -implementation-class=org.scoverage.ScoveragePlugin From 5156622a41697db362225e8000583a08185aa418 Mon Sep 17 00:00:00 2001 From: Stu Date: Sat, 1 May 2021 16:19:33 +0100 Subject: [PATCH 115/167] update configuration names in preparation for gradle 7 --- .../2_12/build.gradle | 4 ++-- .../2_13/build.gradle | 4 ++-- .../scala-multi-module-cross-version/build.gradle | 4 ++-- .../projects/composite-build/proj1/build.gradle | 10 +++++----- .../projects/composite-build/proj2/build.gradle | 8 ++++---- .../detect-scala-library/compile/build.gradle | 4 ++-- .../gradle-consistent-versions/build.gradle | 2 +- .../build.gradle | 2 +- .../java_only/build.gradle | 2 +- .../scala_only/build.gradle | 6 +++--- .../multiple-checks/build.gradle | 8 ++++---- .../multiple-check-tasks/no-check/build.gradle | 8 ++++---- .../old-and-new-syntax/build.gradle | 8 ++++---- .../single-check-new-syntax/build.gradle | 8 ++++---- .../single-check-old-syntax/build.gradle | 8 ++++---- .../projects/scala-java-multi-module/build.gradle | 2 +- .../scala-java-multi-module/java_only/build.gradle | 2 +- .../mixed_scala_java/build.gradle | 6 +++--- .../scala-java-multi-module/scala_only/build.gradle | 6 +++--- .../a/build.gradle | 2 +- .../b/build.gradle | 2 +- .../build.gradle | 12 ++++++------ .../build.gradle | 10 +++++----- .../projects/scala-multi-module/a/build.gradle | 2 +- .../projects/scala-multi-module/b/build.gradle | 2 +- .../projects/scala-multi-module/build.gradle | 8 ++++---- .../build.gradle | 8 ++++---- .../build.gradle | 12 ++++++------ .../projects/scala-single-module/build.gradle | 8 ++++---- 29 files changed, 84 insertions(+), 84 deletions(-) diff --git a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_12/build.gradle b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_12/build.gradle index 0a8112a..88c5533 100644 --- a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_12/build.gradle +++ b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_12/build.gradle @@ -1,4 +1,4 @@ dependencies { - compile group: 'org.scala-lang', name: 'scala-library', version: "2.12.8" - testCompile group: 'org.scalatest', name: "scalatest_2.12", version: scalatestVersion + implementation group: 'org.scala-lang', name: 'scala-library', version: "2.12.8" + testImplementation group: 'org.scalatest', name: "scalatest_2.12", version: scalatestVersion } diff --git a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_13/build.gradle b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_13/build.gradle index 8be20a7..4820211 100644 --- a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_13/build.gradle +++ b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_13/build.gradle @@ -1,4 +1,4 @@ dependencies { - compile group: 'org.scala-lang', name: 'scala-library', version: "2.13.1" - testCompile group: 'org.scalatest', name: "scalatest_2.13", version: scalatestVersion + implementation group: 'org.scala-lang', name: 'scala-library', version: "2.13.1" + testImplementation group: 'org.scalatest', name: "scalatest_2.13", version: scalatestVersion } diff --git a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/build.gradle b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/build.gradle index 8577cf5..f9d1535 100644 --- a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/build.gradle +++ b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/build.gradle @@ -17,8 +17,8 @@ allprojects { apply plugin: 'org.scoverage' dependencies { - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion - testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testImplementation group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion } test { diff --git a/src/functionalTest/resources/projects/composite-build/proj1/build.gradle b/src/functionalTest/resources/projects/composite-build/proj1/build.gradle index d0e32d3..897dc59 100644 --- a/src/functionalTest/resources/projects/composite-build/proj1/build.gradle +++ b/src/functionalTest/resources/projects/composite-build/proj1/build.gradle @@ -16,14 +16,14 @@ group "org.composite" version '1.0' dependencies { - compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + implementation group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion - testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testImplementation group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion - testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion + testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion - compile "org.composite:proj2:1.0" + implementation "org.composite:proj2:1.0" } test { diff --git a/src/functionalTest/resources/projects/composite-build/proj2/build.gradle b/src/functionalTest/resources/projects/composite-build/proj2/build.gradle index b86570e..99bf400 100644 --- a/src/functionalTest/resources/projects/composite-build/proj2/build.gradle +++ b/src/functionalTest/resources/projects/composite-build/proj2/build.gradle @@ -16,12 +16,12 @@ group "org.composite" version '1.0' dependencies { - compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + implementation group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion - testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testImplementation group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion - testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion + testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion } test { diff --git a/src/functionalTest/resources/projects/detect-scala-library/compile/build.gradle b/src/functionalTest/resources/projects/detect-scala-library/compile/build.gradle index 8201e48..be9936b 100644 --- a/src/functionalTest/resources/projects/detect-scala-library/compile/build.gradle +++ b/src/functionalTest/resources/projects/detect-scala-library/compile/build.gradle @@ -6,8 +6,8 @@ repositories { jcenter() } -description = 'defines scala library using the "compile" configuration' +description = 'defines scala library using the "implementation" configuration' dependencies { - compile group: 'org.scala-lang', name: 'scala-library', version: "${detectedScalaLibraryVersion}" + implementation group: 'org.scala-lang', name: 'scala-library', version: "${detectedScalaLibraryVersion}" } \ No newline at end of file diff --git a/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/build.gradle b/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/build.gradle index 030a1c1..9e4d81d 100644 --- a/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/build.gradle +++ b/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/build.gradle @@ -1,5 +1,5 @@ plugins { - id "com.palantir.consistent-versions" version "1.16.0" + id "com.palantir.consistent-versions" version "1.28.0" id 'org.scoverage' } diff --git a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/build.gradle b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/build.gradle index 450d3e7..ba236a7 100644 --- a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/build.gradle +++ b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/build.gradle @@ -15,7 +15,7 @@ subprojects { p -> apply plugin: 'java' dependencies { implementation platform(project(':dependencies')) - testCompile group: 'org.junit.platform', name: 'junit-platform-runner' + testImplementation group: 'org.junit.platform', name: 'junit-platform-runner' } test { diff --git a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/build.gradle b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/build.gradle index bbcd2f4..c9a43d3 100644 --- a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/build.gradle +++ b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/build.gradle @@ -1,3 +1,3 @@ dependencies { - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine' + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine' } diff --git a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/build.gradle b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/build.gradle index 28ca396..2df2f4e 100644 --- a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/build.gradle +++ b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/build.gradle @@ -2,8 +2,8 @@ apply plugin: 'scala' // apply plugin: 'org.scoverage' // Oops forgot to configure scoverage dependencies { - compile group: 'org.scala-lang', name: 'scala-library' + implementation group: 'org.scala-lang', name: 'scala-library' - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine' - testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}" + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine' + testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}" } diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/multiple-checks/build.gradle b/src/functionalTest/resources/projects/multiple-check-tasks/multiple-checks/build.gradle index 01abbe0..4c0a9fb 100644 --- a/src/functionalTest/resources/projects/multiple-check-tasks/multiple-checks/build.gradle +++ b/src/functionalTest/resources/projects/multiple-check-tasks/multiple-checks/build.gradle @@ -12,12 +12,12 @@ apply plugin: 'java' apply plugin: 'scala' dependencies { - compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + implementation group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion - testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testImplementation group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion - testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion + testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion } test { diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/no-check/build.gradle b/src/functionalTest/resources/projects/multiple-check-tasks/no-check/build.gradle index 07ca734..3ad1fea 100644 --- a/src/functionalTest/resources/projects/multiple-check-tasks/no-check/build.gradle +++ b/src/functionalTest/resources/projects/multiple-check-tasks/no-check/build.gradle @@ -12,12 +12,12 @@ apply plugin: 'java' apply plugin: 'scala' dependencies { - compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + implementation group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion - testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testImplementation group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion - testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion + testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion } test { diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/old-and-new-syntax/build.gradle b/src/functionalTest/resources/projects/multiple-check-tasks/old-and-new-syntax/build.gradle index a672629..3e69976 100644 --- a/src/functionalTest/resources/projects/multiple-check-tasks/old-and-new-syntax/build.gradle +++ b/src/functionalTest/resources/projects/multiple-check-tasks/old-and-new-syntax/build.gradle @@ -12,12 +12,12 @@ apply plugin: 'java' apply plugin: 'scala' dependencies { - compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + implementation group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion - testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testImplementation group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion - testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion + testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion } test { diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/single-check-new-syntax/build.gradle b/src/functionalTest/resources/projects/multiple-check-tasks/single-check-new-syntax/build.gradle index 4967ad1..8be7d9a 100644 --- a/src/functionalTest/resources/projects/multiple-check-tasks/single-check-new-syntax/build.gradle +++ b/src/functionalTest/resources/projects/multiple-check-tasks/single-check-new-syntax/build.gradle @@ -12,12 +12,12 @@ apply plugin: 'java' apply plugin: 'scala' dependencies { - compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + implementation group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion - testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testImplementation group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion - testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion + testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion } test { diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/single-check-old-syntax/build.gradle b/src/functionalTest/resources/projects/multiple-check-tasks/single-check-old-syntax/build.gradle index 93fa3a8..719e14e 100644 --- a/src/functionalTest/resources/projects/multiple-check-tasks/single-check-old-syntax/build.gradle +++ b/src/functionalTest/resources/projects/multiple-check-tasks/single-check-old-syntax/build.gradle @@ -12,12 +12,12 @@ apply plugin: 'java' apply plugin: 'scala' dependencies { - compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + implementation group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion - testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testImplementation group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion - testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion + testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion } test { diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/build.gradle b/src/functionalTest/resources/projects/scala-java-multi-module/build.gradle index 27246b6..40e08b7 100644 --- a/src/functionalTest/resources/projects/scala-java-multi-module/build.gradle +++ b/src/functionalTest/resources/projects/scala-java-multi-module/build.gradle @@ -14,7 +14,7 @@ subprojects { apply plugin: 'java' dependencies { - testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + testImplementation group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion } test { diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/java_only/build.gradle b/src/functionalTest/resources/projects/scala-java-multi-module/java_only/build.gradle index c2060d5..69fe4c7 100644 --- a/src/functionalTest/resources/projects/scala-java-multi-module/java_only/build.gradle +++ b/src/functionalTest/resources/projects/scala-java-multi-module/java_only/build.gradle @@ -1,3 +1,3 @@ dependencies { - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion } diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/build.gradle b/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/build.gradle index c107f19..53e3405 100644 --- a/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/build.gradle +++ b/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/build.gradle @@ -1,11 +1,11 @@ apply plugin: 'scala' dependencies { - compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + implementation group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion - testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion + testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion } // A common practice in mixed java/scala modules to make Java code able to import Scala code diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/scala_only/build.gradle b/src/functionalTest/resources/projects/scala-java-multi-module/scala_only/build.gradle index abca859..2ed4e0e 100644 --- a/src/functionalTest/resources/projects/scala-java-multi-module/scala_only/build.gradle +++ b/src/functionalTest/resources/projects/scala-java-multi-module/scala_only/build.gradle @@ -1,11 +1,11 @@ apply plugin: 'scala' dependencies { - compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + implementation group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion - testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion + testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion } apply plugin: 'org.scoverage' diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/build.gradle index 368d0bc..a3553b5 100644 --- a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/build.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/build.gradle @@ -1,3 +1,3 @@ dependencies { - compile project(":common") + implementation project(":common") } diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/build.gradle index 368d0bc..a3553b5 100644 --- a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/build.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/build.gradle @@ -1,3 +1,3 @@ dependencies { - compile project(":common") + implementation project(":common") } diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle index 310e1da..7bf8c92 100644 --- a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle @@ -17,12 +17,12 @@ allprojects { apply plugin: 'org.scoverage' dependencies { - compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + implementation group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion - testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testImplementation group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion - testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion + testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion } test { @@ -31,8 +31,8 @@ allprojects { } configurations { - intTestCompile.extendsFrom testCompile - intTestRuntime.extendsFrom testRuntime + intTestImplementation.extendsFrom testImplementation + intTestRuntimeOnly.extendsFrom testRuntimeOnly } sourceSets { intTest { diff --git a/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/build.gradle index ea5f8aa..4205b6a 100644 --- a/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/build.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/build.gradle @@ -18,15 +18,15 @@ allprojects { p -> dependencies { - compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + implementation group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" - testCompile group: 'org.junit.platform', name: 'junit-platform-runner' + testImplementation group: 'org.junit.platform', name: 'junit-platform-runner' - testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}" + testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}" } } dependencies { - compile project(':a') - compile project(':b') + implementation project(':a') + implementation project(':b') } \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/a/build.gradle b/src/functionalTest/resources/projects/scala-multi-module/a/build.gradle index 054045f..ee1a4ab 100644 --- a/src/functionalTest/resources/projects/scala-multi-module/a/build.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module/a/build.gradle @@ -1,3 +1,3 @@ dependencies { - compile project(":common") + implementation project(":common") } \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/b/build.gradle b/src/functionalTest/resources/projects/scala-multi-module/b/build.gradle index 054045f..ee1a4ab 100644 --- a/src/functionalTest/resources/projects/scala-multi-module/b/build.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module/b/build.gradle @@ -1,3 +1,3 @@ dependencies { - compile project(":common") + implementation project(":common") } \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/build.gradle b/src/functionalTest/resources/projects/scala-multi-module/build.gradle index 3f10c36..9235b85 100644 --- a/src/functionalTest/resources/projects/scala-multi-module/build.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module/build.gradle @@ -17,12 +17,12 @@ allprojects { p -> dependencies { implementation platform(project(':dependencies')) - compile group: 'org.scala-lang', name: 'scala-library' + implementation group: 'org.scala-lang', name: 'scala-library' - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine' - testCompile group: 'org.junit.platform', name: 'junit-platform-runner' + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine' + testImplementation group: 'org.junit.platform', name: 'junit-platform-runner' - testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}" + testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}" } test { diff --git a/src/functionalTest/resources/projects/scala-single-module-dependency-manager/build.gradle b/src/functionalTest/resources/projects/scala-single-module-dependency-manager/build.gradle index 8d36fb3..84d3e1c 100644 --- a/src/functionalTest/resources/projects/scala-single-module-dependency-manager/build.gradle +++ b/src/functionalTest/resources/projects/scala-single-module-dependency-manager/build.gradle @@ -20,12 +20,12 @@ dependencyManagement { } dependencies { - compile group: 'org.scala-lang', name: 'scala-library' + implementation group: 'org.scala-lang', name: 'scala-library' - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion - testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testImplementation group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion - testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion + testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion } test { diff --git a/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle index b26ba4f..fcf174b 100644 --- a/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle +++ b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle @@ -19,12 +19,12 @@ dependencyManagement { } dependencies { - compile group: 'org.scala-lang', name: 'scala-library' + implementation group: 'org.scala-lang', name: 'scala-library' - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion - testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testImplementation group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion - testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion + testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion } test { @@ -33,8 +33,8 @@ test { configurations { - intTestCompile.extendsFrom testCompile - intTestRuntime.extendsFrom testRuntime + intTestImplementation.extendsFrom testImplementation + intTestRuntimeOnly.extendsFrom testRuntimeOnly } sourceSets { intTest { diff --git a/src/functionalTest/resources/projects/scala-single-module/build.gradle b/src/functionalTest/resources/projects/scala-single-module/build.gradle index 997bf7d..e96efe1 100644 --- a/src/functionalTest/resources/projects/scala-single-module/build.gradle +++ b/src/functionalTest/resources/projects/scala-single-module/build.gradle @@ -12,12 +12,12 @@ apply plugin: 'java' apply plugin: 'scala' dependencies { - compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + implementation group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion - testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testImplementation group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion - testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion + testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion } test { From f26b82b1354f05e031644ce729aa737d7879208a Mon Sep 17 00:00:00 2001 From: Stu Date: Sat, 1 May 2021 20:04:38 +0100 Subject: [PATCH 116/167] update to Gradle 7 --- gradle/wrapper/gradle-wrapper.properties | 2 +- .../java/org/scoverage/DetectScalaLibraryTest.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 12d38de..f371643 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/functionalTest/java/org/scoverage/DetectScalaLibraryTest.java b/src/functionalTest/java/org/scoverage/DetectScalaLibraryTest.java index bcda654..9c607a4 100644 --- a/src/functionalTest/java/org/scoverage/DetectScalaLibraryTest.java +++ b/src/functionalTest/java/org/scoverage/DetectScalaLibraryTest.java @@ -39,7 +39,8 @@ public static Collection data() { {"/compileOnly", new String[] {".0", ".+"}, true, new String[0]}, {"/implementation", new String[] {".0", ".+"}, true, new String[0]}, {"/dependency-management", new String[] {".0", ".+"}, true, new String[0]}, - {"/gradle-consistent-versions", new String[] {"ignored"}, false, new String[] {"--write-locks"}}, +// disabled until the consistent-versions plugin supports Gradle 7 +// {"/gradle-consistent-versions", new String[] {"ignored"}, false, new String[] {"--write-locks"}}, }; return Arrays.asList(data); } From 0d5cb3bd463212ae29dfdb93f99909266c3e38e5 Mon Sep 17 00:00:00 2001 From: Helder Pereira Date: Wed, 9 Jun 2021 00:05:14 +0100 Subject: [PATCH 117/167] Use Scala full version in plugin and binary version in runtime --- README.md | 2 +- build.gradle | 2 +- .../org/scoverage/DetectScalaLibraryTest.java | 22 +++++++++---------- .../org/scoverage/ScoverageExtension.groovy | 2 +- .../org/scoverage/ScoveragePlugin.groovy | 15 ++++++------- 5 files changed, 20 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index bf3c548..b44ec2e 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ You can find instructions on how to apply the plugin at http://plugins.gradle.or The plugin exposes multiple options that can be configured by setting them in an `scoverage` block within the project's build script. These options are as follows: -* `scoverageVersion = ` (default `"1.4.2`): The version of the scoverage scalac plugin. This (gradle) plugin +* `scoverageVersion = ` (default `"1.4.8`): The version of the scoverage scalac plugin. This (gradle) plugin should be compatible with all 1+ versions. * `scoverageScalaVersion = ` (default `detected`): The scala version of the scoverage scalac plugin. This diff --git a/build.gradle b/build.gradle index ea6cb92..65a3bcd 100644 --- a/build.gradle +++ b/build.gradle @@ -53,7 +53,7 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-api:5.5.2' testRuntimeOnly 'org.junit.vintage:junit-vintage-engine:5.5.2' - testImplementation 'org.hamcrest:hamcrest-library:1.3' + testImplementation 'org.hamcrest:hamcrest:2.2' } sourceSets { diff --git a/src/functionalTest/java/org/scoverage/DetectScalaLibraryTest.java b/src/functionalTest/java/org/scoverage/DetectScalaLibraryTest.java index bcda654..ba2fb16 100644 --- a/src/functionalTest/java/org/scoverage/DetectScalaLibraryTest.java +++ b/src/functionalTest/java/org/scoverage/DetectScalaLibraryTest.java @@ -1,25 +1,23 @@ package org.scoverage; -import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import java.util.Arrays; import java.util.Collection; -import java.util.List; import java.util.stream.Stream; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.stringContainsInOrder; + @RunWith(Parameterized.class) public class DetectScalaLibraryTest extends ScoverageFunctionalTest { - private static final String SCALA_VERSION = "2.12"; + private static final String SCALA_VERSION = "2.13"; private static final String SCALA_LIBRARY_PARAMETER = "-PdetectedScalaLibraryVersion="; - private static final String EXPECTED_OUTPUT_CONFIGURED_VERSION = "Using configured Scala version"; - private static final String EXPECTED_OUTPUT_DETECTED_VERSION = "Detected scala library in compilation classpath"; - private static final String EXPECTED_OUTPUT_USING = "Using scoverage scalac plugin version '" + SCALA_VERSION; - @Parameterized.Parameter(0) public String projectDir; @@ -56,7 +54,7 @@ public void test() { } } - private void testWithParameter(String parameter, Boolean detect) { + private void testWithParameter(String parameter, boolean detect) { String[] basicParameters = {"clean", parameter, "--info"}; String[] parameters = Stream.concat(Arrays.stream(basicParameters), Arrays.stream(additionalParameters)) @@ -65,11 +63,11 @@ private void testWithParameter(String parameter, Boolean detect) { String output = result.getResult().getOutput(); if (detect) { - Assert.assertTrue(output.contains(EXPECTED_OUTPUT_DETECTED_VERSION)); + assertThat(output, containsString("Detected scala library in compilation classpath")); } else { - Assert.assertTrue(output.contains(EXPECTED_OUTPUT_CONFIGURED_VERSION)); + assertThat(output, containsString("Using configured Scala version")); } - Assert.assertTrue(output.contains(EXPECTED_OUTPUT_USING)); + assertThat(output, stringContainsInOrder("Using scoverage scalac plugin", "for scala", SCALA_VERSION)); } -} \ No newline at end of file +} diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index 06d22ba..e106306 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -57,7 +57,7 @@ class ScoverageExtension { project.plugins.apply(ScalaPlugin.class) scoverageVersion = project.objects.property(String) - scoverageVersion.set('1.4.2') + scoverageVersion.set('1.4.8') scoverageScalaVersion = project.objects.property(String) diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index aa21566..063ba04 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -24,7 +24,7 @@ class ScoveragePlugin implements Plugin { static final String CHECK_NAME = 'checkScoverage' static final String COMPILE_NAME = 'compileScoverageScala' static final String AGGREGATE_NAME = 'aggregateScoverage' - static final String DEFAULT_SCALA_VERSION = '2.12' + static final String DEFAULT_SCALA_VERSION = '2.13.6' static final String DEFAULT_REPORT_DIR = 'reports' + File.separatorChar + 'scoverage' @@ -60,15 +60,15 @@ class ScoveragePlugin implements Plugin { } project.afterEvaluate { - def scalaVersion = resolveScalaVersion(project) + def scalaFullVersion = resolveScalaVersion(project) + def scalaBinaryVersion = scalaFullVersion.substring(0, scalaFullVersion.lastIndexOf('.')) def scoverageVersion = project.extensions.scoverage.scoverageVersion.get() - def fullScoverageVersion = "$scalaVersion:$scoverageVersion" - project.logger.info("Using scoverage scalac plugin version '$fullScoverageVersion'") + project.logger.info("Using scoverage scalac plugin $scoverageVersion for scala $scalaFullVersion") project.dependencies { - scoverage("org.scoverage:scalac-scoverage-plugin_$fullScoverageVersion") - scoverage("org.scoverage:scalac-scoverage-runtime_$fullScoverageVersion") + scoverage("org.scoverage:scalac-scoverage-plugin_$scalaFullVersion:$scoverageVersion") + scoverage("org.scoverage:scalac-scoverage-runtime_$scalaBinaryVersion:$scoverageVersion") } } } @@ -360,8 +360,7 @@ class ScoveragePlugin implements Plugin { it.moduleVersion.group == "org.scala-lang" && it.moduleVersion.name == "scala-library" } if (scalaLibrary != null) { - def fullScalaVersion = scalaLibrary.moduleVersion.version - def scalaVersion = fullScalaVersion.substring(0, fullScalaVersion.lastIndexOf(".")) + def scalaVersion = scalaLibrary.moduleVersion.version project.logger.info("Detected scala library in compilation classpath. Scala version: $scalaVersion") return scalaVersion } else { From 50498be38c4e26d779054e3cf2370305791f57cc Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 13 Jun 2021 22:16:44 +0100 Subject: [PATCH 118/167] remove illegal self-closing tag --- src/main/groovy/org/scoverage/ScoverageWriter.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/groovy/org/scoverage/ScoverageWriter.java b/src/main/groovy/org/scoverage/ScoverageWriter.java index bf0e2df..2f95a51 100644 --- a/src/main/groovy/org/scoverage/ScoverageWriter.java +++ b/src/main/groovy/org/scoverage/ScoverageWriter.java @@ -12,7 +12,6 @@ /** * Util for generating and saving coverage files. - *

* Copied from sbt-scoverage and converted to Java to avoid dependency to Scala. */ public class ScoverageWriter { From 6cd02b68f3f5fae80a6dd8d629c4c936887c3ad1 Mon Sep 17 00:00:00 2001 From: Gabriel Jones <18059585+gabrieljones@users.noreply.github.com> Date: Mon, 14 Jun 2021 16:50:52 -0400 Subject: [PATCH 119/167] gradle: wrapper v7.1 --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f371643..69a9715 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 9a3f53111540a370637b8bd5af988d6b60e43c1a Mon Sep 17 00:00:00 2001 From: Stu Date: Mon, 12 Jul 2021 22:36:52 +0100 Subject: [PATCH 120/167] bump gradle plugin publish to 0.15 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0bf35c3..2ccabbb 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java-gradle-plugin' - id "com.gradle.plugin-publish" version "0.12.0" + id "com.gradle.plugin-publish" version "0.15.0" id "org.jetbrains.gradle.plugin.idea-ext" version "1.0" } From cbc76578d69cb4d81bd9b09f31f85bdd6af63db1 Mon Sep 17 00:00:00 2001 From: Georg Rollinger Date: Wed, 4 Aug 2021 16:13:44 +0200 Subject: [PATCH 121/167] Set default version to 6.0.0-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 2ccabbb..b5ea655 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ repositories { group 'org.scoverage' description = 'gradle-scoverage is a Gradle plugin for calculating code coverage using Scoverage' if (project.version == 'unspecified') { - version = '3.0.0-SNAPSHOT' + version = '6.0.0-SNAPSHOT' } ext { website = 'http://scoverage.org' From 7a65806ff8399f6e471ded7fbca74ae2c79fc590 Mon Sep 17 00:00:00 2001 From: maiflai Date: Sun, 8 Aug 2021 22:31:40 +0100 Subject: [PATCH 122/167] Create gradle.yml --- .github/workflows/gradle.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/gradle.yml diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml new file mode 100644 index 0000000..37bbdbf --- /dev/null +++ b/.github/workflows/gradle.yml @@ -0,0 +1,27 @@ +# This workflow will build a Java project with Gradle +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle + +name: Java CI with Gradle + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 11 + uses: actions/setup-java@v2 + with: + java-version: '11' + distribution: 'adopt' + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Build with Gradle + run: ./gradlew --info --stacktrace check From fed5faa41f57b74dcb54f881d11d156bcdc6db3d Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 8 Aug 2021 23:07:49 +0100 Subject: [PATCH 123/167] build status badge from github actions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b44ec2e..7048e70 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.org/scoverage/gradle-scoverage.png?branch=master)](https://travis-ci.org/scoverage/gradle-scoverage) +[![Java CI with Gradle](https://github.com/scoverage/gradle-scoverage/actions/workflows/gradle.yml/badge.svg)](https://github.com/scoverage/gradle-scoverage/actions/workflows/gradle.yml) gradle-scoverage ================ From 720a6869d0736653ad0077a3ea5a2da0c2f2ced7 Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 8 Aug 2021 23:20:30 +0100 Subject: [PATCH 124/167] remove travis --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 1e5da93..0000000 --- a/.travis.yml +++ /dev/null @@ -1,3 +0,0 @@ -language: groovy -script: - - "./gradlew --info --stacktrace check" \ No newline at end of file From cc77b818300103dbcf49072d9251f2fa4fff8162 Mon Sep 17 00:00:00 2001 From: Georg Rollinger Date: Wed, 4 Aug 2021 16:20:33 +0200 Subject: [PATCH 125/167] Add support for mixed Java/Scala modules that use Java annotation processors --- .../ScalaJavaAnnotationProcessorTest.java | 56 +++++++++++++++++++ .../build.gradle | 50 +++++++++++++++++ .../java_only/build.gradle | 3 + .../main/java/org/hello/WorldJavaOnly.java | 8 +++ .../java/org/hello/WorldJavaOnlyTest.java | 11 ++++ .../lombok.config | 1 + .../mixed_scala_java/build.gradle | 14 +++++ .../src/main/java/org/hello/WorldJava.java | 8 +++ .../src/main/scala/org/hello/WorldScala.scala | 7 +++ .../test/java/org/hello/WorldJavaTest.java | 11 ++++ .../scala/org/hello/WorldScalaSuite.scala | 13 +++++ .../settings.gradle | 1 + .../org/scoverage/ScoveragePlugin.groovy | 1 + 13 files changed, 184 insertions(+) create mode 100644 src/functionalTest/java/org/scoverage/ScalaJavaAnnotationProcessorTest.java create mode 100644 src/functionalTest/resources/projects/scala-java-annotation-processor/build.gradle create mode 100644 src/functionalTest/resources/projects/scala-java-annotation-processor/java_only/build.gradle create mode 100644 src/functionalTest/resources/projects/scala-java-annotation-processor/java_only/src/main/java/org/hello/WorldJavaOnly.java create mode 100644 src/functionalTest/resources/projects/scala-java-annotation-processor/java_only/src/test/java/org/hello/WorldJavaOnlyTest.java create mode 100644 src/functionalTest/resources/projects/scala-java-annotation-processor/lombok.config create mode 100644 src/functionalTest/resources/projects/scala-java-annotation-processor/mixed_scala_java/build.gradle create mode 100644 src/functionalTest/resources/projects/scala-java-annotation-processor/mixed_scala_java/src/main/java/org/hello/WorldJava.java create mode 100644 src/functionalTest/resources/projects/scala-java-annotation-processor/mixed_scala_java/src/main/scala/org/hello/WorldScala.scala create mode 100644 src/functionalTest/resources/projects/scala-java-annotation-processor/mixed_scala_java/src/test/java/org/hello/WorldJavaTest.java create mode 100644 src/functionalTest/resources/projects/scala-java-annotation-processor/mixed_scala_java/src/test/scala/org/hello/WorldScalaSuite.scala create mode 100644 src/functionalTest/resources/projects/scala-java-annotation-processor/settings.gradle diff --git a/src/functionalTest/java/org/scoverage/ScalaJavaAnnotationProcessorTest.java b/src/functionalTest/java/org/scoverage/ScalaJavaAnnotationProcessorTest.java new file mode 100644 index 0000000..ba82eae --- /dev/null +++ b/src/functionalTest/java/org/scoverage/ScalaJavaAnnotationProcessorTest.java @@ -0,0 +1,56 @@ +package org.scoverage; + +import org.gradle.testkit.runner.TaskOutcome; +import org.junit.Assert; +import org.junit.Test; + +import java.io.File; + +public class ScalaJavaAnnotationProcessorTest extends ScoverageFunctionalTest { + + public ScalaJavaAnnotationProcessorTest() { + super("scala-java-annotation-processor"); + } + + @Test + public void checkAndAggregateScoverage() throws Exception { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME(), + ScoveragePlugin.getAGGREGATE_NAME()); + + result.assertTaskSkipped("java_only:" + ScoveragePlugin.getCOMPILE_NAME()); + + result.assertTaskSkipped(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("mixed_scala_java:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSkipped("java_only:" + ScoveragePlugin.getREPORT_NAME()); + + result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded("mixed_scala_java:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSkipped("java_only:" + ScoveragePlugin.getCHECK_NAME()); + + result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); + + assertAllReportFilesExist(); + assertCoverage(100.0); + } + + private void assertAllReportFilesExist() { + + Assert.assertTrue(resolve(reportDir(), "index.html").exists()); + + assertMixedScalaJavaReportFilesExist(); + assertAggregationFilesExist(); + } + + private void assertAggregationFilesExist() { + + Assert.assertTrue(resolve(reportDir(), "mixed_scala_java/src/main/scala/org/hello/WorldScala.scala.html").exists()); + } + + private void assertMixedScalaJavaReportFilesExist() { + + File reportDir = reportDir(projectDir().toPath().resolve("mixed_scala_java").toFile()); + Assert.assertTrue(resolve(reportDir, "index.html").exists()); + Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/WorldScala.scala.html").exists()); + } +} diff --git a/src/functionalTest/resources/projects/scala-java-annotation-processor/build.gradle b/src/functionalTest/resources/projects/scala-java-annotation-processor/build.gradle new file mode 100644 index 0000000..9e5797f --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-annotation-processor/build.gradle @@ -0,0 +1,50 @@ +plugins { + id 'org.scoverage' apply false +} + +description = 'a multi-module Scala and Java project using a Java annotation processor' + +allprojects { + repositories { + jcenter() + } +} + +def lombokVersion = '1.18.20' + +subprojects { + apply plugin: 'java' + + dependencies { + testImplementation group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + compileOnly "org.projectlombok:lombok:$lombokVersion" + annotationProcessor "org.projectlombok:lombok:$lombokVersion" + + testCompileOnly "org.projectlombok:lombok:$lombokVersion" + testAnnotationProcessor "org.projectlombok:lombok:$lombokVersion" + } + + test { + useJUnitPlatform() + } +} + +/* +Because the Scala compiler doesn't support annotation processors, Java files using a Java annotation +processor MUST be compiled by the Java compiler. So we can't use the same +configuration as in `scala-java-multi-module` here. + +// A common practice in mixed java/scala modules to make Java code able to import Scala code +ext.configureSources = { set, name -> + set.scala.srcDir("src/$name/java") + set.java.srcDirs = [] +} +configureSources(sourceSets.main, 'main') +configureSources(sourceSets.test, 'test') +*/ + +apply plugin: 'org.scoverage' +scoverage { + minimumRate = 0.5 +} diff --git a/src/functionalTest/resources/projects/scala-java-annotation-processor/java_only/build.gradle b/src/functionalTest/resources/projects/scala-java-annotation-processor/java_only/build.gradle new file mode 100644 index 0000000..69fe4c7 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-annotation-processor/java_only/build.gradle @@ -0,0 +1,3 @@ +dependencies { + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion +} diff --git a/src/functionalTest/resources/projects/scala-java-annotation-processor/java_only/src/main/java/org/hello/WorldJavaOnly.java b/src/functionalTest/resources/projects/scala-java-annotation-processor/java_only/src/main/java/org/hello/WorldJavaOnly.java new file mode 100644 index 0000000..27f643b --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-annotation-processor/java_only/src/main/java/org/hello/WorldJavaOnly.java @@ -0,0 +1,8 @@ +package org.hello; + +import lombok.Value; + +@Value +public class WorldJavaOnly { + private final String foo = "java_only"; +} diff --git a/src/functionalTest/resources/projects/scala-java-annotation-processor/java_only/src/test/java/org/hello/WorldJavaOnlyTest.java b/src/functionalTest/resources/projects/scala-java-annotation-processor/java_only/src/test/java/org/hello/WorldJavaOnlyTest.java new file mode 100644 index 0000000..9a029b2 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-annotation-processor/java_only/src/test/java/org/hello/WorldJavaOnlyTest.java @@ -0,0 +1,11 @@ +package org.hello; + +import org.junit.Test; + +public class WorldJavaOnlyTest { + + @Test + public void foo() { + new WorldJavaOnly().foo(); + } +} diff --git a/src/functionalTest/resources/projects/scala-java-annotation-processor/lombok.config b/src/functionalTest/resources/projects/scala-java-annotation-processor/lombok.config new file mode 100644 index 0000000..3d2c462 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-annotation-processor/lombok.config @@ -0,0 +1 @@ +lombok.accessors.fluent=true diff --git a/src/functionalTest/resources/projects/scala-java-annotation-processor/mixed_scala_java/build.gradle b/src/functionalTest/resources/projects/scala-java-annotation-processor/mixed_scala_java/build.gradle new file mode 100644 index 0000000..c0021f0 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-annotation-processor/mixed_scala_java/build.gradle @@ -0,0 +1,14 @@ +apply plugin: 'scala' + +dependencies { + implementation group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + + testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion +} + +apply plugin: 'org.scoverage' +scoverage { + minimumRate = 0.5 +} diff --git a/src/functionalTest/resources/projects/scala-java-annotation-processor/mixed_scala_java/src/main/java/org/hello/WorldJava.java b/src/functionalTest/resources/projects/scala-java-annotation-processor/mixed_scala_java/src/main/java/org/hello/WorldJava.java new file mode 100644 index 0000000..0bcf847 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-annotation-processor/mixed_scala_java/src/main/java/org/hello/WorldJava.java @@ -0,0 +1,8 @@ +package org.hello; + +import lombok.Value; + +@Value +public class WorldJava { + private final String foo = "java"; +} diff --git a/src/functionalTest/resources/projects/scala-java-annotation-processor/mixed_scala_java/src/main/scala/org/hello/WorldScala.scala b/src/functionalTest/resources/projects/scala-java-annotation-processor/mixed_scala_java/src/main/scala/org/hello/WorldScala.scala new file mode 100644 index 0000000..3e46057 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-annotation-processor/mixed_scala_java/src/main/scala/org/hello/WorldScala.scala @@ -0,0 +1,7 @@ +package org.hello + +class WorldScala { + private val worldJava = new WorldJava() + + def foo() = worldJava.foo() +} diff --git a/src/functionalTest/resources/projects/scala-java-annotation-processor/mixed_scala_java/src/test/java/org/hello/WorldJavaTest.java b/src/functionalTest/resources/projects/scala-java-annotation-processor/mixed_scala_java/src/test/java/org/hello/WorldJavaTest.java new file mode 100644 index 0000000..316815c --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-annotation-processor/mixed_scala_java/src/test/java/org/hello/WorldJavaTest.java @@ -0,0 +1,11 @@ +package org.hello; + +import org.junit.Test; + +public class WorldJavaTest { + + @Test + public void foo() { + new WorldJava().foo(); + } +} diff --git a/src/functionalTest/resources/projects/scala-java-annotation-processor/mixed_scala_java/src/test/scala/org/hello/WorldScalaSuite.scala b/src/functionalTest/resources/projects/scala-java-annotation-processor/mixed_scala_java/src/test/scala/org/hello/WorldScalaSuite.scala new file mode 100644 index 0000000..08edf75 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-annotation-processor/mixed_scala_java/src/test/scala/org/hello/WorldScalaSuite.scala @@ -0,0 +1,13 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldScalaSuite extends FunSuite { + + test("foo") { + new WorldScala().foo() + } +} diff --git a/src/functionalTest/resources/projects/scala-java-annotation-processor/settings.gradle b/src/functionalTest/resources/projects/scala-java-annotation-processor/settings.gradle new file mode 100644 index 0000000..57567e8 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-annotation-processor/settings.gradle @@ -0,0 +1 @@ +include 'java_only', 'mixed_scala_java' diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 063ba04..f13ac44 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -87,6 +87,7 @@ class ScoveragePlugin implements Plugin { java.source(originalSourceSet.java) scala.source(originalSourceSet.scala) + annotationProcessorPath += originalSourceSet.annotationProcessorPath + project.configurations.scoverage compileClasspath += originalSourceSet.compileClasspath + project.configurations.scoverage runtimeClasspath = it.output + project.configurations.scoverage + originalSourceSet.runtimeClasspath } From 7586ad8a8c4cfc1133d55d1670b0dfbeb274bc23 Mon Sep 17 00:00:00 2001 From: Helder Pereira Date: Sun, 8 Aug 2021 20:11:01 +0100 Subject: [PATCH 126/167] Replace jcenter() by mavenCentral() --- build.gradle | 2 +- .../projects/scala-multi-module-cross-version/build.gradle | 2 +- .../resources/projects/composite-build/proj1/build.gradle | 2 +- .../resources/projects/composite-build/proj2/build.gradle | 2 +- .../projects/detect-scala-library/compile/build.gradle | 2 +- .../projects/detect-scala-library/compileOnly/build.gradle | 2 +- .../detect-scala-library/dependency-management/build.gradle | 2 +- .../gradle-consistent-versions/build.gradle | 2 +- .../projects/detect-scala-library/implementation/build.gradle | 2 +- .../multi-module-plugin-not-configured-for-scala/build.gradle | 2 +- .../projects/multiple-check-tasks/multiple-checks/build.gradle | 2 +- .../projects/multiple-check-tasks/no-check/build.gradle | 2 +- .../multiple-check-tasks/old-and-new-syntax/build.gradle | 2 +- .../multiple-check-tasks/single-check-new-syntax/build.gradle | 2 +- .../multiple-check-tasks/single-check-old-syntax/build.gradle | 2 +- .../resources/projects/scala-java-multi-module/build.gradle | 2 +- .../scala-multi-module-multiple-test-tasks/build.gradle | 2 +- .../scala-multi-module-with-partial-scoverage-use/build.gradle | 2 +- .../resources/projects/scala-multi-module/build.gradle | 2 +- .../scala-single-module-dependency-manager/build.gradle | 2 +- .../scala-single-module-multiple-test-tasks/build.gradle | 2 +- .../resources/projects/scala-single-module/build.gradle | 2 +- 22 files changed, 22 insertions(+), 22 deletions(-) diff --git a/build.gradle b/build.gradle index 2ccabbb..25d51c7 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } group 'org.scoverage' diff --git a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/build.gradle b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/build.gradle index f9d1535..38e7b9f 100644 --- a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/build.gradle +++ b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/build.gradle @@ -4,7 +4,7 @@ plugins { allprojects { repositories { - jcenter() + mavenCentral() } } diff --git a/src/functionalTest/resources/projects/composite-build/proj1/build.gradle b/src/functionalTest/resources/projects/composite-build/proj1/build.gradle index 897dc59..88cbf46 100644 --- a/src/functionalTest/resources/projects/composite-build/proj1/build.gradle +++ b/src/functionalTest/resources/projects/composite-build/proj1/build.gradle @@ -3,7 +3,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } description = 'a single-module Scala project taking part in a composite build (1)' diff --git a/src/functionalTest/resources/projects/composite-build/proj2/build.gradle b/src/functionalTest/resources/projects/composite-build/proj2/build.gradle index 99bf400..8ea2bff 100644 --- a/src/functionalTest/resources/projects/composite-build/proj2/build.gradle +++ b/src/functionalTest/resources/projects/composite-build/proj2/build.gradle @@ -3,7 +3,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } description = 'a single-module Scala project taking part in a composite build (2)' diff --git a/src/functionalTest/resources/projects/detect-scala-library/compile/build.gradle b/src/functionalTest/resources/projects/detect-scala-library/compile/build.gradle index be9936b..50a45ca 100644 --- a/src/functionalTest/resources/projects/detect-scala-library/compile/build.gradle +++ b/src/functionalTest/resources/projects/detect-scala-library/compile/build.gradle @@ -3,7 +3,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } description = 'defines scala library using the "implementation" configuration' diff --git a/src/functionalTest/resources/projects/detect-scala-library/compileOnly/build.gradle b/src/functionalTest/resources/projects/detect-scala-library/compileOnly/build.gradle index 4dd36e8..8444413 100644 --- a/src/functionalTest/resources/projects/detect-scala-library/compileOnly/build.gradle +++ b/src/functionalTest/resources/projects/detect-scala-library/compileOnly/build.gradle @@ -3,7 +3,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } description = 'defines scala library using the "compileOnly" configuration' diff --git a/src/functionalTest/resources/projects/detect-scala-library/dependency-management/build.gradle b/src/functionalTest/resources/projects/detect-scala-library/dependency-management/build.gradle index c4de0c2..9232cf4 100644 --- a/src/functionalTest/resources/projects/detect-scala-library/dependency-management/build.gradle +++ b/src/functionalTest/resources/projects/detect-scala-library/dependency-management/build.gradle @@ -4,7 +4,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } description = 'defines scala library using the "implementation" configuration and the dependency-management plugin' diff --git a/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/build.gradle b/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/build.gradle index 9e4d81d..1b0f2f4 100644 --- a/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/build.gradle +++ b/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/build.gradle @@ -4,7 +4,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } description = 'defines scala library using the "implementation" configuration and the gradle-consistent-versions plugin' diff --git a/src/functionalTest/resources/projects/detect-scala-library/implementation/build.gradle b/src/functionalTest/resources/projects/detect-scala-library/implementation/build.gradle index be9936b..50a45ca 100644 --- a/src/functionalTest/resources/projects/detect-scala-library/implementation/build.gradle +++ b/src/functionalTest/resources/projects/detect-scala-library/implementation/build.gradle @@ -3,7 +3,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } description = 'defines scala library using the "implementation" configuration' diff --git a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/build.gradle b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/build.gradle index ba236a7..7fd12a9 100644 --- a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/build.gradle +++ b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/build.gradle @@ -6,7 +6,7 @@ description = 'a multi-module Scala and Java project that defines scoverage only allprojects { repositories { - jcenter() + mavenCentral() } } diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/multiple-checks/build.gradle b/src/functionalTest/resources/projects/multiple-check-tasks/multiple-checks/build.gradle index 4c0a9fb..ba61184 100644 --- a/src/functionalTest/resources/projects/multiple-check-tasks/multiple-checks/build.gradle +++ b/src/functionalTest/resources/projects/multiple-check-tasks/multiple-checks/build.gradle @@ -3,7 +3,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } description = 'a single-module Scala project that has multiple check configurations' diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/no-check/build.gradle b/src/functionalTest/resources/projects/multiple-check-tasks/no-check/build.gradle index 3ad1fea..e9f2522 100644 --- a/src/functionalTest/resources/projects/multiple-check-tasks/no-check/build.gradle +++ b/src/functionalTest/resources/projects/multiple-check-tasks/no-check/build.gradle @@ -3,7 +3,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } description = 'a single-module Scala project with no check configured' diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/old-and-new-syntax/build.gradle b/src/functionalTest/resources/projects/multiple-check-tasks/old-and-new-syntax/build.gradle index 3e69976..1b5137e 100644 --- a/src/functionalTest/resources/projects/multiple-check-tasks/old-and-new-syntax/build.gradle +++ b/src/functionalTest/resources/projects/multiple-check-tasks/old-and-new-syntax/build.gradle @@ -3,7 +3,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } description = 'a single-module Scala project that has multiple check configurations - some new syntax, some old' diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/single-check-new-syntax/build.gradle b/src/functionalTest/resources/projects/multiple-check-tasks/single-check-new-syntax/build.gradle index 8be7d9a..c3b22ec 100644 --- a/src/functionalTest/resources/projects/multiple-check-tasks/single-check-new-syntax/build.gradle +++ b/src/functionalTest/resources/projects/multiple-check-tasks/single-check-new-syntax/build.gradle @@ -3,7 +3,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } description = 'a single-module Scala project that has a single check configurations (with the new syntax)' diff --git a/src/functionalTest/resources/projects/multiple-check-tasks/single-check-old-syntax/build.gradle b/src/functionalTest/resources/projects/multiple-check-tasks/single-check-old-syntax/build.gradle index 719e14e..8d7c020 100644 --- a/src/functionalTest/resources/projects/multiple-check-tasks/single-check-old-syntax/build.gradle +++ b/src/functionalTest/resources/projects/multiple-check-tasks/single-check-old-syntax/build.gradle @@ -3,7 +3,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } description = 'a single-module Scala project that has a single check configurations (with the old syntax)' diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/build.gradle b/src/functionalTest/resources/projects/scala-java-multi-module/build.gradle index 40e08b7..fa88c6f 100644 --- a/src/functionalTest/resources/projects/scala-java-multi-module/build.gradle +++ b/src/functionalTest/resources/projects/scala-java-multi-module/build.gradle @@ -6,7 +6,7 @@ description = 'a multi-module Scala and Java project that builds successfully wi allprojects { repositories { - jcenter() + mavenCentral() } } diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle index 7bf8c92..af770c5 100644 --- a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle @@ -4,7 +4,7 @@ plugins { allprojects { repositories { - jcenter() + mavenCentral() } } diff --git a/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/build.gradle index 4205b6a..512b324 100644 --- a/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/build.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use/build.gradle @@ -6,7 +6,7 @@ description = 'a multi-module Scala project that builds successfully and has mod allprojects { p -> repositories { - jcenter() + mavenCentral() } apply plugin: 'java' diff --git a/src/functionalTest/resources/projects/scala-multi-module/build.gradle b/src/functionalTest/resources/projects/scala-multi-module/build.gradle index 9235b85..0177c34 100644 --- a/src/functionalTest/resources/projects/scala-multi-module/build.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module/build.gradle @@ -6,7 +6,7 @@ description = 'a multi-module Scala project that builds successfully with 100% c allprojects { p -> repositories { - jcenter() + mavenCentral() } if (p.name != 'dependencies') { diff --git a/src/functionalTest/resources/projects/scala-single-module-dependency-manager/build.gradle b/src/functionalTest/resources/projects/scala-single-module-dependency-manager/build.gradle index 84d3e1c..7c1f4e6 100644 --- a/src/functionalTest/resources/projects/scala-single-module-dependency-manager/build.gradle +++ b/src/functionalTest/resources/projects/scala-single-module-dependency-manager/build.gradle @@ -4,7 +4,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } description = 'a single-module Scala project with dependency manager that builds successfully with 100% coverage' diff --git a/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle index fcf174b..a10ddbb 100644 --- a/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle +++ b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle @@ -4,7 +4,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } description = 'a single-module Scala project with dependency manager that builds successfully with 100% coverage' diff --git a/src/functionalTest/resources/projects/scala-single-module/build.gradle b/src/functionalTest/resources/projects/scala-single-module/build.gradle index e96efe1..593f52e 100644 --- a/src/functionalTest/resources/projects/scala-single-module/build.gradle +++ b/src/functionalTest/resources/projects/scala-single-module/build.gradle @@ -3,7 +3,7 @@ plugins { } repositories { - jcenter() + mavenCentral() } description = 'a single-module Scala project that builds successfully with 50% coverage' From 4a1112800b6b51d1013df4c86a11f2697e267105 Mon Sep 17 00:00:00 2001 From: Helder Pereira Date: Fri, 13 Aug 2021 08:48:11 +0100 Subject: [PATCH 127/167] Fix deprecated destinationDir property --- build.gradle | 10 ++++++++-- .../scoverage/ScalaCrossVersionAggregationTest.java | 7 ------- .../java/org/scoverage/CompositeBuildTest.java | 2 +- .../java/org/scoverage/ScalaJavaMultiModuleTest.java | 1 - .../java/org/scoverage/ScoverageFunctionalTest.java | 7 ++++--- src/main/groovy/org/scoverage/CoverageChecker.groovy | 2 +- src/main/groovy/org/scoverage/ScoveragePlugin.groovy | 9 ++++++--- src/main/groovy/org/scoverage/ScoverageRunner.groovy | 2 +- 8 files changed, 21 insertions(+), 19 deletions(-) diff --git a/build.gradle b/build.gradle index 03f32f4..0b56067 100644 --- a/build.gradle +++ b/build.gradle @@ -84,7 +84,10 @@ task crossScalaVersionTest(type: Test) { classpath = sourceSets.crossScalaVersionTest.runtimeClasspath forkEvery = 1 // crucial to run every test in its own JVM - testLogging.showStandardStreams = true + testLogging { + events 'passed', 'failed', 'skipped' + showStandardStreams = System.env.CI == 'true' + } mustRunAfter test } @@ -96,7 +99,10 @@ task functionalTest(type: Test) { testClassesDirs = sourceSets.functionalTest.output classpath = sourceSets.functionalTest.runtimeClasspath - testLogging.showStandardStreams = true + testLogging { + events 'passed', 'failed', 'skipped' + showStandardStreams = System.env.CI == 'true' + } mustRunAfter crossScalaVersionTest } diff --git a/src/crossScalaVersionTest/java/org/scoverage/ScalaCrossVersionAggregationTest.java b/src/crossScalaVersionTest/java/org/scoverage/ScalaCrossVersionAggregationTest.java index 62850aa..e6c3bf3 100644 --- a/src/crossScalaVersionTest/java/org/scoverage/ScalaCrossVersionAggregationTest.java +++ b/src/crossScalaVersionTest/java/org/scoverage/ScalaCrossVersionAggregationTest.java @@ -2,13 +2,6 @@ import org.junit.Assert; import org.junit.Test; -import org.junit.jupiter.api.Tag; -import org.junit.runner.RunWith; -import org.junit.runners.Suite; -import org.scoverage.ScoverageFunctionalTest; -import org.scoverage.ScoveragePlugin; - -import java.io.File; public class ScalaCrossVersionAggregationTest extends ScoverageFunctionalTest { diff --git a/src/functionalTest/java/org/scoverage/CompositeBuildTest.java b/src/functionalTest/java/org/scoverage/CompositeBuildTest.java index 98a9ee8..21a5c6d 100644 --- a/src/functionalTest/java/org/scoverage/CompositeBuildTest.java +++ b/src/functionalTest/java/org/scoverage/CompositeBuildTest.java @@ -34,7 +34,7 @@ public void reportComposite() { private AssertableBuildResult runComposite(String... arguments) { - List fullArguments = new ArrayList(); + List fullArguments = new ArrayList<>(); fullArguments.add("-p"); fullArguments.add("proj1"); fullArguments.add("--include-build"); diff --git a/src/functionalTest/java/org/scoverage/ScalaJavaMultiModuleTest.java b/src/functionalTest/java/org/scoverage/ScalaJavaMultiModuleTest.java index 6f094bf..8a35add 100644 --- a/src/functionalTest/java/org/scoverage/ScalaJavaMultiModuleTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaJavaMultiModuleTest.java @@ -1,6 +1,5 @@ package org.scoverage; -import org.gradle.testkit.runner.TaskOutcome; import org.junit.Assert; import org.junit.Test; diff --git a/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java b/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java index c1bd0b1..e08d1e5 100644 --- a/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java +++ b/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java @@ -1,7 +1,7 @@ package org.scoverage; import groovy.util.Node; -import groovy.util.XmlParser; +import groovy.xml.XmlParser; import org.gradle.testkit.runner.BuildResult; import org.gradle.testkit.runner.BuildTask; import org.gradle.testkit.runner.GradleRunner; @@ -87,7 +87,7 @@ protected AssertableBuildResult runAndFail(String... arguments) { protected AssertableBuildResult dryRun(String... arguments) { - List withDryArgument = new ArrayList(Arrays.asList(arguments)); + List withDryArgument = new ArrayList<>(Arrays.asList(arguments)); withDryArgument.add("--dry-run"); return run(withDryArgument.toArray(new String[]{})); } @@ -119,7 +119,7 @@ private Double coverage(File reportDir, CoverageType coverageType) throws IOExce private void configureArguments(String... arguments) { - List fullArguments = new ArrayList(); + List fullArguments = new ArrayList<>(); fullArguments.add("-PscalaVersionMajor=2"); fullArguments.add("-PscalaVersionMinor=12"); @@ -127,6 +127,7 @@ private void configureArguments(String... arguments) { fullArguments.add("-PjunitVersion=5.3.2"); fullArguments.add("-PjunitPlatformVersion=1.3.2"); fullArguments.add("-PscalatestVersion=3.0.8"); + fullArguments.add("--warning-mode=all"); fullArguments.addAll(Arrays.asList(arguments)); runner.withArguments(fullArguments); diff --git a/src/main/groovy/org/scoverage/CoverageChecker.groovy b/src/main/groovy/org/scoverage/CoverageChecker.groovy index d647f12..1af7b4e 100644 --- a/src/main/groovy/org/scoverage/CoverageChecker.groovy +++ b/src/main/groovy/org/scoverage/CoverageChecker.groovy @@ -1,6 +1,6 @@ package org.scoverage - +import groovy.xml.XmlParser import org.gradle.api.GradleException import org.gradle.api.logging.Logger import org.gradle.internal.impldep.com.google.common.annotations.VisibleForTesting diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index f13ac44..a772060 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -28,7 +28,7 @@ class ScoveragePlugin implements Plugin { static final String DEFAULT_REPORT_DIR = 'reports' + File.separatorChar + 'scoverage' - private final ConcurrentHashMap> taskDependencies = new ConcurrentHashMap<>(); + private final ConcurrentHashMap> taskDependencies = new ConcurrentHashMap<>() @Override void apply(PluginAware pluginAware) { @@ -232,9 +232,10 @@ class ScoveragePlugin implements Plugin { compileTask.configure { if (!graph.hasTask(originalCompileTask)) { project.logger.info("Making scoverage compilation the primary compilation task (instead of compileScala)") - destinationDir = originalCompileTask.destinationDir + destinationDirectory = originalCompileTask.destinationDirectory } else { doFirst { + def destinationDir = destinationDirectory.get().asFile destinationDir.deleteDir() } @@ -243,7 +244,9 @@ class ScoveragePlugin implements Plugin { project.logger.info("Deleting classes compiled by scoverage but non-instrumented (identical to normal compilation)") def originalCompileTaskName = project.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) .getCompileTaskName("scala") - def originalDestinationDir = project.tasks[originalCompileTaskName].destinationDir + def originalDestinationDirectory = project.tasks[originalCompileTaskName].destinationDirectory + def originalDestinationDir = originalDestinationDirectory.get().asFile + def destinationDir = destinationDirectory.get().asFile def findFiles = { File dir, Closure condition = null -> def files = [] diff --git a/src/main/groovy/org/scoverage/ScoverageRunner.groovy b/src/main/groovy/org/scoverage/ScoverageRunner.groovy index 713b9e4..a5dd552 100644 --- a/src/main/groovy/org/scoverage/ScoverageRunner.groovy +++ b/src/main/groovy/org/scoverage/ScoverageRunner.groovy @@ -23,7 +23,7 @@ class ScoverageRunner { method.setAccessible(true) runtimeClasspath.files.each { f -> - def url = f.toURL() + def url = f.toURI().toURL() if (!cloader.getURLs().contains(url)) { method.invoke(cloader, url) } From 8779b73173fd8afb29da9fd3db88139e444e8cbd Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Sat, 21 Aug 2021 16:30:03 +0300 Subject: [PATCH 128/167] Change running without normal compilation to a property so its configuration could be made only when the mode is enabled --- README.md | 10 +- .../org/scoverage/ScalaMultiModuleTest.java | 17 +- ...aMultiModuleWithMultipleTestTasksTest.java | 4 +- .../org/scoverage/ScalaSingleModuleTest.java | 6 +- ...SingleModuleWithMultipleTestTasksTest.java | 4 +- .../org/scoverage/ScoveragePlugin.groovy | 146 +++++++++--------- 6 files changed, 103 insertions(+), 84 deletions(-) diff --git a/README.md b/README.md index 7048e70..6792d00 100644 --- a/README.md +++ b/README.md @@ -112,9 +112,10 @@ and using the scoverage scalac plugin (`compileScoverageScala`). In cases where you only wish to generate reports / validate coverage, but are not interested in publishing the code, it is possible to only compile the code with the scoverage scalac plugin, thus reducing build times significantly. -In order to do so, simply add the arguments `-x compileScala` to the gradle execution. -For example: `gradle reportScoverage -x compileScala`. +In order to do so, simply add the arguments `-PscoverageCompileOnly` to the gradle execution. +For example: `gradle reportScoverage -PscoverageCompileOnly`. +Note that this mode is incompatible with parallel builds in multi-module projects. ### Compatibility with Consistent Versions Plugin @@ -122,6 +123,11 @@ In order for the plugin to work alongside [Palantir's consistent versions plugin the Scala version must be manually configured (via `scoverageScalaVersion`); otherwise, the plugin will attempt to resolve the compilation classpath, which is prohibited by the versions plugin. +Migration to 6.1.1 +---------------- + +* Running without normal compilation is now made with `-PscoverageCompileOnly` instead of `-x compileScala`. + Migration to 5.x ---------------- diff --git a/src/functionalTest/java/org/scoverage/ScalaMultiModuleTest.java b/src/functionalTest/java/org/scoverage/ScalaMultiModuleTest.java index 6442b1b..87f5c02 100644 --- a/src/functionalTest/java/org/scoverage/ScalaMultiModuleTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaMultiModuleTest.java @@ -22,6 +22,17 @@ public void reportScoverage() { result.assertTaskExists("common:" + ScoveragePlugin.getREPORT_NAME()); } + @Test + public void reportScoverageParallel() { + + AssertableBuildResult result = dryRun("clean", ScoveragePlugin.getREPORT_NAME(), "--parallel"); + + result.assertTaskExists(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("a:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("b:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("common:" + ScoveragePlugin.getREPORT_NAME()); + } + @Test public void reportScoverageOnlyRoot() { @@ -52,7 +63,7 @@ public void reportScoverageOnlyA() { public void reportScoverageOnlyAWithoutNormalCompilation() { AssertableBuildResult result = run("clean", ":a:" + ScoveragePlugin.getREPORT_NAME(), - "-x", "compileScala"); + "-P" + ScoveragePlugin.getSCOVERAGE_COMPILE_ONLY_PROPERTY()); result.assertTaskSkipped("compileScala"); result.assertTaskSkipped("a:compileScala"); @@ -186,7 +197,7 @@ public void checkScoverageWithoutNormalCompilationAndWithoutCoverageInCommon() t AssertableBuildResult result = runAndFail("clean", ":a:test", ":common:test", "--tests", "org.hello.common.TestNothingCommonSuite", - "-x", "compileScala", + "-P" + ScoveragePlugin.getSCOVERAGE_COMPILE_ONLY_PROPERTY(), ScoveragePlugin.getCHECK_NAME()); result.assertTaskFailed("common:" + ScoveragePlugin.getCHECK_NAME()); @@ -246,7 +257,7 @@ public void checkAndAggregateScoverageWithoutCoverageInAll() throws Exception { public void aggregateScoverageWithoutNormalCompilation() throws Exception { AssertableBuildResult result = run("clean", ScoveragePlugin.getAGGREGATE_NAME(), - "-x", "compileScala"); + "-P" + ScoveragePlugin.getSCOVERAGE_COMPILE_ONLY_PROPERTY()); result.assertTaskSkipped("compileScala"); result.assertTaskSkipped("a:compileScala"); diff --git a/src/functionalTest/java/org/scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java b/src/functionalTest/java/org/scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java index 1905a1c..49d0bc1 100644 --- a/src/functionalTest/java/org/scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java @@ -193,7 +193,7 @@ public void checkScoverageWithoutNormalCompilationAndWithoutCoverageInCommon() t AssertableBuildResult result = runAndFail("clean", ":a:test", ":common:test", "--tests", "org.hello.common.TestNothingCommonSuite", - "-x", "compileScala", + "-P" + ScoveragePlugin.getSCOVERAGE_COMPILE_ONLY_PROPERTY(), ScoveragePlugin.getCHECK_NAME()); result.assertTaskFailed("common:" + ScoveragePlugin.getCHECK_NAME()); @@ -254,7 +254,7 @@ public void checkAndAggregateScoverageWithoutCoverageInAll() throws Exception { public void aggregateScoverageWithoutNormalCompilation() throws Exception { AssertableBuildResult result = run("clean", ScoveragePlugin.getAGGREGATE_NAME(), - "-x", "compileScala"); + "-P" + ScoveragePlugin.getSCOVERAGE_COMPILE_ONLY_PROPERTY()); result.assertTaskSkipped("compileScala"); result.assertTaskSkipped("a:compileScala"); diff --git a/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java b/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java index f93e184..de9da68 100644 --- a/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java @@ -103,7 +103,7 @@ public void reportScoverageWithExcludedClasses() throws Exception { public void reportScoverageWithoutNormalCompilation() throws Exception { AssertableBuildResult result = run("clean", ScoveragePlugin.getREPORT_NAME(), - "-x", "compileScala"); + "-P" + ScoveragePlugin.getSCOVERAGE_COMPILE_ONLY_PROPERTY()); result.assertTaskSkipped("compileScala"); result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); @@ -122,7 +122,7 @@ public void reportScoverageWithoutNormalCompilation() throws Exception { public void reportScoverageWithoutNormalCompilationAndWithExcludedClasses() throws Exception { AssertableBuildResult result = run("clean", ScoveragePlugin.getREPORT_NAME(), - "-PexcludedFile=.*", "-x", "compileScala"); + "-PexcludedFile=.*", "-P" + ScoveragePlugin.getSCOVERAGE_COMPILE_ONLY_PROPERTY()); Assert.assertTrue(resolve(reportDir(), "index.html").exists()); Assert.assertFalse(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); @@ -138,4 +138,4 @@ private void assertReportFilesExist() { Assert.assertTrue(resolve(reportDir(), "index.html").exists()); Assert.assertTrue(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); } -} \ No newline at end of file +} diff --git a/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java b/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java index 3d09d61..0511eb5 100644 --- a/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java @@ -121,7 +121,7 @@ public void reportScoverageWithExcludedClasses() throws Exception { public void reportScoverageWithoutNormalCompilation() throws Exception { AssertableBuildResult result = run("clean", ScoveragePlugin.getREPORT_NAME(), - "-x", "compileScala"); + "-P" + ScoveragePlugin.getSCOVERAGE_COMPILE_ONLY_PROPERTY()); result.assertTaskSkipped("compileScala"); result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); @@ -140,7 +140,7 @@ public void reportScoverageWithoutNormalCompilation() throws Exception { public void reportScoverageWithoutNormalCompilationAndWithExcludedClasses() throws Exception { AssertableBuildResult result = run("clean", ScoveragePlugin.getREPORT_NAME(), - "-PexcludedFile=.*", "-x", "compileScala"); + "-PexcludedFile=.*", "-P" + ScoveragePlugin.getSCOVERAGE_COMPILE_ONLY_PROPERTY()); Assert.assertTrue(resolve(reportDir(), "index.html").exists()); Assert.assertFalse(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index a772060..19b0a13 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -25,6 +25,7 @@ class ScoveragePlugin implements Plugin { static final String COMPILE_NAME = 'compileScoverageScala' static final String AGGREGATE_NAME = 'aggregateScoverage' static final String DEFAULT_SCALA_VERSION = '2.13.6' + static final String SCOVERAGE_COMPILE_ONLY_PROPERTY = 'scoverageCompileOnly'; static final String DEFAULT_REPORT_DIR = 'reports' + File.separatorChar + 'scoverage' @@ -97,7 +98,6 @@ class ScoveragePlugin implements Plugin { def compileTask = project.tasks[instrumentedSourceSet.getCompileTaskName("scala")] compileTask.mustRunAfter(originalCompileTask) - originalJarTask.mustRunAfter(compileTask) def globalReportTask = project.tasks.register(REPORT_NAME, ScoverageAggregate) def globalCheckTask = project.tasks.register(CHECK_NAME) @@ -154,24 +154,6 @@ class ScoveragePlugin implements Plugin { configureCheckTask(project, extension, globalCheckTask, globalReportTask) - // make this project's scoverage compilation depend on scoverage compilation of any other project - // which this project depends on its normal compilation - // (essential when running without normal compilation on multi-module projects with inner dependencies) - def originalCompilationDependencies = recursiveDependenciesOf(compileTask).findAll { - it instanceof ScalaCompile - } - originalCompilationDependencies.each { - def dependencyProjectCompileTask = it.project.tasks.findByName(COMPILE_NAME) - def dependencyProjectReportTask = it.project.tasks.findByName(REPORT_NAME) - if (dependencyProjectCompileTask != null) { - compileTask.dependsOn(dependencyProjectCompileTask) - // we don't want this project's tests to affect the other project's report - testTasks.each { - it.mustRunAfter(dependencyProjectReportTask) - } - } - } - compileTask.configure { List parameters = [] List existingParameters = scalaCompileOptions.additionalParameters @@ -207,6 +189,79 @@ class ScoveragePlugin implements Plugin { } } + if (project.hasProperty(SCOVERAGE_COMPILE_ONLY_PROPERTY)) { + project.logger.info("Making scoverage compilation the primary compilation task (instead of compileScala)") + + originalCompileTask.enabled = false; + compileTask.destinationDirectory = originalCompileTask.destinationDirectory + originalJarTask.mustRunAfter(compileTask) + + // make this project's scoverage compilation depend on scoverage compilation of any other project + // which this project depends on its normal compilation + def originalCompilationDependencies = recursiveDependenciesOf(compileTask).findAll { + it instanceof ScalaCompile + } + originalCompilationDependencies.each { + def dependencyProjectCompileTask = it.project.tasks.findByName(COMPILE_NAME) + def dependencyProjectReportTask = it.project.tasks.findByName(REPORT_NAME) + if (dependencyProjectCompileTask != null) { + compileTask.dependsOn(dependencyProjectCompileTask) + // we don't want this project's tests to affect the other project's report + testTasks.each { + it.mustRunAfter(dependencyProjectReportTask) + } + } + } + } else { + compileTask.configure { + doFirst { + destinationDir.deleteDir() + } + + // delete non-instrumented classes by comparing normally compiled classes to those compiled with scoverage + doLast { + project.logger.info("Deleting classes compiled by scoverage but non-instrumented (identical to normal compilation)") + def originalCompileTaskName = project.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) + .getCompileTaskName("scala") + def originalDestinationDirectory = project.tasks[originalCompileTaskName].destinationDirectory + def originalDestinationDir = originalDestinationDirectory.get().asFile + def destinationDir = destinationDirectory.get().asFile + + + def findFiles = { File dir, Closure condition = null -> + def files = [] + + if (dir.exists()) { + dir.eachFileRecurse(FILES) { f -> + if (condition == null || condition(f)) { + def relativePath = dir.relativePath(f) + files << relativePath + } + } + } + + files + } + + def isSameFile = { String relativePath -> + def fileA = new File(originalDestinationDir, relativePath) + def fileB = new File(destinationDir, relativePath) + FileUtils.contentEquals(fileA, fileB) + } + + def originalClasses = findFiles(originalDestinationDir) + def identicalInstrumentedClasses = findFiles(destinationDir, { f -> + def relativePath = destinationDir.relativePath(f) + originalClasses.contains(relativePath) && isSameFile(relativePath) + }) + + identicalInstrumentedClasses.each { f -> + Files.deleteIfExists(destinationDir.toPath().resolve(f)) + } + } + } + } + project.gradle.taskGraph.whenReady { graph -> def hasAnyReportTask = reportTasks.any { graph.hasTask(it) } @@ -228,59 +283,6 @@ class ScoveragePlugin implements Plugin { } } } - - compileTask.configure { - if (!graph.hasTask(originalCompileTask)) { - project.logger.info("Making scoverage compilation the primary compilation task (instead of compileScala)") - destinationDirectory = originalCompileTask.destinationDirectory - } else { - doFirst { - def destinationDir = destinationDirectory.get().asFile - destinationDir.deleteDir() - } - - // delete non-instrumented classes by comparing normally compiled classes to those compiled with scoverage - doLast { - project.logger.info("Deleting classes compiled by scoverage but non-instrumented (identical to normal compilation)") - def originalCompileTaskName = project.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) - .getCompileTaskName("scala") - def originalDestinationDirectory = project.tasks[originalCompileTaskName].destinationDirectory - def originalDestinationDir = originalDestinationDirectory.get().asFile - def destinationDir = destinationDirectory.get().asFile - - def findFiles = { File dir, Closure condition = null -> - def files = [] - - if (dir.exists()) { - dir.eachFileRecurse(FILES) { f -> - if (condition == null || condition(f)) { - def relativePath = dir.relativePath(f) - files << relativePath - } - } - } - - files - } - - def isSameFile = { String relativePath -> - def fileA = new File(originalDestinationDir, relativePath) - def fileB = new File(destinationDir, relativePath) - FileUtils.contentEquals(fileA, fileB) - } - - def originalClasses = findFiles(originalDestinationDir) - def identicalInstrumentedClasses = findFiles(destinationDir, { f -> - def relativePath = destinationDir.relativePath(f) - originalClasses.contains(relativePath) && isSameFile(relativePath) - }) - - identicalInstrumentedClasses.each { f -> - Files.deleteIfExists(destinationDir.toPath().resolve(f)) - } - } - } - } } // define aggregation task From 3a75583968c2aa7ba18b7a0107ba290fe99b455d Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Sat, 21 Aug 2021 17:55:31 +0300 Subject: [PATCH 129/167] #163 Fix deprecation warning from Gradle 7.1.1 about undeclared dependency between report and jar tasks --- src/main/groovy/org/scoverage/ScoveragePlugin.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index a772060..feb77b6 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -119,7 +119,7 @@ class ScoveragePlugin implements Plugin { def taskReportDir = project.file("${project.buildDir}/reports/scoverage${testTask.name.capitalize()}") project.tasks.create(reportTaskName, ScoverageReport) { - dependsOn compileTask, testTask + dependsOn originalJarTask, compileTask, testTask onlyIf { extension.dataDir.get().list() } group = 'verification' runner = scoverageRunner From 1ac48a82395fddb839112537f17093cf666e19bc Mon Sep 17 00:00:00 2001 From: Stu Date: Mon, 23 Aug 2021 12:28:08 +0100 Subject: [PATCH 130/167] bump next version to 7 --- README.md | 2 +- build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6792d00..60bbfae 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ In order for the plugin to work alongside [Palantir's consistent versions plugin the Scala version must be manually configured (via `scoverageScalaVersion`); otherwise, the plugin will attempt to resolve the compilation classpath, which is prohibited by the versions plugin. -Migration to 6.1.1 +Migration to 7.x ---------------- * Running without normal compilation is now made with `-PscoverageCompileOnly` instead of `-x compileScala`. diff --git a/build.gradle b/build.gradle index 0b56067..abbc5eb 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ repositories { group 'org.scoverage' description = 'gradle-scoverage is a Gradle plugin for calculating code coverage using Scoverage' if (project.version == 'unspecified') { - version = '6.0.0-SNAPSHOT' + version = '7.0.0-SNAPSHOT' } ext { website = 'http://scoverage.org' From 2cc7085baec564788322edd81475d924e1245dbc Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Sat, 28 Aug 2021 15:38:44 +0300 Subject: [PATCH 131/167] Upgrade Gradle version from '7.1' to '7.1.1' --- gradle/wrapper/gradle-wrapper.jar | Bin 55616 -> 59536 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 39 +++++++++++------------ gradlew.bat | 27 +++++----------- 4 files changed, 27 insertions(+), 41 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 5c2d1cf016b3885f6930543d57b744ea8c220a1a..7454180f2ae8848c63b8b4dea2cb829da983f2fa 100644 GIT binary patch delta 26482 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 delta 22605 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 69a9715..05679dc 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index b0d6d0a..744e882 100755 --- a/gradlew +++ b/gradlew @@ -7,7 +7,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -72,7 +72,7 @@ case "`uname`" in Darwin* ) darwin=true ;; - MINGW* ) + MSYS* | MINGW* ) msys=true ;; NONSTOP* ) @@ -82,6 +82,7 @@ esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -125,10 +126,11 @@ if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath @@ -154,19 +156,19 @@ if $cygwin ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi @@ -175,14 +177,9 @@ save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } -APP_ARGS=$(save "$@") +APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 15e1ee3..ac1b06f 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -5,7 +5,7 @@ @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem -@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -51,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -61,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell From d7da6b1c5fc470357d1d6baceb7975445d849670 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Sat, 28 Aug 2021 15:39:38 +0300 Subject: [PATCH 132/167] Add a step to the CI build that fails on warnings in the functional tests (doesn't fail the build) --- .github/workflows/gradle.yml | 13 ++++++++++++- build.gradle | 4 +++- .../java/org/scoverage/ScoverageFunctionalTest.java | 6 +++++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 37bbdbf..a8189eb 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -11,8 +11,19 @@ on: jobs: build: + strategy: + fail-fast: false + matrix: + include: + - name: 'ignore warnings' + additional-check-args: '' + continue-on-error: false + - name: 'fail on warning' + additional-check-args: '--warning-mode=fail -PfailOnWarning' + continue-on-error: true runs-on: ubuntu-latest + continue-on-error: ${{ matrix.continue-on-error }} steps: - uses: actions/checkout@v2 @@ -24,4 +35,4 @@ jobs: - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Build with Gradle - run: ./gradlew --info --stacktrace check + run: ./gradlew --info --stacktrace check ${{ matrix.additional-check-args }} diff --git a/build.gradle b/build.gradle index abbc5eb..8e122bd 100644 --- a/build.gradle +++ b/build.gradle @@ -104,6 +104,8 @@ task functionalTest(type: Test) { showStandardStreams = System.env.CI == 'true' } + systemProperty 'failOnWarning', project.hasProperty('failOnWarning') + mustRunAfter crossScalaVersionTest } check.dependsOn functionalTest @@ -206,4 +208,4 @@ idea.project.settings { taskTriggers { beforeBuild fixIdeaPluginClasspath, pluginUnderTestMetadata } -} \ No newline at end of file +} diff --git a/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java b/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java index e08d1e5..051b6bb 100644 --- a/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java +++ b/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java @@ -127,7 +127,11 @@ private void configureArguments(String... arguments) { fullArguments.add("-PjunitVersion=5.3.2"); fullArguments.add("-PjunitPlatformVersion=1.3.2"); fullArguments.add("-PscalatestVersion=3.0.8"); - fullArguments.add("--warning-mode=all"); + if (Boolean.parseBoolean(System.getProperty("failOnWarning"))) { + fullArguments.add("--warning-mode=fail"); + } else { + fullArguments.add("--warning-mode=all"); + } fullArguments.addAll(Arrays.asList(arguments)); runner.withArguments(fullArguments); From 73bd170e48fe2caaa471ef207016daf0b73c6165 Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Sat, 28 Aug 2021 20:55:21 +0300 Subject: [PATCH 133/167] #163 Fix deprecation warning from Gradle 7.1.1 about undeclared dependency between report task and test tasks outputs --- .../ScalaCrossVersionAggregationTest.java | 4 +- .../java/org/scoverage/ScalaVersionTest.java | 4 +- .../ScalaJavaAnnotationProcessorTest.java | 4 +- .../scoverage/ScalaJavaMultiModuleTest.java | 8 +-- .../org/scoverage/ScalaMultiModuleTest.java | 14 +++--- ...aMultiModuleWithMultipleTestTasksTest.java | 14 +++--- .../org/scoverage/ScalaSingleModuleTest.java | 6 +-- ...SingleModuleWithDependencyManagerTest.java | 4 +- ...SingleModuleWithMultipleTestTasksTest.java | 6 +-- .../org/scoverage/ScoverageAggregate.groovy | 11 +++- .../org/scoverage/ScoverageExtension.groovy | 5 -- .../org/scoverage/ScoveragePlugin.groovy | 8 ++- .../org/scoverage/ScoverageReport.groovy | 8 +-- .../groovy/org/scoverage/ScoverageWriter.java | 50 ++++++++++++++++--- 14 files changed, 97 insertions(+), 49 deletions(-) diff --git a/src/crossScalaVersionTest/java/org/scoverage/ScalaCrossVersionAggregationTest.java b/src/crossScalaVersionTest/java/org/scoverage/ScalaCrossVersionAggregationTest.java index e6c3bf3..a7b7e5b 100644 --- a/src/crossScalaVersionTest/java/org/scoverage/ScalaCrossVersionAggregationTest.java +++ b/src/crossScalaVersionTest/java/org/scoverage/ScalaCrossVersionAggregationTest.java @@ -30,7 +30,7 @@ public void checkAndAggregateAll() throws Exception { private void assertAggregationFilesExist() { Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertTrue(resolve(reportDir(), "2_12/src/main/scala/org/hello/World2_12.scala.html").exists()); - Assert.assertTrue(resolve(reportDir(), "2_13/src/main/scala/org/hello/World2_13.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/World2_12.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/World2_13.scala.html").exists()); } } diff --git a/src/crossScalaVersionTest/java/org/scoverage/ScalaVersionTest.java b/src/crossScalaVersionTest/java/org/scoverage/ScalaVersionTest.java index 55a15c8..657ca8e 100644 --- a/src/crossScalaVersionTest/java/org/scoverage/ScalaVersionTest.java +++ b/src/crossScalaVersionTest/java/org/scoverage/ScalaVersionTest.java @@ -27,6 +27,6 @@ public void report() throws Exception { File reportDir = reportDir(projectDir().toPath().resolve(scalaVersion).toFile()); Assert.assertTrue(resolve(reportDir, "index.html").exists()); - Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/World" + scalaVersion + ".scala.html").exists()); + Assert.assertTrue(resolve(reportDir, "org/hello/World" + scalaVersion + ".scala.html").exists()); } -} \ No newline at end of file +} diff --git a/src/functionalTest/java/org/scoverage/ScalaJavaAnnotationProcessorTest.java b/src/functionalTest/java/org/scoverage/ScalaJavaAnnotationProcessorTest.java index ba82eae..c4c2e38 100644 --- a/src/functionalTest/java/org/scoverage/ScalaJavaAnnotationProcessorTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaJavaAnnotationProcessorTest.java @@ -44,13 +44,13 @@ private void assertAllReportFilesExist() { private void assertAggregationFilesExist() { - Assert.assertTrue(resolve(reportDir(), "mixed_scala_java/src/main/scala/org/hello/WorldScala.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/WorldScala.scala.html").exists()); } private void assertMixedScalaJavaReportFilesExist() { File reportDir = reportDir(projectDir().toPath().resolve("mixed_scala_java").toFile()); Assert.assertTrue(resolve(reportDir, "index.html").exists()); - Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/WorldScala.scala.html").exists()); + Assert.assertTrue(resolve(reportDir, "org/hello/WorldScala.scala.html").exists()); } } diff --git a/src/functionalTest/java/org/scoverage/ScalaJavaMultiModuleTest.java b/src/functionalTest/java/org/scoverage/ScalaJavaMultiModuleTest.java index 8a35add..2b09933 100644 --- a/src/functionalTest/java/org/scoverage/ScalaJavaMultiModuleTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaJavaMultiModuleTest.java @@ -46,21 +46,21 @@ private void assertAllReportFilesExist() { private void assertAggregationFilesExist() { - Assert.assertTrue(resolve(reportDir(), "scala_only/src/main/scala/org/hello/WorldScalaOnly.scala.html").exists()); - Assert.assertTrue(resolve(reportDir(), "mixed_scala_java/src/main/scala/org/hello/WorldScala.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/WorldScalaOnly.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/WorldScala.scala.html").exists()); } private void assertScalaOnlyReportFilesExist() { File reportDir = reportDir(projectDir().toPath().resolve("scala_only").toFile()); Assert.assertTrue(resolve(reportDir, "index.html").exists()); - Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/WorldScalaOnly.scala.html").exists()); + Assert.assertTrue(resolve(reportDir, "org/hello/WorldScalaOnly.scala.html").exists()); } private void assertMixedScalaJavaReportFilesExist() { File reportDir = reportDir(projectDir().toPath().resolve("mixed_scala_java").toFile()); Assert.assertTrue(resolve(reportDir, "index.html").exists()); - Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/WorldScala.scala.html").exists()); + Assert.assertTrue(resolve(reportDir, "org/hello/WorldScala.scala.html").exists()); } } diff --git a/src/functionalTest/java/org/scoverage/ScalaMultiModuleTest.java b/src/functionalTest/java/org/scoverage/ScalaMultiModuleTest.java index 87f5c02..5da6f60 100644 --- a/src/functionalTest/java/org/scoverage/ScalaMultiModuleTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaMultiModuleTest.java @@ -297,35 +297,35 @@ private void assertAllReportFilesExist() { private void assertAggregationFilesExist() { - Assert.assertTrue(resolve(reportDir(), "a/src/main/scala/org/hello/a/WorldA.scala.html").exists()); - Assert.assertTrue(resolve(reportDir(), "b/src/main/scala/org/hello/b/WorldB.scala.html").exists()); - Assert.assertTrue(resolve(reportDir(), "common/src/main/scala/org/hello/common/WorldCommon.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/a/WorldA.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/b/WorldB.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/common/WorldCommon.scala.html").exists()); } private void assertRootReportFilesExist() { Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertTrue(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/World.scala.html").exists()); } private void assertAReportFilesExist() { File reportDir = reportDir(projectDir().toPath().resolve("a").toFile()); Assert.assertTrue(resolve(reportDir, "index.html").exists()); - Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/a/WorldA.scala.html").exists()); + Assert.assertTrue(resolve(reportDir, "org/hello/a/WorldA.scala.html").exists()); } private void assertBReportFilesExist() { File reportDir = reportDir(projectDir().toPath().resolve("b").toFile()); Assert.assertTrue(resolve(reportDir, "index.html").exists()); - Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/b/WorldB.scala.html").exists()); + Assert.assertTrue(resolve(reportDir, "org/hello/b/WorldB.scala.html").exists()); } private void assertCommonReportFilesExist() { File reportDir = reportDir(projectDir().toPath().resolve("common").toFile()); Assert.assertTrue(resolve(reportDir, "index.html").exists()); - Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/common/WorldCommon.scala.html").exists()); + Assert.assertTrue(resolve(reportDir, "org/hello/common/WorldCommon.scala.html").exists()); } } diff --git a/src/functionalTest/java/org/scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java b/src/functionalTest/java/org/scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java index 49d0bc1..dc84e1f 100644 --- a/src/functionalTest/java/org/scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java @@ -294,35 +294,35 @@ private void assertAllReportFilesExist() { private void assertAggregationFilesExist() { - Assert.assertTrue(resolve(reportDir(), "a/src/main/scala/org/hello/a/WorldA.scala.html").exists()); - Assert.assertTrue(resolve(reportDir(), "b/src/main/scala/org/hello/b/WorldB.scala.html").exists()); - Assert.assertTrue(resolve(reportDir(), "common/src/main/scala/org/hello/common/WorldCommon.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/a/WorldA.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/b/WorldB.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/common/WorldCommon.scala.html").exists()); } private void assertRootReportFilesExist() { Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertTrue(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/World.scala.html").exists()); } private void assertAReportFilesExist() { File reportDir = reportDir(projectDir().toPath().resolve("a").toFile()); Assert.assertTrue(resolve(reportDir, "index.html").exists()); - Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/a/WorldA.scala.html").exists()); + Assert.assertTrue(resolve(reportDir, "org/hello/a/WorldA.scala.html").exists()); } private void assertBReportFilesExist() { File reportDir = reportDir(projectDir().toPath().resolve("b").toFile()); Assert.assertTrue(resolve(reportDir, "index.html").exists()); - Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/b/WorldB.scala.html").exists()); + Assert.assertTrue(resolve(reportDir, "org/hello/b/WorldB.scala.html").exists()); } private void assertCommonReportFilesExist() { File reportDir = reportDir(projectDir().toPath().resolve("common").toFile()); Assert.assertTrue(resolve(reportDir, "index.html").exists()); - Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/common/WorldCommon.scala.html").exists()); + Assert.assertTrue(resolve(reportDir, "org/hello/common/WorldCommon.scala.html").exists()); } } diff --git a/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java b/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java index de9da68..19e0e82 100644 --- a/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java @@ -91,7 +91,7 @@ public void reportScoverageWithExcludedClasses() throws Exception { result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertFalse(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + Assert.assertFalse(resolve(reportDir(), "org/hello/World.scala.html").exists()); assertCoverage(100.0); // coverage is 100 since no classes are covered // compiled class should exist in the default classes directory, but not in scoverage @@ -125,7 +125,7 @@ public void reportScoverageWithoutNormalCompilationAndWithExcludedClasses() thro "-PexcludedFile=.*", "-P" + ScoveragePlugin.getSCOVERAGE_COMPILE_ONLY_PROPERTY()); Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertFalse(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + Assert.assertFalse(resolve(reportDir(), "org/hello/World.scala.html").exists()); assertCoverage(100.0); // coverage is 100 since no classes are covered // compiled class should exist in the default classes directory, but not in scoverage @@ -136,6 +136,6 @@ public void reportScoverageWithoutNormalCompilationAndWithExcludedClasses() thro private void assertReportFilesExist() { Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertTrue(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/World.scala.html").exists()); } } diff --git a/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithDependencyManagerTest.java b/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithDependencyManagerTest.java index e7f701a..3ce3b63 100644 --- a/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithDependencyManagerTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithDependencyManagerTest.java @@ -26,6 +26,6 @@ public void checkScoverage() throws Exception { private void assertReportFilesExist() { Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertTrue(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/World.scala.html").exists()); } -} \ No newline at end of file +} diff --git a/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java b/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java index 0511eb5..cba1c6a 100644 --- a/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java @@ -109,7 +109,7 @@ public void reportScoverageWithExcludedClasses() throws Exception { result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertFalse(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + Assert.assertFalse(resolve(reportDir(), "org/hello/World.scala.html").exists()); assertCoverage(100.0); // coverage is 100 since no classes are covered // compiled class should exist in the default classes directory, but not in scoverage @@ -143,7 +143,7 @@ public void reportScoverageWithoutNormalCompilationAndWithExcludedClasses() thro "-PexcludedFile=.*", "-P" + ScoveragePlugin.getSCOVERAGE_COMPILE_ONLY_PROPERTY()); Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertFalse(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + Assert.assertFalse(resolve(reportDir(), "org/hello/World.scala.html").exists()); assertCoverage(100.0); // coverage is 100 since no classes are covered // compiled class should exist in the default classes directory, but not in scoverage @@ -155,6 +155,6 @@ public void reportScoverageWithoutNormalCompilationAndWithExcludedClasses() thro private void assertReportFilesExist() { Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertTrue(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/World.scala.html").exists()); } } diff --git a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy index b445e29..9815dd1 100644 --- a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy +++ b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy @@ -1,19 +1,28 @@ package org.scoverage import org.gradle.api.DefaultTask +import org.gradle.api.file.FileCollection import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputFiles import org.gradle.api.tasks.Nested import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.PathSensitive import org.gradle.api.tasks.TaskAction import scoverage.report.CoverageAggregator +import static org.gradle.api.tasks.PathSensitivity.RELATIVE + class ScoverageAggregate extends DefaultTask { @Nested ScoverageRunner runner + @InputFiles + @PathSensitive(RELATIVE) + final Property sources = project.objects.property(FileCollection) + @OutputDirectory final Property reportDir = project.objects.property(File) @@ -52,7 +61,7 @@ class ScoverageAggregate extends DefaultTask { if (coverage.nonEmpty()) { new ScoverageWriter(project.logger).write( - project.projectDir, + sources.get().getFiles(), reportDir.get(), coverage.get(), sourceEncoding.get(), diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index e106306..210a825 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -28,8 +28,6 @@ class ScoverageExtension { final Property dataDir /** a directory to write final output to */ final Property reportDir - /** sources to highlight */ - final Property sources /** range positioning for highlighting */ final Property highlighting /** regex for each excluded package */ @@ -61,9 +59,6 @@ class ScoverageExtension { scoverageScalaVersion = project.objects.property(String) - sources = project.objects.property(File) - sources.set(project.projectDir) - dataDir = project.objects.property(File) dataDir.set(new File(project.buildDir, 'scoverage')) diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index ae5d68e..6191ac7 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -124,7 +124,7 @@ class ScoveragePlugin implements Plugin { group = 'verification' runner = scoverageRunner reportDir = taskReportDir - sources = extension.sources + sources = originalSourceSet.scala.getSourceDirectories() dataDir = extension.dataDir sourceEncoding.set(detectedSourceEncoding) coverageOutputCobertura = extension.coverageOutputCobertura @@ -143,6 +143,7 @@ class ScoveragePlugin implements Plugin { group = 'verification' runner = scoverageRunner reportDir = extension.reportDir + sources = originalSourceSet.scala.getSourceDirectories() dirsToAggregateFrom = dataDirs sourceEncoding.set(detectedSourceEncoding) deleteReportsOnAggregation = false @@ -299,6 +300,10 @@ class ScoveragePlugin implements Plugin { } } def allReportTasks = childReportTasks + globalReportTask.get() + def allSources = project.objects.fileCollection() + allReportTasks.each { + allSources = allSources.plus(it.sources.get()) + } def aggregationTask = project.tasks.create(AGGREGATE_NAME, ScoverageAggregate) { def dataDirs = allReportTasks.findResults { it.dirsToAggregateFrom.get() }.flatten() onlyIf { @@ -308,6 +313,7 @@ class ScoveragePlugin implements Plugin { group = 'verification' runner = scoverageRunner reportDir = extension.reportDir + sources = allSources sourceEncoding.set(detectedSourceEncoding) dirsToAggregateFrom = dataDirs deleteReportsOnAggregation = extension.deleteReportsOnAggregation diff --git a/src/main/groovy/org/scoverage/ScoverageReport.groovy b/src/main/groovy/org/scoverage/ScoverageReport.groovy index e95f547..8a15aab 100644 --- a/src/main/groovy/org/scoverage/ScoverageReport.groovy +++ b/src/main/groovy/org/scoverage/ScoverageReport.groovy @@ -1,10 +1,12 @@ package org.scoverage import org.gradle.api.DefaultTask +import org.gradle.api.file.FileCollection import org.gradle.api.provider.Property import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.Input import org.gradle.api.tasks.InputDirectory +import org.gradle.api.tasks.InputFiles import org.gradle.api.tasks.Nested import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.PathSensitive @@ -23,9 +25,9 @@ class ScoverageReport extends DefaultTask { @PathSensitive(RELATIVE) final Property dataDir = project.objects.property(File) - @InputDirectory + @InputFiles @PathSensitive(RELATIVE) - final Property sources = project.objects.property(File) + final Property sources = project.objects.property(FileCollection) @OutputDirectory final Property reportDir = project.objects.property(File) @@ -54,7 +56,7 @@ class ScoverageReport extends DefaultTask { project.logger.info("[scoverage] Could not find coverage file, skipping...") } else { new ScoverageWriter(project.logger).write( - sources.get(), + sources.get().getFiles(), reportDir.get(), coverage.get(), sourceEncoding.get(), diff --git a/src/main/groovy/org/scoverage/ScoverageWriter.java b/src/main/groovy/org/scoverage/ScoverageWriter.java index 2f95a51..1e09105 100644 --- a/src/main/groovy/org/scoverage/ScoverageWriter.java +++ b/src/main/groovy/org/scoverage/ScoverageWriter.java @@ -1,14 +1,23 @@ package org.scoverage; import org.gradle.api.logging.Logger; +import scala.Option; import scala.Some; +import scala.collection.immutable.Seq; +import scala.collection.mutable.Buffer; import scoverage.Constants; import scoverage.Coverage; import scoverage.report.CoberturaXmlWriter; import scoverage.report.ScoverageHtmlWriter; import scoverage.report.ScoverageXmlWriter; +import scala.collection.JavaConverters; import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Set; /** * Util for generating and saving coverage files. @@ -26,7 +35,7 @@ public ScoverageWriter(Logger logger) { /** * Generates all reports from given data. * - * @param sourceDir directory with project sources + * @param sourceDirs directories with project sources * @param reportDir directory for generate reports * @param coverage coverage data * @param sourceEncoding the encoding of the source files @@ -35,21 +44,33 @@ public ScoverageWriter(Logger logger) { * @param coverageOutputHTML switch for Scoverage HTML output * @param coverageDebug switch for Scoverage Debug output */ - public void write(File sourceDir, + public void write(Set sourceDirs, File reportDir, Coverage coverage, String sourceEncoding, Boolean coverageOutputCobertura, Boolean coverageOutputXML, Boolean coverageOutputHTML, - Boolean coverageDebug) { + Boolean coverageDebug) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException { logger.info("[scoverage] Generating scoverage reports..."); reportDir.mkdirs(); + Object scalaBuffer = Class.forName("scala.collection.JavaConverters") + .getMethod("asScalaBuffer", java.util.List.class) + .invoke(null, new ArrayList<>(sourceDirs)); + Object sourceDirsSeq = scalaBuffer.getClass().getMethod("toIndexedSeq").invoke(scalaBuffer); + if (coverageOutputCobertura) { - new CoberturaXmlWriter(sourceDir, reportDir).write(coverage); + Constructor cst; + try { + cst = CoberturaXmlWriter.class.getConstructor(Class.forName("scala.collection.immutable.Seq"), File.class); + } catch (NoSuchMethodException | ClassNotFoundException e) { + cst = CoberturaXmlWriter.class.getConstructor(Class.forName("scala.collection.Seq"), File.class); + } + CoberturaXmlWriter writer = cst.newInstance(sourceDirsSeq, reportDir); + writer.write(coverage); logger.info("[scoverage] Written Cobertura XML report to " + reportDir.getAbsolutePath() + File.separator + @@ -57,13 +78,21 @@ public void write(File sourceDir, } if (coverageOutputXML) { - new ScoverageXmlWriter(sourceDir, reportDir, /* debug = */ false).write(coverage); + Constructor cst; + try { + cst = ScoverageXmlWriter.class.getConstructor(Class.forName("scala.collection.immutable.Seq"), File.class, boolean.class); + } catch (NoSuchMethodException | ClassNotFoundException e) { + cst = ScoverageXmlWriter.class.getConstructor(Class.forName("scala.collection.Seq"), File.class, boolean.class); + } + ScoverageXmlWriter writer = cst.newInstance(sourceDirsSeq, reportDir, false); + writer.write(coverage); logger.info("[scoverage] Written XML report to " + reportDir.getAbsolutePath() + File.separator + Constants.XMLReportFilename()); if (coverageDebug) { - new ScoverageXmlWriter(sourceDir, reportDir, /* debug = */ true).write(coverage); + ScoverageXmlWriter writerDebug = cst.newInstance(sourceDirsSeq, reportDir, true); + writerDebug.write(coverage); logger.info("[scoverage] Written XML report with debug information to " + reportDir.getAbsolutePath() + File.separator + @@ -72,7 +101,14 @@ public void write(File sourceDir, } if (coverageOutputHTML) { - new ScoverageHtmlWriter(new File[]{sourceDir}, reportDir, new Some<>(sourceEncoding)).write(coverage); + Constructor cst; + try { + cst = ScoverageHtmlWriter.class.getConstructor(Class.forName("scala.collection.immutable.Seq"), File.class, Option.class); + } catch (NoSuchMethodException | ClassNotFoundException e) { + cst = ScoverageHtmlWriter.class.getConstructor(Class.forName("scala.collection.Seq"), File.class, Option.class); + } + ScoverageHtmlWriter writer = cst.newInstance(sourceDirsSeq, reportDir, new Some<>(sourceEncoding)); + writer.write(coverage); logger.info("[scoverage] Written HTML report to " + reportDir.getAbsolutePath() + File.separator + From c637d551bd84308a49afa5efa40916ae0f980c7a Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Sat, 4 Sep 2021 19:04:01 +0300 Subject: [PATCH 134/167] #163 Fix remaining deprecation warnings from Gradle 7.1.1 --- .../build.gradle | 2 +- .../org/scoverage/ScoveragePlugin.groovy | 28 +++++++++++++------ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/functionalTest/resources/projects/scala-java-annotation-processor/build.gradle b/src/functionalTest/resources/projects/scala-java-annotation-processor/build.gradle index 9e5797f..c67b12d 100644 --- a/src/functionalTest/resources/projects/scala-java-annotation-processor/build.gradle +++ b/src/functionalTest/resources/projects/scala-java-annotation-processor/build.gradle @@ -6,7 +6,7 @@ description = 'a multi-module Scala and Java project using a Java annotation pro allprojects { repositories { - jcenter() + mavenCentral() } } diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 6191ac7..4f1ba18 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -29,7 +29,8 @@ class ScoveragePlugin implements Plugin { static final String DEFAULT_REPORT_DIR = 'reports' + File.separatorChar + 'scoverage' - private final ConcurrentHashMap> taskDependencies = new ConcurrentHashMap<>() + private final ConcurrentHashMap> crossProjectTaskDependencies = new ConcurrentHashMap<>() + private final ConcurrentHashMap> sameProjectTaskDependencies = new ConcurrentHashMap<>() @Override void apply(PluginAware pluginAware) { @@ -195,11 +196,16 @@ class ScoveragePlugin implements Plugin { originalCompileTask.enabled = false; compileTask.destinationDirectory = originalCompileTask.destinationDirectory - originalJarTask.mustRunAfter(compileTask) + + project.getTasks().each { + if (recursiveDependenciesOf(it, true).contains(originalCompileTask)) { + it.dependsOn(compileTask) + } + } // make this project's scoverage compilation depend on scoverage compilation of any other project // which this project depends on its normal compilation - def originalCompilationDependencies = recursiveDependenciesOf(compileTask).findAll { + def originalCompilationDependencies = recursiveDependenciesOf(compileTask, false).findAll { it instanceof ScalaCompile } originalCompilationDependencies.each { @@ -382,16 +388,22 @@ class ScoveragePlugin implements Plugin { } } - private Set recursiveDependenciesOf(Task task) { - if (!taskDependencies.containsKey(task)) { + private Set recursiveDependenciesOf(Task task, boolean sameProjectOnly) { + def cache = sameProjectOnly ? sameProjectTaskDependencies : crossProjectTaskDependencies + if (!cache.containsKey(task)) { def directDependencies = task.getTaskDependencies().getDependencies(task) - def nestedDependencies = directDependencies.collect { recursiveDependenciesOf(it) }.flatten() + if (sameProjectOnly) { + directDependencies = directDependencies.findAll { + it.project == task.project + } + } + def nestedDependencies = directDependencies.collect { recursiveDependenciesOf(it, sameProjectOnly) }.flatten() def dependencies = directDependencies + nestedDependencies - taskDependencies.put(task, dependencies) + cache.put(task, dependencies) return dependencies } else { - return taskDependencies.get(task) + return cache.get(task) } } } From 367b80185981e836c8df448b8b935696356501ae Mon Sep 17 00:00:00 2001 From: Eyal Roth Date: Sat, 4 Sep 2021 19:07:45 +0300 Subject: [PATCH 135/167] Upgrade Gradle version from '7.1.1' to '7.2' --- gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 257 ++++++++++++++--------- 2 files changed, 154 insertions(+), 105 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 05679dc..ffed3a2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 744e882..1b6c787 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MSYS* | MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" From 7dbbcf37fcbce76abea125413000443e8f65c640 Mon Sep 17 00:00:00 2001 From: Erik Krogen Date: Wed, 17 Nov 2021 09:48:30 -0800 Subject: [PATCH 136/167] Bump scoverage version from 1.4.8 to 1.4.10 to fix Scala 2.12.15 compatibility --- src/main/groovy/org/scoverage/ScoverageExtension.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index 210a825..42219b4 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -55,7 +55,7 @@ class ScoverageExtension { project.plugins.apply(ScalaPlugin.class) scoverageVersion = project.objects.property(String) - scoverageVersion.set('1.4.8') + scoverageVersion.set('1.4.10') scoverageScalaVersion = project.objects.property(String) From f719f2136131147a4a8a824675bf7548fe274f61 Mon Sep 17 00:00:00 2001 From: Erik Krogen Date: Wed, 12 Jan 2022 09:12:20 -0800 Subject: [PATCH 137/167] Update src/main/groovy/org/scoverage/ScoverageExtension.groovy Co-authored-by: Gabriel Jones <18059585+gabrieljones@users.noreply.github.com> --- src/main/groovy/org/scoverage/ScoverageExtension.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index 42219b4..39eb8e4 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -55,7 +55,7 @@ class ScoverageExtension { project.plugins.apply(ScalaPlugin.class) scoverageVersion = project.objects.property(String) - scoverageVersion.set('1.4.10') + scoverageVersion.set('1.4.11') scoverageScalaVersion = project.objects.property(String) From 7a8e608f1e66ebb516de3df1d068f5d635b3cb7c Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 28 Aug 2022 21:10:02 +0100 Subject: [PATCH 138/167] bump publish plugin --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8e122bd..d064b22 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java-gradle-plugin' - id "com.gradle.plugin-publish" version "0.15.0" + id "com.gradle.plugin-publish" version "1.0.0" id "org.jetbrains.gradle.plugin.idea-ext" version "1.0" } From 3021528fa7cfc46440a74f5a8df8cff18653cf42 Mon Sep 17 00:00:00 2001 From: Stu Date: Mon, 29 Aug 2022 10:45:24 +0100 Subject: [PATCH 139/167] sources now published by default --- build.gradle | 6 ------ 1 file changed, 6 deletions(-) diff --git a/build.gradle b/build.gradle index d064b22..efecced 100644 --- a/build.gradle +++ b/build.gradle @@ -119,11 +119,6 @@ task groovydocJar(type: Jar, dependsOn: groovydoc) { classifier 'groovydoc' } -task sourcesJar(type: Jar) { - from sourceSets.main.allSource - classifier 'sources' -} - def propOrDefault(String property) { if (project.hasProperty(property)) { return project.getProperty(property) @@ -179,7 +174,6 @@ publishing { } from components.java artifact groovydocJar - artifact sourcesJar } } } From 206a7843dfdbb3ff2fe9084a8195b7384e0ade95 Mon Sep 17 00:00:00 2001 From: Marton Sigmond <5667024+msigmond@users.noreply.github.com> Date: Wed, 2 Nov 2022 18:37:10 -0400 Subject: [PATCH 140/167] Scala 3 support; Scoverage v2.0.7 --- build.gradle | 5 +- .../groovy/org/scoverage/ScalaVersion.groovy | 31 +++++ .../org/scoverage/ScoverageAggregate.groovy | 5 +- .../org/scoverage/ScoverageExtension.groovy | 2 +- .../org/scoverage/ScoveragePlugin.groovy | 116 +++++++++++------- .../org/scoverage/ScoverageReport.groovy | 5 +- .../groovy/org/scoverage/ScoverageWriter.java | 36 ++++-- 7 files changed, 140 insertions(+), 60 deletions(-) create mode 100644 src/main/groovy/org/scoverage/ScalaVersion.groovy diff --git a/build.gradle b/build.gradle index efecced..be13b5e 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ repositories { group 'org.scoverage' description = 'gradle-scoverage is a Gradle plugin for calculating code coverage using Scoverage' if (project.version == 'unspecified') { - version = '7.0.0-SNAPSHOT' + version = '8.0.0-SNAPSHOT' } ext { website = 'http://scoverage.org' @@ -46,7 +46,8 @@ targetCompatibility = '1.8' dependencies { - compileOnly "org.scoverage:scalac-scoverage-plugin_2.13:1.4.2" + compileOnly "org.scoverage:scalac-scoverage-plugin_2.13.8:2.0.5" + compileOnly "org.scoverage:scalac-scoverage-reporter_2.13:2.0.5" implementation group: 'commons-io', name: 'commons-io', version: '2.6' testImplementation 'junit:junit:4.12' diff --git a/src/main/groovy/org/scoverage/ScalaVersion.groovy b/src/main/groovy/org/scoverage/ScalaVersion.groovy new file mode 100644 index 0000000..7d76dc4 --- /dev/null +++ b/src/main/groovy/org/scoverage/ScalaVersion.groovy @@ -0,0 +1,31 @@ +package org.scoverage + +class ScalaVersion { + final String primaryVersion + final Optional secondaryVersion + final Integer majorVersion + final String scalacScoverageVersion + final String scalacScoveragePluginVersion + final String scalacScoverageRuntimeVersion + + ScalaVersion(primaryVersion) { + this(primaryVersion, Optional.empty()) + } + + ScalaVersion(String primaryVersion, Optional secondaryVersion) { + this.primaryVersion = primaryVersion + this.secondaryVersion = secondaryVersion + + this.majorVersion = primaryVersion.substring(0, primaryVersion.indexOf('.')).toInteger() + this.scalacScoverageVersion = this.majorVersion < 3 + ? primaryVersion.substring(0, primaryVersion.lastIndexOf('.')) + : this.majorVersion.toString() + this.scalacScoveragePluginVersion = secondaryVersion.orElse(primaryVersion) + this.scalacScoverageRuntimeVersion = scalacScoveragePluginVersion.substring(0, scalacScoveragePluginVersion.lastIndexOf('.')) + } + + @Override + String toString() { + return majorVersion < 3 ? primaryVersion : "$primaryVersion (${secondaryVersion.get()})" + } +} diff --git a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy index 9815dd1..f39ff98 100644 --- a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy +++ b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy @@ -10,7 +10,7 @@ import org.gradle.api.tasks.Nested import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.PathSensitive import org.gradle.api.tasks.TaskAction -import scoverage.report.CoverageAggregator +import scoverage.reporter.CoverageAggregator import static org.gradle.api.tasks.PathSensitivity.RELATIVE @@ -57,7 +57,8 @@ class ScoverageAggregate extends DefaultTask { def dirs = [] dirs.addAll(dirsToAggregateFrom.get()) - def coverage = CoverageAggregator.aggregate(dirs.unique() as File[]) + def sourceRoot = getProject().getRootDir() + def coverage = CoverageAggregator.aggregate(dirs.unique() as File[], sourceRoot) if (coverage.nonEmpty()) { new ScoverageWriter(project.logger).write( diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index 39eb8e4..510f42d 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -55,7 +55,7 @@ class ScoverageExtension { project.plugins.apply(ScalaPlugin.class) scoverageVersion = project.objects.property(String) - scoverageVersion.set('1.4.11') + scoverageVersion.set('2.0.7') scoverageScalaVersion = project.objects.property(String) diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 4f1ba18..7e239ba 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -51,9 +51,12 @@ class ScoveragePlugin implements Plugin { project.logger.info("Project ${project.name} already has the scoverage plugin") return } - project.logger.info("Applying scoverage plugin to $project.name") + project.logger.info("Applying scoverage plugin to $project.name") def extension = project.extensions.create('scoverage', ScoverageExtension, project) + + def scalaVersion = resolveScalaVersions(project) + if (!project.configurations.asMap[CONFIGURATION_NAME]) { project.configurations.create(CONFIGURATION_NAME) { visible = false @@ -62,23 +65,27 @@ class ScoveragePlugin implements Plugin { } project.afterEvaluate { - def scalaFullVersion = resolveScalaVersion(project) - def scalaBinaryVersion = scalaFullVersion.substring(0, scalaFullVersion.lastIndexOf('.')) def scoverageVersion = project.extensions.scoverage.scoverageVersion.get() + project.logger.info("Using scoverage scalac plugin $scoverageVersion for scala $scalaVersion") - project.logger.info("Using scoverage scalac plugin $scoverageVersion for scala $scalaFullVersion") + def scalacScoverageVersion = scalaVersion.scalacScoverageVersion + def scalacScoveragePluginVersion = scalaVersion.scalacScoveragePluginVersion + def scalacScoverageRuntimeVersion = scalaVersion.scalacScoverageRuntimeVersion project.dependencies { - scoverage("org.scoverage:scalac-scoverage-plugin_$scalaFullVersion:$scoverageVersion") - scoverage("org.scoverage:scalac-scoverage-runtime_$scalaBinaryVersion:$scoverageVersion") + scoverage("org.scoverage:scalac-scoverage-domain_$scalacScoverageVersion:$scoverageVersion") + scoverage("org.scoverage:scalac-scoverage-reporter_$scalacScoverageVersion:$scoverageVersion") + scoverage("org.scoverage:scalac-scoverage-serializer_$scalacScoverageVersion:$scoverageVersion") + scoverage("org.scoverage:scalac-scoverage-runtime_$scalacScoverageRuntimeVersion:$scoverageVersion") + scoverage("org.scoverage:scalac-scoverage-plugin_$scalacScoveragePluginVersion:$scoverageVersion") } } } - createTasks(project, extension) + createTasks(project, extension, scalaVersion) } - private void createTasks(Project project, ScoverageExtension extension) { + private void createTasks(Project project, ScoverageExtension extension, ScalaVersion scalaVersion) { ScoverageRunner scoverageRunner = new ScoverageRunner(project.configurations.scoverage) @@ -162,32 +169,43 @@ class ScoveragePlugin implements Plugin { if (existingParameters) { parameters.addAll(existingParameters) } - parameters.add("-P:scoverage:dataDir:${extension.dataDir.get().absolutePath}".toString()) - if (extension.excludedPackages.get()) { - def packages = extension.excludedPackages.get().join(';') - parameters.add("-P:scoverage:excludedPackages:$packages".toString()) - } - if (extension.excludedFiles.get()) { - def packages = extension.excludedFiles.get().join(';') - parameters.add("-P:scoverage:excludedFiles:$packages".toString()) - } - if (extension.highlighting.get()) { - parameters.add('-Yrangepos') - } - scalaCompileOptions.additionalParameters = parameters - // the compile task creates a store of measured statements - outputs.file(new File(extension.dataDir.get(), 'scoverage.coverage')) - - dependsOn project.configurations[CONFIGURATION_NAME] - doFirst { - /* - It is crucial that this would run in `doFirst`, as this resolves the (dependencies of the) - configuration, which we do not want to do at configuration time (but only at execution time). - */ - def pluginFile = project.configurations[CONFIGURATION_NAME].find { - it.name.startsWith("scalac-scoverage-plugin") + + if (scalaVersion.majorVersion < 3) { + parameters.add("-P:scoverage:dataDir:${extension.dataDir.get().absolutePath}".toString()) + parameters.add("-P:scoverage:sourceRoot:${extension.project.getRootDir().absolutePath}".toString()) + if (extension.excludedPackages.get()) { + def packages = extension.excludedPackages.get().join(';') + parameters.add("-P:scoverage:excludedPackages:$packages".toString()) + } + if (extension.excludedFiles.get()) { + def packages = extension.excludedFiles.get().join(';') + parameters.add("-P:scoverage:excludedFiles:$packages".toString()) + } + if (extension.highlighting.get()) { + parameters.add('-Yrangepos') + } + scalaCompileOptions.additionalParameters = parameters + // the compile task creates a store of measured statements + outputs.file(new File(extension.dataDir.get(), 'scoverage.coverage')) + + dependsOn project.configurations[CONFIGURATION_NAME] + doFirst { + /* + It is crucial that this would run in `doFirst`, as this resolves the (dependencies of the) + configuration, which we do not want to do at configuration time (but only at execution time). + */ + def pluginFiles = project.configurations[CONFIGURATION_NAME].findAll { + it.name.startsWith("scalac-scoverage-plugin") || + it.name.startsWith("scalac-scoverage-domain") || + it.name.startsWith("scalac-scoverage-serializer") + }.collect { + it.absolutePath + } + scalaCompileOptions.additionalParameters.add('-Xplugin:' + pluginFiles.join(":")) } - scalaCompileOptions.additionalParameters.add('-Xplugin:' + pluginFile.absolutePath) + } else { + parameters.add("-coverage-out:${extension.dataDir.get().absolutePath}".toString()) + scalaCompileOptions.additionalParameters = parameters } } @@ -364,27 +382,41 @@ class ScoveragePlugin implements Plugin { } } - private String resolveScalaVersion(Project project) { - + private ScalaVersion resolveScalaVersions(Project project) { def scalaVersionProperty = project.extensions.scoverage.scoverageScalaVersion if (scalaVersionProperty.isPresent()) { def configuredScalaVersion = scalaVersionProperty.get() project.logger.info("Using configured Scala version: $configuredScalaVersion") - return configuredScalaVersion + return new ScalaVersion(configuredScalaVersion) } else { project.logger.info("No Scala version configured. Detecting scala library...") def components = project.configurations.compileClasspath.incoming.resolutionResult.getAllComponents() + + def scala3Library = components.find { + it.moduleVersion.group == "org.scala-lang" && it.moduleVersion.name == "scala3-library_3" + } def scalaLibrary = components.find { it.moduleVersion.group == "org.scala-lang" && it.moduleVersion.name == "scala-library" } + + // Scala 3 + if (scala3Library != null) { + def scala3Version = scala3Library.moduleVersion.version + def scala2Version = scalaLibrary.moduleVersion.version + project.logger.info("Detected scala 3 library in compilation classpath. Scala 3 version: $scala3Version; using Scala 2 library: $scala2Version") + return new ScalaVersion(scala3Version, Optional.of(scala2Version)) + } + + // Scala 2 if (scalaLibrary != null) { - def scalaVersion = scalaLibrary.moduleVersion.version - project.logger.info("Detected scala library in compilation classpath. Scala version: $scalaVersion") - return scalaVersion - } else { - project.logger.info("No scala library detected. Using default Scala version: $DEFAULT_SCALA_VERSION") - return DEFAULT_SCALA_VERSION + def scala2Version = scalaLibrary.moduleVersion.version + project.logger.info("Detected scala library in compilation classpath. Scala version: $scala2Version") + return new ScalaVersion(scala2Version) } + + // No Scala library was found, using default Scala version + project.logger.info("No scala library detected. Using default Scala version: $DEFAULT_SCALA_VERSION") + return new ScalaVersion(DEFAULT_SCALA_VERSION) } } diff --git a/src/main/groovy/org/scoverage/ScoverageReport.groovy b/src/main/groovy/org/scoverage/ScoverageReport.groovy index 8a15aab..ef09483 100644 --- a/src/main/groovy/org/scoverage/ScoverageReport.groovy +++ b/src/main/groovy/org/scoverage/ScoverageReport.groovy @@ -11,7 +11,7 @@ import org.gradle.api.tasks.Nested import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.PathSensitive import org.gradle.api.tasks.TaskAction -import scoverage.report.CoverageAggregator +import scoverage.reporter.CoverageAggregator import static org.gradle.api.tasks.PathSensitivity.RELATIVE @@ -50,7 +50,8 @@ class ScoverageReport extends DefaultTask { reportDir.get().delete() reportDir.get().mkdirs() - def coverage = CoverageAggregator.aggregate([dataDir.get()] as File[]) + def sourceRoot = getProject().getRootDir() + def coverage = CoverageAggregator.aggregate([dataDir.get()] as File[], sourceRoot) if (coverage.isEmpty()) { project.logger.info("[scoverage] Could not find coverage file, skipping...") diff --git a/src/main/groovy/org/scoverage/ScoverageWriter.java b/src/main/groovy/org/scoverage/ScoverageWriter.java index 1e09105..5e0278e 100644 --- a/src/main/groovy/org/scoverage/ScoverageWriter.java +++ b/src/main/groovy/org/scoverage/ScoverageWriter.java @@ -5,11 +5,11 @@ import scala.Some; import scala.collection.immutable.Seq; import scala.collection.mutable.Buffer; -import scoverage.Constants; -import scoverage.Coverage; -import scoverage.report.CoberturaXmlWriter; -import scoverage.report.ScoverageHtmlWriter; -import scoverage.report.ScoverageXmlWriter; +import scoverage.domain.Constants; +import scoverage.domain.Coverage; +import scoverage.reporter.CoberturaXmlWriter; +import scoverage.reporter.ScoverageHtmlWriter; +import scoverage.reporter.ScoverageXmlWriter; import scala.collection.JavaConverters; import java.io.File; @@ -65,11 +65,17 @@ public void write(Set sourceDirs, if (coverageOutputCobertura) { Constructor cst; try { - cst = CoberturaXmlWriter.class.getConstructor(Class.forName("scala.collection.immutable.Seq"), File.class); + cst = CoberturaXmlWriter.class.getConstructor( + Class.forName("scala.collection.immutable.Seq"), + File.class, + Class.forName("scala.Option")); } catch (NoSuchMethodException | ClassNotFoundException e) { - cst = CoberturaXmlWriter.class.getConstructor(Class.forName("scala.collection.Seq"), File.class); + cst = CoberturaXmlWriter.class.getConstructor( + Class.forName("scala.collection.Seq"), + File.class, + Class.forName("scala.Option")); } - CoberturaXmlWriter writer = cst.newInstance(sourceDirsSeq, reportDir); + CoberturaXmlWriter writer = cst.newInstance(sourceDirsSeq, reportDir, new Some<>(sourceEncoding)); writer.write(coverage); logger.info("[scoverage] Written Cobertura XML report to " + reportDir.getAbsolutePath() + @@ -80,11 +86,19 @@ public void write(Set sourceDirs, if (coverageOutputXML) { Constructor cst; try { - cst = ScoverageXmlWriter.class.getConstructor(Class.forName("scala.collection.immutable.Seq"), File.class, boolean.class); + cst = ScoverageXmlWriter.class.getConstructor( + Class.forName("scala.collection.immutable.Seq"), + File.class, + boolean.class, + Class.forName("scala.Option")); } catch (NoSuchMethodException | ClassNotFoundException e) { - cst = ScoverageXmlWriter.class.getConstructor(Class.forName("scala.collection.Seq"), File.class, boolean.class); + cst = ScoverageXmlWriter.class.getConstructor( + Class.forName("scala.collection.Seq"), + File.class, + boolean.class, + Class.forName("scala.Option")); } - ScoverageXmlWriter writer = cst.newInstance(sourceDirsSeq, reportDir, false); + ScoverageXmlWriter writer = cst.newInstance(sourceDirsSeq, reportDir, false, new Some<>(sourceEncoding)); writer.write(coverage); logger.info("[scoverage] Written XML report to " + reportDir.getAbsolutePath() + From 7ab41c748c6b0e4bd8584df6f247e829b9e0c290 Mon Sep 17 00:00:00 2001 From: Marton Sigmond <5667024+msigmond@users.noreply.github.com> Date: Tue, 15 Nov 2022 22:11:07 -0500 Subject: [PATCH 141/167] Scala 3 support; Scoverage v2.0.7 Lookup Scala version at the right time to avoid forcing early dependency resolution --- build.gradle | 4 ++-- .../2_12/build.gradle | 2 +- .../2_13/build.gradle | 2 +- src/main/groovy/org/scoverage/ScoveragePlugin.groovy | 12 ++++++------ 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/build.gradle b/build.gradle index be13b5e..601e79b 100644 --- a/build.gradle +++ b/build.gradle @@ -46,8 +46,8 @@ targetCompatibility = '1.8' dependencies { - compileOnly "org.scoverage:scalac-scoverage-plugin_2.13.8:2.0.5" - compileOnly "org.scoverage:scalac-scoverage-reporter_2.13:2.0.5" + compileOnly "org.scoverage:scalac-scoverage-plugin_2.13.8:2.0.7" + compileOnly "org.scoverage:scalac-scoverage-reporter_2.13:2.0.7" implementation group: 'commons-io', name: 'commons-io', version: '2.6' testImplementation 'junit:junit:4.12' diff --git a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_12/build.gradle b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_12/build.gradle index 88c5533..a510442 100644 --- a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_12/build.gradle +++ b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_12/build.gradle @@ -1,4 +1,4 @@ dependencies { - implementation group: 'org.scala-lang', name: 'scala-library', version: "2.12.8" + implementation group: 'org.scala-lang', name: 'scala-library', version: "2.12.17" testImplementation group: 'org.scalatest', name: "scalatest_2.12", version: scalatestVersion } diff --git a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_13/build.gradle b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_13/build.gradle index 4820211..ea57742 100644 --- a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_13/build.gradle +++ b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_13/build.gradle @@ -1,4 +1,4 @@ dependencies { - implementation group: 'org.scala-lang', name: 'scala-library', version: "2.13.1" + implementation group: 'org.scala-lang', name: 'scala-library', version: "2.13.10" testImplementation group: 'org.scalatest', name: "scalatest_2.13", version: scalatestVersion } diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 7e239ba..c2f067d 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -51,12 +51,9 @@ class ScoveragePlugin implements Plugin { project.logger.info("Project ${project.name} already has the scoverage plugin") return } - project.logger.info("Applying scoverage plugin to $project.name") - def extension = project.extensions.create('scoverage', ScoverageExtension, project) - - def scalaVersion = resolveScalaVersions(project) + def extension = project.extensions.create('scoverage', ScoverageExtension, project) if (!project.configurations.asMap[CONFIGURATION_NAME]) { project.configurations.create(CONFIGURATION_NAME) { visible = false @@ -65,6 +62,8 @@ class ScoveragePlugin implements Plugin { } project.afterEvaluate { + def scalaVersion = resolveScalaVersions(project) + def scoverageVersion = project.extensions.scoverage.scoverageVersion.get() project.logger.info("Using scoverage scalac plugin $scoverageVersion for scala $scalaVersion") @@ -82,10 +81,10 @@ class ScoveragePlugin implements Plugin { } } - createTasks(project, extension, scalaVersion) + createTasks(project, extension) } - private void createTasks(Project project, ScoverageExtension extension, ScalaVersion scalaVersion) { + private void createTasks(Project project, ScoverageExtension extension) { ScoverageRunner scoverageRunner = new ScoverageRunner(project.configurations.scoverage) @@ -170,6 +169,7 @@ class ScoveragePlugin implements Plugin { parameters.addAll(existingParameters) } + def scalaVersion = resolveScalaVersions(project) if (scalaVersion.majorVersion < 3) { parameters.add("-P:scoverage:dataDir:${extension.dataDir.get().absolutePath}".toString()) parameters.add("-P:scoverage:sourceRoot:${extension.project.getRootDir().absolutePath}".toString()) From 4c2e1bf998593a15cd68a67a5bf5a2a91195a465 Mon Sep 17 00:00:00 2001 From: Marton Sigmond <5667024+msigmond@users.noreply.github.com> Date: Sun, 20 Nov 2022 12:16:10 -0500 Subject: [PATCH 142/167] Scala 3 support; Scoverage v2.0.7 Fix ScoverageFunctionalTest to use scalaVersionBuild=17 (2.12.17) --- .../java/org/scoverage/ScoverageFunctionalTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java b/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java index 051b6bb..789ccfa 100644 --- a/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java +++ b/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java @@ -123,7 +123,7 @@ private void configureArguments(String... arguments) { fullArguments.add("-PscalaVersionMajor=2"); fullArguments.add("-PscalaVersionMinor=12"); - fullArguments.add("-PscalaVersionBuild=8"); + fullArguments.add("-PscalaVersionBuild=17"); fullArguments.add("-PjunitVersion=5.3.2"); fullArguments.add("-PjunitPlatformVersion=1.3.2"); fullArguments.add("-PscalatestVersion=3.0.8"); From 07bbcabd736551b099fe7af2c7d51b548d362506 Mon Sep 17 00:00:00 2001 From: Marton Sigmond <5667024+msigmond@users.noreply.github.com> Date: Wed, 23 Nov 2022 20:11:45 -0500 Subject: [PATCH 143/167] Scala 3 support; Scoverage v2.0.7 Unit test for Scala 3 - picks up wrong Scala 2 compiler - push to ask for help --- .../java/org/scoverage/Scala32Test.java | 6 ++++++ .../3_2/build.gradle | 4 ++++ .../3_2/src/main/scala/org/hello/World3_2.scala | 14 ++++++++++++++ .../src/test/scala/org/hello/World3_2Suite.scala | 13 +++++++++++++ .../settings.gradle | 2 +- 5 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/crossScalaVersionTest/java/org/scoverage/Scala32Test.java create mode 100644 src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/build.gradle create mode 100644 src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/src/main/scala/org/hello/World3_2.scala create mode 100644 src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/src/test/scala/org/hello/World3_2Suite.scala diff --git a/src/crossScalaVersionTest/java/org/scoverage/Scala32Test.java b/src/crossScalaVersionTest/java/org/scoverage/Scala32Test.java new file mode 100644 index 0000000..d657410 --- /dev/null +++ b/src/crossScalaVersionTest/java/org/scoverage/Scala32Test.java @@ -0,0 +1,6 @@ +package org.scoverage; + +public class Scala32Test extends ScalaVersionTest { + + public Scala32Test() { super("3_2"); } +} diff --git a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/build.gradle b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/build.gradle new file mode 100644 index 0000000..43643ea --- /dev/null +++ b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/build.gradle @@ -0,0 +1,4 @@ +dependencies { + implementation 'org.scala-lang:scala3-library_3:3.2.0' + testImplementation 'org.scalatest:scalatest_3:3.2.14' +} \ No newline at end of file diff --git a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/src/main/scala/org/hello/World3_2.scala b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/src/main/scala/org/hello/World3_2.scala new file mode 100644 index 0000000..2e2530b --- /dev/null +++ b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/src/main/scala/org/hello/World3_2.scala @@ -0,0 +1,14 @@ +package org.hello + +class World3_2 { + + // Scala 3 enum to force Scala 3 (Dotty) compiler + enum Num(val value: String): + case Three extends Num("3") + case Two extends Num("2") + + def foo(): String = { + val s = Num.Three.value + Num.Two.value + s + } +} \ No newline at end of file diff --git a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/src/test/scala/org/hello/World3_2Suite.scala b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/src/test/scala/org/hello/World3_2Suite.scala new file mode 100644 index 0000000..8b1cd69 --- /dev/null +++ b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/src/test/scala/org/hello/World3_2Suite.scala @@ -0,0 +1,13 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class World3_2Suite extends FunSuite { + + test("foo") { + new World3_2().foo() + } +} \ No newline at end of file diff --git a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/settings.gradle b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/settings.gradle index f294f6a..9123650 100644 --- a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/settings.gradle +++ b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/settings.gradle @@ -1 +1 @@ -include '2_12', '2_13' \ No newline at end of file +include '2_12', '2_13', '3_2' \ No newline at end of file From 02ca776ea743f10a3ecbcbbc6402efa7980f7089 Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 14 May 2023 23:49:19 +0100 Subject: [PATCH 144/167] bump to gradle 7.4.2 for scala3 support --- gradle/wrapper/gradle-wrapper.properties | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ffed3a2..1730841 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip +distributionSha256Sum=29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 1641c841ab41c7e376a4c37d8e20aa675e42577b Mon Sep 17 00:00:00 2001 From: Stu Date: Sun, 14 May 2023 22:22:49 +0100 Subject: [PATCH 145/167] fix scala 3.2 test --- .../scala-multi-module-cross-version/3_2/build.gradle | 1 + .../3_2/src/test/scala/org/hello/World3_2Suite.scala | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/build.gradle b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/build.gradle index 43643ea..a703f21 100644 --- a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/build.gradle +++ b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/build.gradle @@ -1,4 +1,5 @@ dependencies { implementation 'org.scala-lang:scala3-library_3:3.2.0' testImplementation 'org.scalatest:scalatest_3:3.2.14' + testImplementation "org.scalatestplus:junit-4-13_3:3.2.14.0" } \ No newline at end of file diff --git a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/src/test/scala/org/hello/World3_2Suite.scala b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/src/test/scala/org/hello/World3_2Suite.scala index 8b1cd69..4582dc8 100644 --- a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/src/test/scala/org/hello/World3_2Suite.scala +++ b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/src/test/scala/org/hello/World3_2Suite.scala @@ -1,11 +1,11 @@ package org.hello import org.junit.runner.RunWith -import org.scalatest.FunSuite -import org.scalatest.junit.JUnitRunner +import org.scalatest.funsuite.AnyFunSuite +import org.scalatestplus.junit.JUnitRunner @RunWith(classOf[JUnitRunner]) -class World3_2Suite extends FunSuite { +class World3_2Suite extends AnyFunSuite { test("foo") { new World3_2().foo() From be1bf554fd8607b7b5125f6ef73cc14d00a336b8 Mon Sep 17 00:00:00 2001 From: Stu Date: Mon, 15 May 2023 19:36:23 +0100 Subject: [PATCH 146/167] pass sourceroot at compilation time to resolve relative path issue --- src/main/groovy/org/scoverage/ScoveragePlugin.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index c2f067d..d8d5138 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -204,6 +204,7 @@ class ScoveragePlugin implements Plugin { scalaCompileOptions.additionalParameters.add('-Xplugin:' + pluginFiles.join(":")) } } else { + parameters.add("-sourceroot:${project.rootDir.absolutePath}".toString()) parameters.add("-coverage-out:${extension.dataDir.get().absolutePath}".toString()) scalaCompileOptions.additionalParameters = parameters } From f99718a3cecc57fa5bd6fbb5b507508209a4c7af Mon Sep 17 00:00:00 2001 From: Stu Date: Mon, 15 May 2023 19:36:38 +0100 Subject: [PATCH 147/167] bump to scoverage 2.0.8 as default --- src/main/groovy/org/scoverage/ScoverageExtension.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index 510f42d..cb45b94 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -55,7 +55,7 @@ class ScoverageExtension { project.plugins.apply(ScalaPlugin.class) scoverageVersion = project.objects.property(String) - scoverageVersion.set('2.0.7') + scoverageVersion.set('2.0.8') scoverageScalaVersion = project.objects.property(String) From 17a18af2104485c80c636f5c682a0baf748e7499 Mon Sep 17 00:00:00 2001 From: Stu Date: Mon, 15 May 2023 22:47:17 +0100 Subject: [PATCH 148/167] disable -PscoverageCompileOnly with a view to getting a release out --- README.md | 17 +-- .../org/scoverage/ScalaMultiModuleTest.java | 4 + ...aMultiModuleWithMultipleTestTasksTest.java | 3 + .../org/scoverage/ScalaSingleModuleTest.java | 2 + ...SingleModuleWithMultipleTestTasksTest.java | 2 + .../org/scoverage/ScoveragePlugin.groovy | 102 +++++++----------- 6 files changed, 52 insertions(+), 78 deletions(-) diff --git a/README.md b/README.md index 60bbfae..cddb83f 100644 --- a/README.md +++ b/README.md @@ -105,24 +105,17 @@ scoverage { } ``` -### Run without normal compilation - -By default, running any of the plugin tasks will compile the code both using "normal" compilation (`compileScala`) -and using the scoverage scalac plugin (`compileScoverageScala`). - -In cases where you only wish to generate reports / validate coverage, but are not interested in publishing the code, -it is possible to only compile the code with the scoverage scalac plugin, thus reducing build times significantly. -In order to do so, simply add the arguments `-PscoverageCompileOnly` to the gradle execution. -For example: `gradle reportScoverage -PscoverageCompileOnly`. - -Note that this mode is incompatible with parallel builds in multi-module projects. - ### Compatibility with Consistent Versions Plugin In order for the plugin to work alongside [Palantir's consistent versions plugin](https://github.com/palantir/gradle-consistent-versions), the Scala version must be manually configured (via `scoverageScalaVersion`); otherwise, the plugin will attempt to resolve the compilation classpath, which is prohibited by the versions plugin. +Migration to 8.x +---------------- + +* Running without normal compilation is no longer supported. + Migration to 7.x ---------------- diff --git a/src/functionalTest/java/org/scoverage/ScalaMultiModuleTest.java b/src/functionalTest/java/org/scoverage/ScalaMultiModuleTest.java index 5da6f60..fa85c16 100644 --- a/src/functionalTest/java/org/scoverage/ScalaMultiModuleTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaMultiModuleTest.java @@ -1,6 +1,7 @@ package org.scoverage; import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; import java.io.File; @@ -60,6 +61,7 @@ public void reportScoverageOnlyA() { } @Test + @Ignore public void reportScoverageOnlyAWithoutNormalCompilation() { AssertableBuildResult result = run("clean", ":a:" + ScoveragePlugin.getREPORT_NAME(), @@ -192,6 +194,7 @@ public void checkScoverageWithoutCoverageInA() throws Exception { } @Test + @Ignore public void checkScoverageWithoutNormalCompilationAndWithoutCoverageInCommon() throws Exception { AssertableBuildResult result = runAndFail("clean", @@ -254,6 +257,7 @@ public void checkAndAggregateScoverageWithoutCoverageInAll() throws Exception { } @Test + @Ignore public void aggregateScoverageWithoutNormalCompilation() throws Exception { AssertableBuildResult result = run("clean", ScoveragePlugin.getAGGREGATE_NAME(), diff --git a/src/functionalTest/java/org/scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java b/src/functionalTest/java/org/scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java index dc84e1f..8d9982b 100644 --- a/src/functionalTest/java/org/scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java @@ -1,6 +1,7 @@ package org.scoverage; import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; @@ -188,6 +189,7 @@ public void checkScoverageWithoutCoverageInA() throws Exception { } @Test + @Ignore public void checkScoverageWithoutNormalCompilationAndWithoutCoverageInCommon() throws Exception { AssertableBuildResult result = runAndFail("clean", @@ -251,6 +253,7 @@ public void checkAndAggregateScoverageWithoutCoverageInAll() throws Exception { } @Test + @Ignore public void aggregateScoverageWithoutNormalCompilation() throws Exception { AssertableBuildResult result = run("clean", ScoveragePlugin.getAGGREGATE_NAME(), diff --git a/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java b/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java index 19e0e82..ed7b8f4 100644 --- a/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java @@ -1,6 +1,7 @@ package org.scoverage; import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; public class ScalaSingleModuleTest extends ScoverageFunctionalTest { @@ -100,6 +101,7 @@ public void reportScoverageWithExcludedClasses() throws Exception { } @Test + @Ignore public void reportScoverageWithoutNormalCompilation() throws Exception { AssertableBuildResult result = run("clean", ScoveragePlugin.getREPORT_NAME(), diff --git a/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java b/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java index cba1c6a..6b485b6 100644 --- a/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java @@ -1,6 +1,7 @@ package org.scoverage; import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; public class ScalaSingleModuleWithMultipleTestTasksTest extends ScoverageFunctionalTest { @@ -118,6 +119,7 @@ public void reportScoverageWithExcludedClasses() throws Exception { } @Test + @Ignore public void reportScoverageWithoutNormalCompilation() throws Exception { AssertableBuildResult result = run("clean", ScoveragePlugin.getREPORT_NAME(), diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index d8d5138..7d7fd1f 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -210,80 +210,50 @@ class ScoveragePlugin implements Plugin { } } - if (project.hasProperty(SCOVERAGE_COMPILE_ONLY_PROPERTY)) { - project.logger.info("Making scoverage compilation the primary compilation task (instead of compileScala)") - - originalCompileTask.enabled = false; - compileTask.destinationDirectory = originalCompileTask.destinationDirectory - - project.getTasks().each { - if (recursiveDependenciesOf(it, true).contains(originalCompileTask)) { - it.dependsOn(compileTask) - } - } - - // make this project's scoverage compilation depend on scoverage compilation of any other project - // which this project depends on its normal compilation - def originalCompilationDependencies = recursiveDependenciesOf(compileTask, false).findAll { - it instanceof ScalaCompile - } - originalCompilationDependencies.each { - def dependencyProjectCompileTask = it.project.tasks.findByName(COMPILE_NAME) - def dependencyProjectReportTask = it.project.tasks.findByName(REPORT_NAME) - if (dependencyProjectCompileTask != null) { - compileTask.dependsOn(dependencyProjectCompileTask) - // we don't want this project's tests to affect the other project's report - testTasks.each { - it.mustRunAfter(dependencyProjectReportTask) - } - } + compileTask.configure { + doFirst { + destinationDir.deleteDir() } - } else { - compileTask.configure { - doFirst { - destinationDir.deleteDir() - } - // delete non-instrumented classes by comparing normally compiled classes to those compiled with scoverage - doLast { - project.logger.info("Deleting classes compiled by scoverage but non-instrumented (identical to normal compilation)") - def originalCompileTaskName = project.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) - .getCompileTaskName("scala") - def originalDestinationDirectory = project.tasks[originalCompileTaskName].destinationDirectory - def originalDestinationDir = originalDestinationDirectory.get().asFile - def destinationDir = destinationDirectory.get().asFile - - - def findFiles = { File dir, Closure condition = null -> - def files = [] - - if (dir.exists()) { - dir.eachFileRecurse(FILES) { f -> - if (condition == null || condition(f)) { - def relativePath = dir.relativePath(f) - files << relativePath - } + // delete non-instrumented classes by comparing normally compiled classes to those compiled with scoverage + doLast { + project.logger.info("Deleting classes compiled by scoverage but non-instrumented (identical to normal compilation)") + def originalCompileTaskName = project.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) + .getCompileTaskName("scala") + def originalDestinationDirectory = project.tasks[originalCompileTaskName].destinationDirectory + def originalDestinationDir = originalDestinationDirectory.get().asFile + def destinationDir = destinationDirectory.get().asFile + + + def findFiles = { File dir, Closure condition = null -> + def files = [] + + if (dir.exists()) { + dir.eachFileRecurse(FILES) { f -> + if (condition == null || condition(f)) { + def relativePath = dir.relativePath(f) + files << relativePath } } - - files } - def isSameFile = { String relativePath -> - def fileA = new File(originalDestinationDir, relativePath) - def fileB = new File(destinationDir, relativePath) - FileUtils.contentEquals(fileA, fileB) - } + files + } - def originalClasses = findFiles(originalDestinationDir) - def identicalInstrumentedClasses = findFiles(destinationDir, { f -> - def relativePath = destinationDir.relativePath(f) - originalClasses.contains(relativePath) && isSameFile(relativePath) - }) + def isSameFile = { String relativePath -> + def fileA = new File(originalDestinationDir, relativePath) + def fileB = new File(destinationDir, relativePath) + FileUtils.contentEquals(fileA, fileB) + } - identicalInstrumentedClasses.each { f -> - Files.deleteIfExists(destinationDir.toPath().resolve(f)) - } + def originalClasses = findFiles(originalDestinationDir) + def identicalInstrumentedClasses = findFiles(destinationDir, { f -> + def relativePath = destinationDir.relativePath(f) + originalClasses.contains(relativePath) && isSameFile(relativePath) + }) + + identicalInstrumentedClasses.each { f -> + Files.deleteIfExists(destinationDir.toPath().resolve(f)) } } } From 32d2564f8c44288eac3fb090df5091a7b5c54d1d Mon Sep 17 00:00:00 2001 From: Stu Date: Mon, 15 May 2023 23:08:15 +0100 Subject: [PATCH 149/167] upgrade to gradle 8.1.1 --- build.gradle | 15 ++--- gradle/wrapper/gradle-wrapper.properties | 4 +- .../scoverage/ScoverageFunctionalTest.java | 4 +- .../build.gradle | 53 +++++++++-------- .../build.gradle | 57 +++++++++---------- .../org/scoverage/ScoveragePlugin.groovy | 2 +- 6 files changed, 64 insertions(+), 71 deletions(-) diff --git a/build.gradle b/build.gradle index 601e79b..b0251c2 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java-gradle-plugin' - id "com.gradle.plugin-publish" version "1.0.0" + id "com.gradle.plugin-publish" version "1.1.0" id "org.jetbrains.gradle.plugin.idea-ext" version "1.0" } @@ -22,22 +22,19 @@ ext { } gradlePlugin { + website = project.ext.website + vcsUrl = project.ext.vcsUrl + description = project.description plugins { gradleScoverage { id = 'org.scoverage' implementationClass = 'org.scoverage.ScoveragePlugin' displayName = 'Gradle Scoverage plugin' + tags.set(['coverage', 'scala', 'scoverage']) } } } -pluginBundle { - website = project.website - vcsUrl = ext.vcsUrl - description = project.description - tags = ['coverage', 'scala', 'scoverage'] -} - apply plugin: 'maven-publish' apply plugin: 'groovy' @@ -117,7 +114,7 @@ gradlePlugin { task groovydocJar(type: Jar, dependsOn: groovydoc) { from "$buildDir/docs/groovydoc" - classifier 'groovydoc' + archiveClassifier.set('groovydoc') } def propOrDefault(String property) { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1730841..d79d004 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip -distributionSha256Sum=29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +distributionSha256Sum=e111cb9948407e26351227dabce49822fb88c37ee72f1d1582a69c68af2e702f zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java b/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java index 789ccfa..bfc1c09 100644 --- a/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java +++ b/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java @@ -122,8 +122,8 @@ private void configureArguments(String... arguments) { List fullArguments = new ArrayList<>(); fullArguments.add("-PscalaVersionMajor=2"); - fullArguments.add("-PscalaVersionMinor=12"); - fullArguments.add("-PscalaVersionBuild=17"); + fullArguments.add("-PscalaVersionMinor=13"); + fullArguments.add("-PscalaVersionBuild=10"); fullArguments.add("-PjunitVersion=5.3.2"); fullArguments.add("-PjunitPlatformVersion=1.3.2"); fullArguments.add("-PscalatestVersion=3.0.8"); diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle index af770c5..27fca57 100644 --- a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle @@ -25,36 +25,35 @@ allprojects { testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion } - test { - useJUnitPlatform() - maxParallelForks = 1 - } - - configurations { - intTestImplementation.extendsFrom testImplementation - intTestRuntimeOnly.extendsFrom testRuntimeOnly - } - sourceSets { - intTest { - resources.srcDir file('src/intTest/resources') - scala { - compileClasspath += main.output + test.output - runtimeClasspath += main.output + test.output - srcDir file("${projectDir}/src/intTest/scala") + testing { + suites { + configureEach { + useJUnit() + targets.configureEach { + testTask.configure { + maxParallelForks = 1 + } + } + } + intTest(JvmTestSuite) { + testType = TestSuiteType.INTEGRATION_TEST + // dependencies { ... } does not appear to work as advertised? + sources { + scala { + compileClasspath += sourceSets.test.compileClasspath + sourceSets.main.output + sourceSets.test.output + runtimeClasspath += sourceSets.test.runtimeClasspath + } + } + targets.configureEach { + testTask.configure{ + outputs.upToDateWhen { false } + mustRunAfter(test) + } + } } } } - - - task intTest(type: Test) { - testClassesDirs = sourceSets.intTest.output.classesDirs - classpath = sourceSets.intTest.runtimeClasspath - outputs.upToDateWhen { false } - - maxParallelForks = 1 - } - check.dependsOn(intTest) - intTest.mustRunAfter(test) + check.dependsOn(testing.suites.intTest) scoverage { minimumRate = 0.5 diff --git a/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle index a10ddbb..3f7ffd5 100644 --- a/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle +++ b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle @@ -1,6 +1,7 @@ plugins { id 'io.spring.dependency-management' version "1.0.4.RELEASE" id 'org.scoverage' + id 'jvm-test-suite' } repositories { @@ -27,39 +28,35 @@ dependencies { testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion } -test { - useJUnitPlatform() -} - - -configurations { - intTestImplementation.extendsFrom testImplementation - intTestRuntimeOnly.extendsFrom testRuntimeOnly -} -sourceSets { - intTest { - resources.srcDir file('src/intTest/resources') - scala { - compileClasspath += main.output + test.output - runtimeClasspath += main.output + test.output - srcDir file("${projectDir}/src/intTest/scala") +testing { + suites { + configureEach { + useJUnit() + targets.configureEach { + testTask.configure { + maxParallelForks = 1 + } + } + } + intTest(JvmTestSuite) { + testType = TestSuiteType.INTEGRATION_TEST + // dependencies { ... } does not appear to work as advertised? + sources { + scala { + compileClasspath += sourceSets.test.compileClasspath + sourceSets.main.output + sourceSets.test.output + runtimeClasspath += sourceSets.test.runtimeClasspath + } + } + targets.configureEach { + testTask.configure{ + outputs.upToDateWhen { false } + mustRunAfter(test) + } + } } } } - -test { - maxParallelForks = 1 -} - -task intTest(type: Test) { - testClassesDirs = sourceSets.intTest.output.classesDirs - classpath = sourceSets.intTest.runtimeClasspath - outputs.upToDateWhen { false } - - maxParallelForks = 1 -} -check.dependsOn(intTest) -intTest.mustRunAfter(test) +check.dependsOn(testing.suites.intTest) scoverage { minimumRate = 0.6 diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 7d7fd1f..ebcb5f6 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -212,7 +212,7 @@ class ScoveragePlugin implements Plugin { compileTask.configure { doFirst { - destinationDir.deleteDir() + destinationDirectory.get().getAsFile().deleteDir() } // delete non-instrumented classes by comparing normally compiled classes to those compiled with scoverage From 1abb277ee169a9370002bde95dbaa49855313310 Mon Sep 17 00:00:00 2001 From: Stu Date: Sat, 20 May 2023 13:09:54 +0100 Subject: [PATCH 150/167] Use File.pathSeparator to support building on Windows (https://github.com/scoverage/sbt-scoverage/commit/8ba258cff5f44973b74c45ff4792719d8e551279) --- src/main/groovy/org/scoverage/ScoveragePlugin.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index ebcb5f6..e0e88e3 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -201,7 +201,7 @@ class ScoveragePlugin implements Plugin { }.collect { it.absolutePath } - scalaCompileOptions.additionalParameters.add('-Xplugin:' + pluginFiles.join(":")) + scalaCompileOptions.additionalParameters.add('-Xplugin:' + pluginFiles.join(File.pathSeparator)) } } else { parameters.add("-sourceroot:${project.rootDir.absolutePath}".toString()) From 9ed6e8bfaad80356934e7760a98ee7e383394e46 Mon Sep 17 00:00:00 2001 From: maiflai Date: Sat, 20 May 2023 22:00:21 +0100 Subject: [PATCH 151/167] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cddb83f..199d276 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,8 @@ resolve the compilation classpath, which is prohibited by the versions plugin. Migration to 8.x ---------------- -* Running without normal compilation is no longer supported. +* Adds support for Scala 3 +* Drops support for disabling normal compilation Migration to 7.x ---------------- @@ -177,4 +178,4 @@ task aggregateScoverage(type: org.scoverage.ScoverageAggregate) checkScoverage { reportDir = file("$buildDir/scoverage-aggregate") } -``` \ No newline at end of file +``` From 84c97306981bc73fb5534e4405f1d74244e54bd8 Mon Sep 17 00:00:00 2001 From: maiflai Date: Sat, 20 May 2023 22:01:10 +0100 Subject: [PATCH 152/167] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 199d276..69a5791 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,7 @@ resolve the compilation classpath, which is prohibited by the versions plugin. Migration to 8.x ---------------- +* Requires scoverage 2.0 * Adds support for Scala 3 * Drops support for disabling normal compilation From 6bd060c1f24eb9a7be2678cad9e45e7ad273a3a3 Mon Sep 17 00:00:00 2001 From: Rafal Magda Date: Sun, 21 May 2023 17:47:14 +0200 Subject: [PATCH 153/167] (#194) Fix numbers decimal separator --- .../scoverage/ScoverageFunctionalTest.java | 6 +-- .../org/scoverage/CoverageChecker.groovy | 20 ++++------ .../org/scoverage/CoverageCheckerTest.groovy | 38 ++++++++++--------- 3 files changed, 30 insertions(+), 34 deletions(-) diff --git a/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java b/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java index bfc1c09..fdac1cf 100644 --- a/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java +++ b/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java @@ -11,8 +11,6 @@ import java.io.File; import java.io.IOException; -import java.text.NumberFormat; -import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -108,12 +106,12 @@ protected File resolve(File file, String relativePath) { return file.toPath().resolve(relativePath).toFile(); } - private Double coverage(File reportDir, CoverageType coverageType) throws IOException, SAXException, ParseException { + private Double coverage(File reportDir, CoverageType coverageType) throws IOException, SAXException, NumberFormatException { File reportFile = reportDir.toPath().resolve(coverageType.getFileName()).toFile(); Node xml = parser.parse(reportFile); Object attribute = xml.attribute(coverageType.getParamName()); - double rawValue = NumberFormat.getInstance().parse(attribute.toString()).doubleValue(); + double rawValue = Double.parseDouble(attribute.toString()); return coverageType.normalize(rawValue) * 100.0; } diff --git a/src/main/groovy/org/scoverage/CoverageChecker.groovy b/src/main/groovy/org/scoverage/CoverageChecker.groovy index 1af7b4e..d185f82 100644 --- a/src/main/groovy/org/scoverage/CoverageChecker.groovy +++ b/src/main/groovy/org/scoverage/CoverageChecker.groovy @@ -6,7 +6,7 @@ import org.gradle.api.logging.Logger import org.gradle.internal.impldep.com.google.common.annotations.VisibleForTesting import java.text.DecimalFormat -import java.text.NumberFormat +import java.text.DecimalFormatSymbols /** * Handles different types of coverage Scoverage can measure. @@ -56,30 +56,21 @@ class CoverageChecker { } public void checkLineCoverage(File reportDir, CoverageType coverageType, double minimumRate) throws GradleException { - NumberFormat defaultNf = NumberFormat.getInstance(Locale.getDefault()) - checkLineCoverage(reportDir, coverageType, minimumRate, defaultNf) - } - - public void checkLineCoverage(File reportDir, CoverageType coverageType, double minimumRate, NumberFormat nf) throws GradleException { logger.info("Checking coverage. Type: {}. Minimum rate: {}", coverageType, minimumRate) XmlParser 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) - DecimalFormat df = new DecimalFormat("#.##") - try { File reportFile = new File(reportDir, coverageType.fileName) Node xml = parser.parse(reportFile) - Double coverageValue = nf.parse(xml.attribute(coverageType.paramName) as String).doubleValue() + Double coverageValue = (xml.attribute(coverageType.paramName) as String).toDouble() Double overallRate = coverageType.normalize(coverageValue) def difference = (minimumRate - overallRate) if (difference > 1e-7) { - String is = df.format(overallRate * 100) - String needed = df.format(minimumRate * 100) - throw new GradleException(errorMsg(is, needed, coverageType)) + throw new GradleException(errorMsg(overallRate, minimumRate, coverageType)) } } catch (FileNotFoundException fnfe) { throw new GradleException(fileNotFoundErrorMsg(coverageType), fnfe) @@ -87,7 +78,10 @@ class CoverageChecker { } @VisibleForTesting - protected static String errorMsg(String actual, String expected, CoverageType type) { + protected static String errorMsg(double overallRate, double minimumRate, CoverageType type) { + DecimalFormat df = new DecimalFormat("#.##", DecimalFormatSymbols.getInstance(Locale.ENGLISH)) + String actual = df.format(overallRate * 100) + String expected = df.format(minimumRate * 100) "Only $actual% of project is covered by tests instead of $expected% (coverageType: $type)" } diff --git a/src/test/groovy/org/scoverage/CoverageCheckerTest.groovy b/src/test/groovy/org/scoverage/CoverageCheckerTest.groovy index 04c695a..844968e 100644 --- a/src/test/groovy/org/scoverage/CoverageCheckerTest.groovy +++ b/src/test/groovy/org/scoverage/CoverageCheckerTest.groovy @@ -10,15 +10,13 @@ import org.junit.rules.TemporaryFolder import org.slf4j.LoggerFactory import java.nio.file.Paths -import java.text.NumberFormat +import static org.junit.Assert.assertEquals import static org.junit.Assert.assertThat import static org.junit.jupiter.api.Assertions.assertThrows class CoverageCheckerTest { - private NumberFormat numberFormat = NumberFormat.getInstance(Locale.US) - private File reportDir = Paths.get(getClass().getClassLoader().getResource("checkTask").toURI()).toFile() private CoverageChecker checker = new CoverageChecker(LoggerFactory.getLogger(CoverageCheckerTest.class)) @@ -31,7 +29,7 @@ class CoverageCheckerTest { @Test void failsWhenReportFileIsNotFound() { assertFailure(CoverageChecker.fileNotFoundErrorMsg(CoverageType.Line), { - checker.checkLineCoverage(tempDir.getRoot(), CoverageType.Line, 0.0, numberFormat) + checker.checkLineCoverage(tempDir.getRoot(), CoverageType.Line, 0.0) }) } @@ -39,60 +37,66 @@ class CoverageCheckerTest { @Test void failsWhenLineRateIsBelowTarget() { - assertFailure(CoverageChecker.errorMsg("66", "100", CoverageType.Line), { - checker.checkLineCoverage(reportDir, CoverageType.Line, 1.0, numberFormat) + assertFailure(CoverageChecker.errorMsg(0.66, 1.0, CoverageType.Line), { + checker.checkLineCoverage(reportDir, CoverageType.Line, 1.0) }) } @Test void doesNotFailWhenLineRateIsAtTarget() { - checker.checkLineCoverage(reportDir, CoverageType.Line, 0.66, numberFormat) + checker.checkLineCoverage(reportDir, CoverageType.Line, 0.66) } @Test void doesNotFailWhenLineRateIsAboveTarget() { - checker.checkLineCoverage(reportDir, CoverageType.Line, 0.6, numberFormat) + checker.checkLineCoverage(reportDir, CoverageType.Line, 0.6) } // Statement coverage @Test void failsWhenStatementRateIsBelowTarget() { - assertFailure(CoverageChecker.errorMsg(numberFormat.format(new Double(33.33)), "100", CoverageType.Statement), { - checker.checkLineCoverage(reportDir, CoverageType.Statement, 1.0, numberFormat) + assertFailure(CoverageChecker.errorMsg(0.3333, 1.0, CoverageType.Statement), { + checker.checkLineCoverage(reportDir, CoverageType.Statement, 1.0) }) } @Test void doesNotFailWhenStatementRateIsAtTarget() { - checker.checkLineCoverage(reportDir, CoverageType.Statement, 0.33, numberFormat) + checker.checkLineCoverage(reportDir, CoverageType.Statement, 0.33) } @Test void doesNotFailWhenStatementRateIsAboveTarget() { - checker.checkLineCoverage(reportDir, CoverageType.Statement, 0.3, numberFormat) + checker.checkLineCoverage(reportDir, CoverageType.Statement, 0.3) } // Branch coverage @Test void failsWhenBranchRateIsBelowTarget() { - assertFailure(CoverageChecker.errorMsg("50", "100", CoverageType.Branch), { - checker.checkLineCoverage(reportDir, CoverageType.Branch, 1.0, numberFormat) + assertFailure(CoverageChecker.errorMsg(0.5, 1.0, CoverageType.Branch), { + checker.checkLineCoverage(reportDir, CoverageType.Branch, 1.0) }) } @Test void doesNotFailWhenBranchRateIsAtTarget() { - checker.checkLineCoverage(reportDir, CoverageType.Branch, 0.5, numberFormat) + checker.checkLineCoverage(reportDir, CoverageType.Branch, 0.5) } @Test void doesNotFailWhenBranchRateIsAboveTarget() { - checker.checkLineCoverage(reportDir, CoverageType.Branch, 0.45, numberFormat) + checker.checkLineCoverage(reportDir, CoverageType.Branch, 0.45) + } + + @Test + void printsErrorMsgInEnglishWithUpTwoDecimalPointsPrecision() { + assertEquals("Only 54.32% of project is covered by tests instead of 90% (coverageType: Branch)", + CoverageChecker.errorMsg(0.54321, 0.9, CoverageType.Branch)) } - private void assertFailure(String message, Executable executable) { + private static void assertFailure(String message, Executable executable) { GradleException e = assertThrows(GradleException.class, executable) assertThat(e, new CauseMatcher(message)) } From 3e386b8cdb645b05fab3e0f1e2f6da1f642c0a18 Mon Sep 17 00:00:00 2001 From: Rafal Magda Date: Sun, 21 May 2023 19:53:47 +0200 Subject: [PATCH 154/167] (#194) Fix numbers decimal separator - Locale.US --- src/main/groovy/org/scoverage/CoverageChecker.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/groovy/org/scoverage/CoverageChecker.groovy b/src/main/groovy/org/scoverage/CoverageChecker.groovy index d185f82..ff240ba 100644 --- a/src/main/groovy/org/scoverage/CoverageChecker.groovy +++ b/src/main/groovy/org/scoverage/CoverageChecker.groovy @@ -79,7 +79,7 @@ class CoverageChecker { @VisibleForTesting protected static String errorMsg(double overallRate, double minimumRate, CoverageType type) { - DecimalFormat df = new DecimalFormat("#.##", DecimalFormatSymbols.getInstance(Locale.ENGLISH)) + DecimalFormat df = new DecimalFormat("#.##", DecimalFormatSymbols.getInstance(Locale.US)) String actual = df.format(overallRate * 100) String expected = df.format(minimumRate * 100) "Only $actual% of project is covered by tests instead of $expected% (coverageType: $type)" From f8ea2e03e3520e00d4dfd2530a41e35624f0a6be Mon Sep 17 00:00:00 2001 From: Stu Date: Sat, 24 Jun 2023 14:23:29 +0100 Subject: [PATCH 155/167] Fix "wrong number of arguments" when coverageDebug is enabled --- .../resources/projects/scala-single-module/build.gradle | 2 ++ src/main/groovy/org/scoverage/ScoverageWriter.java | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/functionalTest/resources/projects/scala-single-module/build.gradle b/src/functionalTest/resources/projects/scala-single-module/build.gradle index 593f52e..1fbb418 100644 --- a/src/functionalTest/resources/projects/scala-single-module/build.gradle +++ b/src/functionalTest/resources/projects/scala-single-module/build.gradle @@ -27,6 +27,8 @@ test { scoverage { minimumRate = 0.3 coverageType = org.scoverage.CoverageType.Line + // verify that debug mode works + coverageDebug = true } if (hasProperty("excludedFile")) { diff --git a/src/main/groovy/org/scoverage/ScoverageWriter.java b/src/main/groovy/org/scoverage/ScoverageWriter.java index 5e0278e..6131977 100644 --- a/src/main/groovy/org/scoverage/ScoverageWriter.java +++ b/src/main/groovy/org/scoverage/ScoverageWriter.java @@ -105,7 +105,7 @@ public void write(Set sourceDirs, File.separator + Constants.XMLReportFilename()); if (coverageDebug) { - ScoverageXmlWriter writerDebug = cst.newInstance(sourceDirsSeq, reportDir, true); + ScoverageXmlWriter writerDebug = cst.newInstance(sourceDirsSeq, reportDir, true, new Some<>(sourceEncoding)); writerDebug.write(coverage); logger.info("[scoverage] Written XML report with debug information to " + reportDir.getAbsolutePath() + From e5086204dcbcc96ebde9c859455c0cd16a978579 Mon Sep 17 00:00:00 2001 From: Marton Sigmond <5667024+msigmond@users.noreply.github.com> Date: Sun, 16 Jun 2024 20:37:52 -0400 Subject: [PATCH 156/167] upgrade to gradle 8.8 --- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d79d004..52a3974 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip -distributionSha256Sum=e111cb9948407e26351227dabce49822fb88c37ee72f1d1582a69c68af2e702f +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionSha256Sum=a4b4158601f8636cdeeab09bd76afb640030bb5b144aafe261a5e8af027dc612 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From b276e623737452758b85d645dca8c2f63cb3dc22 Mon Sep 17 00:00:00 2001 From: Marton Sigmond <5667024+msigmond@users.noreply.github.com> Date: Sun, 16 Jun 2024 20:39:28 -0400 Subject: [PATCH 157/167] upgrades - scoverage version to 2.1.1; default scala version to 2.13.14; Scala 3 cross version test to 3.4.2 --- .../scala-multi-module-cross-version/3_2/build.gradle | 6 +++--- .../java/org/scoverage/ScoverageFunctionalTest.java | 2 +- src/main/groovy/org/scoverage/ScoverageExtension.groovy | 2 +- src/main/groovy/org/scoverage/ScoveragePlugin.groovy | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/build.gradle b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/build.gradle index a703f21..93cb66d 100644 --- a/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/build.gradle +++ b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/build.gradle @@ -1,5 +1,5 @@ dependencies { - implementation 'org.scala-lang:scala3-library_3:3.2.0' - testImplementation 'org.scalatest:scalatest_3:3.2.14' - testImplementation "org.scalatestplus:junit-4-13_3:3.2.14.0" + implementation 'org.scala-lang:scala3-library_3:3.4.2' + testImplementation 'org.scalatest:scalatest_3:3.2.16' + testImplementation "org.scalatestplus:junit-4-13_3:3.2.16.0" } \ No newline at end of file diff --git a/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java b/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java index fdac1cf..1087874 100644 --- a/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java +++ b/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java @@ -121,7 +121,7 @@ private void configureArguments(String... arguments) { fullArguments.add("-PscalaVersionMajor=2"); fullArguments.add("-PscalaVersionMinor=13"); - fullArguments.add("-PscalaVersionBuild=10"); + fullArguments.add("-PscalaVersionBuild=14"); fullArguments.add("-PjunitVersion=5.3.2"); fullArguments.add("-PjunitPlatformVersion=1.3.2"); fullArguments.add("-PscalatestVersion=3.0.8"); diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index cb45b94..d2b5119 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -55,7 +55,7 @@ class ScoverageExtension { project.plugins.apply(ScalaPlugin.class) scoverageVersion = project.objects.property(String) - scoverageVersion.set('2.0.8') + scoverageVersion.set('2.1.1') scoverageScalaVersion = project.objects.property(String) diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index e0e88e3..3a3ec2f 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -24,7 +24,7 @@ class ScoveragePlugin implements Plugin { static final String CHECK_NAME = 'checkScoverage' static final String COMPILE_NAME = 'compileScoverageScala' static final String AGGREGATE_NAME = 'aggregateScoverage' - static final String DEFAULT_SCALA_VERSION = '2.13.6' + static final String DEFAULT_SCALA_VERSION = '2.13.14' static final String SCOVERAGE_COMPILE_ONLY_PROPERTY = 'scoverageCompileOnly'; static final String DEFAULT_REPORT_DIR = 'reports' + File.separatorChar + 'scoverage' From 43732c1a14e6a42efb4dd15dda4d0142821ba82f Mon Sep 17 00:00:00 2001 From: Marton Sigmond <5667024+msigmond@users.noreply.github.com> Date: Sat, 22 Jun 2024 18:12:07 -0400 Subject: [PATCH 158/167] Add support for -coverage-exclude-classlikes and -coverage-exclude-files for Scala 3 --- .../org/scoverage/ScalaSingleModuleTest.java | 2 +- .../ScalaSingleModuleTestScala3.java | 57 +++++++++++++++++++ .../org/scoverage/ScalaVersionArguments.java | 24 ++++++++ .../scoverage/ScoverageFunctionalTest.java | 12 ++-- .../projects/scala-single-module/build.gradle | 14 ++++- .../scala/org/hello/TestNothingSuite.scala | 6 +- .../src/test/scala/org/hello/WorldSuite.scala | 6 +- .../org/scoverage/ScoveragePlugin.groovy | 8 +++ 8 files changed, 112 insertions(+), 17 deletions(-) create mode 100644 src/functionalTest/java/org/scoverage/ScalaSingleModuleTestScala3.java create mode 100644 src/functionalTest/java/org/scoverage/ScalaVersionArguments.java diff --git a/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java b/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java index ed7b8f4..63f27c8 100644 --- a/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java @@ -135,7 +135,7 @@ public void reportScoverageWithoutNormalCompilationAndWithExcludedClasses() thro Assert.assertFalse(resolve(buildDir(), "classes/scala/scoverage/org/hello/World.class").exists()); } - private void assertReportFilesExist() { + protected void assertReportFilesExist() { Assert.assertTrue(resolve(reportDir(), "index.html").exists()); Assert.assertTrue(resolve(reportDir(), "org/hello/World.scala.html").exists()); diff --git a/src/functionalTest/java/org/scoverage/ScalaSingleModuleTestScala3.java b/src/functionalTest/java/org/scoverage/ScalaSingleModuleTestScala3.java new file mode 100644 index 0000000..38bf371 --- /dev/null +++ b/src/functionalTest/java/org/scoverage/ScalaSingleModuleTestScala3.java @@ -0,0 +1,57 @@ +package org.scoverage; + +import org.junit.Assert; + +import java.util.List; + +public class ScalaSingleModuleTestScala3 extends ScalaSingleModuleTest { + + @Override + protected List getVersionAgruments() { + return ScalaVersionArguments.version3; + } + + @Override + public void checkScoverage() throws Exception { + AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME()); + + result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + + assertReportFilesExist(); + assertCoverage(66.67); + } + + @Override + public void reportScoverageWithExcludedClasses() throws Exception { + AssertableBuildResult result = run("clean", ScoveragePlugin.getREPORT_NAME(), + "-PexcludedFile=.*"); + + result.assertTaskSucceeded(ScoveragePlugin.getCOMPILE_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); + + Assert.assertTrue(resolve(reportDir(), "index.html").exists()); + Assert.assertFalse(resolve(reportDir(), "org/hello/World.scala.html").exists()); + assertCoverage(100.0); // coverage is 100 since no classes are covered + + // compiled class should exist in the default classes directory, but not in scoverage + Assert.assertTrue(resolve(buildDir(), "classes/scala/main/org/hello/World.class").exists()); + } + + @Override + public void reportScoverageWithoutNormalCompilationAndWithExcludedClasses() throws Exception { + AssertableBuildResult result = run("clean", ScoveragePlugin.getREPORT_NAME(), + "-PexcludedFile=.*", "-P" + ScoveragePlugin.getSCOVERAGE_COMPILE_ONLY_PROPERTY()); + + Assert.assertTrue(resolve(reportDir(), "index.html").exists()); + Assert.assertFalse(resolve(reportDir(), "org/hello/World.scala.html").exists()); + assertCoverage(100.0); // coverage is 100 since no classes are covered + + // compiled class should exist in the default classes directory, but not in scoverage + Assert.assertTrue(resolve(buildDir(), "classes/scala/main/org/hello/World.class").exists()); + } +} diff --git a/src/functionalTest/java/org/scoverage/ScalaVersionArguments.java b/src/functionalTest/java/org/scoverage/ScalaVersionArguments.java new file mode 100644 index 0000000..dd622ce --- /dev/null +++ b/src/functionalTest/java/org/scoverage/ScalaVersionArguments.java @@ -0,0 +1,24 @@ +package org.scoverage; + +import java.util.Arrays; +import java.util.List; + +public interface ScalaVersionArguments { + List version2 = Arrays.asList( + "-PscalaVersionMajor=2", + "-PscalaVersionMinor=13", + "-PscalaVersionBuild=14", + "-PjunitVersion=5.3.2", + "-PjunitPlatformVersion=1.3.2", + "-PscalatestVersion=3.2.16" + ); + + List version3 = Arrays.asList( + "-PscalaVersionMajor=3", + "-PscalaVersionMinor=4", + "-PscalaVersionBuild=2", + "-PjunitVersion=5.3.2", + "-PjunitPlatformVersion=1.3.2", + "-PscalatestVersion=3.2.16" + ); +} diff --git a/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java b/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java index 1087874..f24d1f7 100644 --- a/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java +++ b/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java @@ -115,16 +115,14 @@ private Double coverage(File reportDir, CoverageType coverageType) throws IOExce return coverageType.normalize(rawValue) * 100.0; } + protected List getVersionAgruments() { + return ScalaVersionArguments.version2; + } + private void configureArguments(String... arguments) { - List fullArguments = new ArrayList<>(); + List fullArguments = new ArrayList<>(getVersionAgruments()); - fullArguments.add("-PscalaVersionMajor=2"); - fullArguments.add("-PscalaVersionMinor=13"); - fullArguments.add("-PscalaVersionBuild=14"); - fullArguments.add("-PjunitVersion=5.3.2"); - fullArguments.add("-PjunitPlatformVersion=1.3.2"); - fullArguments.add("-PscalatestVersion=3.0.8"); if (Boolean.parseBoolean(System.getProperty("failOnWarning"))) { fullArguments.add("--warning-mode=fail"); } else { diff --git a/src/functionalTest/resources/projects/scala-single-module/build.gradle b/src/functionalTest/resources/projects/scala-single-module/build.gradle index 1fbb418..fd9d9f2 100644 --- a/src/functionalTest/resources/projects/scala-single-module/build.gradle +++ b/src/functionalTest/resources/projects/scala-single-module/build.gradle @@ -12,12 +12,20 @@ apply plugin: 'java' apply plugin: 'scala' dependencies { - implementation group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + if (project.getProperties().get("scalaVersionMajor").equals("2")) { + implementation group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + + testImplementation group: 'org.scalatest', name: 'scalatest_2.13', version: scalatestVersion + testImplementation group: 'org.scalatestplus', name: 'junit-4-13_2.13', version: "${scalatestVersion}.0" + } else { + implementation group: 'org.scala-lang', name: 'scala3-library_3', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + + testImplementation group: 'org.scalatest', name: 'scalatest_3', version: scalatestVersion + testImplementation group: 'org.scalatestplus', name: 'junit-4-13_3', version: "${scalatestVersion}.0" + } testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion testImplementation group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion - - testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion } test { diff --git a/src/functionalTest/resources/projects/scala-single-module/src/test/scala/org/hello/TestNothingSuite.scala b/src/functionalTest/resources/projects/scala-single-module/src/test/scala/org/hello/TestNothingSuite.scala index 1ac25b5..76de321 100644 --- a/src/functionalTest/resources/projects/scala-single-module/src/test/scala/org/hello/TestNothingSuite.scala +++ b/src/functionalTest/resources/projects/scala-single-module/src/test/scala/org/hello/TestNothingSuite.scala @@ -1,11 +1,11 @@ package org.hello import org.junit.runner.RunWith -import org.scalatest.FunSuite -import org.scalatest.junit.JUnitRunner +import org.scalatest.funsuite._ +import org.scalatestplus.junit.JUnitRunner @RunWith(classOf[JUnitRunner]) -class TestNothingSuite extends FunSuite { +class TestNothingSuite extends AnyFunSuite { test("nothing") { } diff --git a/src/functionalTest/resources/projects/scala-single-module/src/test/scala/org/hello/WorldSuite.scala b/src/functionalTest/resources/projects/scala-single-module/src/test/scala/org/hello/WorldSuite.scala index 7281a12..477f27a 100644 --- a/src/functionalTest/resources/projects/scala-single-module/src/test/scala/org/hello/WorldSuite.scala +++ b/src/functionalTest/resources/projects/scala-single-module/src/test/scala/org/hello/WorldSuite.scala @@ -1,11 +1,11 @@ package org.hello import org.junit.runner.RunWith -import org.scalatest.FunSuite -import org.scalatest.junit.JUnitRunner +import org.scalatest.funsuite._ +import org.scalatestplus.junit.JUnitRunner @RunWith(classOf[JUnitRunner]) -class WorldSuite extends FunSuite { +class WorldSuite extends AnyFunSuite { test("foo") { new World().foo() diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 3a3ec2f..8fc8b2c 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -206,6 +206,14 @@ class ScoveragePlugin implements Plugin { } else { parameters.add("-sourceroot:${project.rootDir.absolutePath}".toString()) parameters.add("-coverage-out:${extension.dataDir.get().absolutePath}".toString()) + if (extension.excludedPackages.get()) { + def packages = extension.excludedPackages.get().join(',') + parameters.add("-coverage-exclude-classlikes:$packages".toString()) + } + if (extension.excludedFiles.get()) { + def packages = extension.excludedFiles.get().join(';') + parameters.add("-coverage-exclude-files:$packages".toString()) + } scalaCompileOptions.additionalParameters = parameters } } From 250b840cc9524c60295183ce8c4499b53f7c4f59 Mon Sep 17 00:00:00 2001 From: Marton Sigmond <5667024+msigmond@users.noreply.github.com> Date: Sat, 22 Jun 2024 22:27:37 -0400 Subject: [PATCH 159/167] Add support for -coverage-exclude-classlikes and -coverage-exclude-files for Scala 3 (only ScalaSingleModuleTest goes with new scalatest version) --- .../java/org/scoverage/ScalaSingleModuleTest.java | 7 +++++++ .../java/org/scoverage/ScalaVersionArguments.java | 9 +++++++++ .../java/org/scoverage/ScoverageFunctionalTest.java | 2 +- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java b/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java index 63f27c8..dd74b13 100644 --- a/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java @@ -4,12 +4,19 @@ import org.junit.Ignore; import org.junit.Test; +import java.util.List; + public class ScalaSingleModuleTest extends ScoverageFunctionalTest { public ScalaSingleModuleTest() { super("scala-single-module"); } + @Override + protected List getVersionAgruments() { + return ScalaVersionArguments.version2; + } + @Test public void test() { diff --git a/src/functionalTest/java/org/scoverage/ScalaVersionArguments.java b/src/functionalTest/java/org/scoverage/ScalaVersionArguments.java index dd622ce..e2fbb1c 100644 --- a/src/functionalTest/java/org/scoverage/ScalaVersionArguments.java +++ b/src/functionalTest/java/org/scoverage/ScalaVersionArguments.java @@ -4,6 +4,15 @@ import java.util.List; public interface ScalaVersionArguments { + List version2WithLegacyScalatest = Arrays.asList( + "-PscalaVersionMajor=2", + "-PscalaVersionMinor=13", + "-PscalaVersionBuild=14", + "-PjunitVersion=5.3.2", + "-PjunitPlatformVersion=1.3.2", + "-PscalatestVersion=3.0.8" + ); + List version2 = Arrays.asList( "-PscalaVersionMajor=2", "-PscalaVersionMinor=13", diff --git a/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java b/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java index f24d1f7..c1992d8 100644 --- a/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java +++ b/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java @@ -116,7 +116,7 @@ private Double coverage(File reportDir, CoverageType coverageType) throws IOExce } protected List getVersionAgruments() { - return ScalaVersionArguments.version2; + return ScalaVersionArguments.version2WithLegacyScalatest; } private void configureArguments(String... arguments) { From e910bce8276e6d9bd2ae2d12a79c5e19979456a5 Mon Sep 17 00:00:00 2001 From: Marton Sigmond <5667024+msigmond@users.noreply.github.com> Date: Sat, 22 Jun 2024 22:45:33 -0400 Subject: [PATCH 160/167] Add support for -coverage-exclude-classlikes and -coverage-exclude-files for Scala 3 (README.md updated) --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 69a5791..e46cca0 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ You can find instructions on how to apply the plugin at http://plugins.gradle.or The plugin exposes multiple options that can be configured by setting them in an `scoverage` block within the project's build script. These options are as follows: -* `scoverageVersion = ` (default `"1.4.8`): The version of the scoverage scalac plugin. This (gradle) plugin +* `scoverageVersion = ` (default `"2.1.1`): The version of the scoverage scalac plugin. This (gradle) plugin should be compatible with all 1+ versions. * `scoverageScalaVersion = ` (default `detected`): The scala version of the scoverage scalac plugin. This @@ -64,6 +64,10 @@ required for the validation to pass (otherwise `checkScoverage` will fail the bu `checkScoverage` task. For more information on the different types, please refer to the documentation of the scalac plugin (https://github.com/scoverage/scalac-scoverage-plugin). +* `excludedFiles = ` (default `not set`): Comma separated list of regexes for files to exclude from coverage. + +* `excludedPackages = ` (default `not set`): Comma separated list of regexes for packages, classes and modules to exclude from coverage. + #### Multiple check tasks It is possible to configure multiple checks; for instance, one check for a statement rate and another for a branch rate: From 04b360f8e613d545dcd49a1b1e4b8045e01ab9b5 Mon Sep 17 00:00:00 2001 From: Marton Sigmond <5667024+msigmond@users.noreply.github.com> Date: Mon, 24 Jun 2024 07:35:34 -0400 Subject: [PATCH 161/167] upgrade to gradle 8.8 (fix deprecated features) --- build.gradle | 12 +++++++----- .../dependency-management/build.gradle | 2 +- .../build.gradle | 2 +- .../build.gradle | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index b0251c2..c411888 100644 --- a/build.gradle +++ b/build.gradle @@ -38,13 +38,15 @@ gradlePlugin { apply plugin: 'maven-publish' apply plugin: 'groovy' -sourceCompatibility = '1.8' -targetCompatibility = '1.8' - +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} dependencies { - compileOnly "org.scoverage:scalac-scoverage-plugin_2.13.8:2.0.7" - compileOnly "org.scoverage:scalac-scoverage-reporter_2.13:2.0.7" + compileOnly 'org.scoverage:scalac-scoverage-plugin_2.13.14:2.1.1' + compileOnly 'org.scoverage:scalac-scoverage-reporter_2.13:2.1.1' + implementation group: 'commons-io', name: 'commons-io', version: '2.6' testImplementation 'junit:junit:4.12' diff --git a/src/functionalTest/resources/projects/detect-scala-library/dependency-management/build.gradle b/src/functionalTest/resources/projects/detect-scala-library/dependency-management/build.gradle index 9232cf4..0598896 100644 --- a/src/functionalTest/resources/projects/detect-scala-library/dependency-management/build.gradle +++ b/src/functionalTest/resources/projects/detect-scala-library/dependency-management/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'io.spring.dependency-management' version "1.0.4.RELEASE" + id 'io.spring.dependency-management' version "1.1.5" id 'org.scoverage' } diff --git a/src/functionalTest/resources/projects/scala-single-module-dependency-manager/build.gradle b/src/functionalTest/resources/projects/scala-single-module-dependency-manager/build.gradle index 7c1f4e6..d972fb4 100644 --- a/src/functionalTest/resources/projects/scala-single-module-dependency-manager/build.gradle +++ b/src/functionalTest/resources/projects/scala-single-module-dependency-manager/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'io.spring.dependency-management' version "1.0.4.RELEASE" + id 'io.spring.dependency-management' version "1.1.5" id 'org.scoverage' } diff --git a/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle index 3f7ffd5..1f4b316 100644 --- a/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle +++ b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'io.spring.dependency-management' version "1.0.4.RELEASE" + id 'io.spring.dependency-management' version "1.1.5" id 'org.scoverage' id 'jvm-test-suite' } From b2383019225522e566fc549c69dfd1dcc0f2306d Mon Sep 17 00:00:00 2001 From: Stu Date: Sat, 24 Jun 2023 14:24:14 +0100 Subject: [PATCH 162/167] fix publishing issues --- build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.gradle b/build.gradle index c411888..85cff81 100644 --- a/build.gradle +++ b/build.gradle @@ -30,6 +30,7 @@ gradlePlugin { id = 'org.scoverage' implementationClass = 'org.scoverage.ScoveragePlugin' displayName = 'Gradle Scoverage plugin' + description = 'gradle-scoverage is a Gradle plugin for calculating code coverage using Scoverage' tags.set(['coverage', 'scala', 'scoverage']) } } @@ -183,6 +184,7 @@ if (project.properties.containsKey('signing.keyId')) { signing { sign publishing.publications.mavenJava } + project.tasks.publishMavenJavaPublicationToMavenRepository.inputs.files(project.tasks.signMavenJavaPublication) } // see https://stackoverflow.com/questions/44679007 From ffea9fdac0fb526b10414951fb60f02ecd95f98e Mon Sep 17 00:00:00 2001 From: Stu Date: Mon, 4 Sep 2023 23:12:59 +0100 Subject: [PATCH 163/167] remove unused code --- .../org/scoverage/ScoveragePlugin.groovy | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 8fc8b2c..27b952f 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -9,7 +9,6 @@ import org.gradle.api.plugins.PluginAware import org.gradle.api.plugins.scala.ScalaPlugin import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.TaskProvider -import org.gradle.api.tasks.scala.ScalaCompile import org.gradle.api.tasks.testing.Test import java.nio.file.Files @@ -399,22 +398,4 @@ class ScoveragePlugin implements Plugin { } } - private Set recursiveDependenciesOf(Task task, boolean sameProjectOnly) { - def cache = sameProjectOnly ? sameProjectTaskDependencies : crossProjectTaskDependencies - if (!cache.containsKey(task)) { - def directDependencies = task.getTaskDependencies().getDependencies(task) - if (sameProjectOnly) { - directDependencies = directDependencies.findAll { - it.project == task.project - } - } - def nestedDependencies = directDependencies.collect { recursiveDependenciesOf(it, sameProjectOnly) }.flatten() - def dependencies = directDependencies + nestedDependencies - - cache.put(task, dependencies) - return dependencies - } else { - return cache.get(task) - } - } } From 007334f56d68d550728df36c7c8b83b6a25f30dd Mon Sep 17 00:00:00 2001 From: Stu Date: Mon, 4 Sep 2023 23:13:27 +0100 Subject: [PATCH 164/167] mark the scoverage configuration as resolvable but not consumable --- src/main/groovy/org/scoverage/ScoveragePlugin.groovy | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 27b952f..a6a33d2 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -58,6 +58,8 @@ class ScoveragePlugin implements Plugin { visible = false transitive = true description = 'Scoverage dependencies' + canBeResolved = true + canBeConsumed = false } project.afterEvaluate { From 46afb37beea74337b9b2cd3e3203d3ecb3d5d4c3 Mon Sep 17 00:00:00 2001 From: Stu Date: Tue, 25 Jun 2024 21:50:09 +0100 Subject: [PATCH 165/167] enable skipped test --- src/functionalTest/java/org/scoverage/CompositeBuildTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/functionalTest/java/org/scoverage/CompositeBuildTest.java b/src/functionalTest/java/org/scoverage/CompositeBuildTest.java index 21a5c6d..4bd4bb7 100644 --- a/src/functionalTest/java/org/scoverage/CompositeBuildTest.java +++ b/src/functionalTest/java/org/scoverage/CompositeBuildTest.java @@ -18,14 +18,12 @@ public CompositeBuildTest() { super("composite-build"); } - @Ignore @Test public void buildComposite() { runComposite("clean", "build"); } - @Ignore @Test public void reportComposite() { From 7efebd868db6c4f41dbbc7e663c61e0b32d2dddf Mon Sep 17 00:00:00 2001 From: Marton Sigmond <5667024+msigmond@users.noreply.github.com> Date: Sun, 30 Jun 2024 16:04:15 -0400 Subject: [PATCH 166/167] A hint for Kotlin DSL users --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e46cca0..f5fd7b1 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,15 @@ scoverage { coverageType = CoverageType.Statement } } -``` +``` + +In case you use the Kotlin DSL, the following snippet can give you pointers for configuring Scoverage: +```kotlin +scoverage { + minimumRate.set(BigDecimal("0.80")) + excludedPackages.set(listOf("com.example.scala.demo")) +} +``` ### Compatibility with Consistent Versions Plugin From ffde760f8d74e6855afd02103b86f01840b3007d Mon Sep 17 00:00:00 2001 From: Stu Date: Mon, 16 Dec 2024 21:10:29 +0000 Subject: [PATCH 167/167] upgrade to gradle 8.11.1 --- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 52a3974..7dbd4a7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip -distributionSha256Sum=a4b4158601f8636cdeeab09bd76afb640030bb5b144aafe261a5e8af027dc612 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +distributionSha256Sum=f397b287023acdba1e9f6fc5ea72d22dd63669d59ed4a289a29b1a76eee151c6 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists