Skip to content

Commit 32e538d

Browse files
committed
Add DebugStepAssert and parsing
1 parent 62e0f40 commit 32e538d

13 files changed

+135
-30
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package dotty.tools.debug
2+
3+
import scala.util.Using
4+
import scala.io.Source
5+
import java.nio.charset.StandardCharsets
6+
import scala.io.Codec
7+
import dotty.tools.io.JFile
8+
import java.nio.file.Files
9+
import dotty.tools.readLines
10+
11+
/**
12+
* A debug step and an associated assertion to validate the step.
13+
* A sequence of DebugStepAssert is parsed from the check file in tests/debug
14+
*/
15+
private[debug] case class DebugStepAssert[T](step: DebugStep[T], assert: T => Unit)
16+
17+
private[debug] object DebugStepAssert:
18+
import DebugStep.*
19+
def parseCheckFile(checkFile: JFile): Seq[DebugStepAssert[?]] =
20+
val sym = "[a-zA-Z0-9$.]+"
21+
val line = "\\d+"
22+
val break = s"break ($sym) ($line)".r
23+
val step = s"step ($sym|$line)".r
24+
val next = s"next ($sym|$line)".r
25+
val comment = "// .*".r
26+
val empty = "\\w*".r
27+
readLines(checkFile).flatMap:
28+
case break(className , lineStr) =>
29+
val line = lineStr.toInt
30+
Some(DebugStepAssert(Break(className, line), checkFrame(className, line)))
31+
case step(pattern) => Some(DebugStepAssert(Step, checkLineOrMethod(pattern)))
32+
case next(pattern) => Some(DebugStepAssert(Step, checkLineOrMethod(pattern)))
33+
case comment() | empty() => None
34+
case invalid => throw new Exception(s"Cannot parse debug step: $invalid")
35+
36+
private def checkFrame(className: String, line: Int)(frame: Frame): Unit =
37+
assert(className.matches(frame.className))
38+
assert(frame.line == line)
39+
40+
private def checkLineOrMethod(pattern: String): Frame => Unit =
41+
if "(\\d+)".r.matches(pattern) then checkLine(pattern.toInt) else checkMethod(pattern)
42+
43+
private def checkLine(line: Int)(frame: Frame): Unit = assert(frame.line == line)
44+
45+
private def checkMethod(method: String)(frame: Frame): Unit =
46+
assert(method.matches(s"${frame.className}.${frame.methodName}"))
47+
end DebugStepAssert
48+
49+
private[debug] enum DebugStep[T]:
50+
case Break(className: String, line: Int) extends DebugStep[Frame]
51+
case Step extends DebugStep[Frame]
52+
case Next extends DebugStep[Frame]
53+
54+
private[debug] case class Frame(className: String, methodName: String, line: Int)
55+
56+

compiler/test/dotty/tools/debug/DebugTests.scala

+2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ object DebugTests extends ParallelTesting:
4242
private def verifyDebug(dir: JFile, testSource: TestSource, warnings: Int, reporters: Seq[TestReporter], logger: LoggedRunnable) =
4343
if Properties.testsNoRun then addNoRunWarning()
4444
else
45+
val checkFile = testSource.checkFile.getOrElse(throw new Exception("Missing check file"))
46+
val debugSteps = DebugStepAssert.parseCheckFile(checkFile)
4547
val status = debugMain(testSource.runClassPath): debuggee =>
4648
val debugger = Debugger(debuggee.jdiPort, maxDuration)
4749
try debuggee.launch()

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

+2-3
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,8 @@ class CoverageTests:
110110
if run then
111111
val path = if isDirectory then inputFile.toString else inputFile.getParent.toString
112112
val test = compileDir(path, options)
113-
test.checkFilePaths.foreach { checkFilePath =>
114-
assert(checkFilePath.exists, s"Expected checkfile for $path $checkFilePath does not exist.")
115-
}
113+
test.checkFiles.foreach: checkFile =>
114+
assert(checkFile.exists, s"Expected checkfile for $path $checkFile does not exist.")
116115
test.checkRuns()
117116
else
118117
val test =

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

+14-25
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
7070
def outDir: JFile
7171
def flags: TestFlags
7272
def sourceFiles: Array[JFile]
73+
def checkFile: Option[JFile]
7374

7475
def runClassPath: String = outDir.getPath + JFile.pathSeparator + flags.runClassPath
7576

@@ -183,6 +184,10 @@ trait ParallelTesting extends RunnerOrchestration { self =>
183184
decompilation: Boolean = false
184185
) extends TestSource {
185186
def sourceFiles: Array[JFile] = files.filter(isSourceFile)
187+
188+
def checkFile: Option[JFile] =
189+
sourceFiles.map(f => new JFile(f.getPath.replaceFirst("\\.(scala|java)$", ".check")))
190+
.find(_.exists())
186191
}
187192

188193
/** A test source whose files will be compiled separately according to their
@@ -214,6 +219,12 @@ trait ParallelTesting extends RunnerOrchestration { self =>
214219
.map { (g, f) => (g, f.sorted) }
215220

216221
def sourceFiles = compilationGroups.map(_._2).flatten.toArray
222+
223+
def checkFile: Option[JFile] =
224+
val platform =
225+
if allToolArgs.getOrElse(ToolName.Target, Nil).nonEmpty then s".$testPlatform"
226+
else ""
227+
Some(new JFile(dir.getPath + platform + ".check")).filter(_.exists)
217228
}
218229

219230
protected def shouldSkipTestSource(testSource: TestSource): Boolean = false
@@ -259,12 +270,6 @@ trait ParallelTesting extends RunnerOrchestration { self =>
259270
final def countWarnings(reporters: Seq[TestReporter]) = countErrorsAndWarnings(reporters)._2
260271
final def reporterFailed(r: TestReporter) = r.errorCount > 0
261272

262-
/**
263-
* For a given test source, returns a check file against which the result of the test run
264-
* should be compared. Is used by implementations of this trait.
265-
*/
266-
final def checkFile(testSource: TestSource): Option[JFile] = (CompilationLogic.checkFilePath(testSource)).filter(_.exists)
267-
268273
/**
269274
* Checks if the given actual lines are the same as the ones in the check file.
270275
* If not, fails the test.
@@ -340,22 +345,6 @@ trait ParallelTesting extends RunnerOrchestration { self =>
340345
}
341346
}
342347

343-
object CompilationLogic {
344-
private[ParallelTesting] def checkFilePath(testSource: TestSource) = testSource match {
345-
case ts: JointCompilationSource =>
346-
ts.files.collectFirst {
347-
case f if !f.isDirectory =>
348-
new JFile(f.getPath.replaceFirst("\\.(scala|java)$", ".check"))
349-
}
350-
case ts: SeparateCompilationSource =>
351-
val platform =
352-
if testSource.allToolArgs.getOrElse(ToolName.Target, Nil).nonEmpty then
353-
s".$testPlatform"
354-
else ""
355-
Option(new JFile(ts.dir.getPath + platform + ".check"))
356-
}
357-
}
358-
359348
/** Each `Test` takes the `testSources` and performs the compilation and assertions
360349
* according to the implementing class "neg", "run" or "pos".
361350
*/
@@ -735,7 +724,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
735724
private def mkReporter = TestReporter.reporter(realStdout, logLevel = mkLogLevel)
736725

737726
protected def diffCheckfile(testSource: TestSource, reporters: Seq[TestReporter], logger: LoggedRunnable) =
738-
checkFile(testSource).foreach(diffTest(testSource, _, reporterOutputLines(reporters), reporters, logger))
727+
testSource.checkFile.foreach(diffTest(testSource, _, reporterOutputLines(reporters), reporters, logger))
739728

740729
private def reporterOutputLines(reporters: Seq[TestReporter]): List[String] =
741730
reporters.flatMap(_.consoleOutput.split("\n")).toList
@@ -938,7 +927,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
938927
}
939928

940929
override def onSuccess(testSource: TestSource, reporters: Seq[TestReporter], logger: LoggedRunnable) =
941-
verifyOutput(checkFile(testSource), testSource.outDir, testSource, countWarnings(reporters), reporters, logger)
930+
verifyOutput(testSource.checkFile, testSource.outDir, testSource, countWarnings(reporters), reporters, logger)
942931
}
943932

944933
private final class NegTest(testSources: List[TestSource], times: Int, threadLimit: Option[Int], suppressAllOutput: Boolean)(implicit summaryReport: SummaryReporting)
@@ -1177,7 +1166,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
11771166
def this(targets: List[TestSource]) =
11781167
this(targets, 1, true, None, false, false)
11791168

1180-
def checkFilePaths: List[JFile] = targets.map(CompilationLogic.checkFilePath).flatten
1169+
def checkFiles: List[JFile] = targets.flatMap(_.checkFile)
11811170

11821171
def copy(targets: List[TestSource],
11831172
times: Int = times,

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ trait RunnerOrchestration {
5656
monitor.runMain(classPath)
5757

5858
trait Debuggee:
59-
// the jdi port to connect the debugger
59+
/** the jdi port to connect the debugger */
6060
def jdiPort: Int
61-
// start the main method in the background
61+
/** start the main method in the background */
6262
def launch(): Unit
6363

6464
/** Provide a Debuggee for debugging the Test class's main method

tests/debug/for.check

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
break Test$ 3
2+
step 4
3+
step 10

tests/debug/function.check

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
break Test$ 4
2+
step 5
3+
step 10
4+
break Test$ 6
5+
step 7
6+
step 8
7+
next 9
8+
next 10
9+
next 11

tests/debug/if.check

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
break Test$ 4
2+
step 5
3+
step 6
4+
step 8
5+
step 9
6+
step 13
7+
step 16
8+
step 18

tests/debug/method.check

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
break Test$ 3
2+
step 4
3+
step 5
4+
step 10
5+
step 11
6+
step 12
7+
step 5
8+
step 6

tests/debug/nested-method.check

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
break Test$ 3
2+
step 4
3+
step 12
4+
step 7
5+
step 8
6+
step 9
7+
step 12
8+
step 13

tests/debug/sequence.check

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
break Test$ 3
2+
step 4
3+
step 5
4+
step 6
5+
step 7
6+
step 8
7+
step 9

tests/debug/tailrec.check

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
break Test$ 12
2+
step 13
3+
step 3
4+
step 6
5+
step 3
6+
break Test$ 14
7+
step 3
8+
step 4
9+
// incorrect debug line
10+
step 6
11+
step 15

tests/debug/while.check

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
break Test$ 6
2+
step 8
3+
step 9
4+
step 8
5+
break Test$ 12

0 commit comments

Comments
 (0)