Skip to content

Commit 7e6e67e

Browse files
committed
Merge pull request #71 from tmandke/master
Add support for multi module project in runtime
2 parents 49b7e56 + e2958d6 commit 7e6e67e

File tree

2 files changed

+58
-10
lines changed

2 files changed

+58
-10
lines changed

scalac-scoverage-runtime/src/main/scala/scoverage/Invoker.scala

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import scala.io.Source
1010
object Invoker {
1111

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

1616
/**
1717
* We record that the given id has been invoked by appending its id to the coverage
@@ -34,17 +34,18 @@ object Invoker {
3434
// times since for coverage we only care about 1 or more, (it just slows things down to
3535
// do it more than once), anything we can do to help is good. This helps especially with code
3636
// that is executed many times quickly, eg tight loops.
37-
if (!ids.contains(id)) {
37+
if (!ids.contains(dataDir, id)) {
3838
// Each thread writes to a separate measurement file, to reduce contention
3939
// and because file appends via FileWriter are not atomic on Windows.
40-
var writer = threadFile.get()
41-
if (writer == null) {
42-
val file = measurementFile(dataDir)
43-
writer = new FileWriter(file, true)
44-
threadFile.set(writer)
45-
}
40+
var files = threadFiles.get()
41+
if (files == null)
42+
files = TrieMap.empty[String, FileWriter]
43+
threadFiles.set(files)
44+
45+
val writer = files.getOrElseUpdate(dataDir, new FileWriter(measurementFile(dataDir), true))
4646
writer.append(id.toString + '\n').flush()
47-
ids.put(id, ())
47+
48+
ids.put((dataDir, id), ())
4849
}
4950
}
5051

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package scoverage
2+
3+
import java.io.File
4+
5+
import org.scalatest.{BeforeAndAfter, FunSuite}
6+
7+
/**
8+
* Verify that [[Invoker.invoked()]] can handle a multi-module project
9+
*/
10+
class InvokerMultiModuleTest extends FunSuite with BeforeAndAfter {
11+
12+
val measurementDir = Array(new File("invoker-test.measurement0"), new File("invoker-test.measurement1"))
13+
14+
before {
15+
deleteMeasurementFiles()
16+
measurementDir.foreach(_.mkdirs)
17+
}
18+
19+
test("calling Invoker.invoked on with different directories puts mesurments in different directories") {
20+
21+
val testIds: Set[Int] = (1 to 10).toSet
22+
23+
testIds.map { i: Int => Invoker.invoked(i, measurementDir(i % 2).toString) }
24+
25+
// Verify measurements went to correct directory
26+
val measurementFiles0 = Invoker.findMeasurementFiles(measurementDir(0))
27+
val idsFromFile0 = Invoker.invoked(measurementFiles0).toSet
28+
29+
idsFromFile0 === testIds.filter { i: Int => i % 2 == 0 }
30+
31+
val measurementFiles1 = Invoker.findMeasurementFiles(measurementDir(0))
32+
val idsFromFile1 = Invoker.invoked(measurementFiles1).toSet
33+
idsFromFile1 === testIds.filter { i: Int => i % 2 == 1 }
34+
}
35+
36+
after {
37+
deleteMeasurementFiles()
38+
measurementDir.foreach(_.delete)
39+
}
40+
41+
private def deleteMeasurementFiles(): Unit = {
42+
measurementDir.foreach((md) => {
43+
if (md.isDirectory)
44+
md.listFiles().foreach(_.delete())
45+
})
46+
}
47+
}

0 commit comments

Comments
 (0)