From 0b746849d389c0923fa03c99d220f5f3165c7a36 Mon Sep 17 00:00:00 2001 From: Chris Kipp Date: Sat, 23 Oct 2021 16:23:01 +0200 Subject: [PATCH 1/5] feature: break reporter out into its own module --- .github/workflows/ci.yml | 29 ++- build.sbt | 46 ++-- .../src/main/resources/scalac-plugin.xml | 0 .../main/scala/scoverage/CoverageFilter.scala | 0 .../src/main/scala/scoverage/Location.scala | 57 +++++ .../scala/scoverage/ScoverageOptions.scala | 0 .../scala/scoverage/ScoveragePlugin.scala | 14 +- .../scoverage/macrosupport/TesterMacro.scala | 0 .../scala/scoverage/LocationCompiler.scala | 7 +- .../test/scala/scoverage/LocationTest.scala | 1 + .../test/scala/scoverage/MacroSupport.scala | 2 +- .../scoverage/PluginASTSupportTest.scala | 0 .../scoverage/PluginCoverageScalaJsTest.scala | 0 .../scala/scoverage/PluginCoverageTest.scala | 0 .../scoverage/RegexCoverageFilterTest.scala | 0 .../scala/scoverage/ScoverageCompiler.scala | 8 +- .../scala/scoverage/macrosupport/Tester.scala | 0 .../src/main/resources/scoverage/index.html | 0 .../src/main/resources/scoverage/pure-min.css | 0 .../scala/reporter}/BaseReportWriter.scala | 2 +- .../src/main/scala/reporter/Builders.scala | 26 ++ .../scala/reporter}/CoberturaXmlWriter.scala | 5 +- .../src/main/scala/reporter}/CodeGrid.scala | 4 +- .../src/main/scala/reporter}/Constants.scala | 4 +- .../scala/reporter}/CoverageAggregator.scala | 8 +- .../main/scala/reporter/CoverageMetrics.scala | 95 ++++++++ .../main/scala/reporter}/DoubleFormat.scala | 2 +- .../src/main/scala/reporter}/IOUtils.scala | 7 +- .../src/main/scala/reporter/Location.scala | 14 ++ .../scala/reporter}/ScoverageHtmlWriter.scala | 4 +- .../scala/reporter}/ScoverageXmlWriter.scala | 4 +- .../src/main/scala/reporter}/Serializer.scala | 2 +- .../src/main/scala/reporter/Statement.scala | 25 ++ .../main/scala/reporter/StatementStatus.scala | 2 +- .../scala/reporter}/StatementWriter.scala | 4 +- .../src/main/scala/reporter/coverage.scala | 91 +++++++ .../scoverage/reporter}/cobertura.sample.xml | 0 .../scoverage/reporter}/coverage-04.dtd | 0 .../src/main/scala/ClassContainingHtml.scala | 0 .../src/main/scala/ClassInMainDir.scala | 0 .../src/main/scala/subdir/ClassInSubDir.scala | 0 .../reporter}/CoberturaXmlWriterTest.scala | 5 +- .../reporter}/CoverageAggregatorTest.scala | 3 +- .../reporter}/CoverageMetricsTest.scala | 2 +- .../scoverage/reporter}/CoverageTest.scala | 2 +- .../scoverage/reporter}/IOUtilsTest.scala | 2 +- .../reporter}/ScoverageHtmlWriterTest.scala | 3 +- .../scoverage/reporter}/SerializerTest.scala | 2 +- .../src/main/scala/scalajssupport/File.scala | 0 .../scala/scalajssupport/FileWriter.scala | 0 .../main/scala/scalajssupport/JsFile.scala | 0 .../main/scala/scalajssupport/NodeFile.scala | 0 .../scala/scalajssupport/PhantomFile.scala | 0 .../main/scala/scalajssupport/RhinoFile.scala | 0 .../main/scala/scalajssupport/Source.scala | 0 .../src/main/scala/scoverage/Platform.scala | 0 .../src/main/scala/scoverage/Platform.scala | 0 .../scoverage/InvokerConcurrencyTest.scala | 0 .../src/main/scala/scoverage/Invoker.scala | 0 .../scoverage/InvokerMultiModuleTest.scala | 0 .../src/main/scala/scoverage/Location.scala | 67 ----- .../src/main/scala/scoverage/coverage.scala | 230 ------------------ 62 files changed, 416 insertions(+), 363 deletions(-) rename {scalac-scoverage-plugin => plugin}/src/main/resources/scalac-plugin.xml (100%) rename {scalac-scoverage-plugin => plugin}/src/main/scala/scoverage/CoverageFilter.scala (100%) create mode 100644 plugin/src/main/scala/scoverage/Location.scala rename {scalac-scoverage-plugin => plugin}/src/main/scala/scoverage/ScoverageOptions.scala (100%) rename {scalac-scoverage-plugin => plugin}/src/main/scala/scoverage/ScoveragePlugin.scala (98%) rename {scalac-scoverage-plugin => plugin}/src/test/scala-2.11+/scoverage/macrosupport/TesterMacro.scala (100%) rename {scalac-scoverage-plugin => plugin}/src/test/scala/scoverage/LocationCompiler.scala (87%) rename {scalac-scoverage-plugin => plugin}/src/test/scala/scoverage/LocationTest.scala (99%) rename {scalac-scoverage-plugin => plugin}/src/test/scala/scoverage/MacroSupport.scala (78%) rename {scalac-scoverage-plugin => plugin}/src/test/scala/scoverage/PluginASTSupportTest.scala (100%) rename {scalac-scoverage-plugin => plugin}/src/test/scala/scoverage/PluginCoverageScalaJsTest.scala (100%) rename {scalac-scoverage-plugin => plugin}/src/test/scala/scoverage/PluginCoverageTest.scala (100%) rename {scalac-scoverage-plugin => plugin}/src/test/scala/scoverage/RegexCoverageFilterTest.scala (100%) rename {scalac-scoverage-plugin => plugin}/src/test/scala/scoverage/ScoverageCompiler.scala (96%) rename {scalac-scoverage-plugin => plugin}/src/test/scala/scoverage/macrosupport/Tester.scala (100%) rename {scalac-scoverage-plugin => reporter}/src/main/resources/scoverage/index.html (100%) rename {scalac-scoverage-plugin => reporter}/src/main/resources/scoverage/pure-min.css (100%) rename {scalac-scoverage-plugin/src/main/scala/scoverage/report => reporter/src/main/scala/reporter}/BaseReportWriter.scala (98%) create mode 100644 reporter/src/main/scala/reporter/Builders.scala rename {scalac-scoverage-plugin/src/main/scala/scoverage/report => reporter/src/main/scala/reporter}/CoberturaXmlWriter.scala (97%) rename {scalac-scoverage-plugin/src/main/scala/scoverage/report => reporter/src/main/scala/reporter}/CodeGrid.scala (98%) rename {scalac-scoverage-plugin/src/main/scala/scoverage => reporter/src/main/scala/reporter}/Constants.scala (86%) rename {scalac-scoverage-plugin/src/main/scala/scoverage/report => reporter/src/main/scala/reporter}/CoverageAggregator.scala (88%) create mode 100644 reporter/src/main/scala/reporter/CoverageMetrics.scala rename {scalac-scoverage-plugin/src/main/scala/scoverage => reporter/src/main/scala/reporter}/DoubleFormat.scala (94%) rename {scalac-scoverage-plugin/src/main/scala/scoverage => reporter/src/main/scala/reporter}/IOUtils.scala (92%) create mode 100644 reporter/src/main/scala/reporter/Location.scala rename {scalac-scoverage-plugin/src/main/scala/scoverage/report => reporter/src/main/scala/reporter}/ScoverageHtmlWriter.scala (99%) rename {scalac-scoverage-plugin/src/main/scala/scoverage/report => reporter/src/main/scala/reporter}/ScoverageXmlWriter.scala (99%) rename {scalac-scoverage-plugin/src/main/scala/scoverage => reporter/src/main/scala/reporter}/Serializer.scala (99%) create mode 100644 reporter/src/main/scala/reporter/Statement.scala rename scalac-scoverage-plugin/src/main/scala/scoverage/report/status.scala => reporter/src/main/scala/reporter/StatementStatus.scala (87%) rename {scalac-scoverage-plugin/src/main/scala/scoverage/report => reporter/src/main/scala/reporter}/StatementWriter.scala (94%) create mode 100644 reporter/src/main/scala/reporter/coverage.scala rename {scalac-scoverage-plugin/src/test/resources/scoverage => reporter/src/test/resources/scoverage/reporter}/cobertura.sample.xml (100%) rename {scalac-scoverage-plugin/src/test/resources/scoverage => reporter/src/test/resources/scoverage/reporter}/coverage-04.dtd (100%) rename {scalac-scoverage-plugin/src/test/resources/scoverage => reporter/src/test/resources/scoverage/reporter}/forHtmlWriter/src/main/scala/ClassContainingHtml.scala (100%) rename {scalac-scoverage-plugin/src/test/resources/scoverage => reporter/src/test/resources/scoverage/reporter}/forHtmlWriter/src/main/scala/ClassInMainDir.scala (100%) rename {scalac-scoverage-plugin/src/test/resources/scoverage => reporter/src/test/resources/scoverage/reporter}/forHtmlWriter/src/main/scala/subdir/ClassInSubDir.scala (100%) rename {scalac-scoverage-plugin/src/test/scala/scoverage => reporter/src/test/scala/scoverage/reporter}/CoberturaXmlWriterTest.scala (98%) rename {scalac-scoverage-plugin/src/test/scala/scoverage => reporter/src/test/scala/scoverage/reporter}/CoverageAggregatorTest.scala (97%) rename {scalac-scoverage-plugin/src/test/scala/scoverage => reporter/src/test/scala/scoverage/reporter}/CoverageMetricsTest.scala (97%) rename {scalac-scoverage-plugin/src/test/scala/scoverage => reporter/src/test/scala/scoverage/reporter}/CoverageTest.scala (98%) rename {scalac-scoverage-plugin/src/test/scala/scoverage => reporter/src/test/scala/scoverage/reporter}/IOUtilsTest.scala (98%) rename {scalac-scoverage-plugin/src/test/scala/scoverage => reporter/src/test/scala/scoverage/reporter}/ScoverageHtmlWriterTest.scala (98%) rename {scalac-scoverage-plugin/src/test/scala/scoverage => reporter/src/test/scala/scoverage/reporter}/SerializerTest.scala (99%) rename {scalac-scoverage-runtime => runtime}/js/src/main/scala/scalajssupport/File.scala (100%) rename {scalac-scoverage-runtime => runtime}/js/src/main/scala/scalajssupport/FileWriter.scala (100%) rename {scalac-scoverage-runtime => runtime}/js/src/main/scala/scalajssupport/JsFile.scala (100%) rename {scalac-scoverage-runtime => runtime}/js/src/main/scala/scalajssupport/NodeFile.scala (100%) rename {scalac-scoverage-runtime => runtime}/js/src/main/scala/scalajssupport/PhantomFile.scala (100%) rename {scalac-scoverage-runtime => runtime}/js/src/main/scala/scalajssupport/RhinoFile.scala (100%) rename {scalac-scoverage-runtime => runtime}/js/src/main/scala/scalajssupport/Source.scala (100%) rename {scalac-scoverage-runtime => runtime}/js/src/main/scala/scoverage/Platform.scala (100%) rename {scalac-scoverage-runtime => runtime}/jvm/src/main/scala/scoverage/Platform.scala (100%) rename {scalac-scoverage-runtime => runtime}/jvm/src/test/scala/scoverage/InvokerConcurrencyTest.scala (100%) rename {scalac-scoverage-runtime => runtime}/shared/src/main/scala/scoverage/Invoker.scala (100%) rename {scalac-scoverage-runtime => runtime}/shared/src/test/scala/scoverage/InvokerMultiModuleTest.scala (100%) delete mode 100644 scalac-scoverage-plugin/src/main/scala/scoverage/Location.scala delete mode 100644 scalac-scoverage-plugin/src/main/scala/scoverage/coverage.scala diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 95fa8444..db7fdafa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,13 +12,13 @@ on: pull_request: jobs: - test: + test-plugin: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ 'ubuntu-latest', 'windows-latest' ] - java: [ '8', '11', '17' ] + java: ['11', '17'] scala: [ { version: '2.12.15' }, { version: '2.12.14' }, @@ -40,7 +40,30 @@ jobs: java-version: ${{ matrix.java }} - name: run tests - run: sbt ++${{ matrix.scala.version }} test + run: sbt ++${{ matrix.scala.version }} plugin/test + + test-the-rest: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ 'ubuntu-latest', 'windows-latest' ] + java: ['11', '17' ] + module: ['runtime', 'runtimeJS', 'reporter'] + steps: + - name: checkout the repo + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Set up JVM + uses: actions/setup-java@v2 + with: + distribution: 'temurin' + java-version: ${{ matrix.java }} + + - name: run tests + run: sbt +${{ matrix.module }}/test style-check: runs-on: ubuntu-latest diff --git a/build.sbt b/build.sbt index 6d9b9ad7..a3d38053 100644 --- a/build.sbt +++ b/build.sbt @@ -1,12 +1,14 @@ import sbtcrossproject.CrossProject import sbtcrossproject.CrossType -val munitVersion = "0.7.29" -val scalametaVersion = "4.4.28" -val defaultScala213 = "2.13.6" -val bin212 = +lazy val munitVersion = "0.7.29" +lazy val scalametaVersion = "4.4.28" +lazy val defaultScala212 = "2.12.15" +lazy val defaultScala213 = "2.13.6" +lazy val defaultScala3 = "3.1.0" +lazy val bin212 = Seq( - "2.12.15", + defaultScala212, "2.12.14", "2.12.13", "2.12.12", @@ -15,7 +17,7 @@ val bin212 = "2.12.9", "2.12.8" ) -val bin213 = +lazy val bin213 = Seq( defaultScala213, "2.13.5", @@ -80,8 +82,7 @@ lazy val sharedSettings = List( } else { scalacOptions.value } - }, - crossScalaVersions := bin212 ++ bin213 + } ) lazy val root = Project("scalac-scoverage", file(".")) @@ -90,16 +91,17 @@ lazy val root = Project("scalac-scoverage", file(".")) publishArtifact := false, publishLocal := {} ) - .aggregate(plugin, runtime.jvm, runtime.js) + .aggregate(plugin, runtime.jvm, runtime.js, reporter) lazy val runtime = CrossProject( - "scalac-scoverage-runtime", - file("scalac-scoverage-runtime") + "runtime", + file("runtime") )(JVMPlatform, JSPlatform) .crossType(CrossType.Full) .withoutSuffixFor(JVMPlatform) .settings( name := "scalac-scoverage-runtime", + crossScalaVersions := Seq(defaultScala212, defaultScala213), crossTarget := target.value / s"scala-${scalaVersion.value}", libraryDependencies ++= Seq( "org.scalameta" %% "munit" % munitVersion % Test @@ -113,15 +115,16 @@ lazy val runtime = CrossProject( scalaJSStage := FastOptStage ) -lazy val `scalac-scoverage-runtimeJVM` = runtime.jvm -lazy val `scalac-scoverage-runtimeJS` = runtime.js +lazy val `runtimeJVM` = runtime.jvm +lazy val `runtimeJS` = runtime.js lazy val plugin = - Project("scalac-scoverage-plugin", file("scalac-scoverage-plugin")) - .dependsOn(`scalac-scoverage-runtimeJVM` % Test) + Project("plugin", file("plugin")) + .dependsOn(runtimeJVM % Test) .settings( name := "scalac-scoverage-plugin", crossTarget := target.value / s"scala-${scalaVersion.value}", + crossScalaVersions := bin212 ++ bin213, crossVersion := CrossVersion.full, libraryDependencies ++= Seq( "org.scala-lang.modules" %% "scala-xml" % "2.0.0", @@ -133,6 +136,19 @@ lazy val plugin = .settings( (Test / unmanagedSourceDirectories) += (Test / sourceDirectory).value / "scala-2.12+" ) + .dependsOn(reporter) + +lazy val reporter = + Project("reporter", file("reporter")) + .settings( + name := "scalac-scoverage-reporter", + libraryDependencies ++= Seq( + "org.scala-lang.modules" %% "scala-xml" % "2.0.0", + "org.scalameta" %% "munit" % munitVersion % Test + ), + sharedSettings, + crossScalaVersions := Seq(defaultScala212, defaultScala213, defaultScala3) + ) addCommandAlias( "styleFix", diff --git a/scalac-scoverage-plugin/src/main/resources/scalac-plugin.xml b/plugin/src/main/resources/scalac-plugin.xml similarity index 100% rename from scalac-scoverage-plugin/src/main/resources/scalac-plugin.xml rename to plugin/src/main/resources/scalac-plugin.xml diff --git a/scalac-scoverage-plugin/src/main/scala/scoverage/CoverageFilter.scala b/plugin/src/main/scala/scoverage/CoverageFilter.scala similarity index 100% rename from scalac-scoverage-plugin/src/main/scala/scoverage/CoverageFilter.scala rename to plugin/src/main/scala/scoverage/CoverageFilter.scala diff --git a/plugin/src/main/scala/scoverage/Location.scala b/plugin/src/main/scala/scoverage/Location.scala new file mode 100644 index 00000000..c796fe79 --- /dev/null +++ b/plugin/src/main/scala/scoverage/Location.scala @@ -0,0 +1,57 @@ +package scoverage + +import scala.tools.nsc.Global + +import scoverage.reporter.ClassType + +object Location { + + def fromGlobal(global: Global): global.Tree => Option[reporter.Location] = { + tree => + def packageName(s: global.Symbol): String = { + s.enclosingPackage.fullName + } + + def className(s: global.Symbol): String = { + // anon functions are enclosed in proper classes. + if (s.enclClass.isAnonymousFunction || s.enclClass.isAnonymousClass) + className(s.owner) + else s.enclClass.nameString + } + + def classType(s: global.Symbol): ClassType = { + if (s.enclClass.isTrait) ClassType.Trait + else if (s.enclClass.isModuleOrModuleClass) ClassType.Object + else ClassType.Class + } + + def fullClassName(s: global.Symbol): String = { + // anon functions are enclosed in proper classes. + if (s.enclClass.isAnonymousFunction || s.enclClass.isAnonymousClass) + fullClassName(s.owner) + else s.enclClass.fullNameString + } + + def enclosingMethod(s: global.Symbol): String = { + // check if we are in a proper method and return that, otherwise traverse up + if (s.enclClass.isAnonymousFunction) enclosingMethod(s.owner) + else if (s.enclMethod.isPrimaryConstructor) "" + else Option(s.enclMethod.nameString).getOrElse("") + } + + def sourcePath(symbol: global.Symbol): String = { + Option(symbol.sourceFile).map(_.canonicalPath).getOrElse("") + } + + Option(tree.symbol) map { symbol => + reporter.Location( + packageName(symbol), + className(symbol), + fullClassName(symbol), + classType(symbol), + enclosingMethod(symbol), + sourcePath(symbol) + ) + } + } +} diff --git a/scalac-scoverage-plugin/src/main/scala/scoverage/ScoverageOptions.scala b/plugin/src/main/scala/scoverage/ScoverageOptions.scala similarity index 100% rename from scalac-scoverage-plugin/src/main/scala/scoverage/ScoverageOptions.scala rename to plugin/src/main/scala/scoverage/ScoverageOptions.scala diff --git a/scalac-scoverage-plugin/src/main/scala/scoverage/ScoveragePlugin.scala b/plugin/src/main/scala/scoverage/ScoveragePlugin.scala similarity index 98% rename from scalac-scoverage-plugin/src/main/scala/scoverage/ScoveragePlugin.scala rename to plugin/src/main/scala/scoverage/ScoveragePlugin.scala index 996e2312..eea15a18 100644 --- a/scalac-scoverage-plugin/src/main/scala/scoverage/ScoveragePlugin.scala +++ b/plugin/src/main/scala/scoverage/ScoveragePlugin.scala @@ -11,6 +11,12 @@ import scala.tools.nsc.plugins.PluginComponent import scala.tools.nsc.transform.Transform import scala.tools.nsc.transform.TypingTransformers +import scoverage.reporter.Coverage +import scoverage.reporter.IOUtils +import scoverage.reporter.Serializer +import scoverage.reporter.Statement +import scoverage.reporter.{Location => LocationThatNeedsANewName} + /** @author Stephen Samuel */ class ScoveragePlugin(val global: Global) extends Plugin { @@ -129,11 +135,11 @@ class ScoverageInstrumentationComponent( Serializer.serialize( coverage, - Serializer.coverageFile(options.dataDir), + IOUtils.coverageFile(options.dataDir), new File(options.sourceRoot) ) reporter.echo( - s"Wrote instrumentation file [${Serializer.coverageFile(options.dataDir)}]" + s"Wrote instrumentation file [${IOUtils.coverageFile(options.dataDir)}]" ) reporter.echo(s"Will write measurement data to [${options.dataDir}]") } @@ -148,7 +154,7 @@ class ScoverageInstrumentationComponent( import global._ // contains the location of the last node - var location: Location = _ + var location: LocationThatNeedsANewName = _ /** The 'start' of the position, if it is available, else -1 * We cannot use 'isDefined' to test whether pos.start will work, as some @@ -353,7 +359,7 @@ class ScoverageInstrumentationComponent( coverageFilter.isSymbolIncluded(symbol.fullNameString) def updateLocation(t: Tree): Unit = { - Location(global)(t) match { + Location.fromGlobal(global)(t) match { case Some(loc) => this.location = loc case _ => reporter.warning(t.pos, s"[warn] Cannot update location for $t") diff --git a/scalac-scoverage-plugin/src/test/scala-2.11+/scoverage/macrosupport/TesterMacro.scala b/plugin/src/test/scala-2.11+/scoverage/macrosupport/TesterMacro.scala similarity index 100% rename from scalac-scoverage-plugin/src/test/scala-2.11+/scoverage/macrosupport/TesterMacro.scala rename to plugin/src/test/scala-2.11+/scoverage/macrosupport/TesterMacro.scala diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/LocationCompiler.scala b/plugin/src/test/scala/scoverage/LocationCompiler.scala similarity index 87% rename from scalac-scoverage-plugin/src/test/scala/scoverage/LocationCompiler.scala rename to plugin/src/test/scala/scoverage/LocationCompiler.scala index 45803a4f..7c073767 100644 --- a/scalac-scoverage-plugin/src/test/scala/scoverage/LocationCompiler.scala +++ b/plugin/src/test/scala/scoverage/LocationCompiler.scala @@ -7,12 +7,15 @@ import scala.tools.nsc.plugins.PluginComponent import scala.tools.nsc.transform.Transform import scala.tools.nsc.transform.TypingTransformers +import scoverage.reporter.IOUtils +import scoverage.reporter.{Location => LocationThatNeedsABetterName} + class LocationCompiler( settings: scala.tools.nsc.Settings, reporter: scala.tools.nsc.reporters.Reporter ) extends scala.tools.nsc.Global(settings, reporter) { - val locations = List.newBuilder[(String, Location)] + val locations = List.newBuilder[(String, LocationThatNeedsABetterName)] private val locationSetter = new LocationSetter(this) def compile(code: String): Unit = { @@ -45,7 +48,7 @@ class LocationCompiler( extends TypingTransformer(unit) { override def transform(tree: global.Tree) = { - for (location <- Location(global)(tree)) { + for (location <- Location.fromGlobal(global)(tree)) { locations += (tree.getClass.getSimpleName -> location) } super.transform(tree) diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/LocationTest.scala b/plugin/src/test/scala/scoverage/LocationTest.scala similarity index 99% rename from scalac-scoverage-plugin/src/test/scala/scoverage/LocationTest.scala rename to plugin/src/test/scala/scoverage/LocationTest.scala index 409f44e7..e36abdd0 100644 --- a/scalac-scoverage-plugin/src/test/scala/scoverage/LocationTest.scala +++ b/plugin/src/test/scala/scoverage/LocationTest.scala @@ -1,6 +1,7 @@ package scoverage import munit.FunSuite +import scoverage.reporter.ClassType class LocationTest extends FunSuite { diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/MacroSupport.scala b/plugin/src/test/scala/scoverage/MacroSupport.scala similarity index 78% rename from scalac-scoverage-plugin/src/test/scala/scoverage/MacroSupport.scala rename to plugin/src/test/scala/scoverage/MacroSupport.scala index f79d7707..97f32a9c 100644 --- a/scalac-scoverage-plugin/src/test/scala/scoverage/MacroSupport.scala +++ b/plugin/src/test/scala/scoverage/MacroSupport.scala @@ -14,7 +14,7 @@ trait MacroSupport { val macroSupportDeps = Seq(testClasses) private def testClasses: File = new File( - s"./scalac-scoverage-plugin/target/scala-${ScoverageCompiler.ScalaVersion}/test-classes" + s"./plugin/target/scala-${ScoverageCompiler.ScalaVersion}/test-classes" ) } diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/PluginASTSupportTest.scala b/plugin/src/test/scala/scoverage/PluginASTSupportTest.scala similarity index 100% rename from scalac-scoverage-plugin/src/test/scala/scoverage/PluginASTSupportTest.scala rename to plugin/src/test/scala/scoverage/PluginASTSupportTest.scala diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/PluginCoverageScalaJsTest.scala b/plugin/src/test/scala/scoverage/PluginCoverageScalaJsTest.scala similarity index 100% rename from scalac-scoverage-plugin/src/test/scala/scoverage/PluginCoverageScalaJsTest.scala rename to plugin/src/test/scala/scoverage/PluginCoverageScalaJsTest.scala diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/PluginCoverageTest.scala b/plugin/src/test/scala/scoverage/PluginCoverageTest.scala similarity index 100% rename from scalac-scoverage-plugin/src/test/scala/scoverage/PluginCoverageTest.scala rename to plugin/src/test/scala/scoverage/PluginCoverageTest.scala diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/RegexCoverageFilterTest.scala b/plugin/src/test/scala/scoverage/RegexCoverageFilterTest.scala similarity index 100% rename from scalac-scoverage-plugin/src/test/scala/scoverage/RegexCoverageFilterTest.scala rename to plugin/src/test/scala/scoverage/RegexCoverageFilterTest.scala diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/ScoverageCompiler.scala b/plugin/src/test/scala/scoverage/ScoverageCompiler.scala similarity index 96% rename from scalac-scoverage-plugin/src/test/scala/scoverage/ScoverageCompiler.scala rename to plugin/src/test/scala/scoverage/ScoverageCompiler.scala index b83fcadb..e52e60c5 100644 --- a/scalac-scoverage-plugin/src/test/scala/scoverage/ScoverageCompiler.scala +++ b/plugin/src/test/scala/scoverage/ScoverageCompiler.scala @@ -11,6 +11,8 @@ import scala.tools.nsc.plugins.PluginComponent import scala.tools.nsc.transform.Transform import scala.tools.nsc.transform.TypingTransformers +import scoverage.reporter.IOUtils + object ScoverageCompiler { val ScalaVersion: String = scala.util.Properties.versionNumberString @@ -33,7 +35,7 @@ object ScoverageCompiler { s.classpath.value = classPath.mkString(File.pathSeparator) val path = - s"./scalac-scoverage-plugin/target/scala-$ScalaVersion/test-generated-classes" + s"./plugin/target/scala-$ScalaVersion/test-generated-classes" new File(path).mkdirs() s.outdir.value = path s @@ -56,7 +58,7 @@ object ScoverageCompiler { private def sbtCompileDir: File = { val dir = new File( - s"./scalac-scoverage-plugin/target/scala-$ScalaVersion/classes" + s"./plugin/target/scala-$ScalaVersion/classes" ) if (!dir.exists) throw new FileNotFoundException( @@ -66,7 +68,7 @@ object ScoverageCompiler { } private def runtimeClasses: File = new File( - s"./scalac-scoverage-runtime/jvm/target/scala-$ScalaVersion/classes" + s"./runtime/jvm/target/scala-$ScalaVersion/classes" ) private def findScalaJar(artifactId: String): File = diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/macrosupport/Tester.scala b/plugin/src/test/scala/scoverage/macrosupport/Tester.scala similarity index 100% rename from scalac-scoverage-plugin/src/test/scala/scoverage/macrosupport/Tester.scala rename to plugin/src/test/scala/scoverage/macrosupport/Tester.scala diff --git a/scalac-scoverage-plugin/src/main/resources/scoverage/index.html b/reporter/src/main/resources/scoverage/index.html similarity index 100% rename from scalac-scoverage-plugin/src/main/resources/scoverage/index.html rename to reporter/src/main/resources/scoverage/index.html diff --git a/scalac-scoverage-plugin/src/main/resources/scoverage/pure-min.css b/reporter/src/main/resources/scoverage/pure-min.css similarity index 100% rename from scalac-scoverage-plugin/src/main/resources/scoverage/pure-min.css rename to reporter/src/main/resources/scoverage/pure-min.css diff --git a/scalac-scoverage-plugin/src/main/scala/scoverage/report/BaseReportWriter.scala b/reporter/src/main/scala/reporter/BaseReportWriter.scala similarity index 98% rename from scalac-scoverage-plugin/src/main/scala/scoverage/report/BaseReportWriter.scala rename to reporter/src/main/scala/reporter/BaseReportWriter.scala index ebccb95f..6c89b2e4 100644 --- a/scalac-scoverage-plugin/src/main/scala/scoverage/report/BaseReportWriter.scala +++ b/reporter/src/main/scala/reporter/BaseReportWriter.scala @@ -1,4 +1,4 @@ -package scoverage.report +package scoverage.reporter import java.io.File diff --git a/reporter/src/main/scala/reporter/Builders.scala b/reporter/src/main/scala/reporter/Builders.scala new file mode 100644 index 00000000..394822b5 --- /dev/null +++ b/reporter/src/main/scala/reporter/Builders.scala @@ -0,0 +1,26 @@ +package scoverage.reporter + +trait MethodBuilders { + def statements: Iterable[Statement] + def methods: Seq[MeasuredMethod] = { + statements + .groupBy(stmt => + stmt.location.packageName + "/" + stmt.location.className + "/" + stmt.location.method + ) + .map(arg => MeasuredMethod(arg._1, arg._2)) + .toSeq + } + def methodCount = methods.size +} + +trait PackageBuilders { + def statements: Iterable[Statement] + def packageCount = packages.size + def packages: Seq[MeasuredPackage] = { + statements + .groupBy(_.location.packageName) + .map(arg => MeasuredPackage(arg._1, arg._2)) + .toSeq + .sortBy(_.name) + } +} diff --git a/scalac-scoverage-plugin/src/main/scala/scoverage/report/CoberturaXmlWriter.scala b/reporter/src/main/scala/reporter/CoberturaXmlWriter.scala similarity index 97% rename from scalac-scoverage-plugin/src/main/scala/scoverage/report/CoberturaXmlWriter.scala rename to reporter/src/main/scala/reporter/CoberturaXmlWriter.scala index f6f7d2d2..22587462 100644 --- a/scalac-scoverage-plugin/src/main/scala/scoverage/report/CoberturaXmlWriter.scala +++ b/reporter/src/main/scala/reporter/CoberturaXmlWriter.scala @@ -1,12 +1,11 @@ -package scoverage.report +package scoverage.reporter import java.io.File import scala.xml.Node import scala.xml.PrettyPrinter -import scoverage.DoubleFormat.twoFractionDigits -import scoverage._ +import scoverage.reporter.DoubleFormat.twoFractionDigits /** @author Stephen Samuel */ class CoberturaXmlWriter( diff --git a/scalac-scoverage-plugin/src/main/scala/scoverage/report/CodeGrid.scala b/reporter/src/main/scala/reporter/CodeGrid.scala similarity index 98% rename from scalac-scoverage-plugin/src/main/scala/scoverage/report/CodeGrid.scala rename to reporter/src/main/scala/reporter/CodeGrid.scala index 60300245..0d75b71e 100644 --- a/scalac-scoverage-plugin/src/main/scala/scoverage/report/CodeGrid.scala +++ b/reporter/src/main/scala/reporter/CodeGrid.scala @@ -1,10 +1,8 @@ -package scoverage.report +package scoverage.reporter import scala.io.Codec import scala.io.Source -import _root_.scoverage.MeasuredFile - /** @author Stephen Samuel */ class CodeGrid(mFile: MeasuredFile, sourceEncoding: Option[String]) { diff --git a/scalac-scoverage-plugin/src/main/scala/scoverage/Constants.scala b/reporter/src/main/scala/reporter/Constants.scala similarity index 86% rename from scalac-scoverage-plugin/src/main/scala/scoverage/Constants.scala rename to reporter/src/main/scala/reporter/Constants.scala index e1b1e57e..b5d70b2c 100644 --- a/scalac-scoverage-plugin/src/main/scala/scoverage/Constants.scala +++ b/reporter/src/main/scala/reporter/Constants.scala @@ -1,4 +1,4 @@ -package scoverage +package scoverage.reporter object Constants { // the file that contains the statement mappings @@ -10,4 +10,6 @@ object Constants { val DataDir = "scoverage-data" // the prefix the measurement files have val MeasurementsPrefix = "scoverage.measurements." + + val coverageDataFormatVersion = "3.0" } diff --git a/scalac-scoverage-plugin/src/main/scala/scoverage/report/CoverageAggregator.scala b/reporter/src/main/scala/reporter/CoverageAggregator.scala similarity index 88% rename from scalac-scoverage-plugin/src/main/scala/scoverage/report/CoverageAggregator.scala rename to reporter/src/main/scala/reporter/CoverageAggregator.scala index 27f9c564..67ca2b19 100644 --- a/scalac-scoverage-plugin/src/main/scala/scoverage/report/CoverageAggregator.scala +++ b/reporter/src/main/scala/reporter/CoverageAggregator.scala @@ -1,11 +1,7 @@ -package scoverage.report +package scoverage.reporter import java.io.File -import scoverage.Coverage -import scoverage.IOUtils -import scoverage.Serializer - object CoverageAggregator { // to be used by gradle-scoverage plugin @@ -30,7 +26,7 @@ object CoverageAggregator { var id = 0 val coverage = Coverage() dataDirs foreach { dataDir => - val coverageFile: File = Serializer.coverageFile(dataDir) + val coverageFile: File = IOUtils.coverageFile(dataDir) if (coverageFile.exists) { val subcoverage: Coverage = Serializer.deserialize(coverageFile, sourceRoot) diff --git a/reporter/src/main/scala/reporter/CoverageMetrics.scala b/reporter/src/main/scala/reporter/CoverageMetrics.scala new file mode 100644 index 00000000..63bb6fd5 --- /dev/null +++ b/reporter/src/main/scala/reporter/CoverageMetrics.scala @@ -0,0 +1,95 @@ +package scoverage.reporter + +import java.io.File + +import scoverage.reporter.DoubleFormat.twoFractionDigits + +trait CoverageMetrics { + def statements: Iterable[Statement] + def statementCount: Int = statements.size + + def ignoredStatements: Iterable[Statement] + def ignoredStatementCount: Int = ignoredStatements.size + + def invokedStatements: Iterable[Statement] = statements.filter(_.count > 0) + def invokedStatementCount = invokedStatements.size + def statementCoverage: Double = if (statementCount == 0) 1 + else invokedStatementCount / statementCount.toDouble + def statementCoveragePercent = statementCoverage * 100 + def statementCoverageFormatted: String = twoFractionDigits( + statementCoveragePercent + ) + def branches: Iterable[Statement] = statements.filter(_.branch) + def branchCount: Int = branches.size + def branchCoveragePercent = branchCoverage * 100 + def invokedBranches: Iterable[Statement] = branches.filter(_.count > 0) + def invokedBranchesCount = invokedBranches.size + + /** @see http://stackoverflow.com/questions/25184716/scoverage-ambiguous-measurement-from-branch-coverage + */ + def branchCoverage: Double = { + // if there are zero branches, then we have a single line of execution. + // in that case, if there is at least some coverage, we have covered the branch. + // if there is no coverage then we have not covered the branch + if (branchCount == 0) { + if (statementCoverage > 0) 1 + else 0 + } else { + invokedBranchesCount / branchCount.toDouble + } + } + def branchCoverageFormatted: String = twoFractionDigits(branchCoveragePercent) +} + +case class MeasuredMethod(name: String, statements: Iterable[Statement]) + extends CoverageMetrics { + override def ignoredStatements: Iterable[Statement] = Seq() +} + +case class MeasuredClass(fullClassName: String, statements: Iterable[Statement]) + extends CoverageMetrics + with MethodBuilders { + + def source: String = statements.head.source + def loc = statements.map(_.line).max + + /** The class name for display is the FQN minus the package, + * for example "com.a.Foo.Bar.Baz" should display as "Foo.Bar.Baz" + * and "com.a.Foo" should display as "Foo". + * + * This is used in the class lists in the package and overview pages. + */ + def displayClassName = statements.headOption + .map(_.location) + .map { location => + location.fullClassName.stripPrefix(location.packageName + ".") + } + .getOrElse(fullClassName) + + override def ignoredStatements: Iterable[Statement] = Seq() +} + +case class MeasuredPackage(name: String, statements: Iterable[Statement]) + extends CoverageMetrics + with ClassCoverage + with ClassBuilders + with FileBuilders { + override def ignoredStatements: Iterable[Statement] = Seq() +} + +case class MeasuredFile(source: String, statements: Iterable[Statement]) + extends CoverageMetrics + with ClassCoverage + with ClassBuilders { + def filename = new File(source).getName + def loc = statements.map(_.line).max + + override def ignoredStatements: Iterable[Statement] = Seq() +} + +trait ClassCoverage { + this: ClassBuilders => + val statements: Iterable[Statement] + def invokedClasses: Int = classes.count(_.statements.count(_.count > 0) > 0) + def classCoverage: Double = invokedClasses / classes.size.toDouble +} diff --git a/scalac-scoverage-plugin/src/main/scala/scoverage/DoubleFormat.scala b/reporter/src/main/scala/reporter/DoubleFormat.scala similarity index 94% rename from scalac-scoverage-plugin/src/main/scala/scoverage/DoubleFormat.scala rename to reporter/src/main/scala/reporter/DoubleFormat.scala index e470672a..6059bcae 100644 --- a/scalac-scoverage-plugin/src/main/scala/scoverage/DoubleFormat.scala +++ b/reporter/src/main/scala/reporter/DoubleFormat.scala @@ -1,4 +1,4 @@ -package scoverage +package scoverage.reporter import java.text.DecimalFormat import java.text.DecimalFormatSymbols diff --git a/scalac-scoverage-plugin/src/main/scala/scoverage/IOUtils.scala b/reporter/src/main/scala/reporter/IOUtils.scala similarity index 92% rename from scalac-scoverage-plugin/src/main/scala/scoverage/IOUtils.scala rename to reporter/src/main/scala/reporter/IOUtils.scala index 5ecfee29..2e2737aa 100644 --- a/scalac-scoverage-plugin/src/main/scala/scoverage/IOUtils.scala +++ b/reporter/src/main/scala/reporter/IOUtils.scala @@ -1,4 +1,4 @@ -package scoverage +package scoverage.reporter import java.io._ @@ -10,6 +10,11 @@ import scala.io.Source /** @author Stephen Samuel */ object IOUtils { + // TODO Should any of this stuff actually stay in here. probably not + def coverageFile(dataDir: File): File = coverageFile(dataDir.getAbsolutePath) + def coverageFile(dataDir: String): File = + new File(dataDir, Constants.CoverageFileName) + def getTempDirectory: File = new File(getTempPath) def getTempPath: String = System.getProperty("java.io.tmpdir") diff --git a/reporter/src/main/scala/reporter/Location.scala b/reporter/src/main/scala/reporter/Location.scala new file mode 100644 index 00000000..8168cb32 --- /dev/null +++ b/reporter/src/main/scala/reporter/Location.scala @@ -0,0 +1,14 @@ +package scoverage.reporter + +/** @param packageName the name of the enclosing package + * @param className the name of the closest enclosing class + * @param fullClassName the fully qualified name of the closest enclosing class + */ +case class Location( + packageName: String, + className: String, + fullClassName: String, + classType: ClassType, + method: String, + sourcePath: String +) diff --git a/scalac-scoverage-plugin/src/main/scala/scoverage/report/ScoverageHtmlWriter.scala b/reporter/src/main/scala/reporter/ScoverageHtmlWriter.scala similarity index 99% rename from scalac-scoverage-plugin/src/main/scala/scoverage/report/ScoverageHtmlWriter.scala rename to reporter/src/main/scala/reporter/ScoverageHtmlWriter.scala index b1960433..e015dada 100644 --- a/scalac-scoverage-plugin/src/main/scala/scoverage/report/ScoverageHtmlWriter.scala +++ b/reporter/src/main/scala/reporter/ScoverageHtmlWriter.scala @@ -1,12 +1,10 @@ -package scoverage.report +package scoverage.reporter import java.io.File import java.util.Date import scala.xml.Node -import scoverage._ - /** @author Stephen Samuel */ class ScoverageHtmlWriter( sourceDirectories: Seq[File], diff --git a/scalac-scoverage-plugin/src/main/scala/scoverage/report/ScoverageXmlWriter.scala b/reporter/src/main/scala/reporter/ScoverageXmlWriter.scala similarity index 99% rename from scalac-scoverage-plugin/src/main/scala/scoverage/report/ScoverageXmlWriter.scala rename to reporter/src/main/scala/reporter/ScoverageXmlWriter.scala index 9f4866c8..741182cf 100644 --- a/scalac-scoverage-plugin/src/main/scala/scoverage/report/ScoverageXmlWriter.scala +++ b/reporter/src/main/scala/reporter/ScoverageXmlWriter.scala @@ -1,12 +1,10 @@ -package scoverage.report +package scoverage.reporter import java.io.File import scala.xml.Node import scala.xml.PrettyPrinter -import scoverage._ - /** @author Stephen Samuel */ class ScoverageXmlWriter( sourceDirectories: Seq[File], diff --git a/scalac-scoverage-plugin/src/main/scala/scoverage/Serializer.scala b/reporter/src/main/scala/reporter/Serializer.scala similarity index 99% rename from scalac-scoverage-plugin/src/main/scala/scoverage/Serializer.scala rename to reporter/src/main/scala/reporter/Serializer.scala index b292f694..b92710b6 100644 --- a/scalac-scoverage-plugin/src/main/scala/scoverage/Serializer.scala +++ b/reporter/src/main/scala/reporter/Serializer.scala @@ -1,4 +1,4 @@ -package scoverage +package scoverage.reporter import java.io.BufferedWriter import java.io.File diff --git a/reporter/src/main/scala/reporter/Statement.scala b/reporter/src/main/scala/reporter/Statement.scala new file mode 100644 index 00000000..b751e87b --- /dev/null +++ b/reporter/src/main/scala/reporter/Statement.scala @@ -0,0 +1,25 @@ +package scoverage.reporter + +import scala.collection.mutable + +case class Statement( + location: Location, + id: Int, + start: Int, + end: Int, + line: Int, + desc: String, + symbolName: String, + treeName: String, + branch: Boolean, + var count: Int = 0, + ignored: Boolean = false, + tests: mutable.Set[String] = mutable.Set[String]() +) extends java.io.Serializable { + def source = location.sourcePath + def invoked(test: String): Unit = { + count = count + 1 + if (test != "") tests += test + } + def isInvoked = count > 0 +} diff --git a/scalac-scoverage-plugin/src/main/scala/scoverage/report/status.scala b/reporter/src/main/scala/reporter/StatementStatus.scala similarity index 87% rename from scalac-scoverage-plugin/src/main/scala/scoverage/report/status.scala rename to reporter/src/main/scala/reporter/StatementStatus.scala index b8b82387..b4284f39 100644 --- a/scalac-scoverage-plugin/src/main/scala/scoverage/report/status.scala +++ b/reporter/src/main/scala/reporter/StatementStatus.scala @@ -1,4 +1,4 @@ -package scoverage.report +package scoverage.reporter /** @author Stephen Samuel */ sealed trait StatementStatus diff --git a/scalac-scoverage-plugin/src/main/scala/scoverage/report/StatementWriter.scala b/reporter/src/main/scala/reporter/StatementWriter.scala similarity index 94% rename from scalac-scoverage-plugin/src/main/scala/scoverage/report/StatementWriter.scala rename to reporter/src/main/scala/reporter/StatementWriter.scala index 4c0f0ddd..a7d90eaa 100644 --- a/scalac-scoverage-plugin/src/main/scala/scoverage/report/StatementWriter.scala +++ b/reporter/src/main/scala/reporter/StatementWriter.scala @@ -1,9 +1,7 @@ -package scoverage.report +package scoverage.reporter import scala.xml.Node -import _root_.scoverage.MeasuredFile - /** @author Stephen Samuel */ class StatementWriter(mFile: MeasuredFile) { diff --git a/reporter/src/main/scala/reporter/coverage.scala b/reporter/src/main/scala/reporter/coverage.scala new file mode 100644 index 00000000..7c59c545 --- /dev/null +++ b/reporter/src/main/scala/reporter/coverage.scala @@ -0,0 +1,91 @@ +package scoverage.reporter + +import scala.collection.mutable + +import scoverage.reporter.DoubleFormat.twoFractionDigits + +/** @author Stephen Samuel + */ +case class Coverage() + extends CoverageMetrics + with MethodBuilders + with java.io.Serializable + with ClassBuilders + with PackageBuilders + with FileBuilders { + + private val statementsById = mutable.Map[Int, Statement]() + override def statements = statementsById.values + def add(stmt: Statement): Unit = statementsById.put(stmt.id, stmt) + + private val ignoredStatementsById = mutable.Map[Int, Statement]() + override def ignoredStatements = ignoredStatementsById.values + def addIgnoredStatement(stmt: Statement): Unit = + ignoredStatementsById.put(stmt.id, stmt) + + def avgClassesPerPackage = classCount / packageCount.toDouble + def avgClassesPerPackageFormatted: String = twoFractionDigits( + avgClassesPerPackage + ) + + def avgMethodsPerClass = methodCount / classCount.toDouble + def avgMethodsPerClassFormatted: String = twoFractionDigits( + avgMethodsPerClass + ) + + def loc = files.map(_.loc).sum + def linesPerFile = loc / fileCount.toDouble + def linesPerFileFormatted: String = twoFractionDigits(linesPerFile) + + // returns the classes by least coverage + def risks(limit: Int) = classes.toSeq + .sortBy(_.statementCount) + .reverse + .sortBy(_.statementCoverage) + .take(limit) + + def apply(ids: Iterable[(Int, String)]): Unit = ids foreach invoked + def invoked(id: (Int, String)): Unit = + statementsById.get(id._1).foreach(_.invoked(id._2)) +} + +trait ClassBuilders { + def statements: Iterable[Statement] + def classes = statements + .groupBy(_.location.fullClassName) + .map(arg => MeasuredClass(arg._1, arg._2)) + def classCount: Int = classes.size +} + +trait FileBuilders { + def statements: Iterable[Statement] + def files: Iterable[MeasuredFile] = + statements.groupBy(_.source).map(arg => MeasuredFile(arg._1, arg._2)) + def fileCount: Int = files.size +} + +sealed trait ClassType +object ClassType { + case object Object extends ClassType + case object Class extends ClassType + case object Trait extends ClassType + def fromString(str: String): ClassType = { + str.toLowerCase match { + case "object" => Object + case "trait" => Trait + case _ => Class + } + } +} + +case class ClassRef(name: String) { + lazy val simpleName = name.split(".").last + lazy val getPackage = name.split(".").dropRight(1).mkString(".") +} + +object ClassRef { + def fromFilepath(path: String) = ClassRef(path.replace('/', '.')) + def apply(_package: String, className: String): ClassRef = ClassRef( + _package.replace('/', '.') + "." + className + ) +} diff --git a/scalac-scoverage-plugin/src/test/resources/scoverage/cobertura.sample.xml b/reporter/src/test/resources/scoverage/reporter/cobertura.sample.xml similarity index 100% rename from scalac-scoverage-plugin/src/test/resources/scoverage/cobertura.sample.xml rename to reporter/src/test/resources/scoverage/reporter/cobertura.sample.xml diff --git a/scalac-scoverage-plugin/src/test/resources/scoverage/coverage-04.dtd b/reporter/src/test/resources/scoverage/reporter/coverage-04.dtd similarity index 100% rename from scalac-scoverage-plugin/src/test/resources/scoverage/coverage-04.dtd rename to reporter/src/test/resources/scoverage/reporter/coverage-04.dtd diff --git a/scalac-scoverage-plugin/src/test/resources/scoverage/forHtmlWriter/src/main/scala/ClassContainingHtml.scala b/reporter/src/test/resources/scoverage/reporter/forHtmlWriter/src/main/scala/ClassContainingHtml.scala similarity index 100% rename from scalac-scoverage-plugin/src/test/resources/scoverage/forHtmlWriter/src/main/scala/ClassContainingHtml.scala rename to reporter/src/test/resources/scoverage/reporter/forHtmlWriter/src/main/scala/ClassContainingHtml.scala diff --git a/scalac-scoverage-plugin/src/test/resources/scoverage/forHtmlWriter/src/main/scala/ClassInMainDir.scala b/reporter/src/test/resources/scoverage/reporter/forHtmlWriter/src/main/scala/ClassInMainDir.scala similarity index 100% rename from scalac-scoverage-plugin/src/test/resources/scoverage/forHtmlWriter/src/main/scala/ClassInMainDir.scala rename to reporter/src/test/resources/scoverage/reporter/forHtmlWriter/src/main/scala/ClassInMainDir.scala diff --git a/scalac-scoverage-plugin/src/test/resources/scoverage/forHtmlWriter/src/main/scala/subdir/ClassInSubDir.scala b/reporter/src/test/resources/scoverage/reporter/forHtmlWriter/src/main/scala/subdir/ClassInSubDir.scala similarity index 100% rename from scalac-scoverage-plugin/src/test/resources/scoverage/forHtmlWriter/src/main/scala/subdir/ClassInSubDir.scala rename to reporter/src/test/resources/scoverage/reporter/forHtmlWriter/src/main/scala/subdir/ClassInSubDir.scala diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/CoberturaXmlWriterTest.scala b/reporter/src/test/scala/scoverage/reporter/CoberturaXmlWriterTest.scala similarity index 98% rename from scalac-scoverage-plugin/src/test/scala/scoverage/CoberturaXmlWriterTest.scala rename to reporter/src/test/scala/scoverage/reporter/CoberturaXmlWriterTest.scala index 0f6cc460..3dac5333 100644 --- a/scalac-scoverage-plugin/src/test/scala/scoverage/CoberturaXmlWriterTest.scala +++ b/reporter/src/test/scala/scoverage/reporter/CoberturaXmlWriterTest.scala @@ -1,4 +1,4 @@ -package scoverage +package scoverage.reporter import java.io.File import java.util.UUID @@ -12,7 +12,6 @@ import scala.xml.factory.XMLLoader import munit.FunSuite import org.xml.sax.ErrorHandler import org.xml.sax.SAXParseException -import scoverage.report.CoberturaXmlWriter /** @author Stephen Samuel */ class CoberturaXmlWriterTest extends FunSuite { @@ -35,7 +34,7 @@ class CoberturaXmlWriterTest extends FunSuite { val dir = tempDir() - val coverage = scoverage.Coverage() + val coverage = scoverage.reporter.Coverage() coverage .add( Statement( diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/CoverageAggregatorTest.scala b/reporter/src/test/scala/scoverage/reporter/CoverageAggregatorTest.scala similarity index 97% rename from scalac-scoverage-plugin/src/test/scala/scoverage/CoverageAggregatorTest.scala rename to reporter/src/test/scala/scoverage/reporter/CoverageAggregatorTest.scala index c6db910e..9508286e 100644 --- a/scalac-scoverage-plugin/src/test/scala/scoverage/CoverageAggregatorTest.scala +++ b/reporter/src/test/scala/scoverage/reporter/CoverageAggregatorTest.scala @@ -1,11 +1,10 @@ -package scoverage +package scoverage.reporter import java.io.File import java.io.FileWriter import java.util.UUID import munit.FunSuite -import scoverage.report.CoverageAggregator class CoverageAggregatorTest extends FunSuite { diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/CoverageMetricsTest.scala b/reporter/src/test/scala/scoverage/reporter/CoverageMetricsTest.scala similarity index 97% rename from scalac-scoverage-plugin/src/test/scala/scoverage/CoverageMetricsTest.scala rename to reporter/src/test/scala/scoverage/reporter/CoverageMetricsTest.scala index 801d9d53..9a1403af 100644 --- a/scalac-scoverage-plugin/src/test/scala/scoverage/CoverageMetricsTest.scala +++ b/reporter/src/test/scala/scoverage/reporter/CoverageMetricsTest.scala @@ -1,4 +1,4 @@ -package scoverage +package scoverage.reporter import munit.FunSuite diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/CoverageTest.scala b/reporter/src/test/scala/scoverage/reporter/CoverageTest.scala similarity index 98% rename from scalac-scoverage-plugin/src/test/scala/scoverage/CoverageTest.scala rename to reporter/src/test/scala/scoverage/reporter/CoverageTest.scala index b469fd25..59cea490 100644 --- a/scalac-scoverage-plugin/src/test/scala/scoverage/CoverageTest.scala +++ b/reporter/src/test/scala/scoverage/reporter/CoverageTest.scala @@ -1,4 +1,4 @@ -package scoverage +package scoverage.reporter import munit.FunSuite diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/IOUtilsTest.scala b/reporter/src/test/scala/scoverage/reporter/IOUtilsTest.scala similarity index 98% rename from scalac-scoverage-plugin/src/test/scala/scoverage/IOUtilsTest.scala rename to reporter/src/test/scala/scoverage/reporter/IOUtilsTest.scala index 538d6d63..8fd018d0 100644 --- a/scalac-scoverage-plugin/src/test/scala/scoverage/IOUtilsTest.scala +++ b/reporter/src/test/scala/scoverage/reporter/IOUtilsTest.scala @@ -1,4 +1,4 @@ -package scoverage +package scoverage.reporter import java.io.File import java.io.FileWriter diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/ScoverageHtmlWriterTest.scala b/reporter/src/test/scala/scoverage/reporter/ScoverageHtmlWriterTest.scala similarity index 98% rename from scalac-scoverage-plugin/src/test/scala/scoverage/ScoverageHtmlWriterTest.scala rename to reporter/src/test/scala/scoverage/reporter/ScoverageHtmlWriterTest.scala index 33240611..5443f61d 100644 --- a/scalac-scoverage-plugin/src/test/scala/scoverage/ScoverageHtmlWriterTest.scala +++ b/reporter/src/test/scala/scoverage/reporter/ScoverageHtmlWriterTest.scala @@ -1,4 +1,4 @@ -package scoverage +package scoverage.reporter import java.io._ import java.util.UUID @@ -7,7 +7,6 @@ import scala.io.Source import scala.xml.XML import munit.FunSuite -import scoverage.report.ScoverageHtmlWriter class ScoverageHtmlWriterTest extends FunSuite { diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/SerializerTest.scala b/reporter/src/test/scala/scoverage/reporter/SerializerTest.scala similarity index 99% rename from scalac-scoverage-plugin/src/test/scala/scoverage/SerializerTest.scala rename to reporter/src/test/scala/scoverage/reporter/SerializerTest.scala index dea4f21e..62f8f29c 100644 --- a/scalac-scoverage-plugin/src/test/scala/scoverage/SerializerTest.scala +++ b/reporter/src/test/scala/scoverage/reporter/SerializerTest.scala @@ -1,4 +1,4 @@ -package scoverage +package scoverage.reporter import java.io.File import java.io.StringWriter diff --git a/scalac-scoverage-runtime/js/src/main/scala/scalajssupport/File.scala b/runtime/js/src/main/scala/scalajssupport/File.scala similarity index 100% rename from scalac-scoverage-runtime/js/src/main/scala/scalajssupport/File.scala rename to runtime/js/src/main/scala/scalajssupport/File.scala diff --git a/scalac-scoverage-runtime/js/src/main/scala/scalajssupport/FileWriter.scala b/runtime/js/src/main/scala/scalajssupport/FileWriter.scala similarity index 100% rename from scalac-scoverage-runtime/js/src/main/scala/scalajssupport/FileWriter.scala rename to runtime/js/src/main/scala/scalajssupport/FileWriter.scala diff --git a/scalac-scoverage-runtime/js/src/main/scala/scalajssupport/JsFile.scala b/runtime/js/src/main/scala/scalajssupport/JsFile.scala similarity index 100% rename from scalac-scoverage-runtime/js/src/main/scala/scalajssupport/JsFile.scala rename to runtime/js/src/main/scala/scalajssupport/JsFile.scala diff --git a/scalac-scoverage-runtime/js/src/main/scala/scalajssupport/NodeFile.scala b/runtime/js/src/main/scala/scalajssupport/NodeFile.scala similarity index 100% rename from scalac-scoverage-runtime/js/src/main/scala/scalajssupport/NodeFile.scala rename to runtime/js/src/main/scala/scalajssupport/NodeFile.scala diff --git a/scalac-scoverage-runtime/js/src/main/scala/scalajssupport/PhantomFile.scala b/runtime/js/src/main/scala/scalajssupport/PhantomFile.scala similarity index 100% rename from scalac-scoverage-runtime/js/src/main/scala/scalajssupport/PhantomFile.scala rename to runtime/js/src/main/scala/scalajssupport/PhantomFile.scala diff --git a/scalac-scoverage-runtime/js/src/main/scala/scalajssupport/RhinoFile.scala b/runtime/js/src/main/scala/scalajssupport/RhinoFile.scala similarity index 100% rename from scalac-scoverage-runtime/js/src/main/scala/scalajssupport/RhinoFile.scala rename to runtime/js/src/main/scala/scalajssupport/RhinoFile.scala diff --git a/scalac-scoverage-runtime/js/src/main/scala/scalajssupport/Source.scala b/runtime/js/src/main/scala/scalajssupport/Source.scala similarity index 100% rename from scalac-scoverage-runtime/js/src/main/scala/scalajssupport/Source.scala rename to runtime/js/src/main/scala/scalajssupport/Source.scala diff --git a/scalac-scoverage-runtime/js/src/main/scala/scoverage/Platform.scala b/runtime/js/src/main/scala/scoverage/Platform.scala similarity index 100% rename from scalac-scoverage-runtime/js/src/main/scala/scoverage/Platform.scala rename to runtime/js/src/main/scala/scoverage/Platform.scala diff --git a/scalac-scoverage-runtime/jvm/src/main/scala/scoverage/Platform.scala b/runtime/jvm/src/main/scala/scoverage/Platform.scala similarity index 100% rename from scalac-scoverage-runtime/jvm/src/main/scala/scoverage/Platform.scala rename to runtime/jvm/src/main/scala/scoverage/Platform.scala diff --git a/scalac-scoverage-runtime/jvm/src/test/scala/scoverage/InvokerConcurrencyTest.scala b/runtime/jvm/src/test/scala/scoverage/InvokerConcurrencyTest.scala similarity index 100% rename from scalac-scoverage-runtime/jvm/src/test/scala/scoverage/InvokerConcurrencyTest.scala rename to runtime/jvm/src/test/scala/scoverage/InvokerConcurrencyTest.scala diff --git a/scalac-scoverage-runtime/shared/src/main/scala/scoverage/Invoker.scala b/runtime/shared/src/main/scala/scoverage/Invoker.scala similarity index 100% rename from scalac-scoverage-runtime/shared/src/main/scala/scoverage/Invoker.scala rename to runtime/shared/src/main/scala/scoverage/Invoker.scala diff --git a/scalac-scoverage-runtime/shared/src/test/scala/scoverage/InvokerMultiModuleTest.scala b/runtime/shared/src/test/scala/scoverage/InvokerMultiModuleTest.scala similarity index 100% rename from scalac-scoverage-runtime/shared/src/test/scala/scoverage/InvokerMultiModuleTest.scala rename to runtime/shared/src/test/scala/scoverage/InvokerMultiModuleTest.scala diff --git a/scalac-scoverage-plugin/src/main/scala/scoverage/Location.scala b/scalac-scoverage-plugin/src/main/scala/scoverage/Location.scala deleted file mode 100644 index 94a6fcef..00000000 --- a/scalac-scoverage-plugin/src/main/scala/scoverage/Location.scala +++ /dev/null @@ -1,67 +0,0 @@ -package scoverage - -import scala.tools.nsc.Global - -/** @param packageName the name of the enclosing package - * @param className the name of the closest enclosing class - * @param fullClassName the fully qualified name of the closest enclosing class - */ -case class Location( - packageName: String, - className: String, - fullClassName: String, - classType: ClassType, - method: String, - sourcePath: String -) extends java.io.Serializable - -object Location { - - def apply(global: Global): global.Tree => Option[Location] = { tree => - def packageName(s: global.Symbol): String = { - s.enclosingPackage.fullName - } - - def className(s: global.Symbol): String = { - // anon functions are enclosed in proper classes. - if (s.enclClass.isAnonymousFunction || s.enclClass.isAnonymousClass) - className(s.owner) - else s.enclClass.nameString - } - - def classType(s: global.Symbol): ClassType = { - if (s.enclClass.isTrait) ClassType.Trait - else if (s.enclClass.isModuleOrModuleClass) ClassType.Object - else ClassType.Class - } - - def fullClassName(s: global.Symbol): String = { - // anon functions are enclosed in proper classes. - if (s.enclClass.isAnonymousFunction || s.enclClass.isAnonymousClass) - fullClassName(s.owner) - else s.enclClass.fullNameString - } - - def enclosingMethod(s: global.Symbol): String = { - // check if we are in a proper method and return that, otherwise traverse up - if (s.enclClass.isAnonymousFunction) enclosingMethod(s.owner) - else if (s.enclMethod.isPrimaryConstructor) "" - else Option(s.enclMethod.nameString).getOrElse("") - } - - def sourcePath(symbol: global.Symbol): String = { - Option(symbol.sourceFile).map(_.canonicalPath).getOrElse("") - } - - Option(tree.symbol) map { symbol => - Location( - packageName(symbol), - className(symbol), - fullClassName(symbol), - classType(symbol), - enclosingMethod(symbol), - sourcePath(symbol) - ) - } - } -} diff --git a/scalac-scoverage-plugin/src/main/scala/scoverage/coverage.scala b/scalac-scoverage-plugin/src/main/scala/scoverage/coverage.scala deleted file mode 100644 index aaad4cb2..00000000 --- a/scalac-scoverage-plugin/src/main/scala/scoverage/coverage.scala +++ /dev/null @@ -1,230 +0,0 @@ -package scoverage - -import java.io.File - -import scala.collection.mutable - -import scoverage.DoubleFormat.twoFractionDigits - -/** @author Stephen Samuel - */ -case class Coverage() - extends CoverageMetrics - with MethodBuilders - with java.io.Serializable - with ClassBuilders - with PackageBuilders - with FileBuilders { - - private val statementsById = mutable.Map[Int, Statement]() - override def statements = statementsById.values - def add(stmt: Statement): Unit = statementsById.put(stmt.id, stmt) - - private val ignoredStatementsById = mutable.Map[Int, Statement]() - override def ignoredStatements = ignoredStatementsById.values - def addIgnoredStatement(stmt: Statement): Unit = - ignoredStatementsById.put(stmt.id, stmt) - - def avgClassesPerPackage = classCount / packageCount.toDouble - def avgClassesPerPackageFormatted: String = twoFractionDigits( - avgClassesPerPackage - ) - - def avgMethodsPerClass = methodCount / classCount.toDouble - def avgMethodsPerClassFormatted: String = twoFractionDigits( - avgMethodsPerClass - ) - - def loc = files.map(_.loc).sum - def linesPerFile = loc / fileCount.toDouble - def linesPerFileFormatted: String = twoFractionDigits(linesPerFile) - - // returns the classes by least coverage - def risks(limit: Int) = classes.toSeq - .sortBy(_.statementCount) - .reverse - .sortBy(_.statementCoverage) - .take(limit) - - def apply(ids: Iterable[(Int, String)]): Unit = ids foreach invoked - def invoked(id: (Int, String)): Unit = - statementsById.get(id._1).foreach(_.invoked(id._2)) -} - -trait MethodBuilders { - def statements: Iterable[Statement] - def methods: Seq[MeasuredMethod] = { - statements - .groupBy(stmt => - stmt.location.packageName + "/" + stmt.location.className + "/" + stmt.location.method - ) - .map(arg => MeasuredMethod(arg._1, arg._2)) - .toSeq - } - def methodCount = methods.size -} - -trait PackageBuilders { - def statements: Iterable[Statement] - def packageCount = packages.size - def packages: Seq[MeasuredPackage] = { - statements - .groupBy(_.location.packageName) - .map(arg => MeasuredPackage(arg._1, arg._2)) - .toSeq - .sortBy(_.name) - } -} - -trait ClassBuilders { - def statements: Iterable[Statement] - def classes = statements - .groupBy(_.location.fullClassName) - .map(arg => MeasuredClass(arg._1, arg._2)) - def classCount: Int = classes.size -} - -trait FileBuilders { - def statements: Iterable[Statement] - def files: Iterable[MeasuredFile] = - statements.groupBy(_.source).map(arg => MeasuredFile(arg._1, arg._2)) - def fileCount: Int = files.size -} - -case class MeasuredMethod(name: String, statements: Iterable[Statement]) - extends CoverageMetrics { - override def ignoredStatements: Iterable[Statement] = Seq() -} - -case class MeasuredClass(fullClassName: String, statements: Iterable[Statement]) - extends CoverageMetrics - with MethodBuilders { - - def source: String = statements.head.source - def loc = statements.map(_.line).max - - /** The class name for display is the FQN minus the package, - * for example "com.a.Foo.Bar.Baz" should display as "Foo.Bar.Baz" - * and "com.a.Foo" should display as "Foo". - * - * This is used in the class lists in the package and overview pages. - */ - def displayClassName = statements.headOption - .map(_.location) - .map { location => - location.fullClassName.stripPrefix(location.packageName + ".") - } - .getOrElse(fullClassName) - - override def ignoredStatements: Iterable[Statement] = Seq() -} - -case class MeasuredPackage(name: String, statements: Iterable[Statement]) - extends CoverageMetrics - with ClassCoverage - with ClassBuilders - with FileBuilders { - override def ignoredStatements: Iterable[Statement] = Seq() -} - -case class MeasuredFile(source: String, statements: Iterable[Statement]) - extends CoverageMetrics - with ClassCoverage - with ClassBuilders { - def filename = new File(source).getName - def loc = statements.map(_.line).max - - override def ignoredStatements: Iterable[Statement] = Seq() -} - -case class Statement( - location: Location, - id: Int, - start: Int, - end: Int, - line: Int, - desc: String, - symbolName: String, - treeName: String, - branch: Boolean, - var count: Int = 0, - ignored: Boolean = false, - tests: mutable.Set[String] = mutable.Set[String]() -) extends java.io.Serializable { - def source = location.sourcePath - def invoked(test: String): Unit = { - count = count + 1 - if (test != "") tests += test - } - def isInvoked = count > 0 -} - -sealed trait ClassType -object ClassType { - case object Object extends ClassType - case object Class extends ClassType - case object Trait extends ClassType - def fromString(str: String): ClassType = { - str.toLowerCase match { - case "object" => Object - case "trait" => Trait - case _ => Class - } - } -} - -case class ClassRef(name: String) { - lazy val simpleName = name.split(".").last - lazy val getPackage = name.split(".").dropRight(1).mkString(".") -} - -object ClassRef { - def fromFilepath(path: String) = ClassRef(path.replace('/', '.')) - def apply(_package: String, className: String): ClassRef = ClassRef( - _package.replace('/', '.') + "." + className - ) -} - -trait CoverageMetrics { - def statements: Iterable[Statement] - def statementCount: Int = statements.size - - def ignoredStatements: Iterable[Statement] - def ignoredStatementCount: Int = ignoredStatements.size - - def invokedStatements: Iterable[Statement] = statements.filter(_.count > 0) - def invokedStatementCount = invokedStatements.size - def statementCoverage: Double = if (statementCount == 0) 1 - else invokedStatementCount / statementCount.toDouble - def statementCoveragePercent = statementCoverage * 100 - def statementCoverageFormatted: String = twoFractionDigits( - statementCoveragePercent - ) - def branches: Iterable[Statement] = statements.filter(_.branch) - def branchCount: Int = branches.size - def branchCoveragePercent = branchCoverage * 100 - def invokedBranches: Iterable[Statement] = branches.filter(_.count > 0) - def invokedBranchesCount = invokedBranches.size - - /** @see http://stackoverflow.com/questions/25184716/scoverage-ambiguous-measurement-from-branch-coverage - */ - def branchCoverage: Double = { - // if there are zero branches, then we have a single line of execution. - // in that case, if there is at least some coverage, we have covered the branch. - // if there is no coverage then we have not covered the branch - if (branchCount == 0) { - if (statementCoverage > 0) 1 - else 0 - } else { - invokedBranchesCount / branchCount.toDouble - } - } - def branchCoverageFormatted: String = twoFractionDigits(branchCoveragePercent) -} - -trait ClassCoverage { - this: ClassBuilders => - val statements: Iterable[Statement] - def invokedClasses: Int = classes.count(_.statements.count(_.count > 0) > 0) - def classCoverage: Double = invokedClasses / classes.size.toDouble -} From 07851fb61080ddf32c3adc942dc4ee91c2fd44be Mon Sep 17 00:00:00 2001 From: Chris Kipp Date: Sun, 24 Oct 2021 10:51:35 +0200 Subject: [PATCH 2/5] refactor: break domain out of reporter This allows for a bit more fine-grained control over what we are putting on the classpath. This should allow us to no longer need to include scala-xml on the users compiler claspath and only use it while doing the reporting. --- .github/workflows/ci.yml | 6 +- build.sbt | 17 +++- .../scala/scoverage/domain}/Builders.scala | 2 +- .../scala/scoverage/domain}/CodeGrid.scala | 2 +- .../scala/scoverage/domain}/Constants.scala | 2 +- .../scoverage/domain}/CoverageMetrics.scala | 9 +- .../scoverage/domain}/DoubleFormat.scala | 2 +- .../scala/scoverage/domain}/Location.scala | 2 +- .../scala/scoverage/domain}/Statement.scala | 2 +- .../scoverage/domain}/StatementStatus.scala | 2 +- .../scala/scoverage/domain}/coverage.scala | 11 +-- .../scala/scoverage/domain/CoverageTest.scala | 92 +++++++++++++++++++ .../src/main/scala/scoverage/Location.scala | 6 +- .../scala/scoverage/ScoveragePlugin.scala | 7 +- .../scala/scoverage/LocationCompiler.scala | 3 +- .../test/scala/scoverage/LocationTest.scala | 2 +- .../reporter/BaseReportWriter.scala | 0 .../reporter/CoberturaXmlWriter.scala | 26 ++++-- .../reporter/CoverageAggregator.scala | 2 + .../{ => scoverage}/reporter/IOUtils.scala | 3 +- .../reporter/ScoverageHtmlWriter.scala | 6 ++ .../reporter/ScoverageXmlWriter.scala | 6 ++ .../{ => scoverage}/reporter/Serializer.scala | 6 ++ .../reporter/StatementWriter.scala | 2 + .../reporter/CoberturaXmlWriterTest.scala | 6 +- .../reporter/CoverageAggregatorTest.scala | 5 + .../reporter/CoverageMetricsTest.scala | 2 + .../scoverage/reporter/CoverageTest.scala | 2 +- .../scoverage/reporter/IOUtilsTest.scala | 1 + .../reporter/ScoverageHtmlWriterTest.scala | 4 + .../scoverage/reporter/SerializerTest.scala | 4 + 31 files changed, 196 insertions(+), 46 deletions(-) rename {reporter/src/main/scala/reporter => domain/src/main/scala/scoverage/domain}/Builders.scala (95%) rename {reporter/src/main/scala/reporter => domain/src/main/scala/scoverage/domain}/CodeGrid.scala (99%) rename {reporter/src/main/scala/reporter => domain/src/main/scala/scoverage/domain}/Constants.scala (94%) rename {reporter/src/main/scala/reporter => domain/src/main/scala/scoverage/domain}/CoverageMetrics.scala (93%) rename {reporter/src/main/scala/reporter => domain/src/main/scala/scoverage/domain}/DoubleFormat.scala (94%) rename {reporter/src/main/scala/reporter => domain/src/main/scala/scoverage/domain}/Location.scala (93%) rename {reporter/src/main/scala/reporter => domain/src/main/scala/scoverage/domain}/Statement.scala (95%) rename {reporter/src/main/scala/reporter => domain/src/main/scala/scoverage/domain}/StatementStatus.scala (87%) rename {reporter/src/main/scala/reporter => domain/src/main/scala/scoverage/domain}/coverage.scala (89%) create mode 100644 domain/src/test/scala/scoverage/domain/CoverageTest.scala rename reporter/src/main/scala/{ => scoverage}/reporter/BaseReportWriter.scala (100%) rename reporter/src/main/scala/{ => scoverage}/reporter/CoberturaXmlWriter.scala (74%) rename reporter/src/main/scala/{ => scoverage}/reporter/CoverageAggregator.scala (97%) rename reporter/src/main/scala/{ => scoverage}/reporter/IOUtils.scala (98%) rename reporter/src/main/scala/{ => scoverage}/reporter/ScoverageHtmlWriter.scala (98%) rename reporter/src/main/scala/{ => scoverage}/reporter/ScoverageXmlWriter.scala (96%) rename reporter/src/main/scala/{ => scoverage}/reporter/Serializer.scala (97%) rename reporter/src/main/scala/{ => scoverage}/reporter/StatementWriter.scala (96%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index db7fdafa..bf2823b1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: fail-fast: false matrix: os: [ 'ubuntu-latest', 'windows-latest' ] - java: ['11', '17'] + java: ['8', '17'] scala: [ { version: '2.12.15' }, { version: '2.12.14' }, @@ -48,8 +48,8 @@ jobs: fail-fast: false matrix: os: [ 'ubuntu-latest', 'windows-latest' ] - java: ['11', '17' ] - module: ['runtime', 'runtimeJS', 'reporter'] + java: ['8', '17' ] + module: ['runtime', 'runtimeJS', 'reporter', 'domain'] steps: - name: checkout the repo uses: actions/checkout@v2 diff --git a/build.sbt b/build.sbt index a3d38053..0d7f9a42 100644 --- a/build.sbt +++ b/build.sbt @@ -91,7 +91,7 @@ lazy val root = Project("scalac-scoverage", file(".")) publishArtifact := false, publishLocal := {} ) - .aggregate(plugin, runtime.jvm, runtime.js, reporter) + .aggregate(plugin, runtime.jvm, runtime.js, reporter, domain) lazy val runtime = CrossProject( "runtime", @@ -127,7 +127,6 @@ lazy val plugin = crossScalaVersions := bin212 ++ bin213, crossVersion := CrossVersion.full, libraryDependencies ++= Seq( - "org.scala-lang.modules" %% "scala-xml" % "2.0.0", "org.scalameta" %% "munit" % munitVersion % Test, "org.scala-lang" % "scala-compiler" % scalaVersion.value % Provided ), @@ -136,7 +135,7 @@ lazy val plugin = .settings( (Test / unmanagedSourceDirectories) += (Test / sourceDirectory).value / "scala-2.12+" ) - .dependsOn(reporter) + .dependsOn(reporter, domain) lazy val reporter = Project("reporter", file("reporter")) @@ -149,6 +148,18 @@ lazy val reporter = sharedSettings, crossScalaVersions := Seq(defaultScala212, defaultScala213, defaultScala3) ) + .dependsOn(domain) + +lazy val domain = + Project("domain", file("domain")) + .settings( + name := "scalac-scoverage-domain", + libraryDependencies ++= Seq( + "org.scalameta" %% "munit" % munitVersion % Test + ), + sharedSettings, + crossScalaVersions := Seq(defaultScala212, defaultScala213, defaultScala3) + ) addCommandAlias( "styleFix", diff --git a/reporter/src/main/scala/reporter/Builders.scala b/domain/src/main/scala/scoverage/domain/Builders.scala similarity index 95% rename from reporter/src/main/scala/reporter/Builders.scala rename to domain/src/main/scala/scoverage/domain/Builders.scala index 394822b5..040874a0 100644 --- a/reporter/src/main/scala/reporter/Builders.scala +++ b/domain/src/main/scala/scoverage/domain/Builders.scala @@ -1,4 +1,4 @@ -package scoverage.reporter +package scoverage.domain trait MethodBuilders { def statements: Iterable[Statement] diff --git a/reporter/src/main/scala/reporter/CodeGrid.scala b/domain/src/main/scala/scoverage/domain/CodeGrid.scala similarity index 99% rename from reporter/src/main/scala/reporter/CodeGrid.scala rename to domain/src/main/scala/scoverage/domain/CodeGrid.scala index 0d75b71e..70b33f96 100644 --- a/reporter/src/main/scala/reporter/CodeGrid.scala +++ b/domain/src/main/scala/scoverage/domain/CodeGrid.scala @@ -1,4 +1,4 @@ -package scoverage.reporter +package scoverage.domain import scala.io.Codec import scala.io.Source diff --git a/reporter/src/main/scala/reporter/Constants.scala b/domain/src/main/scala/scoverage/domain/Constants.scala similarity index 94% rename from reporter/src/main/scala/reporter/Constants.scala rename to domain/src/main/scala/scoverage/domain/Constants.scala index b5d70b2c..02921263 100644 --- a/reporter/src/main/scala/reporter/Constants.scala +++ b/domain/src/main/scala/scoverage/domain/Constants.scala @@ -1,4 +1,4 @@ -package scoverage.reporter +package scoverage.domain object Constants { // the file that contains the statement mappings diff --git a/reporter/src/main/scala/reporter/CoverageMetrics.scala b/domain/src/main/scala/scoverage/domain/CoverageMetrics.scala similarity index 93% rename from reporter/src/main/scala/reporter/CoverageMetrics.scala rename to domain/src/main/scala/scoverage/domain/CoverageMetrics.scala index 63bb6fd5..ad296976 100644 --- a/reporter/src/main/scala/reporter/CoverageMetrics.scala +++ b/domain/src/main/scala/scoverage/domain/CoverageMetrics.scala @@ -1,9 +1,7 @@ -package scoverage.reporter +package scoverage.domain import java.io.File -import scoverage.reporter.DoubleFormat.twoFractionDigits - trait CoverageMetrics { def statements: Iterable[Statement] def statementCount: Int = statements.size @@ -16,7 +14,7 @@ trait CoverageMetrics { def statementCoverage: Double = if (statementCount == 0) 1 else invokedStatementCount / statementCount.toDouble def statementCoveragePercent = statementCoverage * 100 - def statementCoverageFormatted: String = twoFractionDigits( + def statementCoverageFormatted: String = DoubleFormat.twoFractionDigits( statementCoveragePercent ) def branches: Iterable[Statement] = statements.filter(_.branch) @@ -38,7 +36,8 @@ trait CoverageMetrics { invokedBranchesCount / branchCount.toDouble } } - def branchCoverageFormatted: String = twoFractionDigits(branchCoveragePercent) + def branchCoverageFormatted: String = + DoubleFormat.twoFractionDigits(branchCoveragePercent) } case class MeasuredMethod(name: String, statements: Iterable[Statement]) diff --git a/reporter/src/main/scala/reporter/DoubleFormat.scala b/domain/src/main/scala/scoverage/domain/DoubleFormat.scala similarity index 94% rename from reporter/src/main/scala/reporter/DoubleFormat.scala rename to domain/src/main/scala/scoverage/domain/DoubleFormat.scala index 6059bcae..edcb8def 100644 --- a/reporter/src/main/scala/reporter/DoubleFormat.scala +++ b/domain/src/main/scala/scoverage/domain/DoubleFormat.scala @@ -1,4 +1,4 @@ -package scoverage.reporter +package scoverage.domain import java.text.DecimalFormat import java.text.DecimalFormatSymbols diff --git a/reporter/src/main/scala/reporter/Location.scala b/domain/src/main/scala/scoverage/domain/Location.scala similarity index 93% rename from reporter/src/main/scala/reporter/Location.scala rename to domain/src/main/scala/scoverage/domain/Location.scala index 8168cb32..89104cc7 100644 --- a/reporter/src/main/scala/reporter/Location.scala +++ b/domain/src/main/scala/scoverage/domain/Location.scala @@ -1,4 +1,4 @@ -package scoverage.reporter +package scoverage.domain /** @param packageName the name of the enclosing package * @param className the name of the closest enclosing class diff --git a/reporter/src/main/scala/reporter/Statement.scala b/domain/src/main/scala/scoverage/domain/Statement.scala similarity index 95% rename from reporter/src/main/scala/reporter/Statement.scala rename to domain/src/main/scala/scoverage/domain/Statement.scala index b751e87b..f92f4f46 100644 --- a/reporter/src/main/scala/reporter/Statement.scala +++ b/domain/src/main/scala/scoverage/domain/Statement.scala @@ -1,4 +1,4 @@ -package scoverage.reporter +package scoverage.domain import scala.collection.mutable diff --git a/reporter/src/main/scala/reporter/StatementStatus.scala b/domain/src/main/scala/scoverage/domain/StatementStatus.scala similarity index 87% rename from reporter/src/main/scala/reporter/StatementStatus.scala rename to domain/src/main/scala/scoverage/domain/StatementStatus.scala index b4284f39..3aa04e7e 100644 --- a/reporter/src/main/scala/reporter/StatementStatus.scala +++ b/domain/src/main/scala/scoverage/domain/StatementStatus.scala @@ -1,4 +1,4 @@ -package scoverage.reporter +package scoverage.domain /** @author Stephen Samuel */ sealed trait StatementStatus diff --git a/reporter/src/main/scala/reporter/coverage.scala b/domain/src/main/scala/scoverage/domain/coverage.scala similarity index 89% rename from reporter/src/main/scala/reporter/coverage.scala rename to domain/src/main/scala/scoverage/domain/coverage.scala index 7c59c545..a6b8764c 100644 --- a/reporter/src/main/scala/reporter/coverage.scala +++ b/domain/src/main/scala/scoverage/domain/coverage.scala @@ -1,9 +1,7 @@ -package scoverage.reporter +package scoverage.domain import scala.collection.mutable -import scoverage.reporter.DoubleFormat.twoFractionDigits - /** @author Stephen Samuel */ case class Coverage() @@ -24,18 +22,19 @@ case class Coverage() ignoredStatementsById.put(stmt.id, stmt) def avgClassesPerPackage = classCount / packageCount.toDouble - def avgClassesPerPackageFormatted: String = twoFractionDigits( + def avgClassesPerPackageFormatted: String = DoubleFormat.twoFractionDigits( avgClassesPerPackage ) def avgMethodsPerClass = methodCount / classCount.toDouble - def avgMethodsPerClassFormatted: String = twoFractionDigits( + def avgMethodsPerClassFormatted: String = DoubleFormat.twoFractionDigits( avgMethodsPerClass ) def loc = files.map(_.loc).sum def linesPerFile = loc / fileCount.toDouble - def linesPerFileFormatted: String = twoFractionDigits(linesPerFile) + def linesPerFileFormatted: String = + DoubleFormat.twoFractionDigits(linesPerFile) // returns the classes by least coverage def risks(limit: Int) = classes.toSeq diff --git a/domain/src/test/scala/scoverage/domain/CoverageTest.scala b/domain/src/test/scala/scoverage/domain/CoverageTest.scala new file mode 100644 index 00000000..35f87b13 --- /dev/null +++ b/domain/src/test/scala/scoverage/domain/CoverageTest.scala @@ -0,0 +1,92 @@ +package scoverage.domain + +import munit.FunSuite + +/** @author Stephen Samuel */ +class CoverageTest extends FunSuite { + + test("coverage for no statements is 1") { + val coverage = Coverage() + assertEquals(1.0, coverage.statementCoverage) + } + + test("coverage for no invoked statements is 0") { + val coverage = Coverage() + coverage.add( + Statement( + Location("", "", "", ClassType.Object, "", ""), + 1, + 2, + 3, + 4, + "", + "", + "", + false, + 0 + ) + ) + assertEquals(0.0, coverage.statementCoverage) + } + + test("coverage for invoked statements") { + val coverage = Coverage() + coverage.add( + Statement( + Location("", "", "", ClassType.Object, "", ""), + 1, + 2, + 3, + 4, + "", + "", + "", + false, + 3 + ) + ) + coverage.add( + Statement( + Location("", "", "", ClassType.Object, "", ""), + 2, + 2, + 3, + 4, + "", + "", + "", + false, + 0 + ) + ) + coverage.add( + Statement( + Location("", "", "", ClassType.Object, "", ""), + 3, + 2, + 3, + 4, + "", + "", + "", + false, + 0 + ) + ) + coverage.add( + Statement( + Location("", "", "", ClassType.Object, "", ""), + 4, + 2, + 3, + 4, + "", + "", + "", + false, + 0 + ) + ) + assertEquals(0.25, coverage.statementCoverage) + } +} diff --git a/plugin/src/main/scala/scoverage/Location.scala b/plugin/src/main/scala/scoverage/Location.scala index c796fe79..bba2b773 100644 --- a/plugin/src/main/scala/scoverage/Location.scala +++ b/plugin/src/main/scala/scoverage/Location.scala @@ -2,11 +2,11 @@ package scoverage import scala.tools.nsc.Global -import scoverage.reporter.ClassType +import scoverage.domain.ClassType object Location { - def fromGlobal(global: Global): global.Tree => Option[reporter.Location] = { + def fromGlobal(global: Global): global.Tree => Option[domain.Location] = { tree => def packageName(s: global.Symbol): String = { s.enclosingPackage.fullName @@ -44,7 +44,7 @@ object Location { } Option(tree.symbol) map { symbol => - reporter.Location( + domain.Location( packageName(symbol), className(symbol), fullClassName(symbol), diff --git a/plugin/src/main/scala/scoverage/ScoveragePlugin.scala b/plugin/src/main/scala/scoverage/ScoveragePlugin.scala index eea15a18..bdaf5090 100644 --- a/plugin/src/main/scala/scoverage/ScoveragePlugin.scala +++ b/plugin/src/main/scala/scoverage/ScoveragePlugin.scala @@ -11,11 +11,10 @@ import scala.tools.nsc.plugins.PluginComponent import scala.tools.nsc.transform.Transform import scala.tools.nsc.transform.TypingTransformers -import scoverage.reporter.Coverage +import scoverage.domain.Coverage +import scoverage.domain.Statement import scoverage.reporter.IOUtils import scoverage.reporter.Serializer -import scoverage.reporter.Statement -import scoverage.reporter.{Location => LocationThatNeedsANewName} /** @author Stephen Samuel */ class ScoveragePlugin(val global: Global) extends Plugin { @@ -154,7 +153,7 @@ class ScoverageInstrumentationComponent( import global._ // contains the location of the last node - var location: LocationThatNeedsANewName = _ + var location: domain.Location = _ /** The 'start' of the position, if it is available, else -1 * We cannot use 'isDefined' to test whether pos.start will work, as some diff --git a/plugin/src/test/scala/scoverage/LocationCompiler.scala b/plugin/src/test/scala/scoverage/LocationCompiler.scala index 7c073767..7d8766a8 100644 --- a/plugin/src/test/scala/scoverage/LocationCompiler.scala +++ b/plugin/src/test/scala/scoverage/LocationCompiler.scala @@ -8,14 +8,13 @@ import scala.tools.nsc.transform.Transform import scala.tools.nsc.transform.TypingTransformers import scoverage.reporter.IOUtils -import scoverage.reporter.{Location => LocationThatNeedsABetterName} class LocationCompiler( settings: scala.tools.nsc.Settings, reporter: scala.tools.nsc.reporters.Reporter ) extends scala.tools.nsc.Global(settings, reporter) { - val locations = List.newBuilder[(String, LocationThatNeedsABetterName)] + val locations = List.newBuilder[(String, domain.Location)] private val locationSetter = new LocationSetter(this) def compile(code: String): Unit = { diff --git a/plugin/src/test/scala/scoverage/LocationTest.scala b/plugin/src/test/scala/scoverage/LocationTest.scala index e36abdd0..0fdcbcec 100644 --- a/plugin/src/test/scala/scoverage/LocationTest.scala +++ b/plugin/src/test/scala/scoverage/LocationTest.scala @@ -1,7 +1,7 @@ package scoverage import munit.FunSuite -import scoverage.reporter.ClassType +import scoverage.domain.ClassType class LocationTest extends FunSuite { diff --git a/reporter/src/main/scala/reporter/BaseReportWriter.scala b/reporter/src/main/scala/scoverage/reporter/BaseReportWriter.scala similarity index 100% rename from reporter/src/main/scala/reporter/BaseReportWriter.scala rename to reporter/src/main/scala/scoverage/reporter/BaseReportWriter.scala diff --git a/reporter/src/main/scala/reporter/CoberturaXmlWriter.scala b/reporter/src/main/scala/scoverage/reporter/CoberturaXmlWriter.scala similarity index 74% rename from reporter/src/main/scala/reporter/CoberturaXmlWriter.scala rename to reporter/src/main/scala/scoverage/reporter/CoberturaXmlWriter.scala index 22587462..327e4ddc 100644 --- a/reporter/src/main/scala/reporter/CoberturaXmlWriter.scala +++ b/reporter/src/main/scala/scoverage/reporter/CoberturaXmlWriter.scala @@ -5,7 +5,11 @@ import java.io.File import scala.xml.Node import scala.xml.PrettyPrinter -import scoverage.reporter.DoubleFormat.twoFractionDigits +import scoverage.domain.Coverage +import scoverage.domain.DoubleFormat +import scoverage.domain.MeasuredClass +import scoverage.domain.MeasuredMethod +import scoverage.domain.MeasuredPackage /** @author Stephen Samuel */ class CoberturaXmlWriter( @@ -30,8 +34,8 @@ class CoberturaXmlWriter( def method(method: MeasuredMethod): Node = { { @@ -47,8 +51,8 @@ class CoberturaXmlWriter( def klass(klass: MeasuredClass): Node = { {klass.methods.map(method)} @@ -66,8 +70,8 @@ class CoberturaXmlWriter( def pack(pack: MeasuredPackage): Node = { {pack.classes.map(klass)} @@ -80,12 +84,16 @@ class CoberturaXmlWriter( } def xml(coverage: Coverage): Node = { - diff --git a/reporter/src/main/scala/reporter/CoverageAggregator.scala b/reporter/src/main/scala/scoverage/reporter/CoverageAggregator.scala similarity index 97% rename from reporter/src/main/scala/reporter/CoverageAggregator.scala rename to reporter/src/main/scala/scoverage/reporter/CoverageAggregator.scala index 67ca2b19..3dcd9e3b 100644 --- a/reporter/src/main/scala/reporter/CoverageAggregator.scala +++ b/reporter/src/main/scala/scoverage/reporter/CoverageAggregator.scala @@ -2,6 +2,8 @@ package scoverage.reporter import java.io.File +import scoverage.domain.Coverage + object CoverageAggregator { // to be used by gradle-scoverage plugin diff --git a/reporter/src/main/scala/reporter/IOUtils.scala b/reporter/src/main/scala/scoverage/reporter/IOUtils.scala similarity index 98% rename from reporter/src/main/scala/reporter/IOUtils.scala rename to reporter/src/main/scala/scoverage/reporter/IOUtils.scala index 2e2737aa..601835ff 100644 --- a/reporter/src/main/scala/reporter/IOUtils.scala +++ b/reporter/src/main/scala/scoverage/reporter/IOUtils.scala @@ -7,10 +7,11 @@ import scala.collection.mutable import scala.io.Codec import scala.io.Source +import scoverage.domain.Constants + /** @author Stephen Samuel */ object IOUtils { - // TODO Should any of this stuff actually stay in here. probably not def coverageFile(dataDir: File): File = coverageFile(dataDir.getAbsolutePath) def coverageFile(dataDir: String): File = new File(dataDir, Constants.CoverageFileName) diff --git a/reporter/src/main/scala/reporter/ScoverageHtmlWriter.scala b/reporter/src/main/scala/scoverage/reporter/ScoverageHtmlWriter.scala similarity index 98% rename from reporter/src/main/scala/reporter/ScoverageHtmlWriter.scala rename to reporter/src/main/scala/scoverage/reporter/ScoverageHtmlWriter.scala index e015dada..849e7663 100644 --- a/reporter/src/main/scala/reporter/ScoverageHtmlWriter.scala +++ b/reporter/src/main/scala/scoverage/reporter/ScoverageHtmlWriter.scala @@ -5,6 +5,12 @@ import java.util.Date import scala.xml.Node +import scoverage.domain.CodeGrid +import scoverage.domain.Coverage +import scoverage.domain.MeasuredClass +import scoverage.domain.MeasuredFile +import scoverage.domain.MeasuredPackage + /** @author Stephen Samuel */ class ScoverageHtmlWriter( sourceDirectories: Seq[File], diff --git a/reporter/src/main/scala/reporter/ScoverageXmlWriter.scala b/reporter/src/main/scala/scoverage/reporter/ScoverageXmlWriter.scala similarity index 96% rename from reporter/src/main/scala/reporter/ScoverageXmlWriter.scala rename to reporter/src/main/scala/scoverage/reporter/ScoverageXmlWriter.scala index 741182cf..49b4eebf 100644 --- a/reporter/src/main/scala/reporter/ScoverageXmlWriter.scala +++ b/reporter/src/main/scala/scoverage/reporter/ScoverageXmlWriter.scala @@ -5,6 +5,12 @@ import java.io.File import scala.xml.Node import scala.xml.PrettyPrinter +import scoverage.domain.Coverage +import scoverage.domain.MeasuredClass +import scoverage.domain.MeasuredMethod +import scoverage.domain.MeasuredPackage +import scoverage.domain.Statement + /** @author Stephen Samuel */ class ScoverageXmlWriter( sourceDirectories: Seq[File], diff --git a/reporter/src/main/scala/reporter/Serializer.scala b/reporter/src/main/scala/scoverage/reporter/Serializer.scala similarity index 97% rename from reporter/src/main/scala/reporter/Serializer.scala rename to reporter/src/main/scala/scoverage/reporter/Serializer.scala index b92710b6..81e683cd 100644 --- a/reporter/src/main/scala/reporter/Serializer.scala +++ b/reporter/src/main/scala/scoverage/reporter/Serializer.scala @@ -9,6 +9,12 @@ import java.io.Writer import scala.io.Codec import scala.io.Source +import scoverage.domain.ClassType +import scoverage.domain.Constants +import scoverage.domain.Coverage +import scoverage.domain.Location +import scoverage.domain.Statement + object Serializer { val coverageDataFormatVersion = "3.0" diff --git a/reporter/src/main/scala/reporter/StatementWriter.scala b/reporter/src/main/scala/scoverage/reporter/StatementWriter.scala similarity index 96% rename from reporter/src/main/scala/reporter/StatementWriter.scala rename to reporter/src/main/scala/scoverage/reporter/StatementWriter.scala index a7d90eaa..13a4d775 100644 --- a/reporter/src/main/scala/reporter/StatementWriter.scala +++ b/reporter/src/main/scala/scoverage/reporter/StatementWriter.scala @@ -2,6 +2,8 @@ package scoverage.reporter import scala.xml.Node +import scoverage.domain.MeasuredFile + /** @author Stephen Samuel */ class StatementWriter(mFile: MeasuredFile) { diff --git a/reporter/src/test/scala/scoverage/reporter/CoberturaXmlWriterTest.scala b/reporter/src/test/scala/scoverage/reporter/CoberturaXmlWriterTest.scala index 3dac5333..b1c091f3 100644 --- a/reporter/src/test/scala/scoverage/reporter/CoberturaXmlWriterTest.scala +++ b/reporter/src/test/scala/scoverage/reporter/CoberturaXmlWriterTest.scala @@ -12,6 +12,10 @@ import scala.xml.factory.XMLLoader import munit.FunSuite import org.xml.sax.ErrorHandler import org.xml.sax.SAXParseException +import scoverage.domain.ClassType +import scoverage.domain.Coverage +import scoverage.domain.Location +import scoverage.domain.Statement /** @author Stephen Samuel */ class CoberturaXmlWriterTest extends FunSuite { @@ -34,7 +38,7 @@ class CoberturaXmlWriterTest extends FunSuite { val dir = tempDir() - val coverage = scoverage.reporter.Coverage() + val coverage = Coverage() coverage .add( Statement( diff --git a/reporter/src/test/scala/scoverage/reporter/CoverageAggregatorTest.scala b/reporter/src/test/scala/scoverage/reporter/CoverageAggregatorTest.scala index 9508286e..8f39f752 100644 --- a/reporter/src/test/scala/scoverage/reporter/CoverageAggregatorTest.scala +++ b/reporter/src/test/scala/scoverage/reporter/CoverageAggregatorTest.scala @@ -5,6 +5,11 @@ import java.io.FileWriter import java.util.UUID import munit.FunSuite +import scoverage.domain.ClassType +import scoverage.domain.Constants +import scoverage.domain.Coverage +import scoverage.domain.Location +import scoverage.domain.Statement class CoverageAggregatorTest extends FunSuite { diff --git a/reporter/src/test/scala/scoverage/reporter/CoverageMetricsTest.scala b/reporter/src/test/scala/scoverage/reporter/CoverageMetricsTest.scala index 9a1403af..bd8d58e5 100644 --- a/reporter/src/test/scala/scoverage/reporter/CoverageMetricsTest.scala +++ b/reporter/src/test/scala/scoverage/reporter/CoverageMetricsTest.scala @@ -1,6 +1,8 @@ package scoverage.reporter import munit.FunSuite +import scoverage.domain.CoverageMetrics +import scoverage.domain.Statement class CoverageMetricsTest extends FunSuite { diff --git a/reporter/src/test/scala/scoverage/reporter/CoverageTest.scala b/reporter/src/test/scala/scoverage/reporter/CoverageTest.scala index 59cea490..35f87b13 100644 --- a/reporter/src/test/scala/scoverage/reporter/CoverageTest.scala +++ b/reporter/src/test/scala/scoverage/reporter/CoverageTest.scala @@ -1,4 +1,4 @@ -package scoverage.reporter +package scoverage.domain import munit.FunSuite diff --git a/reporter/src/test/scala/scoverage/reporter/IOUtilsTest.scala b/reporter/src/test/scala/scoverage/reporter/IOUtilsTest.scala index 8fd018d0..a106988b 100644 --- a/reporter/src/test/scala/scoverage/reporter/IOUtilsTest.scala +++ b/reporter/src/test/scala/scoverage/reporter/IOUtilsTest.scala @@ -5,6 +5,7 @@ import java.io.FileWriter import java.util.UUID import munit.FunSuite +import scoverage.domain.Constants /** @author Stephen Samuel */ class IOUtilsTest extends FunSuite { diff --git a/reporter/src/test/scala/scoverage/reporter/ScoverageHtmlWriterTest.scala b/reporter/src/test/scala/scoverage/reporter/ScoverageHtmlWriterTest.scala index 5443f61d..86e8dd84 100644 --- a/reporter/src/test/scala/scoverage/reporter/ScoverageHtmlWriterTest.scala +++ b/reporter/src/test/scala/scoverage/reporter/ScoverageHtmlWriterTest.scala @@ -7,6 +7,10 @@ import scala.io.Source import scala.xml.XML import munit.FunSuite +import scoverage.domain.ClassType +import scoverage.domain.Coverage +import scoverage.domain.Location +import scoverage.domain.Statement class ScoverageHtmlWriterTest extends FunSuite { diff --git a/reporter/src/test/scala/scoverage/reporter/SerializerTest.scala b/reporter/src/test/scala/scoverage/reporter/SerializerTest.scala index 62f8f29c..f2dac039 100644 --- a/reporter/src/test/scala/scoverage/reporter/SerializerTest.scala +++ b/reporter/src/test/scala/scoverage/reporter/SerializerTest.scala @@ -4,6 +4,10 @@ import java.io.File import java.io.StringWriter import munit.FunSuite +import scoverage.domain.ClassType +import scoverage.domain.Coverage +import scoverage.domain.Location +import scoverage.domain.Statement class SerializerTest extends FunSuite { private val sourceRoot = new File(".").getCanonicalFile() From cea077c1647bd50a72914df8bb37fe84eb39475a Mon Sep 17 00:00:00 2001 From: Chris Kipp Date: Sat, 30 Oct 2021 17:58:48 +0200 Subject: [PATCH 3/5] refactor: Some more rearranging to ensure scala-xml isn't included in the compiler deps --- build.sbt | 10 +- .../scala/scoverage/ScoveragePlugin.scala | 8 +- .../src/main/scala/scoverage/Serializer.scala | 124 ++++++++++++++++++ .../reporter/CoverageAggregator.scala | 2 +- .../{Serializer.scala => Deserializer.scala} | 2 +- .../scala/scoverage/reporter/IOUtils.scala | 1 + .../reporter/CoverageAggregatorTest.scala | 12 +- .../scoverage/reporter/IOUtilsTest.scala | 1 + .../scoverage/reporter/SerializerTest.scala | 16 +-- 9 files changed, 150 insertions(+), 26 deletions(-) create mode 100644 plugin/src/main/scala/scoverage/Serializer.scala rename reporter/src/main/scala/scoverage/reporter/{Serializer.scala => Deserializer.scala} (99%) diff --git a/build.sbt b/build.sbt index 0d7f9a42..d626eb62 100644 --- a/build.sbt +++ b/build.sbt @@ -119,7 +119,7 @@ lazy val `runtimeJVM` = runtime.jvm lazy val `runtimeJS` = runtime.js lazy val plugin = - Project("plugin", file("plugin")) + project .dependsOn(runtimeJVM % Test) .settings( name := "scalac-scoverage-plugin", @@ -133,12 +133,12 @@ lazy val plugin = sharedSettings ) .settings( - (Test / unmanagedSourceDirectories) += (Test / sourceDirectory).value / "scala-2.12+" + Test / unmanagedSourceDirectories += (Test / sourceDirectory).value / "scala-2.12+" ) - .dependsOn(reporter, domain) + .dependsOn(domain, reporter % "test->compile") lazy val reporter = - Project("reporter", file("reporter")) + project .settings( name := "scalac-scoverage-reporter", libraryDependencies ++= Seq( @@ -151,7 +151,7 @@ lazy val reporter = .dependsOn(domain) lazy val domain = - Project("domain", file("domain")) + project .settings( name := "scalac-scoverage-domain", libraryDependencies ++= Seq( diff --git a/plugin/src/main/scala/scoverage/ScoveragePlugin.scala b/plugin/src/main/scala/scoverage/ScoveragePlugin.scala index bdaf5090..7dd8b3b0 100644 --- a/plugin/src/main/scala/scoverage/ScoveragePlugin.scala +++ b/plugin/src/main/scala/scoverage/ScoveragePlugin.scala @@ -13,8 +13,6 @@ import scala.tools.nsc.transform.TypingTransformers import scoverage.domain.Coverage import scoverage.domain.Statement -import scoverage.reporter.IOUtils -import scoverage.reporter.Serializer /** @author Stephen Samuel */ class ScoveragePlugin(val global: Global) extends Plugin { @@ -124,7 +122,7 @@ class ScoverageInstrumentationComponent( // we clean the data directory, because if the code has changed, then the number / order of // statements has changed by definition. So the old data would reference statements incorrectly // and thus skew the results. - IOUtils.clean(options.dataDir) + Serializer.clean(options.dataDir) reporter.echo("Beginning coverage instrumentation") super.run() @@ -134,11 +132,11 @@ class ScoverageInstrumentationComponent( Serializer.serialize( coverage, - IOUtils.coverageFile(options.dataDir), + Serializer.coverageFile(options.dataDir), new File(options.sourceRoot) ) reporter.echo( - s"Wrote instrumentation file [${IOUtils.coverageFile(options.dataDir)}]" + s"Wrote instrumentation file [${Serializer.coverageFile(options.dataDir)}]" ) reporter.echo(s"Will write measurement data to [${options.dataDir}]") } diff --git a/plugin/src/main/scala/scoverage/Serializer.scala b/plugin/src/main/scala/scoverage/Serializer.scala new file mode 100644 index 00000000..f0761af7 --- /dev/null +++ b/plugin/src/main/scala/scoverage/Serializer.scala @@ -0,0 +1,124 @@ +package scoverage + +import java.io.BufferedWriter +import java.io.File +import java.io.FileFilter +import java.io.FileOutputStream +import java.io.OutputStreamWriter +import java.io.Writer + +import scala.io.Codec + +import scoverage.domain.Constants +import scoverage.domain.Coverage +import scoverage.domain.Statement + +object Serializer { + + // TODO this should be probably shared in domain + val coverageDataFormatVersion = "3.0" + + // Write out coverage data to the given data directory, using the default coverage filename + def serialize(coverage: Coverage, dataDir: String, sourceRoot: String): Unit = + serialize(coverage, coverageFile(dataDir), new File(sourceRoot)) + + // Write out coverage data to given file. + def serialize(coverage: Coverage, file: File, sourceRoot: File): Unit = { + val writer: Writer = new BufferedWriter( + new OutputStreamWriter(new FileOutputStream(file), Codec.UTF8.name) + ) + try { + serialize(coverage, writer, sourceRoot) + } finally { + writer.flush() + writer.close() + } + } + + def serialize( + coverage: Coverage, + writer: Writer, + sourceRoot: File + ): Unit = { + def getRelativePath(filePath: String): String = { + val base = sourceRoot.getCanonicalFile().toPath() + // NOTE: In the real world I have no idea if it's likely that you'll end + // up with weird issues on windows where the roots don't match, something + // like your root being D:/ and your file being C:/. If so this blows up. + // This happened on windows CI for me, since I was using a temp dir, and + // then trying to reletavize it off the cwd, which were in different + // drives. For now, we'll let this as is, but if 'other' has different + // root ever shows its, we'll shut that down real quick here... just not + // sure what to do in that situation yet. + val relPath = + base.relativize(new File(filePath).getCanonicalFile().toPath()) + relPath.toString + } + + def writeHeader(writer: Writer): Unit = { + writer.write( + s"""# Coverage data, format version: $coverageDataFormatVersion + |# Statement data: + |# - id + |# - source path + |# - package name + |# - class name + |# - class type (Class, Object or Trait) + |# - full class name + |# - method name + |# - start offset + |# - end offset + |# - line number + |# - symbol name + |# - tree name + |# - is branch + |# - invocations count + |# - is ignored + |# - description (can be multi-line) + |# '\f' sign + |# ------------------------------------------ + |""".stripMargin + ) + } + + def writeStatement(stmt: Statement, writer: Writer): Unit = { + writer.write(s"""${stmt.id} + |${getRelativePath(stmt.location.sourcePath)} + |${stmt.location.packageName} + |${stmt.location.className} + |${stmt.location.classType} + |${stmt.location.fullClassName} + |${stmt.location.method} + |${stmt.start} + |${stmt.end} + |${stmt.line} + |${stmt.symbolName} + |${stmt.treeName} + |${stmt.branch} + |${stmt.count} + |${stmt.ignored} + |${stmt.desc} + |\f + |""".stripMargin) + } + + writeHeader(writer) + coverage.statements.toSeq + .sortBy(_.id) + .foreach(stmt => writeStatement(stmt, writer)) + } + + def coverageFile(dataDir: File): File = coverageFile(dataDir.getAbsolutePath) + def coverageFile(dataDir: String): File = + new File(dataDir, Constants.CoverageFileName) + + def clean(dataDir: File): Unit = + findMeasurementFiles(dataDir).foreach(_.delete) + def clean(dataDir: String): Unit = clean(new File(dataDir)) + + def findMeasurementFiles(dataDir: File): Array[File] = + dataDir.listFiles(new FileFilter { + override def accept(pathname: File): Boolean = + pathname.getName.startsWith(Constants.MeasurementsPrefix) + }) +} diff --git a/reporter/src/main/scala/scoverage/reporter/CoverageAggregator.scala b/reporter/src/main/scala/scoverage/reporter/CoverageAggregator.scala index 3dcd9e3b..4819cb44 100644 --- a/reporter/src/main/scala/scoverage/reporter/CoverageAggregator.scala +++ b/reporter/src/main/scala/scoverage/reporter/CoverageAggregator.scala @@ -31,7 +31,7 @@ object CoverageAggregator { val coverageFile: File = IOUtils.coverageFile(dataDir) if (coverageFile.exists) { val subcoverage: Coverage = - Serializer.deserialize(coverageFile, sourceRoot) + Deserializer.deserialize(coverageFile, sourceRoot) val measurementFiles: Array[File] = IOUtils.findMeasurementFiles(dataDir) val measurements = IOUtils.invoked(measurementFiles.toIndexedSeq) diff --git a/reporter/src/main/scala/scoverage/reporter/Serializer.scala b/reporter/src/main/scala/scoverage/reporter/Deserializer.scala similarity index 99% rename from reporter/src/main/scala/scoverage/reporter/Serializer.scala rename to reporter/src/main/scala/scoverage/reporter/Deserializer.scala index 81e683cd..aba20a3a 100644 --- a/reporter/src/main/scala/scoverage/reporter/Serializer.scala +++ b/reporter/src/main/scala/scoverage/reporter/Deserializer.scala @@ -15,7 +15,7 @@ import scoverage.domain.Coverage import scoverage.domain.Location import scoverage.domain.Statement -object Serializer { +object Deserializer { val coverageDataFormatVersion = "3.0" diff --git a/reporter/src/main/scala/scoverage/reporter/IOUtils.scala b/reporter/src/main/scala/scoverage/reporter/IOUtils.scala index 601835ff..87dbaf57 100644 --- a/reporter/src/main/scala/scoverage/reporter/IOUtils.scala +++ b/reporter/src/main/scala/scoverage/reporter/IOUtils.scala @@ -12,6 +12,7 @@ import scoverage.domain.Constants /** @author Stephen Samuel */ object IOUtils { + // TODO This is duplicated from Serilizer. We may not need them both def coverageFile(dataDir: File): File = coverageFile(dataDir.getAbsolutePath) def coverageFile(dataDir: String): File = new File(dataDir, Constants.CoverageFileName) diff --git a/reporter/src/test/scala/scoverage/reporter/CoverageAggregatorTest.scala b/reporter/src/test/scala/scoverage/reporter/CoverageAggregatorTest.scala index 8f39f752..06cfd9c0 100644 --- a/reporter/src/test/scala/scoverage/reporter/CoverageAggregatorTest.scala +++ b/reporter/src/test/scala/scoverage/reporter/CoverageAggregatorTest.scala @@ -37,9 +37,9 @@ class CoverageAggregatorTest extends FunSuite { coverage1.add(cov1Stmt2.copy(count = 0)) val dir1 = new File(IOUtils.getTempPath, UUID.randomUUID.toString) dir1.mkdir() - Serializer.serialize( + Deserializer.serialize( coverage1, - Serializer.coverageFile(dir1), + Deserializer.coverageFile(dir1), new File(sourceRoot) ) val measurementsFile1 = @@ -53,9 +53,9 @@ class CoverageAggregatorTest extends FunSuite { coverage2.add(cov2Stmt1) val dir2 = new File(IOUtils.getTempPath, UUID.randomUUID.toString) dir2.mkdir() - Serializer.serialize( + Deserializer.serialize( coverage2, - Serializer.coverageFile(dir2), + Deserializer.coverageFile(dir2), new File(sourceRoot) ) @@ -65,9 +65,9 @@ class CoverageAggregatorTest extends FunSuite { coverage3.add(cov3Stmt1.copy(count = 0)) val dir3 = new File(IOUtils.getTempPath, UUID.randomUUID.toString) dir3.mkdir() - Serializer.serialize( + Deserializer.serialize( coverage3, - Serializer.coverageFile(dir3), + Deserializer.coverageFile(dir3), new File(sourceRoot) ) val measurementsFile3 = diff --git a/reporter/src/test/scala/scoverage/reporter/IOUtilsTest.scala b/reporter/src/test/scala/scoverage/reporter/IOUtilsTest.scala index a106988b..8f3bcfe2 100644 --- a/reporter/src/test/scala/scoverage/reporter/IOUtilsTest.scala +++ b/reporter/src/test/scala/scoverage/reporter/IOUtilsTest.scala @@ -6,6 +6,7 @@ import java.util.UUID import munit.FunSuite import scoverage.domain.Constants +import scoverage.reporter.IOUtils /** @author Stephen Samuel */ class IOUtilsTest extends FunSuite { diff --git a/reporter/src/test/scala/scoverage/reporter/SerializerTest.scala b/reporter/src/test/scala/scoverage/reporter/SerializerTest.scala index f2dac039..2b258d9b 100644 --- a/reporter/src/test/scala/scoverage/reporter/SerializerTest.scala +++ b/reporter/src/test/scala/scoverage/reporter/SerializerTest.scala @@ -36,7 +36,7 @@ class SerializerTest extends FunSuite { ) ) val expected = - s"""# Coverage data, format version: ${Serializer.coverageDataFormatVersion} + s"""# Coverage data, format version: ${Deserializer.coverageDataFormatVersion} |# Statement data: |# - id |# - source path @@ -75,13 +75,13 @@ class SerializerTest extends FunSuite { |\f |""".stripMargin val writer = new StringWriter() //TODO-use UTF-8 - val actual = Serializer.serialize(coverage, writer, sourceRoot) + val actual = Deserializer.serialize(coverage, writer, sourceRoot) assertEquals(expected, writer.toString) } test("coverage should be deserializable from plain text") { val input = - s"""# Coverage data, format version: ${Serializer.coverageDataFormatVersion} + s"""# Coverage data, format version: ${Deserializer.coverageDataFormatVersion} |# Statement data: |# - id |# - source path @@ -142,7 +142,7 @@ class SerializerTest extends FunSuite { 1 ) ) - val coverage = Serializer.deserialize(input, sourceRoot) + val coverage = Deserializer.deserialize(input, sourceRoot) assertEquals(statements, coverage.statements.toList) } test("coverage should serialize sourcePath relatively") { @@ -169,7 +169,7 @@ class SerializerTest extends FunSuite { ) ) val expected = - s"""# Coverage data, format version: ${Serializer.coverageDataFormatVersion} + s"""# Coverage data, format version: ${Deserializer.coverageDataFormatVersion} |# Statement data: |# - id |# - source path @@ -208,13 +208,13 @@ class SerializerTest extends FunSuite { |\f |""".stripMargin val writer = new StringWriter() //TODO-use UTF-8 - val actual = Serializer.serialize(coverage, writer, sourceRoot) + val actual = Deserializer.serialize(coverage, writer, sourceRoot) assertEquals(expected, writer.toString) } test("coverage should deserialize sourcePath by prefixing cwd") { val input = - s"""# Coverage data, format version: ${Serializer.coverageDataFormatVersion} + s"""# Coverage data, format version: ${Deserializer.coverageDataFormatVersion} |# Statement data: |# - id |# - source path @@ -273,7 +273,7 @@ class SerializerTest extends FunSuite { 1 ) ) - val coverage = Serializer.deserialize(input, sourceRoot) + val coverage = Deserializer.deserialize(input, sourceRoot) assertEquals(statements, coverage.statements.toList) } } From 6df5aa37287a4519402c788b11af4eb0acb72ec6 Mon Sep 17 00:00:00 2001 From: Chris Kipp Date: Sat, 30 Oct 2021 18:07:43 +0200 Subject: [PATCH 4/5] Bump scalafmt to 3.0.8 --- .scalafmt.conf | 2 +- plugin/src/main/scala/scoverage/ScoveragePlugin.scala | 2 +- .../src/test/scala/scoverage/reporter/SerializerTest.scala | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.scalafmt.conf b/.scalafmt.conf index 4a5fc51c..1e9af78a 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -version = "3.0.7" +version = "3.0.8" project.git = true runner.dialect = "scala213" assumeStandardLibraryStripMargin = true diff --git a/plugin/src/main/scala/scoverage/ScoveragePlugin.scala b/plugin/src/main/scala/scoverage/ScoveragePlugin.scala index 7dd8b3b0..e87cd584 100644 --- a/plugin/src/main/scala/scoverage/ScoveragePlugin.scala +++ b/plugin/src/main/scala/scoverage/ScoveragePlugin.scala @@ -482,7 +482,7 @@ class ScoverageInstrumentationComponent( /** Applications of methods with non trivial args means the args themselves * must also be instrumented */ - //todo remove once scala merges into Apply proper + // todo remove once scala merges into Apply proper case a: ApplyToImplicitArgs => instrument( treeCopy.Apply( diff --git a/reporter/src/test/scala/scoverage/reporter/SerializerTest.scala b/reporter/src/test/scala/scoverage/reporter/SerializerTest.scala index 2b258d9b..e6963d0a 100644 --- a/reporter/src/test/scala/scoverage/reporter/SerializerTest.scala +++ b/reporter/src/test/scala/scoverage/reporter/SerializerTest.scala @@ -74,7 +74,7 @@ class SerializerTest extends FunSuite { |def test : String |\f |""".stripMargin - val writer = new StringWriter() //TODO-use UTF-8 + val writer = new StringWriter() // TODO-use UTF-8 val actual = Deserializer.serialize(coverage, writer, sourceRoot) assertEquals(expected, writer.toString) } @@ -207,7 +207,7 @@ class SerializerTest extends FunSuite { |def test : String |\f |""".stripMargin - val writer = new StringWriter() //TODO-use UTF-8 + val writer = new StringWriter() // TODO-use UTF-8 val actual = Deserializer.serialize(coverage, writer, sourceRoot) assertEquals(expected, writer.toString) } From ffeebb69d7aab4246dea18e93bbcb5e8efee6cb4 Mon Sep 17 00:00:00 2001 From: Chris Kipp Date: Sun, 31 Oct 2021 12:52:06 +0100 Subject: [PATCH 5/5] refactor: split out serializer module --- .github/workflows/ci.yml | 2 +- build.sbt | 18 ++- .../scala/scoverage/domain/Constants.scala | 2 +- .../scala/scoverage/ScoveragePlugin.scala | 11 +- .../src/main/scala/scoverage/Serializer.scala | 124 ------------------ .../reporter/CoverageAggregator.scala | 5 +- .../scala/scoverage/reporter/IOUtils.scala | 5 - .../reporter/CoverageAggregatorTest.scala | 13 +- .../scoverage/serialize/Serializer.scala | 27 ++-- .../scoverage/serialize}/SerializerTest.scala | 25 ++-- 10 files changed, 64 insertions(+), 168 deletions(-) delete mode 100644 plugin/src/main/scala/scoverage/Serializer.scala rename reporter/src/main/scala/scoverage/reporter/Deserializer.scala => serializer/src/main/scala/scoverage/serialize/Serializer.scala (90%) rename {reporter/src/test/scala/scoverage/reporter => serializer/src/test/scala/scoverage/serialize}/SerializerTest.scala (88%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bf2823b1..06d8582f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,7 @@ jobs: matrix: os: [ 'ubuntu-latest', 'windows-latest' ] java: ['8', '17' ] - module: ['runtime', 'runtimeJS', 'reporter', 'domain'] + module: ['runtime', 'runtimeJS', 'reporter', 'domain', 'serializer'] steps: - name: checkout the repo uses: actions/checkout@v2 diff --git a/build.sbt b/build.sbt index d626eb62..868f3b4a 100644 --- a/build.sbt +++ b/build.sbt @@ -91,7 +91,7 @@ lazy val root = Project("scalac-scoverage", file(".")) publishArtifact := false, publishLocal := {} ) - .aggregate(plugin, runtime.jvm, runtime.js, reporter, domain) + .aggregate(plugin, runtime.jvm, runtime.js, reporter, domain, serializer) lazy val runtime = CrossProject( "runtime", @@ -135,7 +135,7 @@ lazy val plugin = .settings( Test / unmanagedSourceDirectories += (Test / sourceDirectory).value / "scala-2.12+" ) - .dependsOn(domain, reporter % "test->compile") + .dependsOn(domain, reporter % "test->compile", serializer) lazy val reporter = project @@ -148,7 +148,7 @@ lazy val reporter = sharedSettings, crossScalaVersions := Seq(defaultScala212, defaultScala213, defaultScala3) ) - .dependsOn(domain) + .dependsOn(domain, serializer) lazy val domain = project @@ -161,6 +161,18 @@ lazy val domain = crossScalaVersions := Seq(defaultScala212, defaultScala213, defaultScala3) ) +lazy val serializer = + project + .settings( + name := "scalac-scoverage-serializer", + libraryDependencies ++= Seq( + "org.scalameta" %% "munit" % munitVersion % Test + ), + sharedSettings, + crossScalaVersions := Seq(defaultScala212, defaultScala213, defaultScala3) + ) + .dependsOn(domain) + addCommandAlias( "styleFix", "scalafixAll ; scalafmtAll ; scalafmtSbt" diff --git a/domain/src/main/scala/scoverage/domain/Constants.scala b/domain/src/main/scala/scoverage/domain/Constants.scala index 02921263..c3633d9c 100644 --- a/domain/src/main/scala/scoverage/domain/Constants.scala +++ b/domain/src/main/scala/scoverage/domain/Constants.scala @@ -11,5 +11,5 @@ object Constants { // the prefix the measurement files have val MeasurementsPrefix = "scoverage.measurements." - val coverageDataFormatVersion = "3.0" + val CoverageDataFormatVersion = "3.0" } diff --git a/plugin/src/main/scala/scoverage/ScoveragePlugin.scala b/plugin/src/main/scala/scoverage/ScoveragePlugin.scala index e87cd584..e11cbbe3 100644 --- a/plugin/src/main/scala/scoverage/ScoveragePlugin.scala +++ b/plugin/src/main/scala/scoverage/ScoveragePlugin.scala @@ -13,6 +13,7 @@ import scala.tools.nsc.transform.TypingTransformers import scoverage.domain.Coverage import scoverage.domain.Statement +import scoverage.serialize.Serializer /** @author Stephen Samuel */ class ScoveragePlugin(val global: Global) extends Plugin { @@ -20,11 +21,11 @@ class ScoveragePlugin(val global: Global) extends Plugin { override val name: String = ScoveragePlugin.name override val description: String = ScoveragePlugin.description - // TODO I'm not 100% sure why, but historically these have been parsed out - // first. One thing to play around with in the future would be to not do this - // here and rather do it later when we utilize setOpts and instead just - // initialize then in the instrumentationCompoent. This will save us - // iterating over these options twice. + // I'm not 100% sure why, but historically these have been parsed out first. + // One thing to play around with in the future would be to not do this here + // and rather do it later when we utilize setOpts and instead just initialize + // then in the instrumentationCompoent. This will save us iterating over + // these options twice. private val (extraAfterPhase, extraBeforePhase) = ScoverageOptions.processPhaseOptions( pluginOptions diff --git a/plugin/src/main/scala/scoverage/Serializer.scala b/plugin/src/main/scala/scoverage/Serializer.scala deleted file mode 100644 index f0761af7..00000000 --- a/plugin/src/main/scala/scoverage/Serializer.scala +++ /dev/null @@ -1,124 +0,0 @@ -package scoverage - -import java.io.BufferedWriter -import java.io.File -import java.io.FileFilter -import java.io.FileOutputStream -import java.io.OutputStreamWriter -import java.io.Writer - -import scala.io.Codec - -import scoverage.domain.Constants -import scoverage.domain.Coverage -import scoverage.domain.Statement - -object Serializer { - - // TODO this should be probably shared in domain - val coverageDataFormatVersion = "3.0" - - // Write out coverage data to the given data directory, using the default coverage filename - def serialize(coverage: Coverage, dataDir: String, sourceRoot: String): Unit = - serialize(coverage, coverageFile(dataDir), new File(sourceRoot)) - - // Write out coverage data to given file. - def serialize(coverage: Coverage, file: File, sourceRoot: File): Unit = { - val writer: Writer = new BufferedWriter( - new OutputStreamWriter(new FileOutputStream(file), Codec.UTF8.name) - ) - try { - serialize(coverage, writer, sourceRoot) - } finally { - writer.flush() - writer.close() - } - } - - def serialize( - coverage: Coverage, - writer: Writer, - sourceRoot: File - ): Unit = { - def getRelativePath(filePath: String): String = { - val base = sourceRoot.getCanonicalFile().toPath() - // NOTE: In the real world I have no idea if it's likely that you'll end - // up with weird issues on windows where the roots don't match, something - // like your root being D:/ and your file being C:/. If so this blows up. - // This happened on windows CI for me, since I was using a temp dir, and - // then trying to reletavize it off the cwd, which were in different - // drives. For now, we'll let this as is, but if 'other' has different - // root ever shows its, we'll shut that down real quick here... just not - // sure what to do in that situation yet. - val relPath = - base.relativize(new File(filePath).getCanonicalFile().toPath()) - relPath.toString - } - - def writeHeader(writer: Writer): Unit = { - writer.write( - s"""# Coverage data, format version: $coverageDataFormatVersion - |# Statement data: - |# - id - |# - source path - |# - package name - |# - class name - |# - class type (Class, Object or Trait) - |# - full class name - |# - method name - |# - start offset - |# - end offset - |# - line number - |# - symbol name - |# - tree name - |# - is branch - |# - invocations count - |# - is ignored - |# - description (can be multi-line) - |# '\f' sign - |# ------------------------------------------ - |""".stripMargin - ) - } - - def writeStatement(stmt: Statement, writer: Writer): Unit = { - writer.write(s"""${stmt.id} - |${getRelativePath(stmt.location.sourcePath)} - |${stmt.location.packageName} - |${stmt.location.className} - |${stmt.location.classType} - |${stmt.location.fullClassName} - |${stmt.location.method} - |${stmt.start} - |${stmt.end} - |${stmt.line} - |${stmt.symbolName} - |${stmt.treeName} - |${stmt.branch} - |${stmt.count} - |${stmt.ignored} - |${stmt.desc} - |\f - |""".stripMargin) - } - - writeHeader(writer) - coverage.statements.toSeq - .sortBy(_.id) - .foreach(stmt => writeStatement(stmt, writer)) - } - - def coverageFile(dataDir: File): File = coverageFile(dataDir.getAbsolutePath) - def coverageFile(dataDir: String): File = - new File(dataDir, Constants.CoverageFileName) - - def clean(dataDir: File): Unit = - findMeasurementFiles(dataDir).foreach(_.delete) - def clean(dataDir: String): Unit = clean(new File(dataDir)) - - def findMeasurementFiles(dataDir: File): Array[File] = - dataDir.listFiles(new FileFilter { - override def accept(pathname: File): Boolean = - pathname.getName.startsWith(Constants.MeasurementsPrefix) - }) -} diff --git a/reporter/src/main/scala/scoverage/reporter/CoverageAggregator.scala b/reporter/src/main/scala/scoverage/reporter/CoverageAggregator.scala index 4819cb44..8f8d6608 100644 --- a/reporter/src/main/scala/scoverage/reporter/CoverageAggregator.scala +++ b/reporter/src/main/scala/scoverage/reporter/CoverageAggregator.scala @@ -3,6 +3,7 @@ package scoverage.reporter import java.io.File import scoverage.domain.Coverage +import scoverage.serialize.Serializer object CoverageAggregator { @@ -28,10 +29,10 @@ object CoverageAggregator { var id = 0 val coverage = Coverage() dataDirs foreach { dataDir => - val coverageFile: File = IOUtils.coverageFile(dataDir) + val coverageFile: File = Serializer.coverageFile(dataDir) if (coverageFile.exists) { val subcoverage: Coverage = - Deserializer.deserialize(coverageFile, sourceRoot) + Serializer.deserialize(coverageFile, sourceRoot) val measurementFiles: Array[File] = IOUtils.findMeasurementFiles(dataDir) val measurements = IOUtils.invoked(measurementFiles.toIndexedSeq) diff --git a/reporter/src/main/scala/scoverage/reporter/IOUtils.scala b/reporter/src/main/scala/scoverage/reporter/IOUtils.scala index 87dbaf57..aae159ab 100644 --- a/reporter/src/main/scala/scoverage/reporter/IOUtils.scala +++ b/reporter/src/main/scala/scoverage/reporter/IOUtils.scala @@ -12,11 +12,6 @@ import scoverage.domain.Constants /** @author Stephen Samuel */ object IOUtils { - // TODO This is duplicated from Serilizer. We may not need them both - def coverageFile(dataDir: File): File = coverageFile(dataDir.getAbsolutePath) - def coverageFile(dataDir: String): File = - new File(dataDir, Constants.CoverageFileName) - def getTempDirectory: File = new File(getTempPath) def getTempPath: String = System.getProperty("java.io.tmpdir") diff --git a/reporter/src/test/scala/scoverage/reporter/CoverageAggregatorTest.scala b/reporter/src/test/scala/scoverage/reporter/CoverageAggregatorTest.scala index 06cfd9c0..3744c0aa 100644 --- a/reporter/src/test/scala/scoverage/reporter/CoverageAggregatorTest.scala +++ b/reporter/src/test/scala/scoverage/reporter/CoverageAggregatorTest.scala @@ -10,6 +10,7 @@ import scoverage.domain.Constants import scoverage.domain.Coverage import scoverage.domain.Location import scoverage.domain.Statement +import scoverage.serialize.Serializer class CoverageAggregatorTest extends FunSuite { @@ -37,9 +38,9 @@ class CoverageAggregatorTest extends FunSuite { coverage1.add(cov1Stmt2.copy(count = 0)) val dir1 = new File(IOUtils.getTempPath, UUID.randomUUID.toString) dir1.mkdir() - Deserializer.serialize( + Serializer.serialize( coverage1, - Deserializer.coverageFile(dir1), + Serializer.coverageFile(dir1), new File(sourceRoot) ) val measurementsFile1 = @@ -53,9 +54,9 @@ class CoverageAggregatorTest extends FunSuite { coverage2.add(cov2Stmt1) val dir2 = new File(IOUtils.getTempPath, UUID.randomUUID.toString) dir2.mkdir() - Deserializer.serialize( + Serializer.serialize( coverage2, - Deserializer.coverageFile(dir2), + Serializer.coverageFile(dir2), new File(sourceRoot) ) @@ -65,9 +66,9 @@ class CoverageAggregatorTest extends FunSuite { coverage3.add(cov3Stmt1.copy(count = 0)) val dir3 = new File(IOUtils.getTempPath, UUID.randomUUID.toString) dir3.mkdir() - Deserializer.serialize( + Serializer.serialize( coverage3, - Deserializer.coverageFile(dir3), + Serializer.coverageFile(dir3), new File(sourceRoot) ) val measurementsFile3 = diff --git a/reporter/src/main/scala/scoverage/reporter/Deserializer.scala b/serializer/src/main/scala/scoverage/serialize/Serializer.scala similarity index 90% rename from reporter/src/main/scala/scoverage/reporter/Deserializer.scala rename to serializer/src/main/scala/scoverage/serialize/Serializer.scala index aba20a3a..de862ae3 100644 --- a/reporter/src/main/scala/scoverage/reporter/Deserializer.scala +++ b/serializer/src/main/scala/scoverage/serialize/Serializer.scala @@ -1,7 +1,8 @@ -package scoverage.reporter +package scoverage.serialize import java.io.BufferedWriter import java.io.File +import java.io.FileFilter import java.io.FileOutputStream import java.io.OutputStreamWriter import java.io.Writer @@ -15,9 +16,11 @@ import scoverage.domain.Coverage import scoverage.domain.Location import scoverage.domain.Statement -object Deserializer { +object Serializer { - val coverageDataFormatVersion = "3.0" + def coverageFile(dataDir: File): File = coverageFile(dataDir.getAbsolutePath) + def coverageFile(dataDir: String): File = + new File(dataDir, Constants.CoverageFileName) // Write out coverage data to the given data directory, using the default coverage filename def serialize(coverage: Coverage, dataDir: String, sourceRoot: String): Unit = @@ -58,7 +61,7 @@ object Deserializer { def writeHeader(writer: Writer): Unit = { writer.write( - s"""# Coverage data, format version: $coverageDataFormatVersion + s"""# Coverage data, format version: ${Constants.CoverageDataFormatVersion} |# Statement data: |# - id |# - source path @@ -109,10 +112,6 @@ object Deserializer { .foreach(stmt => writeStatement(stmt, writer)) } - def coverageFile(dataDir: File): File = coverageFile(dataDir.getAbsolutePath) - def coverageFile(dataDir: String): File = - new File(dataDir, Constants.CoverageFileName) - def deserialize(file: File, sourceRoot: File): Coverage = { val source = Source.fromFile(file)(Codec.UTF8) try deserialize(source.getLines(), sourceRoot) @@ -169,7 +168,7 @@ object Deserializer { val headerFirstLine = lines.next() require( - headerFirstLine == s"# Coverage data, format version: $coverageDataFormatVersion", + headerFirstLine == s"# Coverage data, format version: ${Constants.CoverageDataFormatVersion}", "Wrong file format" ) @@ -186,4 +185,14 @@ object Deserializer { coverage } + def clean(dataDir: File): Unit = + findMeasurementFiles(dataDir).foreach(_.delete) + def clean(dataDir: String): Unit = clean(new File(dataDir)) + + def findMeasurementFiles(dataDir: File): Array[File] = + dataDir.listFiles(new FileFilter { + override def accept(pathname: File): Boolean = + pathname.getName.startsWith(Constants.MeasurementsPrefix) + }) + } diff --git a/reporter/src/test/scala/scoverage/reporter/SerializerTest.scala b/serializer/src/test/scala/scoverage/serialize/SerializerTest.scala similarity index 88% rename from reporter/src/test/scala/scoverage/reporter/SerializerTest.scala rename to serializer/src/test/scala/scoverage/serialize/SerializerTest.scala index e6963d0a..a6e10578 100644 --- a/reporter/src/test/scala/scoverage/reporter/SerializerTest.scala +++ b/serializer/src/test/scala/scoverage/serialize/SerializerTest.scala @@ -1,10 +1,11 @@ -package scoverage.reporter +package scoverage.serialize import java.io.File import java.io.StringWriter import munit.FunSuite import scoverage.domain.ClassType +import scoverage.domain.Constants import scoverage.domain.Coverage import scoverage.domain.Location import scoverage.domain.Statement @@ -36,7 +37,7 @@ class SerializerTest extends FunSuite { ) ) val expected = - s"""# Coverage data, format version: ${Deserializer.coverageDataFormatVersion} + s"""# Coverage data, format version: ${Constants.CoverageDataFormatVersion} |# Statement data: |# - id |# - source path @@ -74,14 +75,14 @@ class SerializerTest extends FunSuite { |def test : String |\f |""".stripMargin - val writer = new StringWriter() // TODO-use UTF-8 - val actual = Deserializer.serialize(coverage, writer, sourceRoot) + val writer = new StringWriter() + val actual = Serializer.serialize(coverage, writer, sourceRoot) assertEquals(expected, writer.toString) } - test("coverage should be deserializable from plain text") { + test("coverage should be eserializable from plain text") { val input = - s"""# Coverage data, format version: ${Deserializer.coverageDataFormatVersion} + s"""# Coverage data, format version: ${Constants.CoverageDataFormatVersion} |# Statement data: |# - id |# - source path @@ -142,7 +143,7 @@ class SerializerTest extends FunSuite { 1 ) ) - val coverage = Deserializer.deserialize(input, sourceRoot) + val coverage = Serializer.deserialize(input, sourceRoot) assertEquals(statements, coverage.statements.toList) } test("coverage should serialize sourcePath relatively") { @@ -169,7 +170,7 @@ class SerializerTest extends FunSuite { ) ) val expected = - s"""# Coverage data, format version: ${Deserializer.coverageDataFormatVersion} + s"""# Coverage data, format version: ${Constants.CoverageDataFormatVersion} |# Statement data: |# - id |# - source path @@ -207,14 +208,14 @@ class SerializerTest extends FunSuite { |def test : String |\f |""".stripMargin - val writer = new StringWriter() // TODO-use UTF-8 - val actual = Deserializer.serialize(coverage, writer, sourceRoot) + val writer = new StringWriter() + val actual = Serializer.serialize(coverage, writer, sourceRoot) assertEquals(expected, writer.toString) } test("coverage should deserialize sourcePath by prefixing cwd") { val input = - s"""# Coverage data, format version: ${Deserializer.coverageDataFormatVersion} + s"""# Coverage data, format version: ${Constants.CoverageDataFormatVersion} |# Statement data: |# - id |# - source path @@ -273,7 +274,7 @@ class SerializerTest extends FunSuite { 1 ) ) - val coverage = Deserializer.deserialize(input, sourceRoot) + val coverage = Serializer.deserialize(input, sourceRoot) assertEquals(statements, coverage.statements.toList) } }