From fe8e794fc47b12adb0d032f2e15135573d4c5aca Mon Sep 17 00:00:00 2001 From: Grzegorz Slowikowski Date: Sun, 11 Nov 2018 14:47:55 +0100 Subject: [PATCH] Aggregate raw coverage data, not XML reports --- .../src/main/scala/scoverage/IOUtils.scala | 9 ++- .../scoverage/report/CoverageAggregator.scala | 36 +++++----- .../scoverage/report/ScoverageXmlReader.scala | 61 ----------------- .../scoverage/CoverageAggregatorTest.scala | 38 ++++++----- .../test/scala/scoverage/IOUtilsTest.scala | 33 ++++------ .../scoverage/ScoverageXmlReaderTest.scala | 65 ------------------- 6 files changed, 60 insertions(+), 182 deletions(-) delete mode 100644 scalac-scoverage-plugin/src/main/scala/scoverage/report/ScoverageXmlReader.scala delete mode 100644 scalac-scoverage-plugin/src/test/scala/scoverage/ScoverageXmlReaderTest.scala diff --git a/scalac-scoverage-plugin/src/main/scala/scoverage/IOUtils.scala b/scalac-scoverage-plugin/src/main/scala/scoverage/IOUtils.scala index 409eb81c..d09ad8ca 100644 --- a/scalac-scoverage-plugin/src/main/scala/scoverage/IOUtils.scala +++ b/scalac-scoverage-plugin/src/main/scala/scoverage/IOUtils.scala @@ -54,10 +54,13 @@ object IOUtils { override def accept(pathname: File): Boolean = pathname.getName.startsWith(Constants.MeasurementsPrefix) }) - def reportFileSearch(baseDir: File, condition: File => Boolean): Seq[File] = { + def scoverageDataDirsSearch(baseDir: File): Seq[File] = { + def directoryFilter = new FileFilter { + override def accept(pathname: File): Boolean = pathname.isDirectory + } def search(file: File): Seq[File] = file match { - case dir if dir.isDirectory => dir.listFiles().toSeq.map(search).flatten - case f if isReportFile(f) => Seq(f) + case dir if dir.isDirectory && dir.getName == Constants.DataDir => Seq(dir) + case dir if dir.isDirectory => dir.listFiles(directoryFilter).toSeq.flatMap(search) case _ => Nil } search(baseDir) diff --git a/scalac-scoverage-plugin/src/main/scala/scoverage/report/CoverageAggregator.scala b/scalac-scoverage-plugin/src/main/scala/scoverage/report/CoverageAggregator.scala index c6be18b4..cbd70dbc 100644 --- a/scalac-scoverage-plugin/src/main/scala/scoverage/report/CoverageAggregator.scala +++ b/scalac-scoverage-plugin/src/main/scala/scoverage/report/CoverageAggregator.scala @@ -2,35 +2,39 @@ package scoverage.report import java.io.File -import scoverage.{Coverage, IOUtils} +import scoverage.{Coverage, IOUtils, Serializer} object CoverageAggregator { + @deprecated("1.4.0", "Used only by gradle-scoverage plugin") def aggregate(baseDir: File, clean: Boolean): Option[Coverage] = { - val files = IOUtils.reportFileSearch(baseDir, IOUtils.isReportFile) - aggregate(files, clean) + aggregate(IOUtils.scoverageDataDirsSearch(baseDir)) } - def aggregate(files: Seq[File], clean: Boolean): Option[Coverage] = { - println(s"[info] Found ${files.size} subproject report files [${files.mkString(",")}]") - if (files.size > 0) { - val coverage = aggregatedCoverage(files) - if (clean) files foreach (_.delete) - Some(coverage) + def aggregate(dataDirs: Seq[File]): Option[Coverage] = { + println(s"[info] Found ${dataDirs.size} subproject scoverage data directories [${dataDirs.mkString(",")}]") + if (dataDirs.size > 0) { + Some(aggregatedCoverage(dataDirs)) } else { None } } - def aggregatedCoverage(files: Seq[File]): Coverage = { + def aggregatedCoverage(dataDirs: Seq[File]): Coverage = { var id = 0 val coverage = Coverage() - files foreach { file => - val subcoverage = ScoverageXmlReader.read(file) - subcoverage.statements foreach { stmt => - // need to ensure all the ids are unique otherwise the coverage object will have stmt collisions - id = id + 1 - coverage add stmt.copy(id = id) + dataDirs foreach { dataDir => + val coverageFile: File = Serializer.coverageFile(dataDir) + if (coverageFile.exists) { + val subcoverage: Coverage = Serializer.deserialize(coverageFile) + val measurementFiles: Array[File] = IOUtils.findMeasurementFiles(dataDir) + val measurements = IOUtils.invoked(measurementFiles) + subcoverage.apply(measurements) + subcoverage.statements foreach { stmt => + // need to ensure all the ids are unique otherwise the coverage object will have stmt collisions + id = id + 1 + coverage add stmt.copy(id = id) + } } } coverage diff --git a/scalac-scoverage-plugin/src/main/scala/scoverage/report/ScoverageXmlReader.scala b/scalac-scoverage-plugin/src/main/scala/scoverage/report/ScoverageXmlReader.scala deleted file mode 100644 index b104695b..00000000 --- a/scalac-scoverage-plugin/src/main/scala/scoverage/report/ScoverageXmlReader.scala +++ /dev/null @@ -1,61 +0,0 @@ -package scoverage.report - -import java.io.File - -import scoverage._ - -import scala.xml.XML - -/** - * Reads in an Scoverage XML report and converts to a Coverage instance. - */ -object ScoverageXmlReader { - - def read(file: File): Coverage = { - val xml = XML.loadFile(file) - - var id = 0 - val coverage = Coverage() - (xml \\ "statement") foreach { node => - - val source = node \ "@source" - val pkg = node \ "@package" - val classname = node \ "@class" - val classType = node \ "@class-type" - val fullClassName = node \ "@full-class-name" - val method = node \ "@method" - val start = node \ "@start" - val end = node \ "@end" - val line = node \ "@line" - val branch = node \ "@branch" - val count = node \ "@invocation-count" - val symbolName = node \ "@symbol" - val treeName = node \ "@tree" - val ignored = node \ "@ignored" - - val location = Location(pkg.text, - classname.text, - fullClassName.text, - ClassType fromString classType.text, - method.text, - source.text) - - id = id + 1 - - coverage add Statement( - location, - id, - start.text.toInt, - end.text.toInt, - line.text.toInt, - "", // not interested in debug info when re-creating - symbolName.text, - treeName.text, - branch.text.toBoolean, - count.text.toInt, - ignored.text.toBoolean - ) - } - coverage - } -} diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/CoverageAggregatorTest.scala b/scalac-scoverage-plugin/src/test/scala/scoverage/CoverageAggregatorTest.scala index e3daac1b..8ff5c807 100644 --- a/scalac-scoverage-plugin/src/test/scala/scoverage/CoverageAggregatorTest.scala +++ b/scalac-scoverage-plugin/src/test/scala/scoverage/CoverageAggregatorTest.scala @@ -1,10 +1,10 @@ package scoverage -import java.io.File +import java.io.{File, FileWriter} import java.util.UUID import org.scalatest.{FreeSpec, Matchers} -import scoverage.report.{CoverageAggregator, ScoverageXmlWriter} +import scoverage.report.CoverageAggregator class CoverageAggregatorTest extends FreeSpec with Matchers { @@ -23,33 +23,41 @@ class CoverageAggregatorTest extends FreeSpec with Matchers { "methlab", source) + val cov1Stmt1 = Statement(location, 1, 155, 176, 4, "", "", "", true, 1) + val cov1Stmt2 = Statement(location, 2, 200, 300, 5, "", "", "", false, 1) val coverage1 = Coverage() - coverage1.add(Statement(location, 1, 155, 176, 4, "", "", "", true, 1)) - coverage1.add(Statement(location, 2, 200, 300, 5, "", "", "", false, 2)) + coverage1.add(cov1Stmt1.copy(count = 0)) + coverage1.add(cov1Stmt2.copy(count = 0)) val dir1 = new File(IOUtils.getTempPath, UUID.randomUUID.toString) dir1.mkdir() - new ScoverageXmlWriter(sourceRoot, dir1, false).write(coverage1) + Serializer.serialize(coverage1, Serializer.coverageFile(dir1)) + val measurementsFile1 = new File(dir1, s"${Constants.MeasurementsPrefix}1") + val measurementsFile1Writer = new FileWriter(measurementsFile1) + measurementsFile1Writer.write("1\n2\n") + measurementsFile1Writer.close() + val cov2Stmt1 = Statement(location, 1, 95, 105, 19, "", "", "", false, 0) val coverage2 = Coverage() - coverage2.add(Statement(location, 1, 95, 105, 19, "", "", "", false, 0)) + coverage2.add(cov2Stmt1) val dir2 = new File(IOUtils.getTempPath, UUID.randomUUID.toString) dir2.mkdir() - new ScoverageXmlWriter(sourceRoot, dir2, false).write(coverage2) + Serializer.serialize(coverage2, Serializer.coverageFile(dir2)) + val cov3Stmt1 = Statement(location, 2, 14, 1515, 544, "", "", "", false, 1) val coverage3 = Coverage() - coverage3.add(Statement(location, 2, 14, 1515, 544, "", "", "", false, 1)) + coverage3.add(cov3Stmt1.copy(count = 0)) val dir3 = new File(IOUtils.getTempPath, UUID.randomUUID.toString) dir3.mkdir() - new ScoverageXmlWriter(sourceRoot, dir3, false).write(coverage3) + Serializer.serialize(coverage3, Serializer.coverageFile(dir3)) + val measurementsFile3 = new File(dir3, s"${Constants.MeasurementsPrefix}1") + val measurementsFile3Writer = new FileWriter(measurementsFile3) + measurementsFile3Writer.write("2\n") + measurementsFile3Writer.close() - val aggregated = CoverageAggregator.aggregatedCoverage( - Seq(IOUtils.reportFile(dir1, debug = false), - IOUtils.reportFile(dir2, debug = false), - IOUtils.reportFile(dir3, debug = false)) - ) + val aggregated = CoverageAggregator.aggregatedCoverage(Seq(dir1, dir2, dir3)) aggregated.statements.toSet.size shouldBe 4 aggregated.statements.map(_.copy(id = 0)).toSet shouldBe - (coverage1.statements ++ coverage2.statements ++ coverage3.statements).map(_.copy(id = 0)).toSet + Set(cov1Stmt1, cov1Stmt2, cov2Stmt1, cov3Stmt1).map(_.copy(id = 0)) } } } diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/IOUtilsTest.scala b/scalac-scoverage-plugin/src/test/scala/scoverage/IOUtilsTest.scala index bd82f33b..c340f31b 100644 --- a/scalac-scoverage-plugin/src/test/scala/scoverage/IOUtilsTest.scala +++ b/scalac-scoverage-plugin/src/test/scala/scoverage/IOUtilsTest.scala @@ -42,34 +42,23 @@ class IOUtilsTest extends FreeSpec with MockitoSugar with OneInstancePerTest wit file1.delete() file2.delete() } - "should deep search for report files" in { + "should deep search for scoverage-data directories" in { // create new folder to hold all our data val base = new File(IOUtils.getTempDirectory, UUID.randomUUID.toString) - base.mkdir() shouldBe true - val file1 = new File(base, Constants.XMLReportFilename) - val writer1 = new FileWriter(file1) - writer1.write("1\n3\n5\n\n\n7\n") - writer1.close() + val dataDir1 = new File(base, Constants.DataDir) + dataDir1.mkdirs() shouldBe true - val file2 = new File(base, UUID.randomUUID.toString + "/" + Constants.XMLReportFilename) - file2.getParentFile.mkdir() - val writer2 = new FileWriter(file2) - writer2.write("2\n4\n6\n\n8\n") - writer2.close() + val subDir = new File(base, UUID.randomUUID.toString) + val dataDir2 = new File(subDir, Constants.DataDir) + dataDir2.mkdirs() shouldBe true - val file3 = new File(file2.getParentFile, UUID.randomUUID.toString + "/" + Constants.XMLReportFilename) - file3.getParentFile.mkdir() - val writer3 = new FileWriter(file3) - writer3.write("11\n20\n30\n\n44\n") - writer3.close() + val subSubDir = new File(subDir, UUID.randomUUID.toString) + val dataDir3 = new File(subSubDir, Constants.DataDir) + dataDir3.mkdirs() shouldBe true - val files = IOUtils.reportFileSearch(base, IOUtils.isReportFile) - val invoked = IOUtils.invoked(files) - assert(invoked === Set(1, 2, 3, 4, 5, 6, 7, 8, 11, 20, 30, 44)) - - file1.delete() - file2.delete() + val dataDirs = IOUtils.scoverageDataDirsSearch(base) + dataDirs should contain only (dataDir1, dataDir2, dataDir3) } } } diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/ScoverageXmlReaderTest.scala b/scalac-scoverage-plugin/src/test/scala/scoverage/ScoverageXmlReaderTest.scala deleted file mode 100644 index 84406d73..00000000 --- a/scalac-scoverage-plugin/src/test/scala/scoverage/ScoverageXmlReaderTest.scala +++ /dev/null @@ -1,65 +0,0 @@ -package scoverage - -import java.io.File -import java.util.UUID - -import org.scalatest.{FreeSpec, Matchers} -import scoverage.report.{ScoverageXmlReader, ScoverageXmlWriter} - -class ScoverageXmlReaderTest extends FreeSpec with Matchers { - - // Let current directory be our source root - private val sourceRoot = new File(".") - private def canonicalPath(fileName: String) = new File(sourceRoot, fileName).getCanonicalPath - - "scoverage xml reader" - { - "should read output from ScoverageXmlWriter" in { - - val coverage = Coverage() - - coverage.add(Statement( - Location("com.scoverage", - "Test", - "com.scoverage.TopLevel.Test", - ClassType.Object, - "somemeth", - canonicalPath("com/scoverage/class.scala")), - 14, - 155, - 176, - 4, - "", - "", - "", - true, - 2)) - - coverage.add(Statement( - Location("com.scoverage.foo", - "ServiceState", - "com.scoverage.foo.Service.ServiceState", - ClassType.Trait, - "methlab", - canonicalPath("com/scoverage/foo/class.scala")), - 16, - 95, - 105, - 19, - "", - "", - "", - false, - 0)) - - val temp = new File(IOUtils.getTempPath, UUID.randomUUID.toString) - temp.mkdir() - temp.deleteOnExit() - new ScoverageXmlWriter(sourceRoot, temp, false).write(coverage) - - val actual = ScoverageXmlReader.read(IOUtils.reportFile(temp, debug = false)) - // we don't care about the statement ids as the will change on reading back in - actual.statements.map(_.copy(id = 0)).toSet shouldEqual coverage.statements.map(_.copy(id = 0)).toSet - - } - } -}