diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml new file mode 100644 index 0000000..a8189eb --- /dev/null +++ b/.github/workflows/gradle.yml @@ -0,0 +1,38 @@ +# 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: + 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 + - 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 ${{ matrix.additional-check-args }} diff --git a/.gitignore b/.gitignore index 7a275d3..143f20e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ +classes build +out .gradle *.iml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 87912d4..0000000 --- a/.travis.yml +++ /dev/null @@ -1,3 +0,0 @@ -language: groovy -script: - - "gradle build test" \ No newline at end of file diff --git a/README.md b/README.md index c59a98d..f5fd7b1 100644 --- a/README.md +++ b/README.md @@ -1,99 +1,194 @@ -[![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 ================ A plugin to enable the use of Scoverage in a gradle Scala project. -Getting started ---------------- -```groovy -http://plugins.gradle.org/plugin/org.scoverage +Usage +----- -This creates an additional task `testScoverage` which will run tests against instrumented code. +You can find instructions on how to apply the plugin at http://plugins.gradle.org/plugin/org.scoverage -A further task `reportScoverage` produces XML and HTML reports for analysing test code coverage. +### Available tasks -You need to configure the version of Scoverage that will be used. This plugin should be compatible with all 1+ versions. +1. `reportScoverage`: Produces XML and HTML reports for analysing test code coverage. -dependencies { - scoverage 'org.scoverage:scalac-scoverage-plugin_2.11:1.1.0', 'org.scoverage:scalac-scoverage-runtime_2.11:1.1.0' + 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`: 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 + 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`). + + One can still use `reportScoverage` in order to generate a report without aggregation. + +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`. + +**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 + +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 `"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 +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). + +* `coverageOutputXML = ` (default `true`): Enables/disables scoverage XML output (for both aggregated and non-aggregated reports). + +* `coverageOutputHTML = ` (default `true`): Enables/disables scoverage HTML output (for both aggregated and non-aggregated reports). + +* `coverageDebug = ` (default `false`): Enables/disables scoverage debug output (for both aggregated and non-aggregated reports). + +* `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 = ` (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). + +* `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: +``` +scoverage { + check { + minimumRate = 0.5 + coverageType = CoverageType.Statement + } + check { + minimumRate = 0.8 + coverageType = CoverageType.Branch + } } ``` -Then launch command : -`gradle reportScoverage` or `gradle checkScoverage` +Note that you cannot mix multiple-checks syntax with plain check configuration: +``` +// ok +scoverage { + check { + minimumRate = 0.5 + coverageType = CoverageType.Statement + } +} -Available tasks ---------------- +// ok +scoverage { + minimumRate = 0.2 +} -* 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. +// NOT ok +scoverage { + minimumRate = 0.2 + check { + minimumRate = 0.5 + coverageType = CoverageType.Statement + } +} +``` -ReportScoverage ---------------- +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")) +} +``` -You can configure output generated by `gradle reportScoverage` using flags: +### Compatibility with Consistent Versions Plugin -| 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. | +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. -Aggregating Reports -------------------- +Migration to 8.x +---------------- -There is now experimental support for aggregating coverage statistics across sub-projects. +* Requires scoverage 2.0 +* Adds support for Scala 3 +* Drops support for disabling normal compilation -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. +Migration to 7.x +---------------- -You also have to declare this task: +* Running without normal compilation is now made with `-PscoverageCompileOnly` instead of `-x compileScala`. -```groovy -task aggregateScoverage(type: org.scoverage.ScoverageAggregate) -``` +Migration to 5.x +---------------- -This will produce a report into `build/scoverage-aggregate` directory. +* 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 -Aggregation uses same flags as reporting for enabling/disabling different output types. +Migration to 4.x +---------------- -For checking coverage of the aggregated result, configure the checkScoverage task: +* 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 -checkScoverage { - reportDir = file("$buildDir/scoverage-aggregate") +plugins { + id 'org.scoverage' version '4.0.0' +} +subprojects { + apply plugin: 'org.scoverage' } ``` -CheckScoverage --------------- +Migration to 3.x +---------------- -By default, when you launch `gradle checkScoverage` build fail if only 75% of statements in project is covered by tests. +* No more `testScoverage` task; instead, `test` will run coverage whenever the build is invoked with any of the scoverage tasks. -To configure it as you want, add this configuration : -``` -checkScoverage { - minimumRate = 0.5 +* 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' } ``` -You can also modify type of value to check from `Statement`s to `Line`s or `Branch`es: +* All configurations are configured in `scoverage` block. For instance: +```groovy +// do this +scoverage { + minimumRate = 0.5 +} -``` +// instead of this checkScoverage { - coverageType = 'Line' 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 { - coverageType = 'Branch' - minimumRate = 0.5 + reportDir = file("$buildDir/scoverage-aggregate") } ``` diff --git a/build.gradle b/build.gradle index 3350136..85cff81 100644 --- a/build.gradle +++ b/build.gradle @@ -1,29 +1,18 @@ -// First, apply the publishing plugin -buildscript { - repositories { - maven { - url "https://plugins.gradle.org/m2/" - } - } - dependencies { - classpath "com.gradle.publish:plugin-publish-plugin:0.9.2" - } -} - -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' - } +plugins { + id 'java-gradle-plugin' + id "com.gradle.plugin-publish" version "1.1.0" + id "org.jetbrains.gradle.plugin.idea-ext" version "1.0" } repositories { mavenCentral() } +group 'org.scoverage' +description = 'gradle-scoverage is a Gradle plugin for calculating code coverage using Scoverage' +if (project.version == 'unspecified') { + version = '8.0.0-SNAPSHOT' +} ext { website = 'http://scoverage.org' vcsUrl = 'https://github.com/scoverage/gradle-scoverage.git' @@ -32,112 +21,187 @@ ext { sonatypePass = System.env.SONATYPE_PASS } -apply plugin: 'idea' -apply plugin: 'maven' -apply plugin: 'groovy' +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' + description = 'gradle-scoverage is a Gradle plugin for calculating code coverage using Scoverage' + tags.set(['coverage', 'scala', 'scoverage']) + } + } +} -group 'org.scoverage' -sourceCompatibility = '1.6' -targetCompatibility = '1.6' +apply plugin: 'maven-publish' +apply plugin: 'groovy' -configurations { - scoverage - compile.extendsFrom scoverage +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 } dependencies { - compile gradleApi() - compile localGroovy() - scoverage 'org.scoverage:scalac-scoverage-plugin_2.11:1.0.2' - testCompile 'org.hamcrest:hamcrest-library:1.3' -} + compileOnly 'org.scoverage:scalac-scoverage-plugin_2.13.14:2.1.1' + compileOnly 'org.scoverage:scalac-scoverage-reporter_2.13:2.1.1' -task groovydocJar(type: Jar, dependsOn: groovydoc) { - classifier = 'groovydoc' - from "$buildDir/docs/groovydoc" -} + 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' -task sourcesJar(type: Jar) { - from sourceSets.main.allSource - classifier = 'sources' + testImplementation 'org.hamcrest:hamcrest:2.2' } -test { - dependsOn jar +sourceSets { + functionalTest { + java.srcDir file('src/functionalTest/java') + 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 + } } -artifacts { - archives jar - archives groovydocJar - archives sourcesJar +configurations { + functionalTestImplementation.extendsFrom testImplementation + functionalTestRuntimeOnly.extendsFrom testRuntimeOnly + + crossScalaVersionTestImplementation.extendsFrom testImplementation + crossScalaVersionTestRuntimeOnly.extendsFrom testRuntimeOnly } -if (project.properties.containsKey('signing.keyId')) { - apply plugin: 'signing' - signing { - sign configurations.archives +task crossScalaVersionTest(type: Test) { + description = 'Runs the cross scala version functional test.' + group = 'verification' + testClassesDirs = sourceSets.crossScalaVersionTest.output + classpath = sourceSets.crossScalaVersionTest.runtimeClasspath + forkEvery = 1 // crucial to run every test in its own JVM + + testLogging { + events 'passed', 'failed', 'skipped' + showStandardStreams = System.env.CI == 'true' } + + mustRunAfter test } +check.dependsOn crossScalaVersionTest -pluginBundle { - website = project.website - vcsUrl = project.vcsUrl - description = project.description - tags = ['coverage', 'scala', 'scoverage'] +task functionalTest(type: Test) { + description = 'Runs the functional tests.' + group = 'verification' + testClassesDirs = sourceSets.functionalTest.output + classpath = sourceSets.functionalTest.runtimeClasspath - plugins { - scoveragePlugin { - id = 'org.scoverage' - displayName = 'Gradle Scoverage plugin' - } + testLogging { + events 'passed', 'failed', 'skipped' + showStandardStreams = System.env.CI == 'true' } + + systemProperty 'failOnWarning', project.hasProperty('failOnWarning') + + mustRunAfter crossScalaVersionTest } +check.dependsOn functionalTest -uploadArchives { - repositories { - mavenDeployer { - if (project.properties.containsKey('signing.keyId')) { - beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } - } +gradlePlugin { + testSourceSets sourceSets.functionalTest, sourceSets.crossScalaVersionTest +} - snapshotRepository(url: 'https://oss.sonatype.org/content/repositories/snapshots') { - authentication(userName: sonatypeUser, password: sonatypePass) - } +task groovydocJar(type: Jar, dependsOn: groovydoc) { + from "$buildDir/docs/groovydoc" + archiveClassifier.set('groovydoc') +} - repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { - authentication(userName: sonatypeUser, password: sonatypePass) - } +def propOrDefault(String property) { + if (project.hasProperty(property)) { + return project.getProperty(property) + } else { + return '' + } +} - pom.project { - name 'GradleScoverage' - description project.description - url project.website +publishing { + repositories { + maven { + url = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" + credentials(PasswordCredentials) { + username = propOrDefault('sonatypeUser') + password = propOrDefault('sonatypePass') + } + } + } + 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' } developer { - id 'ubourdon' + id = 'D-Roch' } developer { - id 'D-Roch' + id = 'eyalroth' } } } + from components.java + artifact groovydocJar } } } + +if (project.properties.containsKey('signing.keyId')) { + apply plugin: 'signing' + signing { + sign publishing.publications.mavenJava + } + project.tasks.publishMavenJavaPublicationToMavenRepository.inputs.files(project.tasks.signMavenJavaPublication) +} + +// 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 + } +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 3c7abdf..7454180 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 39622f4..7dbd4a7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Jun 16 21:08:06 BST 2014 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +distributionSha256Sum=f397b287023acdba1e9f6fc5ea72d22dd63669d59ed4a289a29b1a76eee151c6 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-2.9-bin.zip diff --git a/gradlew b/gradlew index 91a7e26..1b6c787 100755 --- a/gradlew +++ b/gradlew @@ -1,79 +1,129 @@ -#!/usr/bin/env bash +#!/bin/sh + +# +# 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. +# You may obtain a copy of the License at +# +# 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, +# 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 -## +# +# 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/. +# ############################################################################## -# 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 +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 + +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 ( ) { +warn () { echo "$*" -} +} >&2 -die ( ) { +die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | 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. 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 @@ -82,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 @@ -90,75 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "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" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - # 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 # 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=$((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 -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +# 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. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index aec9973..ac1b06f 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 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, +@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 @@ -8,20 +24,23 @@ @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 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" + @rem Find java.exe 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. @@ -35,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% @@ -45,34 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windowz 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. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -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 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 diff --git a/src/crossScalaVersionTest/java/org/scoverage/Scala212Test.java b/src/crossScalaVersionTest/java/org/scoverage/Scala212Test.java new file mode 100644 index 0000000..2c538ae --- /dev/null +++ b/src/crossScalaVersionTest/java/org/scoverage/Scala212Test.java @@ -0,0 +1,7 @@ +package org.scoverage; + +public class Scala212Test extends ScalaVersionTest { + public Scala212Test() { + super("2_12"); + } +} \ No newline at end of file diff --git a/src/crossScalaVersionTest/java/org/scoverage/Scala213Test.java b/src/crossScalaVersionTest/java/org/scoverage/Scala213Test.java new file mode 100644 index 0000000..31d9a38 --- /dev/null +++ b/src/crossScalaVersionTest/java/org/scoverage/Scala213Test.java @@ -0,0 +1,7 @@ +package org.scoverage; + +public class Scala213Test extends ScalaVersionTest { + public Scala213Test() { + super("2_13"); + } +} \ No newline at end of file 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/java/org/scoverage/ScalaCrossVersionAggregationTest.java b/src/crossScalaVersionTest/java/org/scoverage/ScalaCrossVersionAggregationTest.java new file mode 100644 index 0000000..a7b7e5b --- /dev/null +++ b/src/crossScalaVersionTest/java/org/scoverage/ScalaCrossVersionAggregationTest.java @@ -0,0 +1,36 @@ +package org.scoverage; + +import org.junit.Assert; +import org.junit.Test; + +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_12:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded("2_13:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded(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(), "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 new file mode 100644 index 0000000..657ca8e --- /dev/null +++ b/src/crossScalaVersionTest/java/org/scoverage/ScalaVersionTest.java @@ -0,0 +1,32 @@ +package org.scoverage; + +import org.junit.Assert; +import org.junit.Test; + +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, "org/hello/World" + scalaVersion + ".scala.html").exists()); + } +} 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 new file mode 100644 index 0000000..a510442 --- /dev/null +++ b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_12/build.gradle @@ -0,0 +1,4 @@ +dependencies { + 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_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 new file mode 100644 index 0000000..c0cc10b --- /dev/null +++ b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_12/src/main/scala/org/hello/World2_12.scala @@ -0,0 +1,9 @@ +package org.hello + +class World2_12 { + + def foo(): String = { + val s = "2" + "12" + s + } +} \ No newline at end of file diff --git a/src/crossScalaVersionTest/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 new file mode 100644 index 0000000..23e5b04 --- /dev/null +++ b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_12/src/test/scala/org/hello/World2_12Suite.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 World2_12Suite extends FunSuite { + + test("foo") { + new World2_12().foo() + } +} \ No newline at end of file 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 new file mode 100644 index 0000000..ea57742 --- /dev/null +++ b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_13/build.gradle @@ -0,0 +1,4 @@ +dependencies { + 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/crossScalaVersionTest/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 new file mode 100644 index 0000000..d18034b --- /dev/null +++ b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_13/src/main/scala/org/hello/World2_13.scala @@ -0,0 +1,9 @@ +package org.hello + +class World2_13 { + + def foo(): String = { + val s = "2" + "12" + s + } +} \ No newline at end of file diff --git a/src/crossScalaVersionTest/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 new file mode 100644 index 0000000..0628dc4 --- /dev/null +++ b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/2_13/src/test/scala/org/hello/World2_13Suite.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 World2_13().foo() + } +} \ No newline at end of file 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..93cb66d --- /dev/null +++ b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/3_2/build.gradle @@ -0,0 +1,5 @@ +dependencies { + 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/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..4582dc8 --- /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.AnyFunSuite +import org.scalatestplus.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class World3_2Suite extends AnyFunSuite { + + test("foo") { + new World3_2().foo() + } +} \ No newline at end of file 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 new file mode 100644 index 0000000..38e7b9f --- /dev/null +++ b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/build.gradle @@ -0,0 +1,35 @@ +plugins { + id 'org.scoverage' apply false +} + +allprojects { + repositories { + mavenCentral() + } +} + +description = 'a multi-module Scala project with multiple Scala versions that builds successfully with 100% coverage' + +allprojects { + + apply plugin: 'java' + apply plugin: 'scala' + apply plugin: 'org.scoverage' + + dependencies { + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + testImplementation 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/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/settings.gradle b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/settings.gradle new file mode 100644 index 0000000..9123650 --- /dev/null +++ b/src/crossScalaVersionTest/resources/projects/scala-multi-module-cross-version/settings.gradle @@ -0,0 +1 @@ +include '2_12', '2_13', '3_2' \ No newline at end of file diff --git a/src/functionalTest/java/org/scoverage/CompositeBuildTest.java b/src/functionalTest/java/org/scoverage/CompositeBuildTest.java new file mode 100644 index 0000000..4bd4bb7 --- /dev/null +++ b/src/functionalTest/java/org/scoverage/CompositeBuildTest.java @@ -0,0 +1,44 @@ +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 Issue #94. + */ +public class CompositeBuildTest extends ScoverageFunctionalTest { + + public CompositeBuildTest() { + super("composite-build"); + } + + @Test + public void buildComposite() { + + runComposite("clean", "build"); + } + + @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/java/org/scoverage/DetectScalaLibraryTest.java b/src/functionalTest/java/org/scoverage/DetectScalaLibraryTest.java new file mode 100644 index 0000000..26383b4 --- /dev/null +++ b/src/functionalTest/java/org/scoverage/DetectScalaLibraryTest.java @@ -0,0 +1,74 @@ +package org.scoverage; + +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.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.13"; + private static final String SCALA_LIBRARY_PARAMETER = "-PdetectedScalaLibraryVersion="; + + @Parameterized.Parameter(0) + public String projectDir; + + @Parameterized.Parameter(1) + 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", ".+"}, 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]}, +// disabled until the consistent-versions plugin supports Gradle 7 +// {"/gradle-consistent-versions", new String[] {"ignored"}, false, new String[] {"--write-locks"}}, + }; + return Arrays.asList(data); + } + + public DetectScalaLibraryTest() { + super(null); + } + + @Test + public void test() { + setProjectName("detect-scala-library" + projectDir); + for (String subVersion : subVersions) { + testWithParameter(SCALA_LIBRARY_PARAMETER + SCALA_VERSION + subVersion, detect); + } + } + + private void testWithParameter(String parameter, boolean detect) { + + 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(); + if (detect) { + assertThat(output, containsString("Detected scala library in compilation classpath")); + } else { + assertThat(output, containsString("Using configured Scala version")); + } + assertThat(output, stringContainsInOrder("Using scoverage scalac plugin", "for scala", SCALA_VERSION)); + } + +} 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/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/java/org/scoverage/ScalaJavaAnnotationProcessorTest.java b/src/functionalTest/java/org/scoverage/ScalaJavaAnnotationProcessorTest.java new file mode 100644 index 0000000..c4c2e38 --- /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(), "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, "org/hello/WorldScala.scala.html").exists()); + } +} diff --git a/src/functionalTest/java/org/scoverage/ScalaJavaMultiModuleTest.java b/src/functionalTest/java/org/scoverage/ScalaJavaMultiModuleTest.java new file mode 100644 index 0000000..2b09933 --- /dev/null +++ b/src/functionalTest/java/org/scoverage/ScalaJavaMultiModuleTest.java @@ -0,0 +1,66 @@ +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("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(); + assertCoverage(100.0); + } + + private void assertAllReportFilesExist() { + + Assert.assertTrue(resolve(reportDir(), "index.html").exists()); + + assertScalaOnlyReportFilesExist(); + assertMixedScalaJavaReportFilesExist(); + assertAggregationFilesExist(); + } + + private void assertAggregationFilesExist() { + + 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, "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, "org/hello/WorldScala.scala.html").exists()); + } +} diff --git a/src/functionalTest/java/org/scoverage/ScalaMultiModuleTest.java b/src/functionalTest/java/org/scoverage/ScalaMultiModuleTest.java new file mode 100644 index 0000000..fa85c16 --- /dev/null +++ b/src/functionalTest/java/org/scoverage/ScalaMultiModuleTest.java @@ -0,0 +1,335 @@ +package org.scoverage; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +import java.io.File; + +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()); + 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() { + + 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 = run("clean", ":a:" + ScoveragePlugin.getREPORT_NAME()); + + result.assertTaskDoesntExist(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 + @Ignore + public void reportScoverageOnlyAWithoutNormalCompilation() { + + AssertableBuildResult result = run("clean", ":a:" + ScoveragePlugin.getREPORT_NAME(), + "-P" + ScoveragePlugin.getSCOVERAGE_COMPILE_ONLY_PROPERTY()); + + 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 + 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 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"); + + 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"); + + result.assertTaskFailed("a:" + ScoveragePlugin.getCHECK_NAME()); + + assertAReportFilesExist(); + assertCoverage(0.0, reportDir(projectDir().toPath().resolve("a").toFile())); + } + + @Test + @Ignore + public void checkScoverageWithoutNormalCompilationAndWithoutCoverageInCommon() throws Exception { + + AssertableBuildResult result = runAndFail("clean", + ":a:test", + ":common:test", "--tests", "org.hello.common.TestNothingCommonSuite", + "-P" + ScoveragePlugin.getSCOVERAGE_COMPILE_ONLY_PROPERTY(), + 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(87.5); + } + + @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"); + + 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 + @Ignore + public void aggregateScoverageWithoutNormalCompilation() throws Exception { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getAGGREGATE_NAME(), + "-P" + ScoveragePlugin.getSCOVERAGE_COMPILE_ONLY_PROPERTY()); + + 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(), "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(), "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, "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, "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, "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 new file mode 100644 index 0000000..8d9982b --- /dev/null +++ b/src/functionalTest/java/org/scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java @@ -0,0 +1,331 @@ +package org.scoverage; + +import org.junit.Assert; +import org.junit.Ignore; +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 + @Ignore + public void checkScoverageWithoutNormalCompilationAndWithoutCoverageInCommon() throws Exception { + + AssertableBuildResult result = runAndFail("clean", + ":a:test", + ":common:test", "--tests", "org.hello.common.TestNothingCommonSuite", + "-P" + ScoveragePlugin.getSCOVERAGE_COMPILE_ONLY_PROPERTY(), + 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 + @Ignore + public void aggregateScoverageWithoutNormalCompilation() throws Exception { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getAGGREGATE_NAME(), + "-P" + ScoveragePlugin.getSCOVERAGE_COMPILE_ONLY_PROPERTY()); + + 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(), "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(), "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, "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, "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, "org/hello/common/WorldCommon.scala.html").exists()); + } +} 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/java/org/scoverage/ScalaSingleModuleTest.java b/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java new file mode 100644 index 0000000..dd74b13 --- /dev/null +++ b/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java @@ -0,0 +1,150 @@ +package org.scoverage; + +import org.junit.Assert; +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() { + + 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(50.0); + } + + @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(), "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 + @Ignore + public void reportScoverageWithoutNormalCompilation() throws Exception { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getREPORT_NAME(), + "-P" + ScoveragePlugin.getSCOVERAGE_COMPILE_ONLY_PROPERTY()); + + 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(), + "-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()); + Assert.assertFalse(resolve(buildDir(), "classes/scala/scoverage/org/hello/World.class").exists()); + } + + 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/ScalaSingleModuleWithDependencyManagerTest.java b/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithDependencyManagerTest.java new file mode 100644 index 0000000..3ce3b63 --- /dev/null +++ b/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithDependencyManagerTest.java @@ -0,0 +1,31 @@ +package org.scoverage; + +import org.junit.Assert; +import org.junit.Test; + +public class ScalaSingleModuleWithDependencyManagerTest extends ScoverageFunctionalTest { + + public ScalaSingleModuleWithDependencyManagerTest() { + 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(), "org/hello/World.scala.html").exists()); + } +} diff --git a/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java b/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java new file mode 100644 index 0000000..6b485b6 --- /dev/null +++ b/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java @@ -0,0 +1,162 @@ +package org.scoverage; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +public class ScalaSingleModuleWithMultipleTestTasksTest extends ScoverageFunctionalTest { + 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 { + + 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); + } + + @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(), "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 + @Ignore + public void reportScoverageWithoutNormalCompilation() throws Exception { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getREPORT_NAME(), + "-P" + ScoveragePlugin.getSCOVERAGE_COMPILE_ONLY_PROPERTY()); + + 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=.*", "-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()); + 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(), "org/hello/World.scala.html").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..e2fbb1c --- /dev/null +++ b/src/functionalTest/java/org/scoverage/ScalaVersionArguments.java @@ -0,0 +1,33 @@ +package org.scoverage; + +import java.util.Arrays; +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", + "-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 new file mode 100644 index 0000000..c1992d8 --- /dev/null +++ b/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java @@ -0,0 +1,206 @@ +package org.scoverage; + +import groovy.util.Node; +import groovy.xml.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.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 String projectName; + private GradleRunner runner; + private final XmlParser parser; + + protected ScoverageFunctionalTest(String projectName) { + setProjectName(projectName); + 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 void setProjectName(String projectName) { + if (projectName != null) { + this.projectName = projectName; + this.runner = GradleRunner.create() + .withProjectDir(projectDir()) + .withPluginClasspath() + .forwardOutput(); + } + } + + protected File projectDir() { + + return new File(getClass().getClassLoader().getResource("projects/" + projectName).getFile()); + } + + protected File buildDir() { + + return buildDir(projectDir()); + } + + protected File buildDir(File projectDir) { + + return projectDir.toPath().resolve("build").toFile(); + } + + protected File reportDir() { + + return reportDir(projectDir()); + } + + protected File reportDir(File projectDir) { + + return buildDir(projectDir).toPath().resolve(ScoveragePlugin.getDEFAULT_REPORT_DIR()).toFile(); + } + + 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[]{})); + } + + 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, NumberFormatException { + + File reportFile = reportDir.toPath().resolve(coverageType.getFileName()).toFile(); + Node xml = parser.parse(reportFile); + Object attribute = xml.attribute(coverageType.getParamName()); + double rawValue = Double.parseDouble(attribute.toString()); + return coverageType.normalize(rawValue) * 100.0; + } + + protected List getVersionAgruments() { + return ScalaVersionArguments.version2WithLegacyScalatest; + } + + private void configureArguments(String... arguments) { + + List fullArguments = new ArrayList<>(getVersionAgruments()); + + 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); + } + + 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 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); + 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) { + + Pattern regex = Pattern.compile("^(> Task )?" + fullTaskName(taskName), Pattern.MULTILINE); + return regex.matcher(result.getOutput()).find(); + } + } +} + 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..88cbf46 --- /dev/null +++ b/src/functionalTest/resources/projects/composite-build/proj1/build.gradle @@ -0,0 +1,32 @@ +plugins { + id 'org.scoverage' +} + +repositories { + mavenCentral() +} + +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 { + 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.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion + + implementation "org.composite:proj2:1.0" +} + +test { + useJUnitPlatform() +} + diff --git a/src/test/happy day/src/main/resources/main.txt b/src/functionalTest/resources/projects/composite-build/proj1/settings.gradle similarity index 100% rename from src/test/happy day/src/main/resources/main.txt rename to src/functionalTest/resources/projects/composite-build/proj1/settings.gradle 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..8ea2bff --- /dev/null +++ b/src/functionalTest/resources/projects/composite-build/proj2/build.gradle @@ -0,0 +1,30 @@ +plugins { + id 'org.scoverage' +} + +repositories { + mavenCentral() +} + +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 { + 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.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + testImplementation 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) + } +} 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..50a45ca --- /dev/null +++ b/src/functionalTest/resources/projects/detect-scala-library/compile/build.gradle @@ -0,0 +1,13 @@ +plugins { + id 'org.scoverage' +} + +repositories { + mavenCentral() +} + +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/test/happy day/src/test/resources/test.txt b/src/functionalTest/resources/projects/detect-scala-library/compile/settings.gradle similarity index 100% rename from src/test/happy day/src/test/resources/test.txt rename to src/functionalTest/resources/projects/detect-scala-library/compile/settings.gradle 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..8444413 --- /dev/null +++ b/src/functionalTest/resources/projects/detect-scala-library/compileOnly/build.gradle @@ -0,0 +1,13 @@ +plugins { + id 'org.scoverage' +} + +repositories { + mavenCentral() +} + +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..0598896 --- /dev/null +++ b/src/functionalTest/resources/projects/detect-scala-library/dependency-management/build.gradle @@ -0,0 +1,20 @@ +plugins { + id 'io.spring.dependency-management' version "1.1.5" + id 'org.scoverage' +} + +repositories { + mavenCentral() +} + +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/gradle-consistent-versions/build.gradle b/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/build.gradle new file mode 100644 index 0000000..1b0f2f4 --- /dev/null +++ b/src/functionalTest/resources/projects/detect-scala-library/gradle-consistent-versions/build.gradle @@ -0,0 +1,19 @@ +plugins { + id "com.palantir.consistent-versions" version "1.28.0" + id 'org.scoverage' +} + +repositories { + mavenCentral() +} + +description = 'defines scala library using the "implementation" configuration and the gradle-consistent-versions plugin' + +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/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/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..50a45ca --- /dev/null +++ b/src/functionalTest/resources/projects/detect-scala-library/implementation/build.gradle @@ -0,0 +1,13 @@ +plugins { + id 'org.scoverage' +} + +repositories { + mavenCentral() +} + +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/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..7fd12a9 --- /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 { + mavenCentral() + } +} + +subprojects { p -> + if (p.name != 'dependencies') { + apply plugin: 'java' + dependencies { + implementation platform(project(':dependencies')) + testImplementation 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..c9a43d3 --- /dev/null +++ b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/build.gradle @@ -0,0 +1,3 @@ +dependencies { + testRuntimeOnly 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..2df2f4e --- /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 { + implementation group: 'org.scala-lang', name: 'scala-library' + + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine' + testImplementation 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/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..ba61184 --- /dev/null +++ b/src/functionalTest/resources/projects/multiple-check-tasks/multiple-checks/build.gradle @@ -0,0 +1,40 @@ +plugins { + id 'org.scoverage' +} + +repositories { + mavenCentral() +} + +description = 'a single-module Scala project that has multiple check configurations' + +apply plugin: 'java' +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.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + testImplementation 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..e9f2522 --- /dev/null +++ b/src/functionalTest/resources/projects/multiple-check-tasks/no-check/build.gradle @@ -0,0 +1,25 @@ +plugins { + id 'org.scoverage' +} + +repositories { + mavenCentral() +} + +description = 'a single-module Scala project with no check configured' + +apply plugin: 'java' +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.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + testImplementation 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..1b5137e --- /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 { + mavenCentral() +} + +description = 'a single-module Scala project that has multiple check configurations - some new syntax, some old' + +apply plugin: 'java' +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.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + testImplementation 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..c3b22ec --- /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 { + mavenCentral() +} + +description = 'a single-module Scala project that has a single check configurations (with the new syntax)' + +apply plugin: 'java' +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.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + testImplementation 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..8d7c020 --- /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 { + mavenCentral() +} + +description = 'a single-module Scala project that has a single check configurations (with the old syntax)' + +apply plugin: 'java' +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.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + testImplementation 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/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..c67b12d --- /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 { + mavenCentral() + } +} + +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/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..fa88c6f --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-multi-module/build.gradle @@ -0,0 +1,28 @@ +plugins { + id 'org.scoverage' apply false +} + +description = 'a multi-module Scala and Java project that builds successfully with 100% coverage' + +allprojects { + repositories { + mavenCentral() + } +} + +subprojects { + apply plugin: 'java' + + dependencies { + testImplementation group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + } + + test { + useJUnitPlatform() + } +} + +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 new file mode 100644 index 0000000..69fe4c7 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-multi-module/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-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..53e3405 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/build.gradle @@ -0,0 +1,22 @@ +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 +} + +// 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 +} \ No newline at end of file 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..2ed4e0e --- /dev/null +++ b/src/functionalTest/resources/projects/scala-java-multi-module/scala_only/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 +} \ No newline at end of file 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 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..a3553b5 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/a/build.gradle @@ -0,0 +1,3 @@ +dependencies { + implementation 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..a3553b5 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/b/build.gradle @@ -0,0 +1,3 @@ +dependencies { + implementation 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..27fca57 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle @@ -0,0 +1,61 @@ +plugins { + id 'org.scoverage' apply false +} + +allprojects { + repositories { + mavenCentral() + } +} + +description = 'a multi-module Scala project that builds successfully with 100% coverage' + +allprojects { + + apply plugin: 'java' + apply plugin: 'scala' + apply plugin: 'org.scoverage' + + 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.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion + } + + 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) + } + } + } + } + } + check.dependsOn(testing.suites.intTest) + + 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/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..512b324 --- /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 { + mavenCentral() + } + + apply plugin: 'java' + apply plugin: 'scala' + + if (p.name != 'a') { + apply plugin: 'org.scoverage' + } + + dependencies { + + implementation group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + + testImplementation group: 'org.junit.platform', name: 'junit-platform-runner' + + testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}" + } +} + +dependencies { + implementation project(':a') + implementation 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/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..ee1a4ab --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module/a/build.gradle @@ -0,0 +1,3 @@ +dependencies { + implementation 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 new file mode 100644 index 0000000..1d7b2a1 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module/a/src/main/scala/org/hello/a/WorldA.scala @@ -0,0 +1,11 @@ +package org.hello.a + +import org.hello.common.WorldCommon + +class WorldA { + + def fooA(): String = { + val s = "a" + new WorldCommon().fooCommon() + 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/build.gradle b/src/functionalTest/resources/projects/scala-multi-module/b/build.gradle new file mode 100644 index 0000000..ee1a4ab --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module/b/build.gradle @@ -0,0 +1,3 @@ +dependencies { + implementation 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 new file mode 100644 index 0000000..5c8bb57 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module/b/src/main/scala/org/hello/b/WorldB.scala @@ -0,0 +1,11 @@ +package org.hello.b + +import org.hello.common.WorldCommon + +class WorldB { + + def fooB(): String = { + val s = "b" + new WorldCommon().fooCommon() + 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..0177c34 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module/build.gradle @@ -0,0 +1,36 @@ +plugins { + id 'org.scoverage' apply false +} + +description = 'a multi-module Scala project that builds successfully with 100% coverage' + +allprojects { p -> + repositories { + mavenCentral() + } + + if (p.name != 'dependencies') { + apply plugin: 'java' + apply plugin: 'scala' + apply plugin: 'org.scoverage' + + dependencies { + implementation platform(project(':dependencies')) + + implementation group: 'org.scala-lang', name: 'scala-library' + + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine' + testImplementation group: 'org.junit.platform', name: 'junit-platform-runner' + + testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}" + } + + test { + useJUnitPlatform() + } + + 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/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 new file mode 100644 index 0000000..084ba0c --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module/settings.gradle @@ -0,0 +1 @@ +include 'dependencies', 'a', 'b', 'common' \ 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/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..d972fb4 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-single-module-dependency-manager/build.gradle @@ -0,0 +1,38 @@ +plugins { + id 'io.spring.dependency-management' version "1.1.5" + id 'org.scoverage' +} + +repositories { + mavenCentral() +} + +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 { + implementation group: 'org.scala-lang', name: 'scala-library' + + 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 { + 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/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..1f4b316 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/build.gradle @@ -0,0 +1,67 @@ +plugins { + id 'io.spring.dependency-management' version "1.1.5" + id 'org.scoverage' + id 'jvm-test-suite' +} + +repositories { + mavenCentral() +} + +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 { + implementation group: 'org.scala-lang', name: 'scala-library' + + 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 +} + +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) + } + } + } + } +} +check.dependsOn(testing.suites.intTest) + +scoverage { + minimumRate = 0.6 +} + +if (hasProperty("excludedFile")) { + scoverage.excludedFiles = [excludedFile] +} 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/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/WorldIntSuite.scala b/src/functionalTest/resources/projects/scala-single-module-multiple-test-tasks/src/intTest/scala/org/hello/WorldIntSuite.scala new file mode 100644 index 0000000..31458d8 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-single-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() + } +} \ 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..c9edf98 --- /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..7281a12 --- /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/functionalTest/resources/projects/scala-single-module/build.gradle b/src/functionalTest/resources/projects/scala-single-module/build.gradle new file mode 100644 index 0000000..fd9d9f2 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-single-module/build.gradle @@ -0,0 +1,44 @@ +plugins { + id 'org.scoverage' +} + +repositories { + mavenCentral() +} + +description = 'a single-module Scala project that builds successfully with 50% coverage' + +apply plugin: 'java' +apply plugin: 'scala' + +dependencies { + 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 +} + +test { + useJUnitPlatform() +} + +scoverage { + minimumRate = 0.3 + coverageType = org.scoverage.CoverageType.Line + // verify that debug mode works + coverageDebug = true +} + +if (hasProperty("excludedFile")) { + scoverage.excludedFiles = [excludedFile] +} 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..270482f --- /dev/null +++ b/src/functionalTest/resources/projects/scala-single-module/src/main/scala/org/hello/World.scala @@ -0,0 +1,12 @@ +package org.hello + +class World { + + def foo(): String = { + val s = "a" + "b" + s + } + + // not covered by tests + def bar(): String = "y" +} \ 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..76de321 --- /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.scalatestplus.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class TestNothingSuite extends AnyFunSuite { + + 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..477f27a --- /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.scalatestplus.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldSuite extends AnyFunSuite { + + test("foo") { + new World().foo() + } +} \ No newline at end of file diff --git a/src/main/groovy/org/scoverage/AggregateReportApp.java b/src/main/groovy/org/scoverage/AggregateReportApp.java deleted file mode 100644 index 914bc89..0000000 --- a/src/main/groovy/org/scoverage/AggregateReportApp.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.scoverage; - -import scoverage.Coverage; -import scoverage.report.CoberturaXmlWriter; -import scoverage.report.CoverageAggregator; -import scoverage.report.ScoverageHtmlWriter; - -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/CoverageChecker.groovy b/src/main/groovy/org/scoverage/CoverageChecker.groovy new file mode 100644 index 0000000..ff240ba --- /dev/null +++ b/src/main/groovy/org/scoverage/CoverageChecker.groovy @@ -0,0 +1,92 @@ +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 + +import java.text.DecimalFormat +import java.text.DecimalFormatSymbols + +/** + * Handles different types of coverage Scoverage can measure. + */ +enum CoverageType { + 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 */ + String paramName + /** Used to normalize coverage value */ + private double factor + + private CoverageType(String configurationName, String fileName, String paramName, double factor) { + this.configurationName = configurationName + this.fileName = fileName + this.paramName = paramName + this.factor = factor + } + + /** Normalize coverage value to [0, 1] */ + Double normalize(Double value) { + return value / factor + } + + static CoverageType find(String configurationName) { + CoverageType.values().find { + it.configurationName.toLowerCase() == configurationName.toLowerCase() + } + } +} + +/** + * Throws a GradleException if overall coverage dips below the configured percentage. + */ +class CoverageChecker { + + final Logger logger + + CoverageChecker(Logger logger) { + this.logger = logger + } + + public void checkLineCoverage(File reportDir, CoverageType coverageType, double minimumRate) 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) + + try { + File reportFile = new File(reportDir, coverageType.fileName) + Node xml = parser.parse(reportFile) + Double coverageValue = (xml.attribute(coverageType.paramName) as String).toDouble() + Double overallRate = coverageType.normalize(coverageValue) + def difference = (minimumRate - overallRate) + + if (difference > 1e-7) { + throw new GradleException(errorMsg(overallRate, minimumRate, coverageType)) + } + } catch (FileNotFoundException fnfe) { + throw new GradleException(fileNotFoundErrorMsg(coverageType), fnfe) + } + } + + @VisibleForTesting + protected static String errorMsg(double overallRate, double minimumRate, CoverageType type) { + 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)" + } + + @VisibleForTesting + protected static String fileNotFoundErrorMsg(CoverageType coverageType) { + "Coverage file (type: $coverageType) not found, check your configuration." + } +} diff --git a/src/main/groovy/org/scoverage/OverallCheckTask.groovy b/src/main/groovy/org/scoverage/OverallCheckTask.groovy deleted file mode 100644 index f56d0ad..0000000 --- a/src/main/groovy/org/scoverage/OverallCheckTask.groovy +++ /dev/null @@ -1,95 +0,0 @@ -package org.scoverage - -import org.gradle.api.DefaultTask -import org.gradle.api.GradleException -import org.gradle.api.tasks.TaskAction - -import java.text.DecimalFormat -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) - - /** Name of file with coverage data */ - String fileName - /** Name of param in XML file with coverage value */ - String paramName - /** Used to normalize coverage value */ - private double factor - - private CoverageType(String fileName, String paramName, double factor) { - this.fileName = fileName - this.paramName = paramName - this.factor = factor - } - - /** Normalize coverage value to [0, 1] */ - Double normalize(Double value) { - return value / factor - } -} - -/** - * Throws a GradleException if overall coverage dips below the configured percentage. - */ -class OverallCheckTask extends DefaultTask { - - /** Type of coverage to check. Available options: Line, Statement and Branch */ - CoverageType coverageType = CoverageType.Statement - double minimumRate = 0.75 - - /** Set if want to change default from 'reportDir' in scoverage extension. */ - File reportDir - - /** Overwrite to test for a specific locale. */ - Locale locale - - protected XmlParser parser - - protected DecimalFormat df = new DecimalFormat("#.##") - - 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) - } - - /** Extracted to method for testing purposes */ - 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) { - return "Coverage file (type: $coverageType) not found, check your configuration." - } - - @TaskAction - void requireLineCoverage() { - def extension = ScoveragePlugin.extensionIn(project) - - File reportFile = new File(reportDir ? reportDir : extension.reportDir, coverageType.fileName) - - 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(); - 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)) - } - } catch (FileNotFoundException fnfe) { - throw new GradleException(fileNotFoundErrorMsg(coverageType), fnfe) - } - - } -} 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 8703d09..f39ff98 100644 --- a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy +++ b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy @@ -1,32 +1,77 @@ package org.scoverage -import org.gradle.api.tasks.JavaExec - -class ScoverageAggregate extends JavaExec { - - 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() +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.reporter.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) + + @Input + final ListProperty dirsToAggregateFrom = project.objects.listProperty(File) + + @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) + @Input + final Property coverageOutputXML = project.objects.property(Boolean) + @Input + final Property coverageOutputHTML = project.objects.property(Boolean) + @Input + final Property coverageDebug = project.objects.property(Boolean) + + ScoverageAggregate() { + dirsToAggregateFrom.set([project.extensions.scoverage.dataDir.get()]) } - def reportDirOrDefault() { - return reportDir ? reportDir : new File(project.buildDir, 'scoverage-aggregate') + @TaskAction + def aggregate() { + runner.run { + reportDir.get().deleteDir() + reportDir.get().mkdirs() + + def dirs = [] + dirs.addAll(dirsToAggregateFrom.get()) + def sourceRoot = getProject().getRootDir() + def coverage = CoverageAggregator.aggregate(dirs.unique() as File[], sourceRoot) + + if (coverage.nonEmpty()) { + new ScoverageWriter(project.logger).write( + sources.get().getFiles(), + reportDir.get(), + coverage.get(), + sourceEncoding.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 a7af8a3..d2b5119 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,154 +13,96 @@ import java.util.concurrent.Callable */ class ScoverageExtension { - private static boolean isEscaped(String argument) { - return (argument.startsWith('"') && argument.endsWith('"')) || (argument.startsWith('\'') && argument.endsWith('\'')) - } + public static final CoverageType DEFAULT_COVERAGE_TYPE = CoverageType.Statement + public static final double DEFAULT_MINIMUM_RATE = 0.75 - static String escape(String argument) { - if (isEscaped(argument)) { - return argument - } else { - return "\"$argument\"" - } - } + final Project project + + /** 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 - /** sources to highlight */ - File sources + final Property reportDir /** 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 + + final Property deleteReportsOnAggregation + + final List checks = new ArrayList<>() + + final Property coverageType + final Property minimumRate ScoverageExtension(Project project) { - project.plugins.apply(JavaPlugin.class); - project.plugins.apply(ScalaPlugin.class); - project.afterEvaluate(configureRuntimeOptions) + this.project = project + project.plugins.apply(JavaPlugin.class) + project.plugins.apply(ScalaPlugin.class) - project.configurations.create(ScoveragePlugin.CONFIGURATION_NAME) { - visible = false - transitive = true - description = 'Scoverage dependencies' - } + scoverageVersion = project.objects.property(String) + scoverageVersion.set('2.1.1') - def mainSourceSet = project.sourceSets.create('scoverage') { - def original = project.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) + scoverageScalaVersion = project.objects.property(String) - java.source(original.java) - resources.source(original.resources) - scala.source(original.scala) + dataDir = project.objects.property(File) + dataDir.set(new File(project.buildDir, 'scoverage')) - compileClasspath += original.compileClasspath + project.configurations.scoverage - runtimeClasspath = it.output + project.configurations.scoverage + project.configurations.runtime - } + reportDir = project.objects.property(File) + reportDir.set(new File(project.buildDir, ScoveragePlugin.DEFAULT_REPORT_DIR)) - def testSourceSet = project.sourceSets.create('testScoverage') { - def original = project.sourceSets.getByName(SourceSet.TEST_SOURCE_SET_NAME) + highlighting = project.objects.property(Boolean) + highlighting.set(true) - java.source(original.java) - resources.source(original.resources) - scala.source(original.scala) + excludedPackages = project.objects.listProperty(String) + excludedPackages.set([]) - compileClasspath = mainSourceSet.output + project.configurations.testCompile - runtimeClasspath = it.output + mainSourceSet.output + project.configurations.scoverage + project.configurations.testRuntime - } + excludedFiles = project.objects.listProperty(String) + excludedFiles.set([]) - def scoverageJar = project.tasks.create('jarScoverage', Jar.class) { - dependsOn('scoverageClasses') - classifier = ScoveragePlugin.CONFIGURATION_NAME - from mainSourceSet.output - } - project.artifacts { - scoverage project.tasks.jarScoverage - } + coverageOutputCobertura = project.objects.property(Boolean) + coverageOutputCobertura.set(true) - project.tasks.create(ScoveragePlugin.TEST_NAME, Test.class) { - conventionMapping.map("testClassesDir", new Callable() { - public Object call() throws Exception { - return testSourceSet.output.classesDir; - } - }) - conventionMapping.map("classpath", new Callable() { - public Object call() throws Exception { - return testSourceSet.runtimeClasspath; - } - }) - } + coverageOutputXML = project.objects.property(Boolean) + coverageOutputXML.set(true) - project.tasks.create(ScoveragePlugin.REPORT_NAME, ScoverageReport.class) { - dependsOn(project.tasks[ScoveragePlugin.TEST_NAME]) - onlyIf { ScoveragePlugin.extensionIn(project).dataDir.list() } - } + coverageOutputHTML = project.objects.property(Boolean) + coverageOutputHTML.set(true) - project.tasks.create(ScoveragePlugin.CHECK_NAME, OverallCheckTask.class) { - dependsOn(project.tasks[ScoveragePlugin.REPORT_NAME]) - } + coverageDebug = project.objects.property(Boolean) + coverageDebug.set(false) + + deleteReportsOnAggregation = project.objects.property(Boolean) + deleteReportsOnAggregation.set(false) + + coverageType = project.objects.property(CoverageType) + minimumRate = project.objects.property(BigDecimal) + } - 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 + void check(Closure closure) { + CheckConfig check = new CheckConfig() + project.configure(check, closure) + checks.add(check) } - 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 e) { - 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') - } - if (scalaCompileOptions.useAnt) { - scalaCompileOptions.additionalParameters = parameters.collect { escape(it) } - } else { - 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')) - } + 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 31b955e..a6a33d2 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -1,25 +1,403 @@ 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.plugins.scala.ScalaPlugin +import org.gradle.api.tasks.SourceSet +import org.gradle.api.tasks.TaskProvider +import org.gradle.api.tasks.testing.Test -class ScoveragePlugin implements Plugin { - static String CONFIGURATION_NAME = 'scoverage' +import java.nio.file.Files +import java.util.concurrent.ConcurrentHashMap - static String TEST_NAME = 'testScoverage' - static String REPORT_NAME = 'reportScoverage' - static String CHECK_NAME = 'checkScoverage' - static String COMPILE_NAME = 'compileScoverageScala' - static String COMPILE_TEST_NAME = 'compileTestScoverageScala' +import static groovy.io.FileType.FILES + +class ScoveragePlugin implements Plugin { + + static final String CONFIGURATION_NAME = 'scoverage' + static final String REPORT_NAME = 'reportScoverage' + 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.14' + static final String SCOVERAGE_COMPILE_ONLY_PROPERTY = 'scoverageCompileOnly'; + + static final String DEFAULT_REPORT_DIR = 'reports' + File.separatorChar + 'scoverage' + + private final ConcurrentHashMap> crossProjectTaskDependencies = new ConcurrentHashMap<>() + private final ConcurrentHashMap> sameProjectTaskDependencies = new ConcurrentHashMap<>() @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) + } 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") } } - protected static ScoverageExtension extensionIn(Project project) { - project.extensions[CONFIGURATION_NAME] + 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' + canBeResolved = true + canBeConsumed = false + } + + project.afterEvaluate { + def scalaVersion = resolveScalaVersions(project) + + def scoverageVersion = project.extensions.scoverage.scoverageVersion.get() + project.logger.info("Using scoverage scalac plugin $scoverageVersion for scala $scalaVersion") + + def scalacScoverageVersion = scalaVersion.scalacScoverageVersion + def scalacScoveragePluginVersion = scalaVersion.scalacScoveragePluginVersion + def scalacScoverageRuntimeVersion = scalaVersion.scalacScoverageRuntimeVersion + + project.dependencies { + 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) } + + private void createTasks(Project project, ScoverageExtension extension) { + + ScoverageRunner scoverageRunner = new ScoverageRunner(project.configurations.scoverage) + + def originalSourceSet = project.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) + def instrumentedSourceSet = project.sourceSets.create('scoverage') { + + resources.source(originalSourceSet.resources) + 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 + } + + def originalCompileTask = project.tasks[originalSourceSet.getCompileTaskName("scala")] + def originalJarTask = project.tasks[originalSourceSet.getJarTaskName()] + + def compileTask = project.tasks[instrumentedSourceSet.getCompileTaskName("scala")] + compileTask.mustRunAfter(originalCompileTask) + + def globalReportTask = project.tasks.register(REPORT_NAME, ScoverageAggregate) + def globalCheckTask = project.tasks.register(CHECK_NAME) + + 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() + + List reportTasks = testTasks.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 originalJarTask, compileTask, testTask + onlyIf { extension.dataDir.get().list() } + group = 'verification' + runner = scoverageRunner + reportDir = taskReportDir + sources = originalSourceSet.scala.getSourceDirectories() + dataDir = extension.dataDir + sourceEncoding.set(detectedSourceEncoding) + coverageOutputCobertura = extension.coverageOutputCobertura + coverageOutputXML = extension.coverageOutputXML + coverageOutputHTML = extension.coverageOutputHTML + coverageDebug = extension.coverageDebug + } + } + + globalReportTask.configure { + def dataDirs = reportTasks.findResults { it.dataDir.get() } + + dependsOn reportTasks + onlyIf { dataDirs.any { it.list() } } + + group = 'verification' + runner = scoverageRunner + reportDir = extension.reportDir + sources = originalSourceSet.scala.getSourceDirectories() + dirsToAggregateFrom = dataDirs + sourceEncoding.set(detectedSourceEncoding) + deleteReportsOnAggregation = false + coverageOutputCobertura = extension.coverageOutputCobertura + coverageOutputXML = extension.coverageOutputXML + coverageOutputHTML = extension.coverageOutputHTML + coverageDebug = extension.coverageDebug + } + + configureCheckTask(project, extension, globalCheckTask, globalReportTask) + + compileTask.configure { + List parameters = [] + List existingParameters = scalaCompileOptions.additionalParameters + if (existingParameters) { + 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()) + 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(File.pathSeparator)) + } + } 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 + } + } + + compileTask.configure { + doFirst { + destinationDirectory.get().getAsFile().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) } + + if (hasAnyReportTask) { + project.tasks.withType(Test).each { testTask -> + testTask.configure { + project.logger.info("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) { + name.startsWith("scoverage.measurements.") + } + }) + } + } + } + } + } + + // define aggregation task + if (!project.subprojects.empty) { + project.gradle.projectsEvaluated { + 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.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 { + !childReportTasks.empty + } + dependsOn(allReportTasks) + group = 'verification' + runner = scoverageRunner + reportDir = extension.reportDir + sources = allSources + sourceEncoding.set(detectedSourceEncoding) + dirsToAggregateFrom = dataDirs + deleteReportsOnAggregation = extension.deleteReportsOnAggregation + coverageOutputCobertura = extension.coverageOutputCobertura + coverageOutputXML = extension.coverageOutputXML + coverageOutputHTML = extension.coverageOutputHTML + coverageDebug = extension.coverageDebug + } + project.tasks[CHECK_NAME].mustRunAfter(aggregationTask) + } + } + } + } + + 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 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 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 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 ab1f1b7..ef09483 100644 --- a/src/main/groovy/org/scoverage/ScoverageReport.groovy +++ b/src/main/groovy/org/scoverage/ScoverageReport.groovy @@ -1,24 +1,71 @@ package org.scoverage -import org.gradle.api.tasks.JavaExec - -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() +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 +import org.gradle.api.tasks.TaskAction +import scoverage.reporter.CoverageAggregator + +import static org.gradle.api.tasks.PathSensitivity.RELATIVE + +@CacheableTask +class ScoverageReport extends DefaultTask { + + @Nested + ScoverageRunner runner + + @InputDirectory + @PathSensitive(RELATIVE) + final Property dataDir = project.objects.property(File) + + @InputFiles + @PathSensitive(RELATIVE) + final Property sources = project.objects.property(FileCollection) + + @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 + final Property coverageOutputXML = project.objects.property(Boolean) + @Input + final Property coverageOutputHTML = project.objects.property(Boolean) + @Input + final Property coverageDebug = project.objects.property(Boolean) + + @TaskAction + def report() { + runner.run { + reportDir.get().delete() + reportDir.get().mkdirs() + + 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...") + } else { + new ScoverageWriter(project.logger).write( + sources.get().getFiles(), + reportDir.get(), + coverage.get(), + sourceEncoding.get(), + 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..a5dd552 --- /dev/null +++ b/src/main/groovy/org/scoverage/ScoverageRunner.groovy @@ -0,0 +1,34 @@ +package org.scoverage + +import org.gradle.api.file.FileCollection +import org.gradle.api.tasks.Classpath + +import java.lang.reflect.Method + +class ScoverageRunner { + + @Classpath + final 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.toURI().toURL() + if (!cloader.getURLs().contains(url)) { + method.invoke(cloader, url) + } + } + + action.call() + } +} diff --git a/src/main/groovy/org/scoverage/ScoverageWriter.java b/src/main/groovy/org/scoverage/ScoverageWriter.java index 0d8ab2f..6131977 100644 --- a/src/main/groovy/org/scoverage/ScoverageWriter.java +++ b/src/main/groovy/org/scoverage/ScoverageWriter.java @@ -1,60 +1,113 @@ package org.scoverage; -import scoverage.Constants; -import scoverage.Coverage; -import scoverage.report.CoberturaXmlWriter; -import scoverage.report.ScoverageHtmlWriter; -import scoverage.report.ScoverageXmlWriter; +import org.gradle.api.logging.Logger; +import scala.Option; +import scala.Some; +import scala.collection.immutable.Seq; +import scala.collection.mutable.Buffer; +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; +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. - *

* Copied from sbt-scoverage and converted to Java to avoid dependency to Scala. */ public class ScoverageWriter { + private final Logger logger; + + public ScoverageWriter(Logger logger) { + + this.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 * @param coverageOutputCobertura switch for Cobertura output * @param coverageOutputXML switch for Scoverage XML output * @param coverageOutputHTML switch for Scoverage HTML output * @param coverageDebug switch for Scoverage Debug output */ - public static void write(File sourceDir, + 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 { - System.out.println("[scoverage] Generating scoverage reports..."); + 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); - System.out.println("[scoverage] Written Cobertura XML report to " + + Constructor cst; + try { + 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, + Class.forName("scala.Option")); + } + CoberturaXmlWriter writer = cst.newInstance(sourceDirsSeq, reportDir, new Some<>(sourceEncoding)); + writer.write(coverage); + logger.info("[scoverage] Written Cobertura XML report to " + reportDir.getAbsolutePath() + File.separator + "cobertura.xml"); } if (coverageOutputXML) { - new ScoverageXmlWriter(sourceDir, reportDir, /* debug = */ false).write(coverage); - System.out.println("[scoverage] Written XML report to " + + Constructor cst; + try { + 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, + Class.forName("scala.Option")); + } + ScoverageXmlWriter writer = cst.newInstance(sourceDirsSeq, reportDir, false, new Some<>(sourceEncoding)); + 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); - System.out.println("[scoverage] Written XML report with debug information to " + + 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() + File.separator + Constants.XMLReportFilenameWithDebug()); @@ -62,13 +115,20 @@ public static void write(File sourceDir, } if (coverageOutputHTML) { - new ScoverageHtmlWriter(sourceDir, reportDir).write(coverage); - System.out.println("[scoverage] Written HTML report to " + + 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 + "index.html"); } - System.out.println("[scoverage] Coverage reports completed"); + logger.info("[scoverage] Coverage reports completed"); } } 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/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 diff --git a/src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy b/src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy deleted file mode 100644 index 0cc9773..0000000 --- a/src/test/groovy/org/scoverage/AcceptanceTestUtils.groovy +++ /dev/null @@ -1,47 +0,0 @@ -package org.scoverage - -import org.gradle.tooling.BuildLauncher -import org.gradle.tooling.GradleConnector -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 BuildLauncher setupBuild(File projectRoot, boolean useAnt) { - return GradleConnector. - newConnector(). - forProjectDirectory(projectRoot). - connect(). - newBuild(). - withArguments("-PuseAnt=$useAnt") - } - - protected void checkFile(String description, File file, boolean shouldExist) throws Exception { - Assert.assertThat(description + ' should be created at ' + file.absolutePath, file.exists(), Is.is(shouldExist)) - } - - protected File reportDir(File baseDir) { - return new File(baseDir, 'build/reports/scoverage') - } - - protected Double coverage(File reportDir, CoverageType coverageType) { - File reportFile = new File(reportDir, coverageType.fileName) - def xml = parser.parse(reportFile) - 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 a0ac493..0000000 --- a/src/test/groovy/org/scoverage/AggregationAcceptanceTest.groovy +++ /dev/null @@ -1,42 +0,0 @@ -package org.scoverage - -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 { - File projectDir = new File('src/test/water') - - def build = setupBuild(projectDir, useAnt) - 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) - } -} diff --git a/src/test/groovy/org/scoverage/CoverageCheckerTest.groovy b/src/test/groovy/org/scoverage/CoverageCheckerTest.groovy new file mode 100644 index 0000000..844968e --- /dev/null +++ b/src/test/groovy/org/scoverage/CoverageCheckerTest.groovy @@ -0,0 +1,126 @@ +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 static org.junit.Assert.assertEquals +import static org.junit.Assert.assertThat +import static org.junit.jupiter.api.Assertions.assertThrows + +class CoverageCheckerTest { + + 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) + }) + } + + // line coverage + + @Test + void failsWhenLineRateIsBelowTarget() { + 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) + } + + @Test + void doesNotFailWhenLineRateIsAboveTarget() { + checker.checkLineCoverage(reportDir, CoverageType.Line, 0.6) + } + + // Statement coverage + + @Test + void failsWhenStatementRateIsBelowTarget() { + 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) + } + + @Test + void doesNotFailWhenStatementRateIsAboveTarget() { + checker.checkLineCoverage(reportDir, CoverageType.Statement, 0.3) + } + + // Branch coverage + + @Test + void failsWhenBranchRateIsBelowTarget() { + 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) + } + + @Test + void doesNotFailWhenBranchRateIsAboveTarget() { + 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 static 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 aeb3389..0000000 --- a/src/test/groovy/org/scoverage/OverallCheckTaskTest.groovy +++ /dev/null @@ -1,155 +0,0 @@ -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.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 - -/** - * 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; - - public 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 - public void describeTo(Description description) { - description.appendText("expects type ") - .appendValue(type) - .appendText(" and a message ") - .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 - } - - // 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() - } - - // 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() - } - - @Test - void doesNotFailWhenLineRateIsAtTarget() throws Exception { - Project project = projectForRate(0.66, CoverageType.Line) - project.tasks.bob.execute() - } - - @Test - void doesNotFailWhenLineRateIsAboveTarget() throws Exception { - Project project = projectForRate(0.6, CoverageType.Line) - project.tasks.bob.execute() - } - - // 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() - } - - @Test - void doesNotFailWhenStatementRateIsAtTarget() throws Exception { - Project project = projectForRate(0.33, CoverageType.Statement) - project.tasks.bob.execute() - } - - @Test - void doesNotFailWhenStatementRateIsAboveTarget() throws Exception { - Project project = projectForRate(0.3, CoverageType.Statement) - project.tasks.bob.execute() - } - - // 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() - } - - @Test - void doesNotFailWhenBranchRateIsAtTarget() throws Exception { - Project project = projectForRate(0.50, CoverageType.Branch) - project.tasks.bob.execute() - } - - @Test - void doesNotFailWhenBranchRateIsAboveTarget() throws Exception { - Project project = projectForRate(0.45, CoverageType.Branch) - project.tasks.bob.execute() - } - -} 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 deleted file mode 100644 index f9b7158..0000000 --- a/src/test/groovy/org/scoverage/SeparateTestsAcceptanceTest.groovy +++ /dev/null @@ -1,46 +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 { - - private void testSeparate(boolean useAnt) 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) - 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 deleted file mode 100644 index 630d1f9..0000000 --- a/src/test/groovy/org/scoverage/SimpleReportAcceptanceTest.groovy +++ /dev/null @@ -1,37 +0,0 @@ -package org.scoverage - -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) - - 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') - 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 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) - build.forTasks('clean', 'run').run() - } -} diff --git a/src/test/happy day/build.gradle b/src/test/happy day/build.gradle deleted file mode 100644 index 86af52b..0000000 --- a/src/test/happy day/build.gradle +++ /dev/null @@ -1,33 +0,0 @@ -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: '+' - } -} - -apply plugin: 'org.scoverage' - -repositories { - mavenCentral() -} - -dependencies { - scoverage 'org.scoverage:scalac-scoverage-plugin_2.11:1.0.1', - 'org.scoverage:scalac-scoverage-runtime_2.11:1.0.1' - compile 'org.scala-lang:scala-library:2.11.0' - testCompile 'junit:junit:4.11' -} - -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 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 7a1589a..0000000 --- a/src/test/happy day/src/main/scala/hello/World.scala +++ /dev/null @@ -1,5 +0,0 @@ -package hello - -object World { - def say() = println("ahoy") -} \ No newline at end of file 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 8856440..0000000 --- a/src/test/runtime/build.gradle +++ /dev/null @@ -1,30 +0,0 @@ -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: '+' - } -} - -apply plugin: 'org.scoverage' - -repositories { - mavenCentral() -} - -dependencies { - scoverage 'org.scoverage:scalac-scoverage-plugin_2.11:1.0.1', - 'org.scoverage:scalac-scoverage-runtime_2.11:1.0.1' - 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/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 e84bfb7..0000000 --- a/src/test/separate-tests/build.gradle +++ /dev/null @@ -1,64 +0,0 @@ -description = 'a multi-project with separate tests 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: '+' - } -} - -subprojects { - - repositories { - mavenCentral() - } - - apply plugin: 'scala' - apply plugin: 'org.scoverage' - - 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' - - 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 - scoverage mainProject.configurations.scoverage.artifacts.files - } - 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 } - } -} \ 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 d487e80..0000000 --- a/src/test/water/build.gradle +++ /dev/null @@ -1,29 +0,0 @@ -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: '+' - } -} - -task aggregateScoverage(type: org.scoverage.ScoverageAggregate) - -allprojects { - repositories { - mavenCentral() - } - - 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' - 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