diff --git a/README.md b/README.md index 5b54bcbf..107ba4f0 100644 --- a/README.md +++ b/README.md @@ -90,8 +90,7 @@ coverageExcludedFiles := ".*\\/two\\/GoodCoverage;.*\\/three\\/.*" Note: The `.scala` file extension needs to be omitted from the filename, if one is given. -Note: These two options only work for Scala2. Right now Scala3 does not support -a way to exclude packages or files from being instrumented. +Note: These two options only work for Scala2 and Scala 3.4.2+. You can also mark sections of code with comments like: @@ -104,6 +103,8 @@ You can also mark sections of code with comments like: Any code between two such comments will not be instrumented or included in the coverage report. +Note: Comments exclusion works only for Scala2. + ### Minimum coverage Based on minimum coverage, you can fail the build with the following keys: diff --git a/src/main/scala/scoverage/ScoverageSbtPlugin.scala b/src/main/scala/scoverage/ScoverageSbtPlugin.scala index a7a22add..feba91ba 100644 --- a/src/main/scala/scoverage/ScoverageSbtPlugin.scala +++ b/src/main/scala/scoverage/ScoverageSbtPlugin.scala @@ -75,18 +75,28 @@ object ScoverageSbtPlugin extends AutoPlugin { private def isScala2(scalaVersion: String) = CrossVersion .partialVersion(scalaVersion) - .collect { case (2, _) => - true + .exists { + case (2, _) => true + case _ => false } - .getOrElse(false) private def isScala3SupportingScoverage(scalaVersion: String) = CrossVersion .partialVersion(scalaVersion) - .collect { + .exists { case (3, minor) if minor >= 2 => true + case _ => false + } + + private def isScala3SupportingFilePackageExclusion(scalaVersion: String) = { + def patch = scalaVersion.split('.').drop(2).headOption + CrossVersion + .partialVersion(scalaVersion) + .exists { + case (3, minor) if minor >= 4 && patch.exists(_ >= "2") => true + case _ => false } - .getOrElse(false) + } private lazy val coverageSettings = Seq( libraryDependencies ++= { @@ -114,6 +124,18 @@ object ScoverageSbtPlugin extends AutoPlugin { implicit val log = streams.value.log + val excludedPackages = + Option(coverageExcludedPackages.value.trim).filter(_.nonEmpty) + val excludedFiles = Option(coverageExcludedFiles.value.trim) + .filter(_.nonEmpty) + .map(v => + // On windows, replace unix file separators with windows file + // separators. Note that we need to replace / with \\ because + // the plugin treats this string as a regular expression and + // backslashes must be escaped in regular expressions. + if (isWindows) v.replace("/", """\\""") else v + ) + val updateReport = update.value if (coverageEnabled.value && isScala2(scalaVersion.value)) { val scoverageDeps: Seq[File] = @@ -156,19 +178,8 @@ object ScoverageSbtPlugin extends AutoPlugin { Some( s"-P:scoverage:sourceRoot:${coverageSourceRoot.value.getAbsolutePath}" ), - Option(coverageExcludedPackages.value.trim) - .filter(_.nonEmpty) - .map(v => s"-P:scoverage:excludedPackages:$v"), - Option(coverageExcludedFiles.value.trim) - .filter(_.nonEmpty) - .map(v => - // On windows, replace unix file separators with windows file - // separators. Note that we need to replace / with \\ because - // the plugin treats this string as a regular expression and - // backslashes must be escaped in regular expressions. - if (isWindows) v.replace("/", """\\""") else v - ) - .map(v => s"-P:scoverage:excludedFiles:$v"), + excludedPackages.map(v => s"-P:scoverage:excludedPackages:$v"), + excludedFiles.map(v => s"-P:scoverage:excludedFiles:$v"), Some("-P:scoverage:reportTestName"), // rangepos is broken in some releases of scala so option to turn it off if (coverageHighlighting.value) Some("-Yrangepos") else None @@ -177,8 +188,26 @@ object ScoverageSbtPlugin extends AutoPlugin { coverageEnabled.value && isScala3SupportingScoverage(scalaVersion.value) ) { Seq( - s"-coverage-out:${coverageDataDir.value.getAbsolutePath()}/scoverage-data" - ) + Some( + s"-coverage-out:${coverageDataDir.value.getAbsolutePath()}/scoverage-data" + ), + excludedPackages + .collect { + case v + if isScala3SupportingFilePackageExclusion( + scalaVersion.value + ) => + s"-coverage-exclude-classlikes:$v" + }, + excludedFiles + .collect { + case v + if isScala3SupportingFilePackageExclusion( + scalaVersion.value + ) => + s"-coverage-exclude-files:$v" + } + ).flatten } else if (coverageEnabled.value && !isScala2(scalaVersion.value)) { log.warn( "coverage in Scala 3 needs at least 3.2.x. Please update your Scala version and try again." diff --git a/src/sbt-test/scoverage/scala3-coverage-excluded-files/build.sbt b/src/sbt-test/scoverage/scala3-coverage-excluded-files/build.sbt index 939f7489..fef0a139 100644 --- a/src/sbt-test/scoverage/scala3-coverage-excluded-files/build.sbt +++ b/src/sbt-test/scoverage/scala3-coverage-excluded-files/build.sbt @@ -1,6 +1,6 @@ version := "0.1" -scalaVersion := "3.2.0-RC1" +scalaVersion := "3.4.2" libraryDependencies += "org.scalameta" %% "munit" % "0.7.29" % Test diff --git a/src/sbt-test/scoverage/scala3-coverage-excluded-files/test b/src/sbt-test/scoverage/scala3-coverage-excluded-files/test index b19476ca..08688334 100644 --- a/src/sbt-test/scoverage/scala3-coverage-excluded-files/test +++ b/src/sbt-test/scoverage/scala3-coverage-excluded-files/test @@ -4,6 +4,4 @@ > test > coverageReport # There should be no directory for the excluded files -#-$ exists target/scala-3.2.0-RC1/scoverage-report/two -# But right now there is, because Scala3 does not support excluding files -$ exists target/scala-3.2.0-RC1/scoverage-report/two +-$ exists target/scala-3.4.2/scoverage-report/two \ No newline at end of file diff --git a/src/sbt-test/scoverage/scala3-coverage-excluded-packages/build.sbt b/src/sbt-test/scoverage/scala3-coverage-excluded-packages/build.sbt new file mode 100644 index 00000000..083a1e20 --- /dev/null +++ b/src/sbt-test/scoverage/scala3-coverage-excluded-packages/build.sbt @@ -0,0 +1,13 @@ +version := "0.1" + +scalaVersion := "3.4.2" + +libraryDependencies += "org.scalameta" %% "munit" % "0.7.29" % Test + +coverageExcludedPackages := "two\\..*" + +resolvers ++= { + if (sys.props.get("plugin.version").exists(_.endsWith("-SNAPSHOT"))) + Seq(Resolver.sonatypeRepo("snapshots")) + else Seq.empty +} diff --git a/src/sbt-test/scoverage/scala3-coverage-excluded-packages/project/build.properties b/src/sbt-test/scoverage/scala3-coverage-excluded-packages/project/build.properties new file mode 100644 index 00000000..04267b14 --- /dev/null +++ b/src/sbt-test/scoverage/scala3-coverage-excluded-packages/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.9.9 diff --git a/src/sbt-test/scoverage/scala3-coverage-excluded-packages/project/plugins.sbt b/src/sbt-test/scoverage/scala3-coverage-excluded-packages/project/plugins.sbt new file mode 100644 index 00000000..8d349239 --- /dev/null +++ b/src/sbt-test/scoverage/scala3-coverage-excluded-packages/project/plugins.sbt @@ -0,0 +1,16 @@ +val pluginVersion = sys.props.getOrElse( + "plugin.version", + throw new RuntimeException( + """|The system property 'plugin.version' is not defined. + |Specify this property using the scriptedLaunchOpts -D.""".stripMargin + ) +) + +addSbtPlugin("org.scoverage" % "sbt-scoverage" % pluginVersion) + +resolvers ++= { + if (pluginVersion.endsWith("-SNAPSHOT")) + Seq(Resolver.sonatypeRepo("snapshots")) + else + Seq.empty +} diff --git a/src/sbt-test/scoverage/scala3-coverage-excluded-packages/src/main/scala/GoodCoverage.scala b/src/sbt-test/scoverage/scala3-coverage-excluded-packages/src/main/scala/GoodCoverage.scala new file mode 100644 index 00000000..ac6582bb --- /dev/null +++ b/src/sbt-test/scoverage/scala3-coverage-excluded-packages/src/main/scala/GoodCoverage.scala @@ -0,0 +1,7 @@ +object GoodCoverage { + + def sum(num1: Int, num2: Int) = { + if (0 == num1) num2 else if (0 == num2) num1 else num1 + num2 + } + +} diff --git a/src/sbt-test/scoverage/scala3-coverage-excluded-packages/src/main/scala/two/GoodCoverage.scala b/src/sbt-test/scoverage/scala3-coverage-excluded-packages/src/main/scala/two/GoodCoverage.scala new file mode 100644 index 00000000..587e11e1 --- /dev/null +++ b/src/sbt-test/scoverage/scala3-coverage-excluded-packages/src/main/scala/two/GoodCoverage.scala @@ -0,0 +1,9 @@ +package two + +object GoodCoverage { + + def sum(num1: Int, num2: Int) = { + if (0 == num1) num2 else if (0 == num2) num1 else num1 + num2 + } + +} diff --git a/src/sbt-test/scoverage/scala3-coverage-excluded-packages/src/test/scala/GoodCoverageSpec.scala b/src/sbt-test/scoverage/scala3-coverage-excluded-packages/src/test/scala/GoodCoverageSpec.scala new file mode 100644 index 00000000..44eec1c9 --- /dev/null +++ b/src/sbt-test/scoverage/scala3-coverage-excluded-packages/src/test/scala/GoodCoverageSpec.scala @@ -0,0 +1,19 @@ +import munit.FunSuite + +/** Created by tbarke001c on 7/8/14. + */ +class GoodCoverageSpec extends FunSuite { + + test("GoodCoverage should sum two numbers") { + assertEquals(GoodCoverage.sum(1, 2), 3) + assertEquals(GoodCoverage.sum(0, 3), 3) + assertEquals(GoodCoverage.sum(3, 0), 3) + } + + test("two.GoodCoverage should sum two numbers") { + assertEquals(two.GoodCoverage.sum(1, 2), 3) + assertEquals(two.GoodCoverage.sum(0, 3), 3) + assertEquals(two.GoodCoverage.sum(3, 0), 3) + } + +} diff --git a/src/sbt-test/scoverage/scala3-coverage-excluded-packages/test b/src/sbt-test/scoverage/scala3-coverage-excluded-packages/test new file mode 100644 index 00000000..e611b048 --- /dev/null +++ b/src/sbt-test/scoverage/scala3-coverage-excluded-packages/test @@ -0,0 +1,7 @@ +# run scoverage using the coverage task +> clean +> coverage +> test +> coverageReport +# There should be no directory for the excluded package +-$ exists target/scala-3.4.2/scoverage-report/two