Skip to content

Reporting test names #282

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
12 changes: 8 additions & 4 deletions scalac-scoverage-plugin/src/main/scala/scoverage/coverage.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
}

Expand Down
22 changes: 14 additions & 8 deletions scalac-scoverage-plugin/src/main/scala/scoverage/plugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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])
Expand Down Expand Up @@ -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)
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class StatementWriter(mFile: MeasuredFile) {
<th>Pos</th>
<th>Tree</th>
<th>Symbol</th>
<th>Tests</th>
<th>Code</th>
</tr>{mFile.statements.toSeq.sortBy(_.line).map(stmt => {
<tr>
Expand All @@ -44,6 +45,9 @@ class StatementWriter(mFile: MeasuredFile) {
<td>
{stmt.symbolName}
</td>
<td>
{stmt.tests.mkString(",")}
</td>
<td style={cellStyle(stmt.isInvoked)}>
{stmt.desc}
</td>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
Expand All @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -55,12 +55,19 @@ object Invoker {
threadFiles.set(files)
}
val writer = files.getOrElseUpdate(dataDir, new FileWriter(measurementFile(dataDir), true))
writer.append(Integer.toString(id)).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 =
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)

Expand Down