From f20affd2aa956dca48e5a3b722646d4b7f953095 Mon Sep 17 00:00:00 2001 From: Albert Meltzer <7529386+kitbellew@users.noreply.github.com> Date: Tue, 26 Dec 2023 08:06:58 -0800 Subject: [PATCH 1/4] Coverage minima: Add integration tests to check it --- .../test_coverage_minima/invoker.properties | 1 + src/it/test_coverage_minima/module01/pom.xml | 16 +++++ .../src/main/scala/pkg01/HelloService1.scala | 12 ++++ .../test/scala/pkg01/HelloServiceTest.scala | 14 +++++ src/it/test_coverage_minima/module02/pom.xml | 16 +++++ .../src/main/scala/pkg01/HelloService1.scala | 12 ++++ .../src/main/scala/pkg02/HelloService1.scala | 12 ++++ .../test/scala/pkg01/HelloServiceTest.scala | 14 +++++ src/it/test_coverage_minima/module03/pom.xml | 36 +++++++++++ .../src/main/scala/pkg01/HelloService1.scala | 12 ++++ .../test/scala/pkg01/HelloServiceTest.scala | 14 +++++ src/it/test_coverage_minima/pom.xml | 63 +++++++++++++++++++ src/it/test_coverage_minima/validate.groovy | 43 +++++++++++++ 13 files changed, 265 insertions(+) create mode 100644 src/it/test_coverage_minima/invoker.properties create mode 100644 src/it/test_coverage_minima/module01/pom.xml create mode 100644 src/it/test_coverage_minima/module01/src/main/scala/pkg01/HelloService1.scala create mode 100644 src/it/test_coverage_minima/module01/src/test/scala/pkg01/HelloServiceTest.scala create mode 100644 src/it/test_coverage_minima/module02/pom.xml create mode 100644 src/it/test_coverage_minima/module02/src/main/scala/pkg01/HelloService1.scala create mode 100644 src/it/test_coverage_minima/module02/src/main/scala/pkg02/HelloService1.scala create mode 100644 src/it/test_coverage_minima/module02/src/test/scala/pkg01/HelloServiceTest.scala create mode 100644 src/it/test_coverage_minima/module03/pom.xml create mode 100644 src/it/test_coverage_minima/module03/src/main/scala/pkg01/HelloService1.scala create mode 100644 src/it/test_coverage_minima/module03/src/test/scala/pkg01/HelloServiceTest.scala create mode 100644 src/it/test_coverage_minima/pom.xml create mode 100644 src/it/test_coverage_minima/validate.groovy diff --git a/src/it/test_coverage_minima/invoker.properties b/src/it/test_coverage_minima/invoker.properties new file mode 100644 index 00000000..f4f2d3bc --- /dev/null +++ b/src/it/test_coverage_minima/invoker.properties @@ -0,0 +1 @@ +invoker.goals=clean scoverage:check site -e -ntp diff --git a/src/it/test_coverage_minima/module01/pom.xml b/src/it/test_coverage_minima/module01/pom.xml new file mode 100644 index 00000000..eb09e4a1 --- /dev/null +++ b/src/it/test_coverage_minima/module01/pom.xml @@ -0,0 +1,16 @@ + + + + + + it.scoverage-maven-plugin + test_coverage_minima + 1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + module01 + Test SCoverage Coverage Minima : Module 1 + + diff --git a/src/it/test_coverage_minima/module01/src/main/scala/pkg01/HelloService1.scala b/src/it/test_coverage_minima/module01/src/main/scala/pkg01/HelloService1.scala new file mode 100644 index 00000000..9d7c7380 --- /dev/null +++ b/src/it/test_coverage_minima/module01/src/main/scala/pkg01/HelloService1.scala @@ -0,0 +1,12 @@ +package pkg01 + +class HelloService1 +{ + def hello = + { + "Hello from module 1" + } + +} + +object HelloService1 extends HelloService1 diff --git a/src/it/test_coverage_minima/module01/src/test/scala/pkg01/HelloServiceTest.scala b/src/it/test_coverage_minima/module01/src/test/scala/pkg01/HelloServiceTest.scala new file mode 100644 index 00000000..9cac7025 --- /dev/null +++ b/src/it/test_coverage_minima/module01/src/test/scala/pkg01/HelloServiceTest.scala @@ -0,0 +1,14 @@ +package pkg01 + +import org.junit.Test; +import org.junit.Assert.assertEquals + +class HelloServiceTest +{ + @Test + def test1() + { + assertEquals("Hello from module 1", HelloService1.hello) + } + +} diff --git a/src/it/test_coverage_minima/module02/pom.xml b/src/it/test_coverage_minima/module02/pom.xml new file mode 100644 index 00000000..9875282b --- /dev/null +++ b/src/it/test_coverage_minima/module02/pom.xml @@ -0,0 +1,16 @@ + + + + + + it.scoverage-maven-plugin + test_coverage_minima + 1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + module02 + Test SCoverage Coverage Minima : Module 2 + + diff --git a/src/it/test_coverage_minima/module02/src/main/scala/pkg01/HelloService1.scala b/src/it/test_coverage_minima/module02/src/main/scala/pkg01/HelloService1.scala new file mode 100644 index 00000000..1d3c8ca0 --- /dev/null +++ b/src/it/test_coverage_minima/module02/src/main/scala/pkg01/HelloService1.scala @@ -0,0 +1,12 @@ +package pkg01 + +class HelloService1 +{ + def hello = + { + "Hello from module 2" + } + +} + +object HelloService1 extends HelloService1 diff --git a/src/it/test_coverage_minima/module02/src/main/scala/pkg02/HelloService1.scala b/src/it/test_coverage_minima/module02/src/main/scala/pkg02/HelloService1.scala new file mode 100644 index 00000000..b5edc85b --- /dev/null +++ b/src/it/test_coverage_minima/module02/src/main/scala/pkg02/HelloService1.scala @@ -0,0 +1,12 @@ +package pkg02 + +class HelloService1 +{ + def hello = + { + "Hello from module 2" + } + +} + +object HelloService1 extends HelloService1 diff --git a/src/it/test_coverage_minima/module02/src/test/scala/pkg01/HelloServiceTest.scala b/src/it/test_coverage_minima/module02/src/test/scala/pkg01/HelloServiceTest.scala new file mode 100644 index 00000000..8dacc428 --- /dev/null +++ b/src/it/test_coverage_minima/module02/src/test/scala/pkg01/HelloServiceTest.scala @@ -0,0 +1,14 @@ +package pkg01 + +import org.junit.Test; +import org.junit.Assert.assertEquals + +class HelloServiceTest +{ + @Test + def test1() + { + assertEquals("Hello from module 2", HelloService1.hello) + } + +} diff --git a/src/it/test_coverage_minima/module03/pom.xml b/src/it/test_coverage_minima/module03/pom.xml new file mode 100644 index 00000000..d8987f45 --- /dev/null +++ b/src/it/test_coverage_minima/module03/pom.xml @@ -0,0 +1,36 @@ + + + + + + it.scoverage-maven-plugin + test_coverage_minima + 1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + module03 + Test SCoverage Coverage Minima : Module 3 + + + + + @project.groupId@ + @project.artifactId@ + + true + 100 + + + + + check + + + + + + + + diff --git a/src/it/test_coverage_minima/module03/src/main/scala/pkg01/HelloService1.scala b/src/it/test_coverage_minima/module03/src/main/scala/pkg01/HelloService1.scala new file mode 100644 index 00000000..478fbada --- /dev/null +++ b/src/it/test_coverage_minima/module03/src/main/scala/pkg01/HelloService1.scala @@ -0,0 +1,12 @@ +package pkg01 + +class HelloService1 +{ + def hello = + { + "Hello from module 3" + } + +} + +object HelloService1 extends HelloService1 diff --git a/src/it/test_coverage_minima/module03/src/test/scala/pkg01/HelloServiceTest.scala b/src/it/test_coverage_minima/module03/src/test/scala/pkg01/HelloServiceTest.scala new file mode 100644 index 00000000..ffe06705 --- /dev/null +++ b/src/it/test_coverage_minima/module03/src/test/scala/pkg01/HelloServiceTest.scala @@ -0,0 +1,14 @@ +package pkg01 + +import org.junit.Test; +import org.junit.Assert.assertEquals + +class HelloServiceTest +{ + @Test + def test1() + { + assertEquals("Hello from module 3", HelloService1.hello) + } + +} diff --git a/src/it/test_coverage_minima/pom.xml b/src/it/test_coverage_minima/pom.xml new file mode 100644 index 00000000..e232ac02 --- /dev/null +++ b/src/it/test_coverage_minima/pom.xml @@ -0,0 +1,63 @@ + + + + 4.0.0 + + + it.scoverage-maven-plugin + integration_tests_parent + 1.0-SNAPSHOT + ../integration_tests_parent/pom.xml + + + test_coverage_minima + 1.0-SNAPSHOT + pom + Test Scoverage coverage minima + Test Scoverage coverage minima + + + 2.13 + 12 + + + + module01 + module02 + module03 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + net.alchim31.maven + scala-maven-plugin + + + org.apache.maven.plugins + maven-surefire-plugin + + + @project.groupId@ + @project.artifactId@ + + true + 95 + false + + + + + check + + + + + + + diff --git a/src/it/test_coverage_minima/validate.groovy b/src/it/test_coverage_minima/validate.groovy new file mode 100644 index 00000000..470fb21b --- /dev/null +++ b/src/it/test_coverage_minima/validate.groovy @@ -0,0 +1,43 @@ +def checkModule(logText, module, coverageLog) { + assert new File(basedir, module + "/target/scoverage.xml").exists() + assert new File(basedir, module + "/target/site/scoverage/index.html").exists() + def entry = logText.find { + it.startsWith("scoverage") && + it.contains(":check (default-cli) @ " + module + " ---\n") + } + assert entry != null + assert entry.endsWith(" @ " + module + " ---" + coverageLog.replaceAll("\r\n", "\n") + "[INFO] ") +} + +try { + // check coverage minima + def logText = (new File(basedir, "build.log")).text.replaceAll("\r\n", "\n").split(/\n\[INFO\] \-\-\- /) + + checkModule(logText, "module01", + """ + |[INFO] Statement coverage.: 100.00% + |[INFO] Branch coverage....: 100.00% + |[INFO] Coverage is above minimum [100.00% >= 95.00%] + |""".stripMargin() + ) + checkModule(logText, "module02", + """ + |[INFO] Statement coverage.: 50.00% + |[INFO] Branch coverage....: 100.00% + |[ERROR] Coverage is below minimum [50.00% < 95.00%] + |""".stripMargin() + ) + checkModule(logText, "module03", + """ + |[INFO] Statement coverage.: 100.00% + |[INFO] Branch coverage....: 100.00% + |[INFO] 100% Coverage ! + |""".stripMargin() + ) + + return true + +} catch (Throwable e) { + e.printStackTrace() + return false +} From 86f51a37871e758c14b0226333d060b6c9a80610 Mon Sep 17 00:00:00 2001 From: Albert Meltzer <7529386+kitbellew@users.noreply.github.com> Date: Sun, 31 Dec 2023 10:17:04 -0800 Subject: [PATCH 2/4] Coverage minima: report 100% coverage if min < 100 Previously, it was only reported as such for min = 100. --- src/it/test_coverage_minima/validate.groovy | 2 +- src/main/java/org/scoverage/plugin/SCoverageCheckMojo.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/it/test_coverage_minima/validate.groovy b/src/it/test_coverage_minima/validate.groovy index 470fb21b..3542af5b 100644 --- a/src/it/test_coverage_minima/validate.groovy +++ b/src/it/test_coverage_minima/validate.groovy @@ -17,7 +17,7 @@ try { """ |[INFO] Statement coverage.: 100.00% |[INFO] Branch coverage....: 100.00% - |[INFO] Coverage is above minimum [100.00% >= 95.00%] + |[INFO] 100% Coverage ! |""".stripMargin() ) checkModule(logText, "module02", diff --git a/src/main/java/org/scoverage/plugin/SCoverageCheckMojo.java b/src/main/java/org/scoverage/plugin/SCoverageCheckMojo.java index 42d19af2..bf591fae 100644 --- a/src/main/java/org/scoverage/plugin/SCoverageCheckMojo.java +++ b/src/main/java/org/scoverage/plugin/SCoverageCheckMojo.java @@ -175,7 +175,7 @@ public void execute() throws MojoFailureException if ( minimumCoverage > 0.0 ) { String minimumCoverageFormatted = scoverage.domain.DoubleFormat.twoFractionDigits( minimumCoverage ); - if ( is100( minimumCoverage ) && is100( coverage.statementCoveragePercent() ) ) + if ( is100( coverage.statementCoveragePercent() ) ) { getLog().info( "100% Coverage !" ); } @@ -201,7 +201,7 @@ else if ( coverage.statementCoveragePercent() < minimumCoverage ) // Private utility methods - private boolean is100( Double d ) + private static boolean is100( Double d ) { return Math.abs( 100 - d ) <= 0.00001d; } From 6f2b2171196f1500811ac7b95393a3b8edafc420 Mon Sep 17 00:00:00 2001 From: Albert Meltzer <7529386+kitbellew@users.noreply.github.com> Date: Sun, 31 Dec 2023 10:17:08 -0800 Subject: [PATCH 3/4] Coverage minima: add parameter for branch minima Also, extract a coverage computation and logging method. --- README.md | 3 +- src/it/test_coverage_minima/module03/pom.xml | 1 + src/it/test_coverage_minima/pom.xml | 1 + src/it/test_coverage_minima/validate.groovy | 15 +-- .../scoverage/plugin/SCoverageCheckMojo.java | 103 ++++++++++++++---- 5 files changed, 89 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 25394433..e5921d66 100644 --- a/README.md +++ b/README.md @@ -335,7 +335,8 @@ Read [SBT SCoverage Plugin documentation](https://github.com/scoverage/sbt-scove scoverage-maven-plugin ${scoverage.plugin.version} - 80 + 95 + 90 true diff --git a/src/it/test_coverage_minima/module03/pom.xml b/src/it/test_coverage_minima/module03/pom.xml index d8987f45..770005fb 100644 --- a/src/it/test_coverage_minima/module03/pom.xml +++ b/src/it/test_coverage_minima/module03/pom.xml @@ -21,6 +21,7 @@ true 100 + 100 diff --git a/src/it/test_coverage_minima/pom.xml b/src/it/test_coverage_minima/pom.xml index e232ac02..a68c2d67 100644 --- a/src/it/test_coverage_minima/pom.xml +++ b/src/it/test_coverage_minima/pom.xml @@ -48,6 +48,7 @@ true 95 + 90 false diff --git a/src/it/test_coverage_minima/validate.groovy b/src/it/test_coverage_minima/validate.groovy index 3542af5b..9e132b80 100644 --- a/src/it/test_coverage_minima/validate.groovy +++ b/src/it/test_coverage_minima/validate.groovy @@ -15,23 +15,20 @@ try { checkModule(logText, "module01", """ - |[INFO] Statement coverage.: 100.00% - |[INFO] Branch coverage....: 100.00% - |[INFO] 100% Coverage ! + |[INFO] Coverage is 100%: Statement:Total! + |[INFO] Coverage is 100%: Branch:Total! |""".stripMargin() ) checkModule(logText, "module02", """ - |[INFO] Statement coverage.: 50.00% - |[INFO] Branch coverage....: 100.00% - |[ERROR] Coverage is below minimum [50.00% < 95.00%] + |[ERROR] Coverage is below minimum [50.00% < 95.00%]: Statement:Total + |[INFO] Coverage is 100%: Branch:Total! |""".stripMargin() ) checkModule(logText, "module03", """ - |[INFO] Statement coverage.: 100.00% - |[INFO] Branch coverage....: 100.00% - |[INFO] 100% Coverage ! + |[INFO] Coverage is 100%: Statement:Total! + |[INFO] Coverage is 100%: Branch:Total! |""".stripMargin() ) diff --git a/src/main/java/org/scoverage/plugin/SCoverageCheckMojo.java b/src/main/java/org/scoverage/plugin/SCoverageCheckMojo.java index bf591fae..5c2eca75 100644 --- a/src/main/java/org/scoverage/plugin/SCoverageCheckMojo.java +++ b/src/main/java/org/scoverage/plugin/SCoverageCheckMojo.java @@ -23,6 +23,7 @@ import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugin.logging.Log; import org.apache.maven.plugins.annotations.Execute; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; @@ -33,6 +34,8 @@ import scala.jdk.javaapi.CollectionConverters; import scoverage.domain.Coverage; +import scoverage.domain.CoverageMetrics; +import scoverage.domain.DoubleFormat; import scoverage.reporter.IOUtils; import scoverage.serialize.Serializer; @@ -70,7 +73,7 @@ public class SCoverageCheckMojo private File dataDirectory; /** - * Required minimum coverage. + * Required minimum total statement coverage. *
*
* See https://github.com/scoverage/sbt-scoverage#minimum-coverage for additional documentation. @@ -81,6 +84,18 @@ public class SCoverageCheckMojo @Parameter( property = "scoverage.minimumCoverage", defaultValue = "0" ) private Double minimumCoverage; + /** + * Required minimum total branch coverage. + *
+ *
+ * See https://github.com/scoverage/sbt-scoverage#minimum-coverage for additional documentation. + *
+ * + * @since 2.0.1 + */ + @Parameter( property = "scoverage.minimumCoverageBranchTotal", defaultValue = "0" ) + private Double minimumCoverageBranchTotal; + /** * Fail the build if minimum coverage was not reached. *
@@ -168,31 +183,15 @@ public void execute() throws MojoFailureException int invokedBranchesCount = coverage.invokedBranchesCount(); int invokedStatementCount = coverage.invokedStatementCount(); - getLog().info( String.format( "Statement coverage.: %s%%", coverage.statementCoverageFormatted() ) ); - getLog().info( String.format( "Branch coverage....: %s%%", coverage.branchCoverageFormatted() ) ); getLog().debug( String.format( "invokedBranchesCount:%d / branchCount:%d, invokedStatementCount:%d / statementCount:%d", invokedBranchesCount, branchCount, invokedStatementCount, statementCount ) ); - if ( minimumCoverage > 0.0 ) + + boolean ok = checkCoverage( getLog(), "Total", coverage, + minimumCoverage, minimumCoverageBranchTotal, true ); + + if ( !ok && failOnMinimumCoverage ) { - String minimumCoverageFormatted = scoverage.domain.DoubleFormat.twoFractionDigits( minimumCoverage ); - if ( is100( coverage.statementCoveragePercent() ) ) - { - getLog().info( "100% Coverage !" ); - } - else if ( coverage.statementCoveragePercent() < minimumCoverage ) - { - getLog().error( String.format( "Coverage is below minimum [%s%% < %s%%]", - coverage.statementCoverageFormatted(), minimumCoverageFormatted ) ); - if ( failOnMinimumCoverage ) - { - throw new MojoFailureException( "Coverage minimum was not reached" ); - } - } - else - { - getLog().info( String.format( "Coverage is above minimum [%s%% >= %s%%]", - coverage.statementCoverageFormatted(), minimumCoverageFormatted ) ); - } + throw new MojoFailureException( "Coverage minimum was not reached" ); } long te = System.currentTimeMillis(); @@ -206,4 +205,60 @@ private static boolean is100( Double d ) return Math.abs( 100 - d ) <= 0.00001d; } -} \ No newline at end of file + private static boolean checkCoverage( Log logger, String metric, CoverageMetrics metrics, + double minStmt, double minBranch, boolean logSuccessInfo ) + { + boolean stmt = checkCoverage( logger, "Statement:" + metric, + minStmt, metrics.statementCoveragePercent(), logSuccessInfo ); + boolean branch = checkCoverage( logger, "Branch:" + metric, + minBranch, metrics.branchCoveragePercent(), logSuccessInfo ); + return stmt && branch; + } + + private static boolean checkCoverage( Log logger, String metric, + double minimum, double actual, boolean logSuccessInfo ) + { + if ( minimum <= 0 ) + { + return true; + } + + if ( is100( actual ) ) + { + logSuccess( logger, String.format( "Coverage is 100%%: %s!", metric ), logSuccessInfo ); + return true; + } + + String minimumFormatted = DoubleFormat.twoFractionDigits( minimum ); + String actualFormatted = DoubleFormat.twoFractionDigits( actual ); + boolean ok = minimum <= actual; + + if ( ok ) + { + String message = String.format( "Coverage is above minimum [%s%% >= %s%%]: %s", + actualFormatted, minimumFormatted, metric ); + logSuccess( logger, message, logSuccessInfo ); + } + else + { + String message = String.format( "Coverage is below minimum [%s%% < %s%%]: %s", + actualFormatted, minimumFormatted, metric ); + logger.error( message ); + } + + return ok; + } + + private static void logSuccess( Log logger, String message, boolean logSuccessInfo ) + { + if ( logSuccessInfo ) + { + logger.info( message ); + } + else + { + logger.debug( message ); + } + } + +} From 6e1046963b6d70496e8a4dee1c6e42d405cb1b10 Mon Sep 17 00:00:00 2001 From: Albert Meltzer <7529386+kitbellew@users.noreply.github.com> Date: Sun, 31 Dec 2023 10:21:24 -0800 Subject: [PATCH 4/4] Coverage minima: add more fine-grained control Along with existing overall coverage, add parameters for statement and branch minima at the package and file level. --- README.md | 4 + src/it/test_coverage_minima/module03/pom.xml | 4 + src/it/test_coverage_minima/pom.xml | 4 + src/it/test_coverage_minima/validate.groovy | 4 + .../scoverage/plugin/SCoverageCheckMojo.java | 77 +++++++++++++++++++ 5 files changed, 93 insertions(+) diff --git a/README.md b/README.md index e5921d66..65daaa6d 100644 --- a/README.md +++ b/README.md @@ -337,6 +337,10 @@ Read [SBT SCoverage Plugin documentation](https://github.com/scoverage/sbt-scove 95 90 + 90 + 85 + 85 + 80 true diff --git a/src/it/test_coverage_minima/module03/pom.xml b/src/it/test_coverage_minima/module03/pom.xml index 770005fb..a6d61023 100644 --- a/src/it/test_coverage_minima/module03/pom.xml +++ b/src/it/test_coverage_minima/module03/pom.xml @@ -22,6 +22,10 @@ true 100 100 + 100 + 100 + 100 + 100 diff --git a/src/it/test_coverage_minima/pom.xml b/src/it/test_coverage_minima/pom.xml index a68c2d67..0d6ffc03 100644 --- a/src/it/test_coverage_minima/pom.xml +++ b/src/it/test_coverage_minima/pom.xml @@ -49,6 +49,10 @@ true 95 90 + 90 + 85 + 85 + 80 false diff --git a/src/it/test_coverage_minima/validate.groovy b/src/it/test_coverage_minima/validate.groovy index 9e132b80..4de80432 100644 --- a/src/it/test_coverage_minima/validate.groovy +++ b/src/it/test_coverage_minima/validate.groovy @@ -23,6 +23,10 @@ try { """ |[ERROR] Coverage is below minimum [50.00% < 95.00%]: Statement:Total |[INFO] Coverage is 100%: Branch:Total! + |[ERROR] Coverage is below minimum [0.00% < 90.00%]: Statement:Package:pkg02 + |[ERROR] Coverage is below minimum [0.00% < 85.00%]: Branch:Package:pkg02 + |[ERROR] Coverage is below minimum [0.00% < 85.00%]: Statement:File:HelloService1.scala + |[ERROR] Coverage is below minimum [0.00% < 80.00%]: Branch:File:HelloService1.scala |""".stripMargin() ) checkModule(logText, "module03", diff --git a/src/main/java/org/scoverage/plugin/SCoverageCheckMojo.java b/src/main/java/org/scoverage/plugin/SCoverageCheckMojo.java index 5c2eca75..18940379 100644 --- a/src/main/java/org/scoverage/plugin/SCoverageCheckMojo.java +++ b/src/main/java/org/scoverage/plugin/SCoverageCheckMojo.java @@ -20,6 +20,8 @@ import java.io.File; import java.util.Arrays; import java.util.List; +import java.util.function.Function; +import java.util.function.Predicate; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoFailureException; @@ -36,6 +38,8 @@ import scoverage.domain.Coverage; import scoverage.domain.CoverageMetrics; import scoverage.domain.DoubleFormat; +import scoverage.domain.MeasuredFile; +import scoverage.domain.MeasuredPackage; import scoverage.reporter.IOUtils; import scoverage.serialize.Serializer; @@ -96,6 +100,54 @@ public class SCoverageCheckMojo @Parameter( property = "scoverage.minimumCoverageBranchTotal", defaultValue = "0" ) private Double minimumCoverageBranchTotal; + /** + * Required minimum per-package statement coverage. + *
+ *
+ * See https://github.com/scoverage/sbt-scoverage#minimum-coverage for additional documentation. + *
+ * + * @since 2.0.1 + */ + @Parameter( property = "scoverage.minimumCoverageStmtPerPackage", defaultValue = "0" ) + private Double minimumCoverageStmtPerPackage; + + /** + * Required minimum per-package branch coverage. + *
+ *
+ * See https://github.com/scoverage/sbt-scoverage#minimum-coverage for additional documentation. + *
+ * + * @since 2.0.1 + */ + @Parameter( property = "scoverage.minimumCoverageBranchPerPackage", defaultValue = "0" ) + private Double minimumCoverageBranchPerPackage; + + /** + * Required minimum per-file statement coverage. + *
+ *
+ * See https://github.com/scoverage/sbt-scoverage#minimum-coverage for additional documentation. + *
+ * + * @since 2.0.1 + */ + @Parameter( property = "scoverage.minimumCoverageStmtPerFile", defaultValue = "0" ) + private Double minimumCoverageStmtPerFile; + + /** + * Required minimum per-file branch coverage. + *
+ *
+ * See https://github.com/scoverage/sbt-scoverage#minimum-coverage for additional documentation. + *
+ * + * @since 2.0.1 + */ + @Parameter( property = "scoverage.minimumCoverageBranchPerFile", defaultValue = "0" ) + private Double minimumCoverageBranchPerFile; + /** * Fail the build if minimum coverage was not reached. *
@@ -188,6 +240,10 @@ public void execute() throws MojoFailureException boolean ok = checkCoverage( getLog(), "Total", coverage, minimumCoverage, minimumCoverageBranchTotal, true ); + ok = checkCoverage( getLog(), "Package:", coverage.packages(), MeasuredPackage::name, + minimumCoverageStmtPerPackage, minimumCoverageBranchPerPackage ) && ok; + ok = checkCoverage( getLog(), "File:", coverage.files(), MeasuredFile::filename, + minimumCoverageStmtPerFile, minimumCoverageBranchPerFile ) && ok; if ( !ok && failOnMinimumCoverage ) { @@ -205,6 +261,17 @@ private static boolean is100( Double d ) return Math.abs( 100 - d ) <= 0.00001d; } + private static + boolean checkCoverage( Log logger, String metricPrefix, + scala.collection.Iterable< T > metrics, + Function< T, String > toName, + double minStmt, double minBranch ) + { + return minStmt <= 0 && minBranch <= 0 || checkAll(metrics, cov -> + checkCoverage(logger, metricPrefix + toName.apply(cov), cov, minStmt, minBranch, false) + ); + } + private static boolean checkCoverage( Log logger, String metric, CoverageMetrics metrics, double minStmt, double minBranch, boolean logSuccessInfo ) { @@ -261,4 +328,14 @@ private static void logSuccess( Log logger, String message, boolean logSuccessIn } } + private static boolean checkAll( scala.collection.Iterable iterable, Predicate predicate ) + { + boolean ok = true; + for ( T elem : CollectionConverters.asJava( iterable ) ) + { + ok = predicate.test( elem ) && ok; + } + return ok; + } + }