Skip to content

Commit

Permalink
Merge pull request #71 from tmandke/master
Browse files Browse the repository at this point in the history
Add support for multi module project in runtime
  • Loading branch information
sksamuel committed Nov 28, 2014
2 parents 49b7e56 + e2958d6 commit 7e6e67e
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 10 deletions.
21 changes: 11 additions & 10 deletions scalac-scoverage-runtime/src/main/scala/scoverage/Invoker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import scala.io.Source
object Invoker {

private val MeasurementsPrefix = "scoverage.measurements."
private val threadFile = new ThreadLocal[FileWriter]
private val ids = TrieMap.empty[Int, Any]
private val threadFiles = new ThreadLocal[TrieMap[String, FileWriter]]
private val ids = TrieMap.empty[(String, Int), Any]

/**
* We record that the given id has been invoked by appending its id to the coverage
Expand All @@ -34,17 +34,18 @@ object Invoker {
// times since for coverage we only care about 1 or more, (it just slows things down to
// do it more than once), anything we can do to help is good. This helps especially with code
// that is executed many times quickly, eg tight loops.
if (!ids.contains(id)) {
if (!ids.contains(dataDir, id)) {
// Each thread writes to a separate measurement file, to reduce contention
// and because file appends via FileWriter are not atomic on Windows.
var writer = threadFile.get()
if (writer == null) {
val file = measurementFile(dataDir)
writer = new FileWriter(file, true)
threadFile.set(writer)
}
var files = threadFiles.get()
if (files == null)
files = TrieMap.empty[String, FileWriter]
threadFiles.set(files)

val writer = files.getOrElseUpdate(dataDir, new FileWriter(measurementFile(dataDir), true))
writer.append(id.toString + '\n').flush()
ids.put(id, ())

ids.put((dataDir, id), ())
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package scoverage

import java.io.File

import org.scalatest.{BeforeAndAfter, FunSuite}

/**
* Verify that [[Invoker.invoked()]] can handle a multi-module project
*/
class InvokerMultiModuleTest extends FunSuite with BeforeAndAfter {

val measurementDir = Array(new File("invoker-test.measurement0"), new File("invoker-test.measurement1"))

before {
deleteMeasurementFiles()
measurementDir.foreach(_.mkdirs)
}

test("calling Invoker.invoked on with different directories puts mesurments in different directories") {

val testIds: Set[Int] = (1 to 10).toSet

testIds.map { i: Int => Invoker.invoked(i, measurementDir(i % 2).toString) }

// Verify measurements went to correct directory
val measurementFiles0 = Invoker.findMeasurementFiles(measurementDir(0))
val idsFromFile0 = Invoker.invoked(measurementFiles0).toSet

idsFromFile0 === testIds.filter { i: Int => i % 2 == 0 }

val measurementFiles1 = Invoker.findMeasurementFiles(measurementDir(0))
val idsFromFile1 = Invoker.invoked(measurementFiles1).toSet
idsFromFile1 === testIds.filter { i: Int => i % 2 == 1 }
}

after {
deleteMeasurementFiles()
measurementDir.foreach(_.delete)
}

private def deleteMeasurementFiles(): Unit = {
measurementDir.foreach((md) => {
if (md.isDirectory)
md.listFiles().foreach(_.delete())
})
}
}

0 comments on commit 7e6e67e

Please sign in to comment.