From ee7a43c8fda853d49653d127c94a85a4b98caf3b Mon Sep 17 00:00:00 2001 From: Vincent de Haan Date: Thu, 10 Oct 2019 23:28:43 +0200 Subject: [PATCH 1/2] Reporting test names --- .../src/main/scala/scoverage/IOUtils.scala | 9 +++++--- .../src/main/scala/scoverage/coverage.scala | 12 ++++++---- .../src/main/scala/scoverage/plugin.scala | 22 ++++++++++++------- .../scoverage/report/StatementWriter.scala | 4 ++++ .../test/scala/scoverage/IOUtilsTest.scala | 4 ++-- .../src/main/scala/scoverage/Platform.scala | 1 + .../src/main/scala/scoverage/Platform.scala | 2 ++ .../src/main/scala/scoverage/Invoker.scala | 17 ++++++++++++-- 8 files changed, 52 insertions(+), 19 deletions(-) diff --git a/scalac-scoverage-plugin/src/main/scala/scoverage/IOUtils.scala b/scalac-scoverage-plugin/src/main/scala/scoverage/IOUtils.scala index d09ad8ca..2cfa3e1f 100644 --- a/scalac-scoverage-plugin/src/main/scala/scoverage/IOUtils.scala +++ b/scalac-scoverage-plugin/src/main/scala/scoverage/IOUtils.scala @@ -71,13 +71,16 @@ object IOUtils { val isDebugReportFile = (file: File) => file.getName == Constants.XMLReportFilenameWithDebug // loads all the invoked statement ids from the given files - def invoked(files: Seq[File]): Set[Int] = { - val acc = mutable.Set[Int]() + def invoked(files: Seq[File]): Set[(Int, String)] = { + val acc = mutable.Set[(Int, String)]() files.foreach { file => val reader = Source.fromFile(file) for ( line <- reader.getLines() ) { if (!line.isEmpty) { - acc += line.toInt + acc += (line.split(" ").toList match { + case List(idx, clazz) => (idx.toInt, clazz) + case List(idx) => (idx.toInt, "") + }) } } reader.close() diff --git a/scalac-scoverage-plugin/src/main/scala/scoverage/coverage.scala b/scalac-scoverage-plugin/src/main/scala/scoverage/coverage.scala index dfe65258..0f5297a6 100644 --- a/scalac-scoverage-plugin/src/main/scala/scoverage/coverage.scala +++ b/scalac-scoverage-plugin/src/main/scala/scoverage/coverage.scala @@ -38,8 +38,8 @@ case class Coverage() // returns the classes by least coverage def risks(limit: Int) = classes.toSeq.sortBy(_.statementCount).reverse.sortBy(_.statementCoverage).take(limit) - def apply(ids: Iterable[Int]): Unit = ids foreach invoked - def invoked(id: Int): Unit = statementsById.get(id).foreach(_.invoked()) + 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 { @@ -119,9 +119,13 @@ case class Statement(location: Location, treeName: String, branch: Boolean, var count: Int = 0, - ignored: Boolean = false) extends java.io.Serializable { + ignored: Boolean = false, + tests: mutable.Set[String] = mutable.Set[String]()) extends java.io.Serializable { def source = location.sourcePath - def invoked(): Unit = count = count + 1 + 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/plugin.scala b/scalac-scoverage-plugin/src/main/scala/scoverage/plugin.scala index 1aa04d13..11839535 100644 --- a/scalac-scoverage-plugin/src/main/scala/scoverage/plugin.scala +++ b/scalac-scoverage-plugin/src/main/scala/scoverage/plugin.scala @@ -35,6 +35,8 @@ class ScoveragePlugin(val global: Global) extends Plugin { options.dataDir = opt.substring("dataDir:".length) } else if (opt.startsWith("extraAfterPhase:") || opt.startsWith("extraBeforePhase:")) { // skip here, these flags are processed elsewhere + } else if (opt == "reportTestName") { + options.reportTestName = true } else { error("Unknown option: " + opt) } @@ -82,6 +84,7 @@ class ScoverageOptions { var excludedFiles: Seq[String] = Nil var excludedSymbols: Seq[String] = Seq("scala.reflect.api.Exprs.Expr", "scala.reflect.api.Trees.Tree", "scala.reflect.macros.Universe.Tree") var dataDir: String = IOUtils.getTempPath + var reportTestName: Boolean = false } class ScoverageInstrumentationComponent(val global: Global, extraAfterPhase: Option[String], extraBeforePhase: Option[String]) @@ -161,14 +164,17 @@ class ScoverageInstrumentationComponent(val global: Global, extraAfterPhase: Opt ), newTermName("invoked") ), - List( - Literal( - Constant(id) - ), - Literal( - Constant(options.dataDir) - ) - ) + Literal( + Constant(id) + ) :: + Literal( + Constant(options.dataDir) + ) :: + (if(options.reportTestName) + List(Literal( + Constant(true) + )) + else Nil) ) } diff --git a/scalac-scoverage-plugin/src/main/scala/scoverage/report/StatementWriter.scala b/scalac-scoverage-plugin/src/main/scala/scoverage/report/StatementWriter.scala index be800229..fa859f2e 100644 --- a/scalac-scoverage-plugin/src/main/scala/scoverage/report/StatementWriter.scala +++ b/scalac-scoverage-plugin/src/main/scala/scoverage/report/StatementWriter.scala @@ -24,6 +24,7 @@ class StatementWriter(mFile: MeasuredFile) { Pos Tree Symbol + Tests Code {mFile.statements.toSeq.sortBy(_.line).map(stmt => { @@ -44,6 +45,9 @@ class StatementWriter(mFile: MeasuredFile) { {stmt.symbolName} + + {stmt.tests.mkString(",")} + {stmt.desc} diff --git a/scalac-scoverage-plugin/src/test/scala/scoverage/IOUtilsTest.scala b/scalac-scoverage-plugin/src/test/scala/scoverage/IOUtilsTest.scala index afe0fb26..c2159a64 100644 --- a/scalac-scoverage-plugin/src/test/scala/scoverage/IOUtilsTest.scala +++ b/scalac-scoverage-plugin/src/test/scala/scoverage/IOUtilsTest.scala @@ -17,7 +17,7 @@ class IOUtilsTest extends AnyFreeSpec with OneInstancePerTest with Matchers { writer.write("1\n5\n9\n\n10\n") writer.close() val invoked = IOUtils.invoked(Seq(file)) - assert(invoked === Set(1, 5, 9, 10)) + assert(invoked === Set((1, ""), (5, ""), (9, ""), (10, ""))) file.delete() } @@ -38,7 +38,7 @@ class IOUtilsTest extends AnyFreeSpec with OneInstancePerTest with Matchers { val files = IOUtils.findMeasurementFiles(file1.getParent) val invoked = IOUtils.invoked(files.toIndexedSeq) - assert(invoked === Set(1, 2, 5, 7, 9, 10, 14)) + assert(invoked === Set((1, ""), (2, ""), (5, ""), (7, ""), (9, ""), (10, ""), (14, ""))) file1.delete() file2.delete() diff --git a/scalac-scoverage-runtime/js/src/main/scala/scoverage/Platform.scala b/scalac-scoverage-runtime/js/src/main/scala/scoverage/Platform.scala index e59ced2c..ceaea293 100644 --- a/scalac-scoverage-runtime/js/src/main/scala/scoverage/Platform.scala +++ b/scalac-scoverage-runtime/js/src/main/scala/scoverage/Platform.scala @@ -18,4 +18,5 @@ object Platform { lazy val Source = SupportSource + val isJvm = false } \ No newline at end of file diff --git a/scalac-scoverage-runtime/jvm/src/main/scala/scoverage/Platform.scala b/scalac-scoverage-runtime/jvm/src/main/scala/scoverage/Platform.scala index 452f6311..d901cb1a 100644 --- a/scalac-scoverage-runtime/jvm/src/main/scala/scoverage/Platform.scala +++ b/scalac-scoverage-runtime/jvm/src/main/scala/scoverage/Platform.scala @@ -17,4 +17,6 @@ object Platform { type FileFilter = SupportFileFilter lazy val Source = SupportSource + + val isJvm = true } \ No newline at end of file diff --git a/scalac-scoverage-runtime/shared/src/main/scala/scoverage/Invoker.scala b/scalac-scoverage-runtime/shared/src/main/scala/scoverage/Invoker.scala index dccf1ebb..9891feba 100644 --- a/scalac-scoverage-runtime/shared/src/main/scala/scoverage/Invoker.scala +++ b/scalac-scoverage-runtime/shared/src/main/scala/scoverage/Invoker.scala @@ -31,7 +31,7 @@ object Invoker { * @param id the id of the statement that was invoked * @param dataDir the directory where the measurement data is held */ - def invoked(id: Int, dataDir: String): Unit = { + def invoked(id: Int, dataDir: String, reportTestName: Boolean = false): Unit = { // [sam] we can do this simple check to save writing out to a file. // This won't work across JVMs but since there's no harm in writing out the same id multiple // times since for coverage we only care about 1 or more, (it just slows things down to @@ -55,12 +55,25 @@ object Invoker { threadFiles.set(files) } val writer = files.getOrElseUpdate(dataDir, new FileWriter(measurementFile(dataDir), true)) - writer.append(Integer.toString(id)).append("\n").flush() + // For some reason, the JS build does not print the output the correct way. I will look into this later. + if(isJvm && reportTestName) writer.append(Integer.toString(id)).append(" ").append(getCallingScalaTest).append("\n").flush() + else writer.append(Integer.toString(id)).append("\n").flush() ids.put(id, ()) } } + def getCallingScalaTest: String = { + val st = Thread.currentThread.getStackTrace + val idx = st.indexWhere{ + ste => { + val name = ste.getClassName.toLowerCase() + name.endsWith("suite") || name.endsWith("spec") || name.endsWith("test") + } + } + if(idx > 0) st(idx).getClassName else "" + } + def measurementFile(dataDir: File): File = measurementFile(dataDir.getAbsolutePath) def measurementFile(dataDir: String): File = new File(dataDir, MeasurementsPrefix + runtimeUUID + "." + Thread.currentThread.getId) From dc99882bc324e12d40b9abf730f44bbd08c5a206 Mon Sep 17 00:00:00 2001 From: Vincent de Haan Date: Fri, 11 Sep 2020 23:31:35 +0200 Subject: [PATCH 2/2] Minor changes after ScalaJS 1.0 update --- .../js/src/main/scala/scoverage/Platform.scala | 1 - .../src/main/scala/scoverage/Platform.scala | 2 -- .../src/main/scala/scoverage/Invoker.scala | 18 ++++++------------ 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/scalac-scoverage-runtime/js/src/main/scala/scoverage/Platform.scala b/scalac-scoverage-runtime/js/src/main/scala/scoverage/Platform.scala index ceaea293..e59ced2c 100644 --- a/scalac-scoverage-runtime/js/src/main/scala/scoverage/Platform.scala +++ b/scalac-scoverage-runtime/js/src/main/scala/scoverage/Platform.scala @@ -18,5 +18,4 @@ object Platform { lazy val Source = SupportSource - val isJvm = false } \ No newline at end of file diff --git a/scalac-scoverage-runtime/jvm/src/main/scala/scoverage/Platform.scala b/scalac-scoverage-runtime/jvm/src/main/scala/scoverage/Platform.scala index d901cb1a..452f6311 100644 --- a/scalac-scoverage-runtime/jvm/src/main/scala/scoverage/Platform.scala +++ b/scalac-scoverage-runtime/jvm/src/main/scala/scoverage/Platform.scala @@ -17,6 +17,4 @@ object Platform { type FileFilter = SupportFileFilter lazy val Source = SupportSource - - val isJvm = true } \ No newline at end of file diff --git a/scalac-scoverage-runtime/shared/src/main/scala/scoverage/Invoker.scala b/scalac-scoverage-runtime/shared/src/main/scala/scoverage/Invoker.scala index 9891feba..8310c3d5 100644 --- a/scalac-scoverage-runtime/shared/src/main/scala/scoverage/Invoker.scala +++ b/scalac-scoverage-runtime/shared/src/main/scala/scoverage/Invoker.scala @@ -56,23 +56,17 @@ object Invoker { } val writer = files.getOrElseUpdate(dataDir, new FileWriter(measurementFile(dataDir), true)) - // For some reason, the JS build does not print the output the correct way. I will look into this later. - if(isJvm && reportTestName) writer.append(Integer.toString(id)).append(" ").append(getCallingScalaTest).append("\n").flush() + if(reportTestName) writer.append(Integer.toString(id)).append(" ").append(getCallingScalaTest).append("\n").flush() else writer.append(Integer.toString(id)).append("\n").flush() ids.put(id, ()) } } - def getCallingScalaTest: String = { - val st = Thread.currentThread.getStackTrace - val idx = st.indexWhere{ - ste => { - val name = ste.getClassName.toLowerCase() - name.endsWith("suite") || name.endsWith("spec") || name.endsWith("test") - } - } - if(idx > 0) st(idx).getClassName else "" - } + def getCallingScalaTest: String = + Thread.currentThread.getStackTrace + .map(_.getClassName.toLowerCase) + .find(name => name.endsWith("suite") || name.endsWith("spec") || name.endsWith("test")) + .getOrElse("") def measurementFile(dataDir: File): File = measurementFile(dataDir.getAbsolutePath) def measurementFile(dataDir: String): File = new File(dataDir, MeasurementsPrefix + runtimeUUID + "." + Thread.currentThread.getId)