Skip to content

Commit 66ad0cd

Browse files
committed
Support compiling multiple files in coverage tests
1 parent 817d72f commit 66ad0cd

File tree

16 files changed

+236
-22
lines changed

16 files changed

+236
-22
lines changed

compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala

+28-13
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,27 @@ class CoverageTests:
5454
lines
5555
end fixWindowsPaths
5656

57-
def runOnFile(p: Path): Boolean =
58-
scalaFile.matches(p) &&
59-
(Properties.testsFilter.isEmpty || Properties.testsFilter.exists(p.toString.contains))
57+
def runOnFileOrDir(p: Path): Boolean =
58+
(scalaFile.matches(p) || Files.isDirectory(p))
59+
&& (p != dir)
60+
&& (Properties.testsFilter.isEmpty || Properties.testsFilter.exists(p.toString.contains))
61+
62+
Files.walk(dir, 1).filter(runOnFileOrDir).forEach(path => {
63+
// measurement files only exist in the "run" category
64+
// as these are generated at runtime by the scala.runtime.coverage.Invoker
65+
val (targetDir, expectFile, expectMeasurementFile) =
66+
if Files.isDirectory(path) then
67+
val dirName = path.getFileName().toString
68+
assert(!Files.walk(path).filter(scalaFile.matches(_)).toList.isEmpty, s"No scala files found in test directory: ${path}")
69+
val targetDir = computeCoverageInTmp(path, isDirectory = true, dir, run)
70+
(targetDir, path.resolve(s"test.scoverage.check"), path.resolve(s"test.measurement.check"))
71+
else
72+
val fileName = path.getFileName.toString.stripSuffix(".scala")
73+
val targetDir = computeCoverageInTmp(path, isDirectory = false, dir, run)
74+
(targetDir, path.resolveSibling(s"${fileName}.scoverage.check"), path.resolveSibling(s"${fileName}.measurement.check"))
6075

61-
Files.walk(dir).filter(runOnFile).forEach(path => {
62-
val fileName = path.getFileName.toString.stripSuffix(".scala")
63-
val targetDir = computeCoverageInTmp(path, dir, run)
6476
val targetFile = targetDir.resolve(s"scoverage.coverage")
65-
val expectFile = path.resolveSibling(s"$fileName.scoverage.check")
77+
6678
if updateCheckFiles then
6779
Files.copy(targetFile, expectFile, StandardCopyOption.REPLACE_EXISTING)
6880
else
@@ -72,9 +84,6 @@ class CoverageTests:
7284
val instructions = FileDiff.diffMessage(expectFile.toString, targetFile.toString)
7385
fail(s"Coverage report differs from expected data.\n$instructions")
7486

75-
// measurement files only exist in the "run" category
76-
// as these are generated at runtime by the scala.runtime.coverage.Invoker
77-
val expectMeasurementFile = path.resolveSibling(s"$fileName.measurement.check")
7887
if run && Files.exists(expectMeasurementFile) then
7988

8089
// Note that this assumes that the test invoked was single threaded,
@@ -95,14 +104,20 @@ class CoverageTests:
95104
})
96105

97106
/** Generates the coverage report for the given input file, in a temporary directory. */
98-
def computeCoverageInTmp(inputFile: Path, sourceRoot: Path, run: Boolean)(using TestGroup): Path =
107+
def computeCoverageInTmp(inputFile: Path, isDirectory: Boolean, sourceRoot: Path, run: Boolean)(using TestGroup): Path =
99108
val target = Files.createTempDirectory("coverage")
100109
val options = defaultOptions.and("-Ycheck:instrumentCoverage", "-coverage-out", target.toString, "-sourceroot", sourceRoot.toString)
101110
if run then
102-
val test = compileDir(inputFile.getParent.toString, options)
111+
val path = if isDirectory then inputFile.toString else inputFile.getParent.toString
112+
val test = compileDir(path, options)
113+
test.checkFilePaths.foreach { checkFilePath =>
114+
assert(checkFilePath.exists, s"Expected checkfile for $path $checkFilePath does not exist.")
115+
}
103116
test.checkRuns()
104117
else
105-
val test = compileFile(inputFile.toString, options)
118+
val test =
119+
if isDirectory then compileDir(inputFile.toString, options)
120+
else compileFile(inputFile.toString, options)
106121
test.checkCompile()
107122
target
108123

compiler/test/dotty/tools/vulpix/ParallelTesting.scala

+15-9
Original file line numberDiff line numberDiff line change
@@ -258,15 +258,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
258258
* For a given test source, returns a check file against which the result of the test run
259259
* should be compared. Is used by implementations of this trait.
260260
*/
261-
final def checkFile(testSource: TestSource): Option[JFile] = (testSource match {
262-
case ts: JointCompilationSource =>
263-
ts.files.collectFirst {
264-
case f if !f.isDirectory =>
265-
new JFile(f.getPath.replaceFirst("\\.(scala|java)$", ".check"))
266-
}
267-
case ts: SeparateCompilationSource =>
268-
Option(new JFile(ts.dir.getPath + ".check"))
269-
}).filter(_.exists)
261+
final def checkFile(testSource: TestSource): Option[JFile] = (CompilationLogic.checkFilePath(testSource)).filter(_.exists)
270262

271263
/**
272264
* Checks if the given actual lines are the same as the ones in the check file.
@@ -343,6 +335,18 @@ trait ParallelTesting extends RunnerOrchestration { self =>
343335
}
344336
}
345337

338+
object CompilationLogic {
339+
private[ParallelTesting] def checkFilePath(testSource: TestSource) = testSource match {
340+
case ts: JointCompilationSource =>
341+
ts.files.collectFirst {
342+
case f if !f.isDirectory =>
343+
new JFile(f.getPath.replaceFirst("\\.(scala|java)$", ".check"))
344+
}
345+
case ts: SeparateCompilationSource =>
346+
Option(new JFile(ts.dir.getPath + ".check"))
347+
}
348+
}
349+
346350
/** Each `Test` takes the `testSources` and performs the compilation and assertions
347351
* according to the implementing class "neg", "run" or "pos".
348352
*/
@@ -1157,6 +1161,8 @@ trait ParallelTesting extends RunnerOrchestration { self =>
11571161
def this(targets: List[TestSource]) =
11581162
this(targets, 1, true, None, false, false)
11591163

1164+
def checkFilePaths: List[JFile] = targets.map(CompilationLogic.checkFilePath).flatten
1165+
11601166
def copy(targets: List[TestSource],
11611167
times: Int = times,
11621168
shouldDelete: Boolean = shouldDelete,
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
List()
2+
List(abc, def)
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Baz
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
>>> hello <<<
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import scala.quoted.{Expr, Quotes}
2+
3+
object Macro:
4+
inline def decorate(inline s: String): String = ${ decorateQuotes('s) }
5+
def decorateQuotes(s: Expr[String])(using Quotes): Expr[String] = '{ ">>> " + $s + " <<<" }
6+
7+
object Greeting:
8+
def greet() = "hello"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
object Test:
2+
def main(args: Array[String]): Unit =
3+
println(Macro.decorate(Greeting.greet()))
4+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
# Coverage data, format version: 3.0
2+
# Statement data:
3+
# - id
4+
# - source path
5+
# - package name
6+
# - class name
7+
# - class type (Class, Object or Trait)
8+
# - full class name
9+
# - method name
10+
# - start offset
11+
# - end offset
12+
# - line number
13+
# - symbol name
14+
# - tree name
15+
# - is branch
16+
# - invocations count
17+
# - is ignored
18+
# - description (can be multi-line)
19+
# ' ' sign
20+
# ------------------------------------------
21+
0
22+
macro-suspend/Macro.scala
23+
<empty>
24+
Macro
25+
Object
26+
<empty>.Macro
27+
decorateQuotes
28+
195
29+
215
30+
5
31+
unpickleExprV2
32+
Apply
33+
false
34+
0
35+
false
36+
">>> " + $s + " <<<"
37+
38+
1
39+
macro-suspend/Macro.scala
40+
<empty>
41+
Macro
42+
Object
43+
<empty>.Macro
44+
$anonfun
45+
205
46+
206
47+
5
48+
apply
49+
Apply
50+
false
51+
0
52+
false
53+
s
54+
55+
2
56+
macro-suspend/Macro.scala
57+
<empty>
58+
Macro
59+
Object
60+
<empty>.Macro
61+
decorateQuotes
62+
126
63+
144
64+
5
65+
decorateQuotes
66+
DefDef
67+
false
68+
0
69+
false
70+
def decorateQuotes
71+
72+
3
73+
macro-suspend/Macro.scala
74+
<empty>
75+
Greeting
76+
Object
77+
<empty>.Greeting
78+
greet
79+
238
80+
247
81+
8
82+
greet
83+
DefDef
84+
false
85+
0
86+
false
87+
def greet
88+
89+
4
90+
macro-suspend/Test.scala
91+
<empty>
92+
Test
93+
Object
94+
<empty>.Test
95+
main
96+
57
97+
98
98+
3
99+
println
100+
Apply
101+
false
102+
0
103+
false
104+
println(Macro.decorate(Greeting.greet()))
105+
106+
5
107+
macro-suspend/Test.scala
108+
<empty>
109+
Test
110+
Object
111+
<empty>.Test
112+
main
113+
65
114+
97
115+
3
116+
+
117+
Apply
118+
false
119+
0
120+
false
121+
Macro.decorate(Greeting.greet())
122+
123+
6
124+
macro-suspend/Test.scala
125+
<empty>
126+
Test
127+
Object
128+
<empty>.Test
129+
main
130+
65
131+
97
132+
3
133+
+
134+
Apply
135+
false
136+
0
137+
false
138+
Macro.decorate(Greeting.greet())
139+
140+
7
141+
macro-suspend/Test.scala
142+
<empty>
143+
Test
144+
Object
145+
<empty>.Test
146+
main
147+
80
148+
96
149+
3
150+
greet
151+
Apply
152+
false
153+
0
154+
false
155+
Greeting.greet()
156+
157+
8
158+
macro-suspend/Test.scala
159+
<empty>
160+
Test
161+
Object
162+
<empty>.Test
163+
main
164+
15
165+
23
166+
2
167+
main
168+
DefDef
169+
false
170+
0
171+
false
172+
def main
173+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
first0
2+
first0
3+
first3

0 commit comments

Comments
 (0)