[JVM+IR] Unify new debugger tests expectations

This commit unifies the expectation format between the stepping and
LVT tests in the new debugging test harness.

Furthermore, it introduces a compression of runs of locations without
linenumbers. These default to showing as bytecode offsets from
previous line number, which overspecifies the tests: the bytecodes
chosen should not be constrained by a debugging step test.
This commit is contained in:
Kristoffer Andersen
2020-10-19 15:34:16 +02:00
committed by max-kammerer
parent e19ecdfb3d
commit 27fb46712a
16 changed files with 184 additions and 99 deletions
@@ -9,6 +9,7 @@ import com.intellij.openapi.util.SystemInfo
import com.intellij.util.PathUtil
import com.intellij.util.SystemProperties
import com.sun.jdi.AbsentInformationException
import com.sun.jdi.Location
import com.sun.jdi.VirtualMachine
import com.sun.jdi.event.*
import com.sun.jdi.request.EventRequest
@@ -266,6 +267,34 @@ abstract class AbstractDebugTest : CodegenTestCase() {
checkResult(wholeFile, loggedItems)
}
fun Location.formatAsExpectation(): String {
val synthetic = if (method().isSynthetic) " (synthetic)" else ""
return "${sourceName()}:${lineNumber()} ${method().name()}$synthetic"
}
/*
Compresses runs of the same, linenumber-less location in the log:
specifically removes locations without linenumber, that would otherwise
print as byte offsets. This avoids overspecifying code generation
strategy in debug tests.
*/
fun <T> compressRunsWithoutLinenumber(loggedItems: List<T>, getLocation: (T) -> Location): List<T> {
if (loggedItems.isEmpty()) return listOf()
val logIterator = loggedItems.iterator()
var currentItem = logIterator.next()
val result = mutableListOf(currentItem)
for (logItem in logIterator) {
if (getLocation(currentItem).lineNumber() != -1 || getLocation(currentItem).formatAsExpectation() != getLocation(logItem).formatAsExpectation()) {
result.add(logItem)
currentItem = logItem
}
}
return result
}
abstract fun storeStep(loggedItems: ArrayList<Any>, event: Event)
abstract fun checkResult(wholeFile: File, loggedItems: List<Any>)
@@ -72,19 +72,24 @@ abstract class AbstractLocalVariableTest : AbstractDebugTest() {
}
}
data class LVTStep(
val location : Location,
val visibleVars: Collection<LocalVariableRecord>
)
override fun storeStep(loggedItems: ArrayList<Any>, event: Event) {
waitUntil { (event as LocatableEvent).thread().isSuspended }
val frame = (event as LocatableEvent).thread().frame(0)
try {
val visibleVars = frame
.visibleVariables()
.map { variable -> toRecord(frame, variable) }
.joinToString(", ")
loggedItems.add("${event.location()}: $visibleVars".trim())
val locatableEvent = event as LocatableEvent
waitUntil { locatableEvent.thread().isSuspended }
val location = locatableEvent.location()
if (location.method().isSynthetic) return
val frame = locatableEvent.thread().frame(0)
val visibleVars = try {
frame.visibleVariables().map { variable -> toRecord(frame, variable) }
} catch (e: AbsentInformationException) {
// LVT Completely absent - not distinguished from an empty table
loggedItems.add("${event.location()}:".trim())
listOf()
}
loggedItems.add(LVTStep(location, visibleVars))
}
override fun checkResult(wholeFile: File, loggedItems: List<Any>) {
@@ -109,11 +114,14 @@ abstract class AbstractLocalVariableTest : AbstractDebugTest() {
continue
}
if (currentBackend == TargetBackend.ANY || currentBackend == backend) {
expectedLocalVariables.add(line.drop(3))
expectedLocalVariables.add(line)
}
}
val actualLocalVariables = loggedItems.joinToString("\n")
val compressedLog = compressRunsWithoutLinenumber(loggedItems as List<LVTStep>, LVTStep::location)
val actualLocalVariables = compressedLog.joinToString("\n") {
"// ${it.location.formatAsExpectation()}: ${it.visibleVars.joinToString(", ")}".trim()
}
TestCase.assertEquals(expectedLocalVariables.joinToString("\n"), actualLocalVariables)
}
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.codegen.debugInformation
import com.sun.jdi.VirtualMachine
import com.sun.jdi.event.Event
import com.sun.jdi.event.LocatableEvent
import junit.framework.TestCase
import org.jetbrains.kotlin.test.KotlinTestUtils.assertEqualsToFile
import org.jetbrains.kotlin.test.TargetBackend
import org.junit.AfterClass
@@ -57,18 +56,14 @@ abstract class AbstractSteppingTest : AbstractDebugTest() {
val lines = wholeFile.readLines()
val forceStepInto = lines.any { it.startsWith(FORCE_STEP_INTO_MARKER) }
val actualLineNumbers = loggedItems
val actualLineNumbers = compressRunsWithoutLinenumber(loggedItems as List<LocatableEvent>, LocatableEvent::location)
.filter {
val location = (it as LocatableEvent).location()
val location = it.location()
// Ignore synthetic code with no line number information
// unless force step into behavior is requested.
forceStepInto || !location.method().isSynthetic
}
.map { event ->
val location = (event as LocatableEvent).location()
val synthetic = if (location.method().isSynthetic) " (synthetic)" else ""
"// ${location.sourceName()}:${location.lineNumber()} ${location.method().name()}$synthetic"
}
.map { "// ${it.location().formatAsExpectation()}" }
val actualLineNumbersIterator = actualLineNumbers.iterator()
val lineIterator = lines.iterator()