Refactor debugger tests

1. Move tests to their own module
2. Avoid sharing the 'tinyApp' project between tests
3. Clean up option directive handling
This commit is contained in:
Yan Zhulanow
2019-06-26 22:41:56 +09:00
parent d8d81c51d7
commit 472ec72eb9
288 changed files with 4861 additions and 3910 deletions
@@ -0,0 +1,58 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
testCompileOnly(intellijDep())
testCompile(project(":idea:jvm-debugger:jvm-debugger-core"))
testCompile(project(":idea:jvm-debugger:jvm-debugger-evaluation"))
testCompile(project(":idea:jvm-debugger:jvm-debugger-sequence"))
testCompile(project(":compiler:backend"))
testCompile(files("${System.getProperty("java.home")}/../lib/tools.jar"))
testCompile(project(":kotlin-test:kotlin-test-junit"))
testCompile(projectTests(":compiler:tests-common"))
testCompile(projectTests(":idea:idea-test-framework")) { isTransitive = false }
testCompile(commonDep("junit:junit"))
testCompile(intellijPluginDep("stream-debugger"))
Platform[191].orLower {
testCompileOnly(intellijDep()) { includeJars("java-api", "java-impl") }
}
Platform[192].orHigher {
testCompileOnly(intellijPluginDep("java")) { includeJars("java-api", "java-impl") }
testRuntime(intellijPluginDep("java"))
}
testRuntime(project(":nj2k:nj2k-services")) { isTransitive = false }
testRuntime(project(":idea:idea-jvm"))
testRuntime(project(":idea:idea-native")) { isTransitive = false }
testRuntime(project(":idea:idea-gradle-native")) { isTransitive = false }
testRuntime(project(":kotlin-native:kotlin-native-library-reader")) { isTransitive = false }
testRuntime(project(":kotlin-native:kotlin-native-utils")) { isTransitive = false }
testRuntime(project(":kotlin-reflect"))
testRuntime(project(":sam-with-receiver-ide-plugin"))
testRuntime(project(":allopen-ide-plugin"))
testRuntime(project(":noarg-ide-plugin"))
testRuntime(project(":kotlin-scripting-idea"))
testRuntime(project(":kotlinx-serialization-ide-plugin"))
testRuntime(intellijDep())
testRuntime(intellijRuntimeAnnotations())
}
sourceSets {
"main" { none() }
"test" { projectDefault() }
}
projectTest(parallel = true) {
dependsOn(":dist")
workingDir = rootDir
}
testsJar()
@@ -0,0 +1,103 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test
import com.intellij.debugger.engine.AsyncStackTraceProvider
import com.intellij.debugger.engine.JavaValue
import com.intellij.debugger.memory.utils.StackFrameItem
import com.intellij.execution.process.ProcessOutputTypes
import com.intellij.openapi.extensions.Extensions
import org.jetbrains.kotlin.idea.debugger.KotlinCoroutinesAsyncStackTraceProvider
import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferences
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.getSafe
import java.io.PrintWriter
import java.io.StringWriter
import java.lang.reflect.Modifier
abstract class AbstractAsyncStackTraceTest : KotlinDescriptorTestCaseWithStepping() {
private companion object {
const val MARGIN = " "
val ASYNC_STACKTRACE_EP_NAME = AsyncStackTraceProvider.EP.name
}
override fun doMultiFileTest(files: TestFiles, preferences: DebuggerPreferences) {
val asyncStackTraceProvider = getAsyncStackTraceProvider()
if (asyncStackTraceProvider == null) {
finish()
return
}
doOnBreakpoint {
val frameProxy = this.frameProxy
if (frameProxy != null) {
try {
val stackTrace = asyncStackTraceProvider.getAsyncStackTraceSafe(frameProxy, this)
if (stackTrace != null && stackTrace.isNotEmpty()) {
print(renderAsyncStackTrace(stackTrace), ProcessOutputTypes.SYSTEM)
} else {
println("No async stack trace available", ProcessOutputTypes.SYSTEM)
}
} catch (e: Throwable) {
val stackTrace = e.stackTraceAsString()
System.err.println("Exception occurred on calculating async stack traces: $stackTrace")
throw e
}
} else {
println("FrameProxy is 'null', can't calculate async stack trace", ProcessOutputTypes.SYSTEM)
}
resume(this)
}
}
private fun getAsyncStackTraceProvider(): KotlinCoroutinesAsyncStackTraceProvider? {
val area = Extensions.getArea(null)
if (!area.hasExtensionPoint(ASYNC_STACKTRACE_EP_NAME)) {
System.err.println("$ASYNC_STACKTRACE_EP_NAME extension point is not found (probably old IDE version)")
return null
}
val extensionPoint = area.getExtensionPoint<Any>(ASYNC_STACKTRACE_EP_NAME)
val provider = extensionPoint.extensions.firstIsInstanceOrNull<KotlinCoroutinesAsyncStackTraceProvider>()
if (provider == null) {
System.err.println("Kotlin coroutine async stack trace provider is not found")
}
return provider
}
private fun Throwable.stackTraceAsString(): String {
val writer = StringWriter()
printStackTrace(PrintWriter(writer))
return writer.toString()
}
private fun renderAsyncStackTrace(trace: List<StackFrameItem>) = buildString {
appendln("Async stack trace:")
for (item in trace) {
append(MARGIN).appendln(item.toString())
@Suppress("UNCHECKED_CAST")
val variablesField = item.javaClass.declaredFields
.first { !Modifier.isStatic(it.modifiers) && it.type == List::class.java }
@Suppress("UNCHECKED_CAST")
val variables = variablesField.getSafe(item) as? List<JavaValue>
if (variables != null) {
for (variable in variables) {
val descriptor = variable.descriptor
val name = descriptor.calcValueName()
val value = descriptor.calcValue(evaluationContext)
append(MARGIN).append(MARGIN).append(name).append(" = ").appendln(value)
}
}
}
}
}
@@ -0,0 +1,85 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test
import com.intellij.psi.PsiFile
import com.intellij.testFramework.LightProjectDescriptor
import org.jetbrains.kotlin.idea.core.util.getLineCount
import org.jetbrains.kotlin.idea.core.util.getLineEndOffset
import org.jetbrains.kotlin.idea.core.util.getLineStartOffset
import org.jetbrains.kotlin.idea.debugger.breakpoints.*
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
import org.jetbrains.kotlin.idea.test.allKotlinFiles
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.KotlinTestUtils
import java.io.File
abstract class AbstractBreakpointApplicabilityTest : KotlinLightCodeInsightFixtureTestCase() {
private companion object {
private const val COMMENT = "///"
}
override fun getTestDataPath(): String {
return PluginTestCaseBase.getTestDataPathBase() + "/debugger/breakpointApplicability/"
}
override fun setUp() {
super.setUp()
myFixture.testDataPath = PluginTestCaseBase.getTestDataPathBase()
}
override fun getProjectDescriptor(): LightProjectDescriptor {
return KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
}
protected fun doTest(path: String) {
myFixture.configureByFile(getPath(path))
val file = File(path)
val ktFile = project.allKotlinFiles().single()
val actualContents = checkBreakpoints(ktFile, BreakpointChecker())
KotlinTestUtils.assertEqualsToFile(file, actualContents)
}
private fun checkBreakpoints(file: KtFile, checker: BreakpointChecker): String {
val lineCount = file.getLineCount()
return (0..lineCount).joinToString("\n") { line -> checkLine(file, line, checker) }
}
private fun checkLine(file: KtFile, line: Int, checker: BreakpointChecker): String {
val lineText = file.getLine(line)
val expectedBreakpointTypes = lineText.substringAfterLast(COMMENT).trim().split(",").map { it.trim() }.toSortedSet()
val actualBreakpointTypes = checker.check(file, line).map { it.prefix }.distinct().toSortedSet()
return if (expectedBreakpointTypes != actualBreakpointTypes) {
val lineWithoutComments = lineText.substringBeforeLast(COMMENT).trimEnd()
if (actualBreakpointTypes.isNotEmpty()) {
"$lineWithoutComments $COMMENT " + actualBreakpointTypes.joinToString()
} else {
lineWithoutComments
}
} else {
lineText
}
}
private fun PsiFile.getLine(line: Int): String {
val start = getLineStartOffset(line, skipWhitespace = false) ?: error("Cannot find start for line $line")
val end = getLineEndOffset(line) ?: error("Cannot find end for line $line")
if (start >= end) {
return ""
}
return text.substring(start, end)
}
private fun getPath(path: String): String {
return path.substringAfter(PluginTestCaseBase.TEST_DATA_PROJECT_RELATIVE.drop(1), path)
}
}
@@ -0,0 +1,131 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test
import com.sun.jdi.ThreadReference
import org.jetbrains.kotlin.codegen.ClassFileFactory
import org.jetbrains.kotlin.codegen.OriginCollectingClassBuilderFactory
import org.jetbrains.kotlin.codegen.getClassFiles
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.idea.debugger.FileRankingCalculator
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.org.objectweb.asm.tree.ClassNode
import org.junit.Assert
abstract class AbstractFileRankingTest : LowLevelDebuggerTestBase() {
override fun doTest(
options: Set<String>,
mainThread: ThreadReference,
factory: OriginCollectingClassBuilderFactory,
classFileFactory: ClassFileFactory,
state: GenerationState
) {
val allKtFiles = classFileFactory.inputFiles.distinct()
fun getKtFiles(name: String) = allKtFiles.filter { it.name == name }
val doNotCheckClassFqName = "DO_NOT_CHECK_CLASS_FQNAME" in options
val strictMode = "DISABLE_STRICT_MODE" !in options
val expectedRanks: Map<Pair<KtFile, Int>, Int> = allKtFiles.asSequence().flatMap { ktFile ->
ktFile.text.lines()
.asSequence()
.withIndex()
.map {
val matchResult = "^.*// (R: (-?\\d+)( L: (\\d+))?)\\s*$".toRegex().matchEntire(it.value) ?: return@map null
val rank = matchResult.groupValues[2].toInt()
val line = matchResult.groupValues.getOrNull(4)?.takeIf { !it.isEmpty() }?.toInt()
if (line != null && line != it.index + 1) {
throw IllegalArgumentException("Bad line in directive at ${ktFile.name}:${it.index + 1}\n${it.value}")
}
(ktFile to it.index + 1) to rank
}
.filterNotNull()
}.toMap()
val calculator = object : FileRankingCalculator(checkClassFqName = !doNotCheckClassFqName) {
override fun analyze(element: KtElement) = state.bindingContext
}
val problems = mutableListOf<String>()
val classNameToKtFile = factory.origins.asSequence()
.filter { it.key is ClassNode }
.map {
val ktFile = (it.value.element?.containingFile as? KtFile) ?: return@map null
val name = (it.key as ClassNode).name.replace('/', '.')
name to ktFile
}
.filterNotNull()
.toMap()
val skipClasses = skipLoadingClasses(options)
for (outputFile in classFileFactory.getClassFiles()) {
val className = outputFile.internalName.replace('/', '.')
if (className in skipClasses) {
continue
}
val expectedFile = classNameToKtFile[className] ?: throw IllegalStateException("Can't find source for $className")
val jdiClass = mainThread.virtualMachine().classesByName(className).singleOrNull()
?: error("Class '$className' was not found in the debuggee process class loader")
val locations = jdiClass.allLineLocations()
assert(locations.isNotEmpty()) { "There are no locations for class $className" }
val allFilesWithSameName = getKtFiles(expectedFile.name)
for (location in locations) {
if (location.method().isBridge || location.method().isSynthetic) continue
val fileWithRankings: Map<KtFile, Int> = calculator.rankFiles(allFilesWithSameName, location)
for ((ktFile, rank) in fileWithRankings) {
val expectedRank = expectedRanks[ktFile to (location.lineNumber())]
if (expectedRank != null) {
Assert.assertEquals("Invalid expected rank at $location", expectedRank, rank)
}
}
val fileWithMaxScore = fileWithRankings.maxBy { it.value }!!
val actualFile = fileWithMaxScore.key
if (strictMode) {
require(fileWithMaxScore.value >= 0) { "Max score is negative at $location" }
// Allow only one element with max ranking
require(fileWithRankings.filter { it.value == fileWithMaxScore.value }.count() == 1) {
"Score is the same for several files at $location"
}
}
if (actualFile != expectedFile) {
problems += "Location ${location.sourceName()}:${location.lineNumber() - 1} is associated with a wrong KtFile:\n" +
" - expected: ${expectedFile.virtualFilePath}\n" +
" - actual: ${actualFile.virtualFilePath}"
}
}
}
if (problems.isNotEmpty()) {
throw AssertionError(buildString {
appendln("There were association errors:").appendln()
problems.joinTo(this, "\n\n")
})
}
}
override fun skipLoadingClasses(options: Set<String>): Set<String> {
val skipClasses = options.mapTo(mutableSetOf()) { it.substringAfter("DO_NOT_LOAD:", "").trim() }
skipClasses.remove("")
return skipClasses
}
}
@@ -0,0 +1,308 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test
import com.intellij.debugger.engine.ContextUtil
import com.intellij.debugger.engine.SuspendContextImpl
import com.intellij.debugger.engine.evaluation.CodeFragmentKind
import com.intellij.debugger.engine.evaluation.EvaluateException
import com.intellij.debugger.engine.evaluation.TextWithImportsImpl
import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl
import com.intellij.debugger.engine.events.SuspendContextCommandImpl
import com.intellij.debugger.impl.DebuggerContextImpl
import com.intellij.debugger.impl.DebuggerContextImpl.createDebuggerContext
import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl
import com.intellij.openapi.util.io.FileUtil
import com.intellij.ui.treeStructure.Tree
import com.intellij.xdebugger.impl.ui.tree.ValueMarkup
import com.sun.jdi.ObjectReference
import org.jetbrains.eval4j.ObjectValue
import org.jetbrains.eval4j.Value
import org.jetbrains.eval4j.jdi.asValue
import org.jetbrains.kotlin.codegen.CodegenTestCase.TestFile
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinCodeFragmentFactory
import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferences
import org.jetbrains.kotlin.idea.debugger.test.util.FramePrinter
import org.jetbrains.kotlin.idea.debugger.test.util.FramePrinterDelegate
import org.jetbrains.kotlin.idea.debugger.test.util.SteppingInstruction
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.test.InTextDirectivesUtils.findLinesWithPrefixesRemoved
import org.jetbrains.kotlin.test.InTextDirectivesUtils.findStringWithPrefixes
import java.io.File
import javax.swing.tree.TreeNode
private data class CodeFragment(val text: String, val result: String, val kind: CodeFragmentKind)
private data class DebugLabel(val name: String, val localName: String)
private class EvaluationTestData(
val instructions: List<SteppingInstruction>,
val fragments: List<CodeFragment>,
val debugLabels: List<DebugLabel>
)
abstract class AbstractKotlinEvaluateExpressionTest : KotlinDescriptorTestCaseWithStepping(), FramePrinterDelegate {
private companion object {
private val ID_PART_REGEX = "id=[0-9]*".toRegex()
}
override val debuggerContext: DebuggerContextImpl
get() = super.debuggerContext
private var isMultipleBreakpointsTest = false
private var framePrinter: FramePrinter? = null
fun doSingleBreakpointTest(path: String) {
isMultipleBreakpointsTest = false
doTest(path)
}
fun doMultipleBreakpointsTest(path: String) {
isMultipleBreakpointsTest = true
doTest(path)
}
override fun doMultiFileTest(files: TestFiles, preferences: DebuggerPreferences) {
val wholeFile = files.wholeFile
val instructions = SteppingInstruction.parse(wholeFile)
val expressions = loadExpressions(wholeFile)
val blocks = loadCodeBlocks(files.originalFile)
val debugLabels = loadDebugLabels(wholeFile)
val data = EvaluationTestData(instructions, expressions + blocks, debugLabels)
framePrinter = FramePrinter(myDebuggerSession, this, preferences, testRootDisposable)
if (isMultipleBreakpointsTest) {
performMultipleBreakpointTest(data)
} else {
performSingleBreakpointTest(data)
}
}
override fun tearDown() {
framePrinter?.close()
framePrinter = null
super.tearDown()
}
private fun performSingleBreakpointTest(data: EvaluationTestData) {
process(data.instructions)
doOnBreakpoint {
createDebugLabels(data.debugLabels)
val exceptions = linkedMapOf<String, Throwable>()
for ((expression, expected, kind) in data.fragments) {
mayThrow(exceptions, expression) {
evaluate(this, expression, kind, expected)
}
}
val completion = { resume(this) }
framePrinter?.printFrame(completion) ?: completion()
checkExceptions(exceptions)
}
finish()
}
private fun performMultipleBreakpointTest(data: EvaluationTestData) {
val exceptions = linkedMapOf<String, Throwable>()
for ((expression, expected) in data.fragments) {
mayThrow(exceptions, expression) {
doOnBreakpoint {
try {
evaluate(this, expression, CodeFragmentKind.EXPRESSION, expected)
} finally {
val completion = { resume(this) }
framePrinter?.printFrame(completion) ?: completion()
}
}
}
}
checkExceptions(exceptions)
finish()
}
override fun evaluate(suspendContext: SuspendContextImpl, textWithImports: TextWithImportsImpl) {
evaluate(suspendContext, textWithImports, null)
}
private fun evaluate(suspendContext: SuspendContextImpl, text: String, codeFragmentKind: CodeFragmentKind, expectedResult: String?) {
val textWithImports = TextWithImportsImpl(codeFragmentKind, text, "", KotlinFileType.INSTANCE)
return evaluate(suspendContext, textWithImports, expectedResult)
}
private fun evaluate(suspendContext: SuspendContextImpl, item: TextWithImportsImpl, expectedResult: String?) {
val evaluationContext = this.evaluationContext
val sourcePosition = ContextUtil.getSourcePosition(suspendContext)
// Default test debuggerContext doesn't provide a valid stackFrame so we have to create one more for evaluation purposes.
val frameProxy = suspendContext.frameProxy
val threadProxy = frameProxy?.threadProxy()
val debuggerContext = createDebuggerContext(myDebuggerSession, suspendContext, threadProxy, frameProxy)
debuggerContext.initCaches()
val contextElement = ContextUtil.getContextElement(debuggerContext)!!
assert(KotlinCodeFragmentFactory().isContextAccepted(contextElement)) {
val text = runReadAction { contextElement.text }
"KotlinCodeFragmentFactory should be accepted for context element otherwise default evaluator will be called. " +
"ContextElement = $text"
}
contextElement.putCopyableUserData(KotlinCodeFragmentFactory.DEBUG_CONTEXT_FOR_TESTS, debuggerContext)
suspendContext.runActionInSuspendCommand {
try {
val evaluator = runReadAction {
EvaluatorBuilderImpl.build(
item,
contextElement,
sourcePosition,
this@AbstractKotlinEvaluateExpressionTest.project
)
}
?: throw AssertionError("Cannot create an Evaluator for Evaluate Expression")
val value = evaluator.evaluate(evaluationContext)
val actualResult = value.asValue().asString()
if (expectedResult != null) {
assertEquals(
"Evaluate expression returns wrong result for ${item.text}:\n" +
"expected = $expectedResult\n" +
"actual = $actualResult\n",
expectedResult, actualResult
)
}
} catch (e: EvaluateException) {
val expectedMessage = e.message?.replaceFirst(
ID_PART_REGEX,
"id=ID"
)
assertEquals(
"Evaluate expression throws wrong exception for ${item.text}:\n" +
"expected = $expectedResult\n" +
"actual = $expectedMessage\n",
expectedResult,
expectedMessage
)
}
}
}
override fun logDescriptor(descriptor: NodeDescriptorImpl, text: String) {
super.logDescriptor(descriptor, text)
}
override fun expandAll(tree: Tree, runnable: () -> Unit, filter: (TreeNode) -> Boolean, suspendContext: SuspendContextImpl) {
super.expandAll(tree, runnable, HashSet(), filter, suspendContext)
}
private fun SuspendContextImpl.runActionInSuspendCommand(action: SuspendContextImpl.() -> Unit) {
if (myInProgress) {
action()
} else {
val command = object : SuspendContextCommandImpl(this) {
override fun contextAction(suspendContext: SuspendContextImpl) {
action(suspendContext)
}
}
// Try to execute the action inside a command if we aren't already inside it.
debuggerSession.process.managerThread?.invoke(command) ?: command.contextAction(this)
}
}
private fun mayThrow(collector: MutableMap<String, Throwable>, expression: String, f: () -> Unit) {
try {
f()
} catch (e: Throwable) {
collector[expression] = e
}
}
private fun checkExceptions(exceptions: MutableMap<String, Throwable>) {
if (exceptions.isNotEmpty()) {
for (exc in exceptions.values) {
exc.printStackTrace()
}
val expressionsText = exceptions.entries.joinToString("\n") { (k, v) -> "expression: $k, exception: ${v.message}" }
@Suppress("ConvertToStringTemplate")
throw AssertionError("Test failed:\n" + expressionsText)
}
}
private fun Value.asString(): String {
if (this is ObjectValue && this.value is ObjectReference) {
return this.toString().replaceFirst(ID_PART_REGEX, "id=ID")
}
return this.toString()
}
private fun loadExpressions(testFile: TestFile): List<CodeFragment> {
val directives = findLinesWithPrefixesRemoved(testFile.content, "// EXPRESSION: ")
val expected = findLinesWithPrefixesRemoved(testFile.content, "// RESULT: ")
assert(directives.size == expected.size) { "Sizes of test directives are different" }
return directives.zip(expected).map { (text, result) -> CodeFragment(text, result, CodeFragmentKind.EXPRESSION) }
}
private fun loadCodeBlocks(wholeFile: File): List<CodeFragment> {
val regexp = (Regex.escape(wholeFile.name) + ".fragment\\d*").toRegex()
val fragmentFiles = wholeFile.parentFile.listFiles { _, name -> regexp.matches(name) } ?: emptyArray()
val codeFragments = mutableListOf<CodeFragment>()
for (fragmentFile in fragmentFiles) {
val contents = FileUtil.loadFile(fragmentFile, true)
val value = findStringWithPrefixes(contents, "// RESULT: ") ?: error("'RESULT' directive is missing in $fragmentFile")
codeFragments += CodeFragment(contents, value, CodeFragmentKind.CODE_BLOCK)
}
return codeFragments
}
private fun loadDebugLabels(testFile: TestFile): List<DebugLabel> {
return findLinesWithPrefixesRemoved(testFile.content, "// DEBUG_LABEL: ")
.map { text ->
val labelParts = text.split("=")
assert(labelParts.size == 2) { "Wrong format for DEBUG_LABEL directive: // DEBUG_LABEL: {localVariableName} = {labelText}" }
val localName = labelParts[0].trim()
val name = labelParts[1].trim()
DebugLabel(name, localName)
}
}
private fun createDebugLabels(labels: List<DebugLabel>) {
if (labels.isEmpty()) {
return
}
val markupMap = NodeDescriptorImpl.getMarkupMap(debugProcess) ?: return
for ((name, localName) in labels) {
val localVariable = evaluationContext.frameProxy!!.visibleVariableByName(localName)
assert(localVariable != null) { "Cannot find localVariable for label: name = $localName" }
val localVariableValue = evaluationContext.frameProxy!!.getValue(localVariable) as? ObjectReference
assert(localVariableValue != null) { "Local variable $localName should be an ObjectReference" }
markupMap[localVariableValue] = ValueMarkup(name, null, name)
}
}
}
@@ -0,0 +1,57 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test
import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferences
import org.jetbrains.kotlin.idea.debugger.test.util.SteppingInstruction
import org.jetbrains.kotlin.idea.debugger.test.util.SteppingInstructionKind
abstract class AbstractKotlinSteppingTest : KotlinDescriptorTestCaseWithStepping() {
private enum class Category(val instruction: SteppingInstructionKind?) {
StepInto(SteppingInstructionKind.StepInto),
StepOut(SteppingInstructionKind.StepOut),
StepOver(SteppingInstructionKind.StepOver),
ForceStepOver(SteppingInstructionKind.ForceStepOver),
SmartStepInto(SteppingInstructionKind.SmartStepInto),
Custom(null)
}
private var category: Category? = null
protected fun doStepIntoTest(path: String) = doTest(path, Category.StepInto)
protected fun doStepOutTest(path: String) = doTest(path, Category.StepOut)
protected fun doStepOverTest(path: String) = doTest(path, Category.StepOver)
protected fun doStepOverForceTest(path: String) = doTest(path, Category.ForceStepOver)
protected fun doSmartStepIntoTest(path: String) = doTest(path, Category.SmartStepInto)
protected fun doCustomTest(path: String) = doTest(path, Category.Custom)
override fun tearDown() {
category = null
super.tearDown()
}
private fun doTest(path: String, category: Category) {
this.category = category
super.doTest(path)
}
override fun doMultiFileTest(files: TestFiles, preferences: DebuggerPreferences) {
val category = this.category ?: error("Category is not specified")
val specificKind = category.instruction
if (specificKind != null) {
val instruction = SteppingInstruction.parseSingle(files.wholeFile, specificKind)
?: SteppingInstruction(specificKind, 1)
process(listOf(instruction))
} else {
val instructions = SteppingInstruction.parse(files.wholeFile)
process(instructions)
}
finish()
}
}
@@ -0,0 +1,265 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test;
import com.google.common.collect.Lists;
import com.intellij.debugger.NoDataException;
import com.intellij.debugger.PositionManager;
import com.intellij.debugger.SourcePosition;
import com.intellij.debugger.engine.DebugProcess;
import com.intellij.debugger.engine.DebugProcessEvents;
import com.intellij.debugger.engine.DebugProcessImpl;
import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.testFramework.LightProjectDescriptor;
import com.sun.jdi.Location;
import com.sun.jdi.ReferenceType;
import kotlin.collections.CollectionsKt;
import kotlin.io.FilesKt;
import kotlin.sequences.SequencesKt;
import kotlin.text.StringsKt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.backend.common.output.OutputFileCollection;
import org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettings;
import org.jetbrains.kotlin.codegen.ClassBuilderFactories;
import org.jetbrains.kotlin.codegen.GenerationUtils;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.config.*;
import org.jetbrains.kotlin.idea.debugger.KotlinPositionManager;
import org.jetbrains.kotlin.idea.debugger.KotlinPositionManagerFactory;
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches;
import org.jetbrains.kotlin.idea.debugger.test.mock.MockLocation;
import org.jetbrains.kotlin.idea.debugger.test.mock.MockVirtualMachine;
import org.jetbrains.kotlin.idea.debugger.test.mock.SmartMockReferenceTypeContext;
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase;
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCaseKt;
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor;
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase;
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider;
import org.jetbrains.kotlin.psi.KtFile;
import org.jetbrains.kotlin.test.ConfigurationKind;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TestJdkKind;
import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
import java.io.File;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static org.jetbrains.kotlin.idea.debugger.test.DebuggerTestUtils.DEBUGGER_TESTDATA_PATH_BASE;
import static org.jetbrains.kotlin.idea.debugger.test.DebuggerTestUtils.DEBUGGER_TESTDATA_PATH_RELATIVE;
public abstract class AbstractPositionManagerTest extends KotlinLightCodeInsightFixtureTestCase {
// Breakpoint is given as a line comment on a specific line, containing the regexp to match the name of the class where that line
// can be found. This pattern matches against these line comments and saves the class name in the first group
private static final Pattern BREAKPOINT_PATTERN = Pattern.compile("^.*//\\s*(.+)\\s*$");
@NotNull
@Override
protected String getTestDataPath() {
return DEBUGGER_TESTDATA_PATH_BASE + "/positionManager";
}
@Override
public void setUp() {
super.setUp();
myFixture.setTestDataPath(DEBUGGER_TESTDATA_PATH_BASE);
}
private DebugProcessImpl debugProcess;
@NotNull
@Override
protected LightProjectDescriptor getProjectDescriptor() {
return KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE;
}
@NotNull
private static KotlinPositionManager createPositionManager(
@NotNull DebugProcess process,
@NotNull List<KtFile> files,
@NotNull GenerationState state
) {
KotlinPositionManager positionManager = (KotlinPositionManager) new KotlinPositionManagerFactory().createPositionManager(process);
assertNotNull(positionManager);
for (KtFile file : files) {
KotlinDebuggerCaches.Companion.addTypeMapper(file, state.getTypeMapper());
}
return positionManager;
}
protected void doTest(@NotNull String fileName) {
String path = getPath(fileName);
if (fileName.endsWith(".kt")) {
myFixture.configureByFile(path);
} else {
SequencesKt.forEach(FilesKt.walkTopDown(new File(path)), file -> {
String fileName1 = file.getName();
String path1 = getPath(fileName1);
myFixture.configureByFile(path1);
return null;
});
}
performTest();
}
@NotNull
private static String getPath(@NotNull String fileName) {
return StringsKt.substringAfter(fileName, DEBUGGER_TESTDATA_PATH_RELATIVE, fileName);
}
private void performTest() {
Project project = getProject();
List<KtFile> files = new ArrayList<>(KotlinLightCodeInsightFixtureTestCaseKt.allKotlinFiles(project));
if (files.isEmpty()) return;
List<Breakpoint> breakpoints = Lists.newArrayList();
for (KtFile file : files) {
breakpoints.addAll(extractBreakpointsInfo(file, file.getText()));
}
CompilerConfiguration configuration = KotlinTestUtils.newConfiguration(ConfigurationKind.JDK_ONLY, TestJdkKind.MOCK_JDK);
// TODO: delete this once IDEVirtualFileFinder supports loading .kotlin_builtins files
CommonConfigurationKeysKt.setLanguageVersionSettings(configuration, new CompilerTestLanguageVersionSettings(
Collections.emptyMap(),
ApiVersion.LATEST_STABLE,
LanguageVersion.LATEST_STABLE,
Collections.singletonMap(JvmAnalysisFlags.getSuppressMissingBuiltinsError(), true)
));
GenerationState state =
GenerationUtils.compileFiles(files, configuration, ClassBuilderFactories.TEST, scope -> PackagePartProvider.Empty.INSTANCE);
Map<String, ReferenceType> referencesByName = getReferenceMap(state.getFactory());
debugProcess = createDebugProcess(referencesByName);
PositionManager positionManager = createPositionManager(debugProcess, files, state);
ApplicationManager.getApplication().runReadAction(() -> {
try {
for (Breakpoint breakpoint : breakpoints) {
assertBreakpointIsHandledCorrectly(breakpoint, positionManager);
}
}
catch (NoDataException e) {
throw ExceptionUtilsKt.rethrow(e);
}
});
}
@Override
public void tearDown() {
if (debugProcess != null) {
debugProcess.stop(true);
debugProcess.dispose();
debugProcess = null;
}
super.tearDown();
}
private static Collection<Breakpoint> extractBreakpointsInfo(KtFile file, String fileContent) {
Collection<Breakpoint> breakpoints = Lists.newArrayList();
String[] lines = StringUtil.convertLineSeparators(fileContent).split("\n");
for (int i = 0; i < lines.length; i++) {
Matcher matcher = BREAKPOINT_PATTERN.matcher(lines[i]);
if (matcher.matches()) {
breakpoints.add(new Breakpoint(file, i, matcher.group(1)));
}
}
return breakpoints;
}
private static Map<String, ReferenceType> getReferenceMap(OutputFileCollection outputFiles) {
return new SmartMockReferenceTypeContext(outputFiles).getReferenceTypesByName();
}
private DebugProcessEvents createDebugProcess(Map<String, ReferenceType> referencesByName) {
return new DebugProcessEvents(getProject()) {
private VirtualMachineProxyImpl virtualMachineProxy;
@NotNull
@Override
public VirtualMachineProxyImpl getVirtualMachineProxy() {
if (virtualMachineProxy == null) {
virtualMachineProxy = new MockVirtualMachineProxy(this, referencesByName);
}
return virtualMachineProxy;
}
@NotNull
@Override
public GlobalSearchScope getSearchScope() {
return GlobalSearchScope.allScope(getProject());
}
};
}
private static void assertBreakpointIsHandledCorrectly(Breakpoint breakpoint, PositionManager positionManager) throws NoDataException {
SourcePosition position = SourcePosition.createFromLine(breakpoint.file, breakpoint.lineNumber);
List<ReferenceType> classes = positionManager.getAllClasses(position);
assertNotNull(classes);
assertFalse("Classes not found for line " + (breakpoint.lineNumber + 1) + ", expected " + breakpoint.classNameRegexp,
classes.isEmpty());
if (classes.stream().noneMatch(clazz -> clazz.name().matches(breakpoint.classNameRegexp))) {
throw new AssertionError("Breakpoint class '" + breakpoint.classNameRegexp +
"' from line " + (breakpoint.lineNumber + 1) + " was not found in the PositionManager classes names: " +
classes.stream().map(ReferenceType::name).collect(Collectors.joining(",")));
}
ReferenceType typeWithFqName = classes.get(0);
Location location = new MockLocation(typeWithFqName, breakpoint.file.getName(), breakpoint.lineNumber + 1);
SourcePosition actualPosition = positionManager.getSourcePosition(location);
assertNotNull(actualPosition);
assertEquals(position.getFile(), actualPosition.getFile());
assertEquals(position.getLine(), actualPosition.getLine());
}
private static class Breakpoint {
private final KtFile file;
private final int lineNumber; // 0-based
private final String classNameRegexp;
private Breakpoint(KtFile file, int lineNumber, String classNameRegexp) {
this.file = file;
this.lineNumber = lineNumber;
this.classNameRegexp = classNameRegexp;
}
}
private static class MockVirtualMachineProxy extends VirtualMachineProxyImpl {
private final Map<String, ReferenceType> referencesByName;
private MockVirtualMachineProxy(DebugProcessEvents debugProcess, Map<String, ReferenceType> referencesByName) {
super(debugProcess, new MockVirtualMachine());
this.referencesByName = referencesByName;
}
@Override
public List<ReferenceType> allClasses() {
return new ArrayList<>(referencesByName.values());
}
@Override
public List<ReferenceType> classesByName(@NotNull String name) {
return CollectionsKt.listOfNotNull(referencesByName.get(name));
}
}
}
@@ -0,0 +1,50 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.debugger.KotlinEditorTextProvider
import org.jetbrains.kotlin.idea.test.KotlinLightProjectDescriptor
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
import org.jetbrains.kotlin.idea.test.invalidateLibraryCache
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.junit.Assert
abstract class AbstractSelectExpressionForDebuggerTest : LightCodeInsightFixtureTestCase() {
override fun setUp() {
super.setUp()
invalidateLibraryCache(project)
}
fun doTest(path: String) {
doTest(path, true)
}
fun doTestWoMethodCalls(path: String) {
doTest(path, false)
}
fun doTest(path: String, allowMethodCalls: Boolean) {
myFixture.configureByFile(path)
val elementAt = myFixture.file?.findElementAt(myFixture.caretOffset)!!
val selectedExpression = KotlinEditorTextProvider.findExpressionInner(elementAt, allowMethodCalls)
val expected = InTextDirectivesUtils.findStringWithPrefixes(myFixture.file?.text!!, "// EXPECTED: ")
val actualResult = if (selectedExpression != null) {
KotlinEditorTextProvider.getElementInfo(selectedExpression) { it.text }
} else {
"null"
}
Assert.assertEquals("Another expression should be selected", expected, actualResult)
}
override fun getProjectDescriptor(): KotlinLightProjectDescriptor = KotlinLightProjectDescriptor.INSTANCE
override fun getTestDataPath() = PluginTestCaseBase.getTestDataPathBase() + "/debugger/selectExpression"
}
@@ -0,0 +1,79 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test
import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture
import org.jetbrains.kotlin.idea.core.util.CodeInsightUtils
import org.jetbrains.kotlin.idea.debugger.stepping.KotlinSmartStepIntoHandler
import org.jetbrains.kotlin.idea.debugger.test.mock.MockSourcePosition
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
import org.jetbrains.kotlin.test.InTextDirectivesUtils
abstract class AbstractSmartStepIntoTest : KotlinLightCodeInsightFixtureTestCase() {
private val fixture: JavaCodeInsightTestFixture
get() = myFixture
protected fun doTest(path: String) {
fixture.configureByFile(path)
val offset = fixture.caretOffset
val line = fixture.getDocument(fixture.file!!)!!.getLineNumber(offset)
val lineStart = CodeInsightUtils.getStartLineOffset(file, line)!!
val elementAtOffset = file.findElementAt(lineStart)
val position = MockSourcePosition(
myFile = fixture.file,
myLine = line,
myOffset = offset,
myEditor = fixture.editor,
myElementAt = elementAtOffset
)
val actual = KotlinSmartStepIntoHandler().findSmartStepTargets(position).map { it.presentation }
val expected = InTextDirectivesUtils.findListWithPrefixes(fixture.file?.text!!.replace("\\,", "+++"), "// EXISTS: ")
.map { it.replace("+++", ",") }
for (actualTargetName in actual) {
assert(actualTargetName in expected) {
"Unexpected step into target was found: $actualTargetName\n${renderTableWithResults(expected, actual)}" +
"\n // EXISTS: ${actual.joinToString()}"
}
}
for (expectedTargetName in expected) {
assert(expectedTargetName in actual) {
"Missed step into target: $expectedTargetName\n${renderTableWithResults(expected, actual)}" +
"\n // EXISTS: ${actual.joinToString()}"
}
}
}
private fun renderTableWithResults(expected: List<String>, actual: List<String>): String {
val sb = StringBuilder()
val maxExtStrSize = (expected.maxBy { it.length }?.length ?: 0) + 5
val longerList = (if (expected.size < actual.size) actual else expected).sorted()
val shorterList = (if (expected.size < actual.size) expected else actual).sorted()
for ((i, element) in longerList.withIndex()) {
sb.append(element)
sb.append(" ".repeat(maxExtStrSize - element.length))
if (i < shorterList.size) sb.append(shorterList[i])
sb.append("\n")
}
return sb.toString()
}
override fun getTestDataPath(): String {
return "$DEBUGGER_TESTDATA_PATH_BASE/smartStepInto"
}
override fun getProjectDescriptor() = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
}
@@ -0,0 +1,46 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("idea/jvm-debugger/jvm-debugger-test/testData/asyncStackTrace")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class AsyncStackTraceTestGenerated extends AbstractAsyncStackTraceTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInAsyncStackTrace() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/jvm-debugger/jvm-debugger-test/testData/asyncStackTrace"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("asyncFunctions.kt")
public void testAsyncFunctions() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/asyncStackTrace/asyncFunctions.kt");
}
@TestMetadata("asyncLambdas.kt")
public void testAsyncLambdas() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/asyncStackTrace/asyncLambdas.kt");
}
@TestMetadata("asyncSimple.kt")
public void testAsyncSimple() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/asyncStackTrace/asyncSimple.kt");
}
}
@@ -0,0 +1,61 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("idea/jvm-debugger/jvm-debugger-test/testData/breakpointApplicability")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class BreakpointApplicabilityTestGenerated extends AbstractBreakpointApplicabilityTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInBreakpointApplicability() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/jvm-debugger/jvm-debugger-test/testData/breakpointApplicability"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("constructors.kt")
public void testConstructors() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/breakpointApplicability/constructors.kt");
}
@TestMetadata("functions.kt")
public void testFunctions() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/breakpointApplicability/functions.kt");
}
@TestMetadata("inlineOnly.kt")
public void testInlineOnly() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/breakpointApplicability/inlineOnly.kt");
}
@TestMetadata("locals.kt")
public void testLocals() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/breakpointApplicability/locals.kt");
}
@TestMetadata("properties.kt")
public void testProperties() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/breakpointApplicability/properties.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/breakpointApplicability/simple.kt");
}
}
@@ -0,0 +1,241 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil.doWriteAction
import com.intellij.openapi.module.Module
import com.intellij.openapi.roots.LibraryOrderEntry
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.newvfs.ArchiveFileSystem
import com.intellij.psi.PsiManager
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
import org.jetbrains.kotlin.cli.common.output.writeAllTo
import org.jetbrains.kotlin.cli.jvm.compiler.findMainClass
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.CodegenTestCase.TestFile
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
import org.jetbrains.kotlin.idea.debugger.test.util.patchDexTests
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.MockLibraryUtil
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
import java.io.File
class DebuggerTestCompilerFacility(files: List<TestFile>, private val jvmTarget: JvmTarget, private val applyDexPatch: Boolean) {
private val kotlinStdlibPath = ForTestCompileRuntime.runtimeJarForTests().absolutePath
private val mainFiles: TestFilesByLanguage
private val libraryFiles: TestFilesByLanguage
init {
val splitFiles = splitByTarget(files)
mainFiles = splitByLanguage(splitFiles.main)
libraryFiles = splitByLanguage(splitFiles.library)
}
fun compileExternalLibrary(name: String, srcDir: File, classesDir: File) {
val libSrcPath = File(DEBUGGER_TESTDATA_PATH_BASE, "lib/$name")
if (!libSrcPath.exists()) {
error("Library $name does not exist")
}
val testFiles = libSrcPath.walk().filter { it.isFile }.toList().map {
val path = it.toRelativeString(libSrcPath)
TestFile(path, FileUtil.loadFile(it, true))
}
val libraryFiles = splitByLanguage(testFiles)
compileLibrary(libraryFiles, srcDir, classesDir)
}
fun compileLibrary(srcDir: File, classesDir: File) {
compileLibrary(this.libraryFiles, srcDir, classesDir)
srcDir.refreshAndToVirtualFile()?.let { KtUsefulTestCase.refreshRecursively(it) }
classesDir.refreshAndToVirtualFile()?.let { KtUsefulTestCase.refreshRecursively(it) }
}
private fun compileLibrary(libraryFiles: TestFilesByLanguage, srcDir: File, classesDir: File) = with(libraryFiles) {
resources.copy(classesDir)
(kotlin + java).copy(srcDir)
if (kotlin.isNotEmpty()) {
MockLibraryUtil.compileKotlin(
srcDir.absolutePath,
classesDir,
listOf("-jvm-target", jvmTarget.description),
kotlinStdlibPath
)
}
if (java.isNotEmpty()) {
CodegenTestUtil.compileJava(
java.map { File(srcDir, it.name).absolutePath },
listOf(kotlinStdlibPath, classesDir.absolutePath),
listOf("-g"),
classesDir
)
}
if (applyDexPatch) {
patchDexTests(classesDir)
}
}
// Returns the qualified name of the main test class.
fun compileTestSources(module: Module, srcDir: File, classesDir: File, libClassesDir: File): String = with(mainFiles) {
resources.copy(srcDir)
resources.copy(classesDir) // sic!
(kotlin + java).copy(srcDir)
val ktFiles = mutableListOf<KtFile>()
doWriteAction {
for (file in kotlin + java) {
val ioFile = File(srcDir, file.name)
val virtualFile = ioFile.refreshAndToVirtualFile() ?: error("Cannot find a VirtualFile instance for file $file")
val psiFile = PsiManager.getInstance(module.project).findFile(virtualFile) ?: continue
if (psiFile is KtFile) {
ktFiles += psiFile
}
}
}
if (ktFiles.isEmpty()) {
error("No Kotlin files found")
}
LocalFileSystem.getInstance().refreshAndFindFileByIoFile(classesDir)
LocalFileSystem.getInstance().refreshAndFindFileByIoFile(libClassesDir)
lateinit var mainClassName: String
doWriteAction {
mainClassName = compileKotlinFilesInIde(module, ktFiles, classesDir)
}
if (java.isNotEmpty()) {
CodegenTestUtil.compileJava(
java.map { File(srcDir, it.name).absolutePath },
getClasspath(module) + listOf(classesDir.absolutePath),
listOf("-g"),
classesDir
)
}
if (applyDexPatch) {
patchDexTests(classesDir)
}
return mainClassName
}
private fun compileKotlinFilesInIde(module: Module, files: List<KtFile>, classesDir: File): String {
val project = module.project
val resolutionFacade = KotlinCacheService.getInstance(project).getResolutionFacade(files)
val analysisResult = resolutionFacade.analyzeWithAllCompilerChecks(files)
analysisResult.throwIfError()
val moduleDescriptor = resolutionFacade.moduleDescriptor
val bindingContext = analysisResult.bindingContext
val configuration = CompilerConfiguration()
configuration.put(JVMConfigurationKeys.JVM_TARGET, jvmTarget)
val state = GenerationState.Builder(project, ClassBuilderFactories.BINARIES, moduleDescriptor, bindingContext, files, configuration)
.generateDeclaredClassFilter(GenerationState.GenerateClassFilter.GENERATE_ALL)
.codegenFactory(DefaultCodegenFactory)
.build()
KotlinCodegenFacade.compileCorrectFiles(state, CompilationErrorHandler.THROW_EXCEPTION)
val extraDiagnostics = state.collectedExtraJvmDiagnostics
if (!extraDiagnostics.isEmpty()) {
val compoundMessage = extraDiagnostics.joinToString("\n") { DefaultErrorMessages.render(it) }
error("One or more errors occurred during code generation: \n$compoundMessage")
}
state.factory.writeAllTo(classesDir)
return findMainClass(state, files)?.asString() ?: error("Cannot find main class name")
}
private fun getClasspath(module: Module): List<String> {
val moduleRootManager = ModuleRootManager.getInstance(module)
val classpath = moduleRootManager.orderEntries.filterIsInstance<LibraryOrderEntry>()
.flatMap { it.library?.rootProvider?.getFiles(OrderRootType.CLASSES)?.asList().orEmpty() }
val paths = mutableListOf<String>()
for (entry in classpath) {
val fileSystem = entry.fileSystem
if (fileSystem is ArchiveFileSystem) {
val localFile = fileSystem.getLocalByEntry(entry) ?: continue
paths += localFile.path
} else if (fileSystem is LocalFileSystem) {
paths += entry.path
}
}
return paths
}
}
private fun File.refreshAndToVirtualFile(): VirtualFile? = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(this)
private fun List<TestFile>.copy(destination: File) {
for (file in this) {
val target = File(destination, file.name)
target.parentFile.mkdirs()
target.writeText(file.content)
}
}
class TestFilesByTarget(val main: List<TestFile>, val library: List<TestFile>)
class TestFilesByLanguage(val kotlin: List<TestFile>, val java: List<TestFile>, val resources: List<TestFile>)
private fun splitByTarget(files: List<TestFile>): TestFilesByTarget {
val main = mutableListOf<TestFile>()
val lib = mutableListOf<TestFile>()
for (file in files) {
val container = if (file.name.startsWith("lib/") || file.name.startsWith("customLib/")) lib else main
container += file
}
return TestFilesByTarget(main = main, library = lib)
}
private fun splitByLanguage(files: List<TestFile>): TestFilesByLanguage {
val kotlin = mutableListOf<TestFile>()
val java = mutableListOf<TestFile>()
val resources = mutableListOf<TestFile>()
for (file in files) {
@Suppress("MoveVariableDeclarationIntoWhen")
val extension = file.name.substringAfterLast(".", missingDelimiterValue = "")
val container = when (extension) {
"kt", "kts" -> kotlin
"java" -> java
else -> resources
}
container += file
}
return TestFilesByLanguage(kotlin = kotlin, java = java, resources = resources)
}
@@ -0,0 +1,14 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:JvmName("DebuggerTestUtils")
package org.jetbrains.kotlin.idea.debugger.test
import org.jetbrains.kotlin.test.KotlinTestUtils
const val DEBUGGER_TESTDATA_PATH_RELATIVE = "idea/jvm-debugger/jvm-debugger-test/testData"
@JvmField
val DEBUGGER_TESTDATA_PATH_BASE = KotlinTestUtils.getHomeDirectory() + "/" + DEBUGGER_TESTDATA_PATH_RELATIVE
@@ -0,0 +1,91 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("idea/jvm-debugger/jvm-debugger-test/testData/fileRanking")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class FileRankingTestGenerated extends AbstractFileRankingTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInFileRanking() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/jvm-debugger/jvm-debugger-test/testData/fileRanking"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("anonymousClasses.kt")
public void testAnonymousClasses() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/fileRanking/anonymousClasses.kt");
}
@TestMetadata("differentFlags.kt")
public void testDifferentFlags() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/fileRanking/differentFlags.kt");
}
@TestMetadata("init.kt")
public void testInit() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/fileRanking/init.kt");
}
@TestMetadata("lambdas.kt")
public void testLambdas() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/fileRanking/lambdas.kt");
}
@TestMetadata("multilinePrimaryConstructor.kt")
public void testMultilinePrimaryConstructor() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/fileRanking/multilinePrimaryConstructor.kt");
}
@TestMetadata("multilinePrimaryConstructorWithBody.kt")
public void testMultilinePrimaryConstructorWithBody() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/fileRanking/multilinePrimaryConstructorWithBody.kt");
}
@TestMetadata("parametersWithUnloadedClass.kt")
public void testParametersWithUnloadedClass() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/fileRanking/parametersWithUnloadedClass.kt");
}
@TestMetadata("propertyDelegates.kt")
public void testPropertyDelegates() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/fileRanking/propertyDelegates.kt");
}
@TestMetadata("sameClassName.kt")
public void testSameClassName() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/fileRanking/sameClassName.kt");
}
@TestMetadata("sameClassNameDifferentMethodNames.kt")
public void testSameClassNameDifferentMethodNames() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/fileRanking/sameClassNameDifferentMethodNames.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/fileRanking/simple.kt");
}
@TestMetadata("topLevel.kt")
public void testTopLevel() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/fileRanking/topLevel.kt");
}
}
@@ -0,0 +1,224 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test
import com.intellij.debugger.impl.DescriptorTestCase
import com.intellij.debugger.impl.OutputChecker
import com.intellij.execution.configurations.JavaParameters
import com.intellij.execution.process.ProcessOutputTypes
import com.intellij.openapi.roots.LibraryOrderEntry
import com.intellij.openapi.roots.ModifiableRootModel
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.roots.ui.configuration.libraryEditor.NewLibraryEditor
import com.intellij.openapi.util.ThrowableComputable
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.psi.PsiFile
import com.intellij.testFramework.EdtTestUtil
import com.intellij.xdebugger.XDebugSession
import org.jetbrains.kotlin.codegen.CodegenTestCase.TestFile
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches
import org.jetbrains.kotlin.idea.debugger.test.preference.*
import org.jetbrains.kotlin.idea.debugger.test.util.BreakpointCreator
import org.jetbrains.kotlin.idea.debugger.test.util.KotlinOutputChecker
import org.jetbrains.kotlin.idea.debugger.test.util.LogPropagator
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.TestMetadata
import org.jetbrains.kotlin.test.testFramework.runWriteAction
import org.junit.ComparisonFailure
import java.io.File
internal const val KOTLIN_LIBRARY_NAME = "KotlinLibrary"
internal const val TEST_LIBRARY_NAME = "TestLibrary"
class TestFiles(val originalFile: File, val wholeFile: TestFile, files: List<TestFile>) : List<TestFile> by files
abstract class KotlinDescriptorTestCase : DescriptorTestCase() {
private lateinit var testAppDirectory: File
private lateinit var sourcesOutputDirectory: File
private lateinit var librarySrcDirectory: File
private lateinit var libraryOutputDirectory: File
private lateinit var mainClassName: String
override fun getTestAppPath(): String = testAppDirectory.absolutePath
override fun getTestProjectJdk() = PluginTestCaseBase.fullJdk()
private fun systemLogger(message: String) = println(message, ProcessOutputTypes.SYSTEM)
private var breakpointCreator: BreakpointCreator? = null
private var logPropagator: LogPropagator? = null
private var oldValues: OldValuesStorage? = null
override fun runBare() {
testAppDirectory = KotlinTestUtils.tmpDir("debuggerTestSources")
sourcesOutputDirectory = File(testAppDirectory, "src").apply { mkdirs() }
librarySrcDirectory = File(testAppDirectory, "libSrc").apply { mkdirs() }
libraryOutputDirectory = File(testAppDirectory, "lib").apply { mkdirs() }
super.runBare()
}
override fun setUp() {
super.setUp()
KotlinDebuggerCaches.LOG_COMPILATIONS = true
logPropagator = LogPropagator(::systemLogger).apply { attach() }
}
override fun tearDown() {
KotlinDebuggerCaches.LOG_COMPILATIONS = false
oldValues?.revertValues()
oldValues = null
detachLibraries()
logPropagator?.detach()
logPropagator = null
super.tearDown()
}
fun doTest(path: String) {
val wholeFile = File(path)
val wholeFileContents = FileUtil.loadFile(wholeFile, true)
val testFiles = createTestFiles(wholeFile, wholeFileContents)
val preferences = DebuggerPreferences(myProject, wholeFileContents)
oldValues = SettingsMutators.mutate(preferences)
val rawJvmTarget = preferences[DebuggerPreferenceKeys.JVM_TARGET]
val jvmTarget = JvmTarget.fromString(rawJvmTarget) ?: error("Invalid JVM target value: $rawJvmTarget")
val applyDexPatch = preferences[DebuggerPreferenceKeys.EMULATE_DEX]
val compilerFacility = DebuggerTestCompilerFacility(testFiles, jvmTarget, applyDexPatch)
for (library in preferences[DebuggerPreferenceKeys.ATTACH_LIBRARY]) {
compilerFacility.compileExternalLibrary(library, librarySrcDirectory, libraryOutputDirectory)
}
compilerFacility.compileLibrary(librarySrcDirectory, libraryOutputDirectory)
mainClassName = compilerFacility.compileTestSources(myModule, sourcesOutputDirectory, File(appOutputPath), libraryOutputDirectory)
breakpointCreator = BreakpointCreator(
project,
::systemLogger,
preferences
).apply { createAdditionalBreakpoints(wholeFileContents) }
createLocalProcess(mainClassName)
doMultiFileTest(testFiles, preferences)
}
private fun createTestFiles(wholeFile: File, wholeFileContents: String): TestFiles {
val testFiles = KotlinTestUtils.createTestFiles<Void, TestFile>(
wholeFile.name,
wholeFileContents,
object : KotlinTestUtils.TestFileFactoryNoModules<TestFile>() {
override fun create(fileName: String, text: String, directives: Map<String, String>): TestFile {
return TestFile(fileName, text)
}
}
)
val wholeTestFile = TestFile(wholeFile.name, wholeFileContents)
return TestFiles(wholeFile, wholeTestFile, testFiles)
}
abstract fun doMultiFileTest(files: TestFiles, preferences: DebuggerPreferences)
override fun initOutputChecker(): OutputChecker {
return KotlinOutputChecker(getTestDirectoryPath(), testAppPath, appOutputPath)
}
override fun setUpModule() {
super.setUpModule()
attachLibraries()
}
override fun setUpProject() {
super.setUpProject()
File(appOutputPath).mkdirs()
}
override fun createBreakpoints(file: PsiFile?) {
if (file != null) {
val breakpointCreator = this.breakpointCreator ?: error(BreakpointCreator::class.java.simpleName + " should be set")
breakpointCreator.createBreakpoints(file)
}
}
override fun createJavaParameters(mainClass: String?): JavaParameters {
return super.createJavaParameters(mainClass).apply {
ModuleRootManager.getInstance(myModule).orderEntries.asSequence().filterIsInstance<LibraryOrderEntry>()
classPath.add(ForTestCompileRuntime.runtimeJarForTests())
classPath.add(libraryOutputDirectory)
}
}
private fun attachLibraries() {
runWriteAction {
val kotlinStdlibJar = ForTestCompileRuntime.runtimeJarForTests()
val kotlinStdlibSourcesJar = ForTestCompileRuntime.runtimeSourcesJarForTests()
val model = ModuleRootManager.getInstance(myModule).modifiableModel
attachLibrary(model, KOTLIN_LIBRARY_NAME, kotlinStdlibJar, kotlinStdlibSourcesJar)
attachLibrary(model, TEST_LIBRARY_NAME, libraryOutputDirectory, librarySrcDirectory)
model.commit()
}
}
private fun detachLibraries() {
EdtTestUtil.runInEdtAndGet(ThrowableComputable {
ConfigLibraryUtil.removeLibrary(module, KOTLIN_LIBRARY_NAME)
ConfigLibraryUtil.removeLibrary(module, TEST_LIBRARY_NAME)
})
}
private fun attachLibrary(model: ModifiableRootModel, libraryName: String, classes: File, sources: File) {
val customLibEditor = NewLibraryEditor().apply {
name = libraryName
addRoot(VfsUtil.getUrlForLibraryRoot(classes), OrderRootType.CLASSES)
addRoot(VfsUtil.getUrlForLibraryRoot(sources), OrderRootType.SOURCES)
}
ConfigLibraryUtil.addLibrary(customLibEditor, model, null)
}
override fun checkTestOutput() {
if (KotlinTestUtils.isAllFilesPresentTest(getTestName(false))) {
return
}
try {
super.checkTestOutput()
} catch (e: ComparisonFailure) {
KotlinTestUtils.assertEqualsToFile(File(getTestDirectoryPath(), getTestName(true) + ".out"), e.actual)
}
}
override fun getData(dataId: String): Any? {
if (XDebugSession.DATA_KEY.`is`(dataId)) {
return myDebuggerSession?.xDebugSession
}
return super.getData(dataId)
}
private fun getTestDirectoryPath(): String = javaClass.getAnnotation(TestMetadata::class.java).value
}
@@ -0,0 +1,165 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test
import com.intellij.debugger.actions.MethodSmartStepTarget
import com.intellij.debugger.engine.*
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
import com.intellij.debugger.impl.DebuggerContextImpl
import com.intellij.debugger.impl.JvmSteppingCommandProvider
import com.intellij.debugger.impl.PositionUtil
import com.intellij.execution.process.ProcessOutputTypes
import com.sun.jdi.request.StepRequest
import org.jetbrains.kotlin.idea.debugger.stepping.*
import org.jetbrains.kotlin.idea.debugger.test.util.SteppingInstruction
import org.jetbrains.kotlin.idea.debugger.test.util.SteppingInstructionKind
import org.jetbrains.kotlin.idea.debugger.test.util.renderSourcePosition
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
abstract class KotlinDescriptorTestCaseWithStepping : KotlinDescriptorTestCase() {
private val dp: DebugProcessImpl
get() = debugProcess ?: throw AssertionError("createLocalProcess() should be called before getDebugProcess()")
@Volatile
private var myEvaluationContext: EvaluationContextImpl? = null
val evaluationContext get() = myEvaluationContext!!
@Volatile
private var myDebuggerContext: DebuggerContextImpl? = null
protected open val debuggerContext get() = myDebuggerContext!!
@Volatile
private var myCommandProvider: KotlinSteppingCommandProvider? = null
private val commandProvider get() = myCommandProvider!!
private fun initContexts(suspendContext: SuspendContextImpl) {
myEvaluationContext = createEvaluationContext(suspendContext)
myDebuggerContext = createDebuggerContext(suspendContext)
myCommandProvider = JvmSteppingCommandProvider.EP_NAME.extensions.firstIsInstance<KotlinSteppingCommandProvider>()
}
internal fun process(instructions: List<SteppingInstruction>) {
instructions.forEach(this::process)
}
internal fun doOnBreakpoint(action: SuspendContextImpl.() -> Unit) {
super.onBreakpoint {
try {
initContexts(it)
it.printContext()
it.action()
} catch (e: AssertionError) {
throw e
} catch (e: Throwable) {
e.printStackTrace()
resume(it)
}
}
}
internal fun finish() {
doOnBreakpoint {
resume(this)
}
}
private fun SuspendContextImpl.doStepInto(ignoreFilters: Boolean, smartStepFilter: MethodFilter?) {
val stepIntoCommand =
runReadAction { commandProvider.getStepIntoCommand(this, ignoreFilters, smartStepFilter, StepRequest.STEP_LINE) }
?: dp.createStepIntoCommand(this, ignoreFilters, smartStepFilter)
dp.managerThread.schedule(stepIntoCommand)
}
private fun SuspendContextImpl.doStepOut() {
val stepOutCommand = runReadAction { commandProvider.getStepOutCommand(this, debuggerContext) }
?: dp.createStepOutCommand(this)
dp.managerThread.schedule(stepOutCommand)
}
private fun SuspendContextImpl.doStepOver(ignoreBreakpoints: Boolean = false) {
val stepOverCommand = runReadAction { commandProvider.getStepOverCommand(this, ignoreBreakpoints, debuggerContext) }
?: dp.createStepOverCommand(this, ignoreBreakpoints)
dp.managerThread.schedule(stepOverCommand)
}
private fun process(instruction: SteppingInstruction) {
fun loop(count: Int, block: SuspendContextImpl.() -> Unit) {
repeat(count) {
doOnBreakpoint(block)
}
}
when (instruction.kind) {
SteppingInstructionKind.StepInto -> loop(instruction.arg) { doStepInto(false, null) }
SteppingInstructionKind.StepOut -> loop(instruction.arg) { doStepOut() }
SteppingInstructionKind.StepOver -> loop(instruction.arg) { doStepOver() }
SteppingInstructionKind.ForceStepOver -> loop(instruction.arg) { doStepOver(ignoreBreakpoints = true) }
SteppingInstructionKind.SmartStepInto -> loop(instruction.arg) { doSmartStepInto() }
SteppingInstructionKind.SmartStepIntoByIndex -> doOnBreakpoint { doSmartStepInto(instruction.arg) }
SteppingInstructionKind.Resume -> loop(instruction.arg) { resume(this) }
}
}
private fun SuspendContextImpl.doSmartStepInto(chooseFromList: Int = 0) {
this.doSmartStepInto(chooseFromList, false)
}
private fun SuspendContextImpl.printContext() {
runReadAction {
if (this.frameProxy == null) {
return@runReadAction println("Context thread is null", ProcessOutputTypes.SYSTEM)
}
val sourcePosition = PositionUtil.getSourcePosition(this)
println(renderSourcePosition(sourcePosition), ProcessOutputTypes.SYSTEM)
}
}
private fun SuspendContextImpl.doSmartStepInto(chooseFromList: Int, ignoreFilters: Boolean) {
val filters = createSmartStepIntoFilters()
if (chooseFromList == 0) {
filters.forEach {
dp.managerThread!!.schedule(dp.createStepIntoCommand(this, ignoreFilters, it))
}
} else {
try {
dp.managerThread!!.schedule(dp.createStepIntoCommand(this, ignoreFilters, filters[chooseFromList - 1]))
} catch (e: IndexOutOfBoundsException) {
val elementText = runReadAction { debuggerContext.sourcePosition.elementAt.getElementTextWithContext() }
throw AssertionError("Couldn't find smart step into command at: \n$elementText", e)
}
}
}
private fun createSmartStepIntoFilters() = runReadAction {
val position = debuggerContext.sourcePosition
val stepTargets = KotlinSmartStepIntoHandler().findSmartStepTargets(position)
stepTargets.mapNotNull { stepTarget ->
when (stepTarget) {
is KotlinLambdaSmartStepTarget ->
KotlinLambdaMethodFilter(
stepTarget.getLambda(), stepTarget.getCallingExpressionLines()!!, stepTarget.isInline, stepTarget.isSuspend
)
is KotlinMethodSmartStepTarget ->
KotlinBasicStepMethodFilter(
stepTarget.declaration?.createSmartPointer(),
stepTarget.isInvoke,
stepTarget.targetMethodName,
stepTarget.getCallingExpressionLines()!!
)
is MethodSmartStepTarget -> BasicStepMethodFilter(stepTarget.method, stepTarget.getCallingExpressionLines())
else -> null
}
}
}
}
@@ -0,0 +1,191 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test
import com.intellij.util.PathUtil
import com.intellij.util.SystemProperties
import com.sun.jdi.ThreadReference
import com.sun.jdi.VirtualMachine
import com.sun.tools.jdi.SocketAttachingConnector
import org.jetbrains.kotlin.backend.common.output.OutputFile
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.test.ConfigurationKind
import java.io.File
import java.io.IOException
import java.net.Socket
import java.nio.file.Files
import kotlin.properties.Delegates
abstract class LowLevelDebuggerTestBase : CodegenTestCase() {
private companion object {
private const val DEBUG_ADDRESS = "127.0.0.1"
private const val DEBUG_PORT = 5115
}
override fun doMultiFileTest(wholeFile: File, files: List<TestFile>) {
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.ALL, *listOfNotNull(writeJavaFiles(files)).toTypedArray())
val options = wholeFile.readLines()
.asSequence()
.filter { it.matches("^// ?[\\w_]+(:.*)?$".toRegex()) }
.map { it.drop(2).trim() }
.filter { !it.startsWith("FILE:") }
.toSet()
val skipLoadingClasses = skipLoadingClasses(options)
loadMultiFiles(files)
val classBuilderFactory = OriginCollectingClassBuilderFactory(ClassBuilderMode.FULL)
val generationState = GenerationUtils.compileFiles(myFiles.psiFiles, myEnvironment, classBuilderFactory)
classFileFactory = generationState.factory
val tempDirForTest = Files.createTempDirectory("debuggerTest").toFile()
try {
val classesDir = File(tempDirForTest, "classes").apply {
writeMainClass(this)
for (classFile in classFileFactory.getClassFiles()) {
File(this, classFile.relativePath).mkdirAndWriteBytes(classFile.asByteArray())
}
}
val process = startDebuggeeProcess(classesDir, skipLoadingClasses)
waitUntil { isPortOpen() }
val virtualMachine = attachDebugger()
try {
val mainThread = virtualMachine.allThreads().single { it.name() == "main" }
waitUntil { areCompiledClassesLoaded(mainThread, classFileFactory, skipLoadingClasses) }
doTest(options, mainThread, classBuilderFactory, classFileFactory, generationState)
} finally {
virtualMachine.exit(0)
process.destroy()
}
} finally {
tempDirForTest.deleteRecursively()
}
}
protected abstract fun doTest(
options: Set<String>,
mainThread: ThreadReference,
factory: OriginCollectingClassBuilderFactory,
classFileFactory: ClassFileFactory,
state: GenerationState
)
private fun isPortOpen(): Boolean {
return try {
Socket(DEBUG_ADDRESS, DEBUG_PORT).close()
true
} catch (e: IOException) {
false
}
}
private fun areCompiledClassesLoaded(
mainThread: ThreadReference,
classFileFactory: ClassFileFactory,
skipLoadingClasses: Set<String>
): Boolean {
for (outputFile in classFileFactory.getClassFiles()) {
val fqName = outputFile.internalName.replace('/', '.')
if (fqName in skipLoadingClasses) {
continue
}
mainThread.virtualMachine().classesByName(fqName).firstOrNull() ?: return false
}
return true
}
protected open fun skipLoadingClasses(options: Set<String>): Set<String> {
return emptySet()
}
private fun startDebuggeeProcess(classesDir: File, skipLoadingClasses: Set<String>): Process {
val classesToLoad = this.classFileFactory.getClassFiles()
.map { it.qualifiedName }
.filter { it !in skipLoadingClasses }
.joinToString(",")
val classpath = listOf(
classesDir.absolutePath,
PathUtil.getJarPathForClass(Delegates::class.java) // Add Kotlin runtime JAR
)
val command = arrayOf(
findJavaExecutable().absolutePath,
"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=$DEBUG_PORT",
"-ea",
"-classpath", classpath.joinToString(File.pathSeparator),
"-D${DebuggerMain.CLASSES_TO_LOAD}=$classesToLoad",
DebuggerMain::class.java.name
)
return ProcessBuilder(*command).inheritIO().start()
}
private fun attachDebugger(): VirtualMachine {
val connector = SocketAttachingConnector()
return connector.attach(connector.defaultArguments().toMutableMap().apply {
getValue("port").setValue("$DEBUG_PORT")
getValue("hostname").setValue(DEBUG_ADDRESS)
})
}
private fun findJavaExecutable(): File {
val javaBin = File(SystemProperties.getJavaHome(), "bin")
return File(javaBin, "java.exe").takeIf { it.exists() }
?: File(javaBin, "java").also { assert(it.exists()) }
}
private fun writeMainClass(classesDir: File) {
val mainClassResourceName = DebuggerMain::class.java.name.replace('.', '/') + ".class"
val resource = javaClass.classLoader.getResource(mainClassResourceName)
?: error("Resource not found: $mainClassResourceName")
val mainClassBytes = resource.readBytes()
File(classesDir, mainClassResourceName).mkdirAndWriteBytes(mainClassBytes)
}
internal val OutputFile.internalName
get() = relativePath.substringBeforeLast(".class")
internal val OutputFile.qualifiedName
get() = internalName.replace('/', '.')
}
private fun File.mkdirAndWriteBytes(array: ByteArray) {
parentFile.mkdirs()
writeBytes(array)
}
private fun waitUntil(condition: () -> Boolean) {
while (!condition()) {
Thread.sleep(30)
}
}
private object DebuggerMain {
const val CLASSES_TO_LOAD = "classes.to.load"
@JvmField
val lock = Any()
@JvmStatic
fun main(args: Array<String>) {
System.getProperty(CLASSES_TO_LOAD).split(',').forEach { Class.forName(it) }
synchronized(lock) {
// Wait until debugger is attached
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
(lock as Object).wait()
}
}
}
@@ -0,0 +1,157 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@RunWith(JUnit3RunnerWithInners.class)
public class PositionManagerTestGenerated extends AbstractPositionManagerTest {
@TestMetadata("idea/jvm-debugger/jvm-debugger-test/testData/positionManager")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class SingleFile extends AbstractPositionManagerTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInSingleFile() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/jvm-debugger/jvm-debugger-test/testData/positionManager"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, false);
}
@TestMetadata("anonymousFunction.kt")
public void testAnonymousFunction() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/positionManager/anonymousFunction.kt");
}
@TestMetadata("anonymousNamedFunction.kt")
public void testAnonymousNamedFunction() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/positionManager/anonymousNamedFunction.kt");
}
@TestMetadata("class.kt")
public void testClass() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/positionManager/class.kt");
}
@TestMetadata("classObject.kt")
public void testClassObject() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/positionManager/classObject.kt");
}
@TestMetadata("enum.kt")
public void testEnum() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/positionManager/enum.kt");
}
@TestMetadata("extensionFunction.kt")
public void testExtensionFunction() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/positionManager/extensionFunction.kt");
}
@TestMetadata("functionLiteral.kt")
public void testFunctionLiteral() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/positionManager/functionLiteral.kt");
}
@TestMetadata("functionLiteralInVal.kt")
public void testFunctionLiteralInVal() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/positionManager/functionLiteralInVal.kt");
}
@TestMetadata("innerClass.kt")
public void testInnerClass() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/positionManager/innerClass.kt");
}
@TestMetadata("JvmNameAnnotation.kt")
public void testJvmNameAnnotation() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/positionManager/JvmNameAnnotation.kt");
}
@TestMetadata("localFunction.kt")
public void testLocalFunction() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/positionManager/localFunction.kt");
}
@TestMetadata("objectDeclaration.kt")
public void testObjectDeclaration() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/positionManager/objectDeclaration.kt");
}
@TestMetadata("objectExpression.kt")
public void testObjectExpression() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/positionManager/objectExpression.kt");
}
@TestMetadata("package.kt")
public void testPackage() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/positionManager/package.kt");
}
@TestMetadata("propertyAccessor.kt")
public void testPropertyAccessor() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/positionManager/propertyAccessor.kt");
}
@TestMetadata("propertyInitializer.kt")
public void testPropertyInitializer() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/positionManager/propertyInitializer.kt");
}
@TestMetadata("topLevelPropertyInitializer.kt")
public void testTopLevelPropertyInitializer() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/positionManager/topLevelPropertyInitializer.kt");
}
@TestMetadata("trait.kt")
public void testTrait() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/positionManager/trait.kt");
}
@TestMetadata("twoClasses.kt")
public void testTwoClasses() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/positionManager/twoClasses.kt");
}
@TestMetadata("_DefaultPackage.kt")
public void test_DefaultPackage() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/positionManager/_DefaultPackage.kt");
}
}
@TestMetadata("idea/jvm-debugger/jvm-debugger-test/testData/positionManager")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class MultiFile extends AbstractPositionManagerTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInMultiFile() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/jvm-debugger/jvm-debugger-test/testData/positionManager"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, false);
}
@TestMetadata("multiFilePackage")
public void testMultiFilePackage() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/positionManager/multiFilePackage/");
}
@TestMetadata("multiFileSameName")
public void testMultiFileSameName() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/positionManager/multiFileSameName/");
}
}
}
@@ -0,0 +1,337 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@RunWith(JUnit3RunnerWithInners.class)
public class SelectExpressionForDebuggerTestGenerated extends AbstractSelectExpressionForDebuggerTest {
@TestMetadata("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class SelectExpression extends AbstractSelectExpressionForDebuggerTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInSelectExpression() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, false);
}
@TestMetadata("annotation.kt")
public void testAnnotation() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/annotation.kt");
}
@TestMetadata("arrayExpression.kt")
public void testArrayExpression() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/arrayExpression.kt");
}
@TestMetadata("binaryExpression.kt")
public void testBinaryExpression() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/binaryExpression.kt");
}
@TestMetadata("call.kt")
public void testCall() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/call.kt");
}
@TestMetadata("companionObjectCall.kt")
public void testCompanionObjectCall() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/companionObjectCall.kt");
}
@TestMetadata("companionObjectCall2.kt")
public void testCompanionObjectCall2() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/companionObjectCall2.kt");
}
@TestMetadata("expressionInPropertyInitializer.kt")
public void testExpressionInPropertyInitializer() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/expressionInPropertyInitializer.kt");
}
@TestMetadata("extensionFun.kt")
public void testExtensionFun() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/extensionFun.kt");
}
@TestMetadata("firstCallInChain.kt")
public void testFirstCallInChain() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/firstCallInChain.kt");
}
@TestMetadata("fullyQualified.kt")
public void testFullyQualified() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/fullyQualified.kt");
}
@TestMetadata("funArgument.kt")
public void testFunArgument() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/funArgument.kt");
}
@TestMetadata("functionLiteral.kt")
public void testFunctionLiteral() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/functionLiteral.kt");
}
@TestMetadata("getConvention.kt")
public void testGetConvention() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/getConvention.kt");
}
@TestMetadata("imports.kt")
public void testImports() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/imports.kt");
}
@TestMetadata("infixCall.kt")
public void testInfixCall() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/infixCall.kt");
}
@TestMetadata("infixCallArgument.kt")
public void testInfixCallArgument() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/infixCallArgument.kt");
}
@TestMetadata("isExpression.kt")
public void testIsExpression() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/isExpression.kt");
}
@TestMetadata("javaStaticMehtodCall.kt")
public void testJavaStaticMehtodCall() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/javaStaticMehtodCall.kt");
}
@TestMetadata("keyword.kt")
public void testKeyword() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/keyword.kt");
}
@TestMetadata("modifier.kt")
public void testModifier() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/modifier.kt");
}
@TestMetadata("nameArgument.kt")
public void testNameArgument() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/nameArgument.kt");
}
@TestMetadata("objectMethodCall.kt")
public void testObjectMethodCall() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/objectMethodCall.kt");
}
@TestMetadata("package.kt")
public void testPackage() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/package.kt");
}
@TestMetadata("param.kt")
public void testParam() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/param.kt");
}
@TestMetadata("propertyCall.kt")
public void testPropertyCall() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/propertyCall.kt");
}
@TestMetadata("propertyDeclaration.kt")
public void testPropertyDeclaration() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/propertyDeclaration.kt");
}
@TestMetadata("qualifiedExpressionProperty.kt")
public void testQualifiedExpressionProperty() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/qualifiedExpressionProperty.kt");
}
@TestMetadata("qualifiedExpressionReceiver.kt")
public void testQualifiedExpressionReceiver() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/qualifiedExpressionReceiver.kt");
}
@TestMetadata("qualifiedExpressionSelector.kt")
public void testQualifiedExpressionSelector() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/qualifiedExpressionSelector.kt");
}
@TestMetadata("super.kt")
public void testSuper() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/super.kt");
}
@TestMetadata("superSelector.kt")
public void testSuperSelector() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/superSelector.kt");
}
@TestMetadata("this.kt")
public void testThis() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/this.kt");
}
@TestMetadata("thisSelector.kt")
public void testThisSelector() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/thisSelector.kt");
}
@TestMetadata("thisWithLabel.kt")
public void testThisWithLabel() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/thisWithLabel.kt");
}
@TestMetadata("unaryExpression.kt")
public void testUnaryExpression() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/unaryExpression.kt");
}
@TestMetadata("userType.kt")
public void testUserType() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/userType.kt");
}
@TestMetadata("userTypeGeneric.kt")
public void testUserTypeGeneric() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/userTypeGeneric.kt");
}
@TestMetadata("userTypeQualified.kt")
public void testUserTypeQualified() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/userTypeQualified.kt");
}
}
@TestMetadata("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/disallowMethodCalls")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class DisallowMethodCalls extends AbstractSelectExpressionForDebuggerTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTestWoMethodCalls, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInDisallowMethodCalls() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/disallowMethodCalls"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("binaryExpression.kt")
public void testBinaryExpression() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/disallowMethodCalls/binaryExpression.kt");
}
@TestMetadata("call.kt")
public void testCall() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/disallowMethodCalls/call.kt");
}
@TestMetadata("expressionInPropertyInitializer.kt")
public void testExpressionInPropertyInitializer() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/disallowMethodCalls/expressionInPropertyInitializer.kt");
}
@TestMetadata("extensionFun.kt")
public void testExtensionFun() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/disallowMethodCalls/extensionFun.kt");
}
@TestMetadata("funArgument.kt")
public void testFunArgument() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/disallowMethodCalls/funArgument.kt");
}
@TestMetadata("functionLiteral.kt")
public void testFunctionLiteral() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/disallowMethodCalls/functionLiteral.kt");
}
@TestMetadata("getConvention.kt")
public void testGetConvention() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/disallowMethodCalls/getConvention.kt");
}
@TestMetadata("infixCall.kt")
public void testInfixCall() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/disallowMethodCalls/infixCall.kt");
}
@TestMetadata("infixCallArgument.kt")
public void testInfixCallArgument() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/disallowMethodCalls/infixCallArgument.kt");
}
@TestMetadata("isExpression.kt")
public void testIsExpression() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/disallowMethodCalls/isExpression.kt");
}
@TestMetadata("propertyCall.kt")
public void testPropertyCall() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/disallowMethodCalls/propertyCall.kt");
}
@TestMetadata("qualifiedExpressionProperty.kt")
public void testQualifiedExpressionProperty() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/disallowMethodCalls/qualifiedExpressionProperty.kt");
}
@TestMetadata("qualifiedExpressionReceiver.kt")
public void testQualifiedExpressionReceiver() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/disallowMethodCalls/qualifiedExpressionReceiver.kt");
}
@TestMetadata("qualifiedExpressionSelector.kt")
public void testQualifiedExpressionSelector() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/disallowMethodCalls/qualifiedExpressionSelector.kt");
}
@TestMetadata("super.kt")
public void testSuper() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/disallowMethodCalls/super.kt");
}
@TestMetadata("superSelector.kt")
public void testSuperSelector() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/disallowMethodCalls/superSelector.kt");
}
@TestMetadata("this.kt")
public void testThis() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/disallowMethodCalls/this.kt");
}
@TestMetadata("thisSelector.kt")
public void testThisSelector() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/disallowMethodCalls/thisSelector.kt");
}
@TestMetadata("thisWithLabel.kt")
public void testThisWithLabel() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/disallowMethodCalls/thisWithLabel.kt");
}
@TestMetadata("unaryExpression.kt")
public void testUnaryExpression() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/selectExpression/disallowMethodCalls/unaryExpression.kt");
}
}
}
@@ -0,0 +1,186 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class SmartStepIntoTestGenerated extends AbstractSmartStepIntoTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInSmartStepInto() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("annotation.kt")
public void testAnnotation() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/annotation.kt");
}
@TestMetadata("arrayAccess.kt")
public void testArrayAccess() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/arrayAccess.kt");
}
@TestMetadata("callChain.kt")
public void testCallChain() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/callChain.kt");
}
@TestMetadata("constructor.kt")
public void testConstructor() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/constructor.kt");
}
@TestMetadata("conventionMethod.kt")
public void testConventionMethod() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/conventionMethod.kt");
}
@TestMetadata("delegatedPropertyGetter.kt")
public void testDelegatedPropertyGetter() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/delegatedPropertyGetter.kt");
}
@TestMetadata("doWhile.kt")
public void testDoWhile() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/doWhile.kt");
}
@TestMetadata("dotQualified.kt")
public void testDotQualified() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/dotQualified.kt");
}
@TestMetadata("dotQualifiedInParam.kt")
public void testDotQualifiedInParam() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/dotQualifiedInParam.kt");
}
@TestMetadata("empty.kt")
public void testEmpty() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/empty.kt");
}
@TestMetadata("for.kt")
public void testFor() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/for.kt");
}
@TestMetadata("funLiteral.kt")
public void testFunLiteral() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/funLiteral.kt");
}
@TestMetadata("funWithExpressionBody.kt")
public void testFunWithExpressionBody() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/funWithExpressionBody.kt");
}
@TestMetadata("if.kt")
public void testIf() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/if.kt");
}
@TestMetadata("infixCall.kt")
public void testInfixCall() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/infixCall.kt");
}
@TestMetadata("inlinedFunLiteral.kt")
public void testInlinedFunLiteral() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/inlinedFunLiteral.kt");
}
@TestMetadata("inlinedFunctionalExpression.kt")
public void testInlinedFunctionalExpression() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/inlinedFunctionalExpression.kt");
}
@TestMetadata("invoke.kt")
public void testInvoke() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/invoke.kt");
}
@TestMetadata("libraryFun.kt")
public void testLibraryFun() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/libraryFun.kt");
}
@TestMetadata("multiline.kt")
public void testMultiline() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/multiline.kt");
}
@TestMetadata("multilineCallChain.kt")
public void testMultilineCallChain() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/multilineCallChain.kt");
}
@TestMetadata("object.kt")
public void testObject() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/object.kt");
}
@TestMetadata("param.kt")
public void testParam() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/param.kt");
}
@TestMetadata("parantesized.kt")
public void testParantesized() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/parantesized.kt");
}
@TestMetadata("propertyGetter.kt")
public void testPropertyGetter() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/propertyGetter.kt");
}
@TestMetadata("renderer.kt")
public void testRenderer() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/renderer.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/simple.kt");
}
@TestMetadata("stringTemplate.kt")
public void testStringTemplate() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/stringTemplate.kt");
}
@TestMetadata("unary.kt")
public void testUnary() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/unary.kt");
}
@TestMetadata("when.kt")
public void testWhen() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/when.kt");
}
@TestMetadata("while.kt")
public void testWhile() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/smartStepInto/while.kt");
}
}
@@ -0,0 +1,22 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.mock
import com.sun.jdi.*
class MockLocation(private val declaringType: ReferenceType, private val sourceName: String, private val lineNumber: Int) : Location {
override fun declaringType() = declaringType
override fun sourceName() = sourceName
override fun lineNumber() = lineNumber
override fun method() = MockMethod()
override fun codeIndex() = throw UnsupportedOperationException()
override fun sourceName(s: String) = throw UnsupportedOperationException()
override fun sourcePath() = throw AbsentInformationException()
override fun sourcePath(s: String) = throw AbsentInformationException()
override fun lineNumber(s: String) = throw UnsupportedOperationException()
override fun compareTo(other: Location) = throw UnsupportedOperationException()
override fun virtualMachine() = throw UnsupportedOperationException()
}
@@ -0,0 +1,49 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.mock
import com.sun.jdi.Location
import com.sun.jdi.Method
class MockMethod : Method {
override fun name() = ""
override fun allLineLocations() = emptyList<Location>()
override fun isSynthetic() = throw UnsupportedOperationException()
override fun isFinal() = throw UnsupportedOperationException()
override fun isStatic() = throw UnsupportedOperationException()
override fun declaringType() = throw UnsupportedOperationException()
override fun signature() = throw UnsupportedOperationException()
override fun genericSignature() = throw UnsupportedOperationException()
override fun variables() = throw UnsupportedOperationException()
override fun variablesByName(name: String?) = throw UnsupportedOperationException()
override fun bytecodes() = throw UnsupportedOperationException()
override fun isBridge() = throw UnsupportedOperationException()
override fun isObsolete() = throw UnsupportedOperationException()
override fun isSynchronized() = throw UnsupportedOperationException()
override fun allLineLocations(stratum: String?, sourceName: String?) = throw UnsupportedOperationException()
override fun isNative() = throw UnsupportedOperationException()
override fun locationOfCodeIndex(codeIndex: Long) = throw UnsupportedOperationException()
override fun arguments() = throw UnsupportedOperationException()
override fun isAbstract() = throw UnsupportedOperationException()
override fun isVarArgs() = throw UnsupportedOperationException()
override fun returnTypeName() = throw UnsupportedOperationException()
override fun argumentTypes( ) = throw UnsupportedOperationException()
override fun isConstructor() = throw UnsupportedOperationException()
override fun locationsOfLine(lineNumber: Int) = throw UnsupportedOperationException()
override fun locationsOfLine(stratum: String?, sourceName: String?, lineNumber: Int) = throw UnsupportedOperationException()
override fun argumentTypeNames() = throw UnsupportedOperationException()
override fun returnType() = throw UnsupportedOperationException()
override fun isStaticInitializer() = throw UnsupportedOperationException()
override fun location() = throw UnsupportedOperationException()
override fun compareTo(other: Method?) = throw UnsupportedOperationException()
override fun isPackagePrivate() = throw UnsupportedOperationException()
override fun isPrivate() = throw UnsupportedOperationException()
override fun isProtected() = throw UnsupportedOperationException()
override fun isPublic() = throw UnsupportedOperationException()
override fun modifiers() = throw UnsupportedOperationException()
override fun virtualMachine() = throw UnsupportedOperationException()
}
@@ -0,0 +1,51 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.mock
import com.intellij.debugger.SourcePosition
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
class MockSourcePosition(
private val myFile: PsiFile? = null,
private val myElementAt: PsiElement? = null,
private val myLine: Int? = null,
private val myOffset: Int? = null,
private val myEditor: Editor? = null
) : SourcePosition() {
override fun getFile(): PsiFile {
return myFile ?: throw UnsupportedOperationException("Parameter file isn't set for MockSourcePosition")
}
override fun getElementAt(): PsiElement {
return myElementAt ?: throw UnsupportedOperationException("Parameter elementAt isn't set for MockSourcePosition")
}
override fun getLine(): Int {
return myLine ?: throw UnsupportedOperationException("Parameter line isn't set for MockSourcePosition")
}
override fun getOffset(): Int {
return myOffset ?: throw UnsupportedOperationException("Parameter offset isn't set for MockSourcePosition")
}
override fun openEditor(requestFocus: Boolean): Editor {
return myEditor ?: throw UnsupportedOperationException("Parameter editor isn't set for MockSourcePosition")
}
override fun navigate(requestFocus: Boolean) {
throw UnsupportedOperationException("navigate() isn't supported for MockSourcePosition")
}
override fun canNavigate(): Boolean {
throw UnsupportedOperationException("canNavigate() isn't supported for MockSourcePosition")
}
override fun canNavigateToSource(): Boolean {
throw UnsupportedOperationException("canNavigateToSource() isn't supported for MockSourcePosition")
}
}
@@ -0,0 +1,283 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.mock;
import com.sun.jdi.*;
import com.sun.jdi.event.EventQueue;
import com.sun.jdi.request.EventRequestManager;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class MockVirtualMachine implements VirtualMachine {
@Override
public List<ThreadGroupReference> topLevelThreadGroups() {
return Collections.emptyList();
}
@Override
public String version() {
return "1.6";
}
@Override
public List<ReferenceType> classesByName(String s) {
throw new UnsupportedOperationException();
}
@Override
public List<ReferenceType> allClasses() {
// Can't throw since this method is invoked during VirtualMachineProxy initialization
return Collections.emptyList();
}
@Override
public void redefineClasses(Map<? extends ReferenceType, byte[]> map) {
throw new UnsupportedOperationException();
}
@Override
public List<ThreadReference> allThreads() {
return Collections.emptyList();
}
@Override
public void suspend() {
throw new UnsupportedOperationException();
}
@Override
public void resume() {
throw new UnsupportedOperationException();
}
@Override
public EventQueue eventQueue() {
throw new UnsupportedOperationException();
}
@Override
public EventRequestManager eventRequestManager() {
throw new UnsupportedOperationException();
}
@Override
public BooleanValue mirrorOf(boolean b) {
throw new UnsupportedOperationException();
}
@Override
public ByteValue mirrorOf(byte b) {
throw new UnsupportedOperationException();
}
@Override
public CharValue mirrorOf(char c) {
throw new UnsupportedOperationException();
}
@Override
public ShortValue mirrorOf(short i) {
throw new UnsupportedOperationException();
}
@Override
public IntegerValue mirrorOf(int i) {
throw new UnsupportedOperationException();
}
@Override
public LongValue mirrorOf(long l) {
throw new UnsupportedOperationException();
}
@Override
public FloatValue mirrorOf(float v) {
throw new UnsupportedOperationException();
}
@Override
public DoubleValue mirrorOf(double v) {
throw new UnsupportedOperationException();
}
@Override
public StringReference mirrorOf(String s) {
throw new UnsupportedOperationException();
}
@Override
public VoidValue mirrorOfVoid() {
throw new UnsupportedOperationException();
}
@Override
public Process process() {
throw new UnsupportedOperationException();
}
@Override
public void dispose() {
throw new UnsupportedOperationException();
}
@Override
public void exit(int i) {
throw new UnsupportedOperationException();
}
@Override
public void setDefaultStratum(String s) {
throw new UnsupportedOperationException();
}
@Override
public String getDefaultStratum() {
throw new UnsupportedOperationException();
}
@Override
public String description() {
throw new UnsupportedOperationException();
}
@Override
public String name() {
return "JVM mock";
}
@Override
public void setDebugTraceMode(int i) {
throw new UnsupportedOperationException();
}
@Override
public boolean canWatchFieldModification() {
return false;
}
@Override
public boolean canWatchFieldAccess() {
return false;
}
@Override
public boolean canGetBytecodes() {
return false;
}
@Override
public boolean canGetSyntheticAttribute() {
return false;
}
@Override
public boolean canGetOwnedMonitorInfo() {
return false;
}
@Override
public boolean canGetCurrentContendedMonitor() {
return false;
}
@Override
public boolean canGetMonitorInfo() {
return false;
}
@Override
public boolean canUseInstanceFilters() {
return false;
}
@Override
public boolean canRedefineClasses() {
return false;
}
@Override
public boolean canAddMethod() {
return false;
}
@Override
public boolean canUnrestrictedlyRedefineClasses() {
return false;
}
@Override
public boolean canPopFrames() {
return false;
}
@Override
public boolean canGetSourceDebugExtension() {
return false;
}
@Override
public boolean canRequestVMDeathEvent() {
return false;
}
@Override
public boolean canGetMethodReturnValues() {
return false;
}
@Override
public boolean canGetInstanceInfo() {
return false;
}
@Override
public boolean canUseSourceNameFilters() {
return false;
}
@Override
public boolean canForceEarlyReturn() {
return false;
}
@Override
public boolean canBeModified() {
return false;
}
@Override
public boolean canRequestMonitorEvents() {
return false;
}
@Override
public boolean canGetMonitorFrameInfo() {
return false;
}
@Override
public boolean canGetClassFileVersion() {
return false;
}
@Override
public boolean canGetConstantPool() {
return false;
}
@Override
public long[] instanceCounts(List<? extends ReferenceType> types) {
return new long[0];
}
@Override
public VirtualMachine virtualMachine() {
return this;
}
}
@@ -0,0 +1,206 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.mock
import com.sun.jdi.*
import org.jetbrains.kotlin.backend.common.output.OutputFile
import org.jetbrains.kotlin.backend.common.output.OutputFileCollection
import org.jetbrains.org.objectweb.asm.ClassReader
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.tree.ClassNode
import org.jetbrains.org.objectweb.asm.tree.LineNumberNode
import org.jetbrains.org.objectweb.asm.tree.MethodNode
class SmartMockReferenceTypeContext(outputFiles: List<OutputFile>) {
constructor(outputFiles: OutputFileCollection) : this(outputFiles.asList())
val virtualMachine = MockVirtualMachine()
val classes = outputFiles
.filter { it.relativePath.endsWith(".class") }
.map { it.readClass() }
private val referenceTypes: List<ReferenceType> by lazy {
classes.map { SmartMockReferenceType(it, this) }
}
val referenceTypesByName by lazy {
referenceTypes.map { Pair(it.name(), it) }.toMap()
}
}
private fun OutputFile.readClass(): ClassNode {
val classNode = ClassNode()
ClassReader(asByteArray()).accept(classNode, ClassReader.EXPAND_FRAMES)
return classNode
}
class SmartMockReferenceType(val classNode: ClassNode, private val context: SmartMockReferenceTypeContext) : ReferenceType {
override fun instances(maxInstances: Long) = emptyList<ObjectReference>()
override fun isPublic() = (classNode.access and Opcodes.ACC_PUBLIC) != 0
override fun classLoader() = null
override fun sourceName(): String? = classNode.sourceFile
override fun defaultStratum() = "Java"
override fun isStatic() = (classNode.access and Opcodes.ACC_STATIC) != 0
override fun modifiers() = classNode.access
override fun isProtected() = (classNode.access and Opcodes.ACC_PROTECTED) != 0
override fun isFinal() = (classNode.access and Opcodes.ACC_FINAL) != 0
override fun allLineLocations() = methodsCached.flatMap { it.allLineLocations() }
override fun genericSignature(): String? = classNode.signature
override fun isAbstract() = (classNode.access and Opcodes.ACC_ABSTRACT) != 0
override fun isPrepared() = true
override fun name() = classNode.name.replace('/', '.')
override fun isInitialized() = true
override fun sourcePaths(stratum: String) = listOf(classNode.sourceFile)
override fun failedToInitialize() = false
override fun virtualMachine() = context.virtualMachine
override fun isPrivate() = (classNode.access and Opcodes.ACC_PRIVATE) != 0
override fun signature(): String? = classNode.signature
override fun sourceNames(stratum: String) = listOf(classNode.sourceFile)
override fun availableStrata() = emptyList<String>()
private val methodsCached by lazy { classNode.methods.map { MockMethod(it, this) } }
override fun methods() = methodsCached
override fun nestedTypes(): List<ReferenceType> {
val fromInnerClasses = classNode.innerClasses
.filter { it.outerName == classNode.name }
.mapNotNull { context.classes.find { c -> it.name == c.name } }
val fromOuterClasses = context.classes.filter { it.outerClass == classNode.name }
return (fromInnerClasses + fromOuterClasses).distinctBy { it.name }.map { SmartMockReferenceType(it, context) }
}
override fun isPackagePrivate(): Boolean {
return ((classNode.access and Opcodes.ACC_PUBLIC) == 0
&& (classNode.access and Opcodes.ACC_PROTECTED) == 0
&& (classNode.access and Opcodes.ACC_PRIVATE) == 0)
}
override fun isVerified() = true
override fun fields() = TODO()
override fun allFields() = TODO()
override fun fieldByName(fieldName: String) = TODO()
override fun getValue(p0: Field?) = TODO()
override fun visibleFields() = TODO()
override fun allLineLocations(stratum: String, sourceName: String) = TODO()
override fun majorVersion() = TODO()
override fun constantPoolCount() = TODO()
override fun constantPool() = TODO()
override fun compareTo(other: ReferenceType?) = TODO()
override fun sourceDebugExtension() = TODO()
override fun visibleMethods() = TODO()
override fun locationsOfLine(lineNumber: Int) = TODO()
override fun locationsOfLine(stratum: String, sourceName: String, lineNumber: Int) = TODO()
override fun getValues(p0: MutableList<out Field>?) = TODO()
override fun minorVersion() = TODO()
override fun classObject() = TODO()
override fun methodsByName(p0: String?) = TODO()
override fun methodsByName(p0: String?, p1: String?) = TODO()
override fun allMethods() = TODO()
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other?.javaClass != javaClass) return false
other as SmartMockReferenceType
return classNode.name == other.classNode.name
}
override fun hashCode(): Int {
return classNode.name.hashCode()
}
class MockMethod(private val methodNode: MethodNode, val containingClass: SmartMockReferenceType) : Method {
override fun virtualMachine() = containingClass.context.virtualMachine
override fun modifiers() = methodNode.access
override fun isStaticInitializer() = methodNode.name == "<clinit>"
override fun isPublic() = (methodNode.access and Opcodes.ACC_PUBLIC) != 0
override fun isNative() = (methodNode.access and Opcodes.ACC_NATIVE) != 0
override fun isStatic() = (methodNode.access and Opcodes.ACC_STATIC) != 0
override fun isBridge() = (methodNode.access and Opcodes.ACC_BRIDGE) != 0
override fun isProtected() = (methodNode.access and Opcodes.ACC_PROTECTED) != 0
override fun isFinal() = (methodNode.access and Opcodes.ACC_FINAL) != 0
override fun isAbstract() = (methodNode.access and Opcodes.ACC_ABSTRACT) != 0
override fun isSynthetic() = (methodNode.access and Opcodes.ACC_SYNTHETIC) != 0
override fun isConstructor() = methodNode.name == "<init>"
override fun isPrivate() = (methodNode.access and Opcodes.ACC_PRIVATE) != 0
override fun isPackagePrivate(): Boolean {
return ((methodNode.access and Opcodes.ACC_PUBLIC) == 0
&& (methodNode.access and Opcodes.ACC_PROTECTED) == 0
&& (methodNode.access and Opcodes.ACC_PRIVATE) == 0)
}
override fun declaringType() = containingClass
override fun name(): String? = methodNode.name
override fun signature(): String? = methodNode.signature
override fun location(): Location? {
val instructionList = methodNode.instructions ?: return null
var current = instructionList.first
while (current != null) {
if (current is LineNumberNode) {
return MockLocation(this, current.line)
}
current = current.next
}
return null
}
override fun allLineLocations(): List<Location> {
val instructionList = methodNode.instructions ?: return emptyList()
var current = instructionList.first
val locations = mutableListOf<Location>()
while (current != null) {
if (current is LineNumberNode) {
locations += MockLocation(this, current.line)
}
current = current.next
}
return locations
}
override fun argumentTypeNames() = TODO()
override fun arguments() = TODO()
override fun allLineLocations(p0: String?, p1: String?) = TODO()
override fun genericSignature() = TODO()
override fun returnType() = TODO()
override fun compareTo(other: Method?) = TODO()
override fun isObsolete() = false
override fun variablesByName(p0: String?) = TODO()
override fun argumentTypes() = TODO()
override fun locationOfCodeIndex(p0: Long) = TODO()
override fun bytecodes() = TODO()
override fun returnTypeName() = TODO()
override fun locationsOfLine(p0: Int) = TODO()
override fun locationsOfLine(p0: String?, p1: String?, p2: Int) = TODO()
override fun variables() = TODO()
override fun isVarArgs() = TODO()
override fun isSynchronized() = TODO()
}
private class MockLocation(val method: MockMethod, val line: Int) : Location {
override fun virtualMachine() = method.containingClass.context.virtualMachine
override fun sourceName() = method.containingClass.sourceName()
override fun lineNumber() = line
override fun sourcePath() = sourceName()
override fun declaringType() = method.containingClass
override fun method() = method
override fun sourceName(stratum: String) = TODO()
override fun codeIndex() = TODO()
override fun lineNumber(stratum: String) = TODO()
override fun sourcePath(stratum: String) = TODO()
override fun compareTo(other: Location?) = TODO()
}
}
@@ -0,0 +1,58 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("ClassName")
package org.jetbrains.kotlin.idea.debugger.test.preference
import java.lang.reflect.ParameterizedType
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
import kotlin.reflect.full.declaredMemberProperties
import kotlin.reflect.jvm.javaType
class DebuggerPreferenceKey<T : Any>(val name: String, val type: Class<*>, val defaultValue: T)
private inline fun <reified T : Any> debuggerPreferenceKey(defaultValue: T): ReadOnlyProperty<Any, DebuggerPreferenceKey<T>> {
val clazz = T::class.java
return object : ReadOnlyProperty<Any, DebuggerPreferenceKey<T>> {
override fun getValue(thisRef: Any, property: KProperty<*>) = DebuggerPreferenceKey(property.name, clazz, defaultValue)
}
}
internal object DebuggerPreferenceKeys {
val SKIP_SYNTHETIC_METHODS by debuggerPreferenceKey(true)
val SKIP_CONSTRUCTORS: DebuggerPreferenceKey<Boolean> by debuggerPreferenceKey(false)
val SKIP_CLASSLOADERS by debuggerPreferenceKey(true)
val TRACING_FILTERS_ENABLED by debuggerPreferenceKey(true)
val SKIP_GETTERS by debuggerPreferenceKey(false)
val DISABLE_KOTLIN_INTERNAL_CLASSES by debuggerPreferenceKey(false)
val RENDER_DELEGATED_PROPERTIES by debuggerPreferenceKey(false)
val IS_FILTER_FOR_STDLIB_ALREADY_ADDED by debuggerPreferenceKey(false)
val FORCE_RANKING by debuggerPreferenceKey(false)
val EMULATE_DEX by debuggerPreferenceKey(false)
val PRINT_FRAME by debuggerPreferenceKey(false)
val SHOW_KOTLIN_VARIABLES by debuggerPreferenceKey(false)
val DESCRIPTOR_VIEW_OPTIONS by debuggerPreferenceKey("FULL")
val ATTACH_LIBRARY by debuggerPreferenceKey(emptyList<String>())
val SKIP by debuggerPreferenceKey(emptyList<String>())
val WATCH_FIELD_ACCESS by debuggerPreferenceKey(true)
val WATCH_FIELD_MODIFICATION by debuggerPreferenceKey(true)
val WATCH_FIELD_INITIALISATION by debuggerPreferenceKey(false)
val JVM_TARGET by debuggerPreferenceKey("1.8")
val values: List<DebuggerPreferenceKey<*>> by lazy {
DebuggerPreferenceKeys::class.declaredMemberProperties
.filter { (it.returnType.javaType as? ParameterizedType)?.rawType == DebuggerPreferenceKey::class.java }
.map { it.get(DebuggerPreferenceKeys) as DebuggerPreferenceKey<*> }
}
}
@@ -0,0 +1,50 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.preference
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.test.InTextDirectivesUtils
class DebuggerPreferences(val project: Project, fileContents: String) {
private val values: Map<String, Any?>
init {
val values = HashMap<String, Any?>()
for (key in DebuggerPreferenceKeys.values) {
val list = findValues(fileContents, key.name).takeIf { it.isNotEmpty() } ?: continue
fun errorValue(): Nothing = error("Error value for key ${key.name}")
val convertedValue: Any = when (key.type) {
java.lang.Boolean::class.java -> list.singleOrNull()?.toBoolean() ?: errorValue()
String::class.java -> list.singleOrNull() ?: errorValue()
java.lang.Integer::class.java -> list.singleOrNull()?.toIntOrNull() ?: errorValue()
List::class.java -> list
else -> error("Cannot find a converter for type ${key.type}")
}
values[key.name] = convertedValue
}
this.values = values
}
private fun findValues(fileContents: String, key: String): List<String> {
val list: List<String> = InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileContents, "// $key: ")
if (list.isNotEmpty()) {
return list
}
if (InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileContents, true, false, "// $key").isNotEmpty()) {
return listOf("true")
}
return emptyList()
}
operator fun <T : Any> get(key: DebuggerPreferenceKey<T>): T {
@Suppress("UNCHECKED_CAST")
return values[key.name] as T? ?: key.defaultValue
}
}
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.preference
import com.intellij.openapi.project.Project
internal abstract class SettingsMutator<T : Any>(val key: DebuggerPreferenceKey<T>) {
abstract fun setValue(value: T, project: Project): T
open fun revertValue(value: T, project: Project) {
setValue(value, project)
}
}
internal fun <T : Any> SettingsMutator<T>.setValue(preferences: DebuggerPreferences): OldValueStorage<T> {
val project = preferences.project
return OldValueStorage(this, project, setValue(preferences[key], project))
}
internal class OldValueStorage<T : Any>(
private val mutator: SettingsMutator<T>,
private val project: Project,
private val oldValue: T
) {
fun revertValue() = mutator.revertValue(oldValue, project)
}
internal class OldValuesStorage(private val oldValues: List<OldValueStorage<*>>) {
fun revertValues() = oldValues.forEach { it.revertValue() }
}
internal fun List<SettingsMutator<*>>.mutate(preferences: DebuggerPreferences): OldValuesStorage {
return OldValuesStorage(map { it.setValue(preferences) })
}
@@ -0,0 +1,99 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.preference
import com.intellij.debugger.settings.DebuggerSettings
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.idea.compiler.configuration.Kotlin2JvmCompilerArgumentsHolder
import org.jetbrains.kotlin.idea.debugger.DebuggerUtils
import org.jetbrains.kotlin.idea.debugger.KotlinDebuggerSettings
import org.jetbrains.kotlin.idea.debugger.ToggleKotlinVariablesState
import org.jetbrains.kotlin.idea.debugger.emulateDexDebugInTests
import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferenceKeys.DISABLE_KOTLIN_INTERNAL_CLASSES
import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferenceKeys.IS_FILTER_FOR_STDLIB_ALREADY_ADDED
import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferenceKeys.RENDER_DELEGATED_PROPERTIES
import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferenceKeys.SKIP_CONSTRUCTORS
import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferenceKeys.SKIP_CLASSLOADERS
import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferenceKeys.SKIP_GETTERS
import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferenceKeys.SKIP_SYNTHETIC_METHODS
import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferenceKeys.TRACING_FILTERS_ENABLED
import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferenceKeys.EMULATE_DEX
import kotlin.reflect.KMutableProperty1
internal val SettingsMutators: List<SettingsMutator<*>> = listOf(
DebuggerSettingsMutator(SKIP_SYNTHETIC_METHODS, DebuggerSettings::SKIP_SYNTHETIC_METHODS),
DebuggerSettingsMutator(SKIP_CONSTRUCTORS, DebuggerSettings::SKIP_CONSTRUCTORS),
DebuggerSettingsMutator(SKIP_CLASSLOADERS, DebuggerSettings::SKIP_CLASSLOADERS),
DebuggerSettingsMutator(TRACING_FILTERS_ENABLED, DebuggerSettings::TRACING_FILTERS_ENABLED),
DebuggerSettingsMutator(SKIP_GETTERS, DebuggerSettings::SKIP_GETTERS),
KotlinSettingsMutator(DISABLE_KOTLIN_INTERNAL_CLASSES, KotlinDebuggerSettings::DEBUG_DISABLE_KOTLIN_INTERNAL_CLASSES),
KotlinSettingsMutator(RENDER_DELEGATED_PROPERTIES, KotlinDebuggerSettings::DEBUG_RENDER_DELEGATED_PROPERTIES),
KotlinSettingsMutator(IS_FILTER_FOR_STDLIB_ALREADY_ADDED, KotlinDebuggerSettings::DEBUG_IS_FILTER_FOR_STDLIB_ALREADY_ADDED),
DexSettingsMutator(EMULATE_DEX),
KotlinVariablesModeSettingsMutator,
JvmTargetSettingsMutator,
ForceRankingSettingsMutator
)
private class DexSettingsMutator(key: DebuggerPreferenceKey<Boolean>): SettingsMutator<Boolean>(key) {
override fun setValue(value: Boolean, project: Project): Boolean {
val oldValue = emulateDexDebugInTests
emulateDexDebugInTests = value
return oldValue
}
}
private class DebuggerSettingsMutator<T : Any>(
key: DebuggerPreferenceKey<T>,
private val prop: KMutableProperty1<DebuggerSettings, T>
) : SettingsMutator<T>(key) {
override fun setValue(value: T, project: Project): T {
val debuggerSettings = DebuggerSettings.getInstance()
val oldValue = prop.get(debuggerSettings)
prop.set(debuggerSettings, value)
return oldValue
}
}
private class KotlinSettingsMutator<T : Any>(
key: DebuggerPreferenceKey<T>,
private val prop: KMutableProperty1<KotlinDebuggerSettings, T>
) : SettingsMutator<T>(key) {
override fun setValue(value: T, project: Project): T {
val debuggerSettings = KotlinDebuggerSettings.getInstance()
val oldValue = prop.get(debuggerSettings)
prop.set(debuggerSettings, value)
return oldValue
}
}
private object KotlinVariablesModeSettingsMutator : SettingsMutator<Boolean>(DebuggerPreferenceKeys.SHOW_KOTLIN_VARIABLES) {
override fun setValue(value: Boolean, project: Project): Boolean {
val service = ToggleKotlinVariablesState.getService()
val oldValue = service.kotlinVariableView
service.kotlinVariableView = value
return oldValue
}
}
private object JvmTargetSettingsMutator : SettingsMutator<String>(DebuggerPreferenceKeys.JVM_TARGET) {
override fun setValue(value: String, project: Project): String {
var oldValue: String? = null
Kotlin2JvmCompilerArgumentsHolder.getInstance(project).update {
oldValue = jvmTarget
jvmTarget = value.takeIf { it.isNotEmpty() }
}
return oldValue ?: ""
}
}
private object ForceRankingSettingsMutator : SettingsMutator<Boolean>(DebuggerPreferenceKeys.FORCE_RANKING) {
override fun setValue(value: Boolean, project: Project): Boolean {
val oldValue = DebuggerUtils.forceRanking
DebuggerUtils.forceRanking = value
return oldValue
}
}
@@ -0,0 +1,74 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.sequence
import com.intellij.debugger.streams.test.StreamChainBuilderTestCase
import com.intellij.debugger.streams.wrapper.StreamChain
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable
import com.intellij.testFramework.LightPlatformTestCase
import com.intellij.testFramework.PsiTestUtil
import junit.framework.TestCase
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
import org.jetbrains.kotlin.idea.caches.project.LibraryModificationTracker
import org.jetbrains.kotlin.idea.debugger.test.DEBUGGER_TESTDATA_PATH_BASE
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
abstract class KotlinPsiChainBuilderTestCase(private val relativePath: String) : StreamChainBuilderTestCase() {
override fun getTestDataPath(): String = "$DEBUGGER_TESTDATA_PATH_BASE/sequence/psi/$relativeTestPath"
override fun getFileExtension(): String = ".kt"
abstract val kotlinChainBuilder: StreamChainBuilder
override fun getChainBuilder(): StreamChainBuilder = kotlinChainBuilder
private val stdLibName = "kotlin-stdlib"
protected abstract fun doTest()
final override fun getRelativeTestPath(): String = relativePath
override fun setUp() {
super.setUp()
ApplicationManager.getApplication().runWriteAction {
@Suppress("UnstableApiUsage")
if (ProjectLibraryTable.getInstance(LightPlatformTestCase.getProject()).getLibraryByName(stdLibName) == null) {
val stdLibPath = ForTestCompileRuntime.runtimeJarForTests()
PsiTestUtil.addLibrary(
testRootDisposable,
LightPlatformTestCase.getModule(),
stdLibName,
stdLibPath.parent,
stdLibPath.name
)
}
}
LibraryModificationTracker.getInstance(LightPlatformTestCase.getProject()).incModificationCount()
}
override fun getProjectJDK(): Sdk {
return PluginTestCaseBase.mockJdk9()
}
abstract class Positive(relativePath: String) : KotlinPsiChainBuilderTestCase(relativePath) {
override fun doTest() {
val chains = buildChains()
checkChains(chains)
}
private fun checkChains(chains: MutableList<StreamChain>) {
TestCase.assertFalse(chains.isEmpty())
}
}
abstract class Negative(relativePath: String) : KotlinPsiChainBuilderTestCase(relativePath) {
override fun doTest() {
val elementAtCaret = configureAndGetElementAtCaret()
TestCase.assertFalse(chainBuilder.isChainExists(elementAtCaret))
TestCase.assertTrue(chainBuilder.build(elementAtCaret).isEmpty())
}
}
}
@@ -0,0 +1,20 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.sequence.dsl
import com.intellij.debugger.streams.test.DslTestCase
import com.intellij.debugger.streams.trace.dsl.impl.DslImpl
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinCollectionsPeekCallFactory
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinStatementFactory
import org.jetbrains.kotlin.idea.debugger.test.DEBUGGER_TESTDATA_PATH_RELATIVE
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
import org.junit.runner.RunWith
@RunWith(JUnit3WithIdeaConfigurationRunner::class)
class KotlinDslTest : DslTestCase(DslImpl(KotlinStatementFactory(KotlinCollectionsPeekCallFactory()))) {
override fun getTestDataPath(): String {
return "$DEBUGGER_TESTDATA_PATH_RELATIVE/sequence/dsl"
}
}
@@ -0,0 +1,14 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.sequence.exec
import com.intellij.debugger.streams.lib.LibrarySupportProvider
import org.jetbrains.kotlin.idea.debugger.sequence.lib.collections.KotlinCollectionSupportProvider
@Suppress("unused")
abstract class AbstractCollectionTraceTestCase : KotlinTraceTestCase() {
override val librarySupportProvider: LibrarySupportProvider = KotlinCollectionSupportProvider()
}
@@ -0,0 +1,14 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.sequence.exec
import com.intellij.debugger.streams.lib.LibrarySupportProvider
import org.jetbrains.kotlin.idea.debugger.sequence.lib.java.JavaStandardLibrarySupportProvider
@Suppress("unused")
abstract class AbstractJavaStreamTraceTestCase : KotlinTraceTestCase() {
override val librarySupportProvider: LibrarySupportProvider = JavaStandardLibrarySupportProvider()
}
@@ -0,0 +1,13 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.sequence.exec
import com.intellij.debugger.streams.lib.LibrarySupportProvider
import org.jetbrains.kotlin.idea.debugger.sequence.lib.sequence.KotlinSequenceSupportProvider
abstract class AbstractSequenceTraceTestCase : KotlinTraceTestCase() {
override val librarySupportProvider: LibrarySupportProvider = KotlinSequenceSupportProvider()
}
@@ -0,0 +1,170 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.sequence.exec
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
import com.intellij.debugger.impl.OutputChecker
import com.intellij.debugger.streams.lib.LibrarySupportProvider
import com.intellij.debugger.streams.psi.DebuggerPositionResolver
import com.intellij.debugger.streams.psi.impl.DebuggerPositionResolverImpl
import com.intellij.debugger.streams.trace.*
import com.intellij.debugger.streams.trace.impl.TraceResultInterpreterImpl
import com.intellij.debugger.streams.wrapper.StreamChain
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
import com.intellij.execution.process.ProcessOutputTypes
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.util.Computable
import com.intellij.xdebugger.XDebugSessionListener
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches
import org.jetbrains.kotlin.idea.debugger.test.KotlinDescriptorTestCaseWithStepping
import org.jetbrains.kotlin.idea.debugger.test.TestFiles
import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferences
import java.util.concurrent.atomic.AtomicBoolean
abstract class KotlinTraceTestCase : KotlinDescriptorTestCaseWithStepping() {
private companion object {
val DEFAULT_CHAIN_SELECTOR = ChainSelector.byIndex(0)
}
private lateinit var traceChecker: StreamTraceChecker
override fun initOutputChecker(): OutputChecker {
traceChecker = StreamTraceChecker(this)
return super.initOutputChecker()
}
abstract val librarySupportProvider: LibrarySupportProvider
override fun doMultiFileTest(files: TestFiles, preferences: DebuggerPreferences) {
// Sequence expressions are verbose. Disable expression logging for sequence debugger
KotlinDebuggerCaches.LOG_COMPILATIONS = false
val session = debuggerSession.xDebugSession ?: kotlin.test.fail("XDebugSession is null")
assertNotNull(session)
val completed = AtomicBoolean(false)
val positionResolver = getPositionResolver()
val chainBuilder = getChainBuilder()
val resultInterpreter = getResultInterpreter()
val expressionBuilder = getExpressionBuilder()
val chainSelector = DEFAULT_CHAIN_SELECTOR
session.addSessionListener(object : XDebugSessionListener {
override fun sessionPaused() {
if (completed.getAndSet(true)) {
resume()
return
}
try {
sessionPausedImpl()
} catch (t: Throwable) {
println("Exception caught: $t, ${t.message}", ProcessOutputTypes.SYSTEM)
t.printStackTrace()
resume()
}
}
private fun sessionPausedImpl() {
printContext(debugProcess.debuggerContext)
val chain = ApplicationManager.getApplication().runReadAction(
Computable<StreamChain> {
val elementAtBreakpoint = positionResolver.getNearestElementToBreakpoint(session)
val chains = if (elementAtBreakpoint == null) null else chainBuilder.build(elementAtBreakpoint)
if (chains == null || chains.isEmpty()) null else chainSelector.select(chains)
})
if (chain == null) {
complete(null, null, null, FailureReason.CHAIN_CONSTRUCTION)
return
}
EvaluateExpressionTracer(session, expressionBuilder, resultInterpreter).trace(chain, object : TracingCallback {
override fun evaluated(result: TracingResult, context: EvaluationContextImpl) {
complete(chain, result, null, null)
}
override fun evaluationFailed(traceExpression: String, message: String) {
complete(chain, null, message, FailureReason.EVALUATION)
}
override fun compilationFailed(traceExpression: String, message: String) {
complete(chain, null, message, FailureReason.COMPILATION)
}
})
}
private fun complete(chain: StreamChain?, result: TracingResult?, error: String?, errorReason: FailureReason?) {
try {
if (error != null) {
assertNotNull(errorReason)
assertNotNull(chain)
throw AssertionError(error)
} else {
assertNull(errorReason)
handleSuccess(chain, result)
}
} catch (t: Throwable) {
println("Exception caught: " + t + ", " + t.message, ProcessOutputTypes.SYSTEM)
} finally {
resume()
}
}
private fun resume() {
ApplicationManager.getApplication().invokeLater { session.resume() }
}
}, testRootDisposable)
}
private fun getPositionResolver(): DebuggerPositionResolver {
return DebuggerPositionResolverImpl()
}
protected fun handleSuccess(chain: StreamChain?, result: TracingResult?) {
kotlin.test.assertNotNull(chain)
kotlin.test.assertNotNull(result)
println(chain.text, ProcessOutputTypes.SYSTEM)
val trace = result.trace
traceChecker.checkChain(trace)
val resolvedTrace = result.resolve(librarySupportProvider.librarySupport.resolverFactory)
traceChecker.checkResolvedChain(resolvedTrace)
}
private fun getResultInterpreter(): TraceResultInterpreter {
return TraceResultInterpreterImpl(librarySupportProvider.librarySupport.interpreterFactory)
}
private fun getChainBuilder(): StreamChainBuilder {
return librarySupportProvider.chainBuilder
}
private fun getExpressionBuilder(): TraceExpressionBuilder {
return librarySupportProvider.getExpressionBuilder(project)
}
protected enum class FailureReason {
COMPILATION, EVALUATION, CHAIN_CONSTRUCTION
}
@FunctionalInterface
protected interface ChainSelector {
fun select(chains: List<StreamChain>): StreamChain
companion object {
fun byIndex(index: Int): ChainSelector {
return object : ChainSelector {
override fun select(chains: List<StreamChain>): StreamChain = chains[index]
}
}
}
}
}
@@ -0,0 +1,357 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.sequence.exec;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class SequenceTraceTestCaseGenerated extends AbstractSequenceTraceTestCase {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInSequence() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true, "terminal");
}
@TestMetadata("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/append")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Append extends AbstractSequenceTraceTestCase {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInAppend() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/append"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("PlusArray.kt")
public void testPlusArray() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/append/PlusArray.kt");
}
@TestMetadata("PlusElement.kt")
public void testPlusElement() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/append/PlusElement.kt");
}
@TestMetadata("PlusSequence.kt")
public void testPlusSequence() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/append/PlusSequence.kt");
}
@TestMetadata("PlusSingle.kt")
public void testPlusSingle() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/append/PlusSingle.kt");
}
}
@TestMetadata("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/distinct")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Distinct extends AbstractSequenceTraceTestCase {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInDistinct() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/distinct"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("Distinct.kt")
public void testDistinct() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/distinct/Distinct.kt");
}
@TestMetadata("DistinctBy.kt")
public void testDistinctBy() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/distinct/DistinctBy.kt");
}
@TestMetadata("DistinctByBigPrimitives.kt")
public void testDistinctByBigPrimitives() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/distinct/DistinctByBigPrimitives.kt");
}
@TestMetadata("DistinctByNullableElement.kt")
public void testDistinctByNullableElement() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/distinct/DistinctByNullableElement.kt");
}
@TestMetadata("DistinctByNullableKey.kt")
public void testDistinctByNullableKey() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/distinct/DistinctByNullableKey.kt");
}
@TestMetadata("DistinctByNullableKeyAndElement.kt")
public void testDistinctByNullableKeyAndElement() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/distinct/DistinctByNullableKeyAndElement.kt");
}
@TestMetadata("DistinctObjects.kt")
public void testDistinctObjects() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/distinct/DistinctObjects.kt");
}
}
@TestMetadata("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/filter")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Filter extends AbstractSequenceTraceTestCase {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInFilter() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/filter"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("Drop.kt")
public void testDrop() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/filter/Drop.kt");
}
@TestMetadata("DropWhile.kt")
public void testDropWhile() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/filter/DropWhile.kt");
}
@TestMetadata("Filter.kt")
public void testFilter() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/filter/Filter.kt");
}
@TestMetadata("FilterIndexed.kt")
public void testFilterIndexed() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/filter/FilterIndexed.kt");
}
@TestMetadata("FilterIsInstance.kt")
public void testFilterIsInstance() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/filter/FilterIsInstance.kt");
}
@TestMetadata("FilterNot.kt")
public void testFilterNot() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/filter/FilterNot.kt");
}
@TestMetadata("Minus.kt")
public void testMinus() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/filter/Minus.kt");
}
@TestMetadata("MinusElement.kt")
public void testMinusElement() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/filter/MinusElement.kt");
}
@TestMetadata("Take.kt")
public void testTake() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/filter/Take.kt");
}
@TestMetadata("TakeWhile.kt")
public void testTakeWhile() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/filter/TakeWhile.kt");
}
}
@TestMetadata("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/flatMap")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class FlatMap extends AbstractSequenceTraceTestCase {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInFlatMap() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/flatMap"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("FlatMap.kt")
public void testFlatMap() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/flatMap/FlatMap.kt");
}
@TestMetadata("Flatten.kt")
public void testFlatten() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/flatMap/Flatten.kt");
}
}
@TestMetadata("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/map")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Map extends AbstractSequenceTraceTestCase {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInMap() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/map"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("Map.kt")
public void testMap() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/map/Map.kt");
}
@TestMetadata("MapIndexed.kt")
public void testMapIndexed() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/map/MapIndexed.kt");
}
@TestMetadata("MapNotNull.kt")
public void testMapNotNull() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/map/MapNotNull.kt");
}
@TestMetadata("WithIndex.kt")
public void testWithIndex() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/map/WithIndex.kt");
}
}
@TestMetadata("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/misc")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Misc extends AbstractSequenceTraceTestCase {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInMisc() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/misc"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("AsSequence.kt")
public void testAsSequence() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/misc/AsSequence.kt");
}
@TestMetadata("Chunked.kt")
public void testChunked() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/misc/Chunked.kt");
}
@TestMetadata("ChunkedWithTransform.kt")
public void testChunkedWithTransform() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/misc/ChunkedWithTransform.kt");
}
@TestMetadata("ConstrainOnce.kt")
public void testConstrainOnce() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/misc/ConstrainOnce.kt");
}
@TestMetadata("OnEach.kt")
public void testOnEach() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/misc/OnEach.kt");
}
@TestMetadata("RequireNoNulls.kt")
public void testRequireNoNulls() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/misc/RequireNoNulls.kt");
}
@TestMetadata("Windowed.kt")
public void testWindowed() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/misc/Windowed.kt");
}
@TestMetadata("WindowedWithBigStep.kt")
public void testWindowedWithBigStep() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/misc/WindowedWithBigStep.kt");
}
@TestMetadata("WindowedWithPartial.kt")
public void testWindowedWithPartial() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/misc/WindowedWithPartial.kt");
}
@TestMetadata("WindowedWithStep.kt")
public void testWindowedWithStep() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/misc/WindowedWithStep.kt");
}
@TestMetadata("ZipWithGreater.kt")
public void testZipWithGreater() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/misc/ZipWithGreater.kt");
}
@TestMetadata("ZipWithLesser.kt")
public void testZipWithLesser() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/misc/ZipWithLesser.kt");
}
@TestMetadata("ZipWithNextMany.kt")
public void testZipWithNextMany() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/misc/ZipWithNextMany.kt");
}
@TestMetadata("ZipWithNextSingle.kt")
public void testZipWithNextSingle() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/misc/ZipWithNextSingle.kt");
}
@TestMetadata("ZipWithSame.kt")
public void testZipWithSame() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/misc/ZipWithSame.kt");
}
}
@TestMetadata("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/sort")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Sort extends AbstractSequenceTraceTestCase {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInSort() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/sort"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("Sorted.kt")
public void testSorted() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/sort/Sorted.kt");
}
@TestMetadata("SortedBy.kt")
public void testSortedBy() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/sort/SortedBy.kt");
}
@TestMetadata("SortedByDescending.kt")
public void testSortedByDescending() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/sort/SortedByDescending.kt");
}
@TestMetadata("SortedDescending.kt")
public void testSortedDescending() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/sort/SortedDescending.kt");
}
@TestMetadata("SortedWith.kt")
public void testSortedWith() throws Exception {
runTest("idea/jvm-debugger/jvm-debugger-test/testData/sequence/streams/sequence/sort/SortedWith.kt");
}
}
}
@@ -0,0 +1,177 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.sequence.exec
import com.intellij.debugger.streams.resolve.ResolvedStreamCall
import com.intellij.debugger.streams.resolve.ResolvedStreamChain
import com.intellij.debugger.streams.trace.*
import com.intellij.execution.ExecutionTestCase
import com.intellij.execution.process.ProcessOutputTypes
import com.intellij.testFramework.UsefulTestCase
import junit.framework.TestCase
import java.util.*
class StreamTraceChecker(private val testCase: ExecutionTestCase) {
fun checkChain(trace: List<TraceInfo>) {
for (info in trace) {
val name = info.call.name
println(name)
print(" before: ")
val before = info.valuesOrderBefore
println(traceToString(before.values))
print(" after: ")
val after = info.valuesOrderAfter
println(traceToString(after.values))
}
}
fun checkResolvedChain(result: ResolvedTracingResult) {
val resolvedChain = result.resolvedChain
checkChain(resolvedChain)
checkTracesIsCorrectInBothDirections(resolvedChain)
val terminator = resolvedChain.terminator
resolvedChain.intermediateCalls.forEach { x -> printBeforeAndAfterValues(x.stateBefore, x.stateAfter) }
printBeforeAndAfterValues(terminator.stateBefore, terminator.stateAfter)
}
private fun printBeforeAndAfterValues(before: NextAwareState?, after: PrevAwareState?) {
TestCase.assertFalse(before == null && after == null)
val call = before?.nextCall ?: after!!.prevCall
TestCase.assertNotNull(call)
println("mappings for " + call!!.name)
println(" direct:")
if (before != null) {
printMapping(before.trace, { before.getNextValues(it) }, Direction.FORWARD)
} else {
println(" no")
}
println(" reverse:")
if (after != null) {
printMapping(after.trace, { after.getPrevValues(it) }, Direction.BACKWARD)
} else {
println(" not found")
}
}
private fun printMapping(
values: List<TraceElement>,
mapper: (TraceElement) -> List<TraceElement>,
direction: Direction
) {
if (values.isEmpty()) {
println(" empty")
}
for (element in values) {
val mappedValues = mapper(element)
val mapped = traceToString(mappedValues)
val line = when (direction) {
Direction.FORWARD -> element.time.toString() + " -> " + mapped
else -> mapped + " <- " + element.time
}
println(" $line")
}
}
private enum class Direction {
FORWARD, BACKWARD
}
private fun checkChain(chain: ResolvedStreamChain) {
val intermediates = chain.intermediateCalls
val terminator = chain.terminator
if (intermediates.isEmpty()) {
TestCase.assertFalse(terminator.stateBefore is PrevAwareState)
}
checkIntermediates(chain.intermediateCalls)
TestCase.assertEquals(terminator.call.name, terminator.stateBefore.nextCall.name)
val after = terminator.stateAfter
if (after != null) {
val terminatorCall = after.prevCall
TestCase.assertNotNull(terminatorCall)
TestCase.assertEquals(terminator.call.name, terminatorCall!!.name)
}
if (intermediates.isNotEmpty()) {
val lastIntermediate = intermediates[intermediates.size - 1]
val stateAfterIntermediates = lastIntermediate.stateAfter
UsefulTestCase.assertInstanceOf(stateAfterIntermediates, NextAwareState::class.java)
TestCase.assertEquals(terminator.call.name, (stateAfterIntermediates as NextAwareState).nextCall.name)
}
}
private fun checkIntermediates(intermediates: List<ResolvedStreamCall.Intermediate>) {
for (i in 0 until intermediates.size - 1) {
val prev = intermediates[i]
val next = intermediates[i + 1]
TestCase.assertSame(prev.stateAfter, next.stateBefore)
val prevCall = prev.stateAfter.prevCall
TestCase.assertNotNull(prevCall)
TestCase.assertEquals(prev.call.name, prevCall!!.name)
TestCase.assertEquals(next.call.name, next.stateBefore.nextCall.name)
}
}
private fun checkTracesIsCorrectInBothDirections(resolvedChain: ResolvedStreamChain) {
for (intermediate in resolvedChain.intermediateCalls) {
checkNeighborTraces(intermediate.stateBefore, intermediate.stateAfter)
}
val terminator = resolvedChain.terminator
val after = terminator.stateAfter
if (after != null) {
checkNeighborTraces(terminator.stateBefore, after)
}
}
private fun checkNeighborTraces(left: NextAwareState, right: PrevAwareState) {
val leftValues = HashSet(left.trace)
val rightValues = HashSet(right.trace)
checkThatMappingsIsCorrect(
leftValues,
rightValues,
{ left.getNextValues(it) },
{ right.getPrevValues(it) })
checkThatMappingsIsCorrect(
rightValues,
leftValues,
{ right.getPrevValues(it) },
{ left.getNextValues(it) })
}
private fun checkThatMappingsIsCorrect(
prev: Set<TraceElement>,
next: Set<TraceElement>,
toNext: (TraceElement) -> List<TraceElement>,
toPrev: (TraceElement) -> List<TraceElement>
) {
for (leftElement in prev) {
val mapToRight = toNext.invoke(leftElement)
for (rightElement in mapToRight) {
TestCase.assertTrue(next.contains(rightElement))
TestCase.assertTrue(toPrev.invoke(rightElement).contains(leftElement))
}
}
}
private fun traceToString(trace: Collection<TraceElement>): String {
if (trace.isEmpty()) {
return "nothing"
}
return trace.map { it.time }.sorted().joinToString(",")
}
private fun println(msg: String) = testCase.println(msg, ProcessOutputTypes.SYSTEM)
private fun print(msg: String) = testCase.print(msg, ProcessOutputTypes.SYSTEM)
}
@@ -0,0 +1,40 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.sequence.psi
import com.intellij.debugger.streams.trace.impl.handler.type.GenericType
import org.jetbrains.kotlin.idea.debugger.test.sequence.KotlinPsiChainBuilderTestCase
abstract class TypedChainTestCase(relativePath: String) : KotlinPsiChainBuilderTestCase(relativePath) {
protected fun doTest(producerAfterType: GenericType, vararg intermediateAfterTypes: GenericType) {
val elementAtCaret = configureAndGetElementAtCaret()
assertNotNull(elementAtCaret)
val chains = chainBuilder.build(elementAtCaret)
assertFalse(chains.isEmpty())
val chain = chains[0]
val intermediateCalls = chain.intermediateCalls
assertEquals(intermediateAfterTypes.size, intermediateCalls.size)
assertEquals(producerAfterType, chain.qualifierExpression.typeAfter)
if (intermediateAfterTypes.isNotEmpty()) {
assertEquals(producerAfterType, intermediateCalls[0].typeBefore)
for (i in 0 until intermediateAfterTypes.size - 1) {
assertEquals(intermediateAfterTypes[i], intermediateCalls[i].typeAfter)
assertEquals(intermediateAfterTypes[i], intermediateCalls[i + 1].typeBefore)
}
val lastAfterType = intermediateAfterTypes[intermediateAfterTypes.size - 1]
assertEquals(lastAfterType, chain.terminationCall.typeBefore)
val lastCall = intermediateCalls[intermediateCalls.size - 1]
assertEquals(lastAfterType, lastCall.typeAfter)
} else {
assertEquals(producerAfterType, chain.terminationCall.typeBefore)
}
}
override fun doTest() {
fail("Use doTest(producerAfterType, vararg intermediateAfterTypes)")
}
}
@@ -0,0 +1,21 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.sequence.psi.collection
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
import org.jetbrains.kotlin.idea.debugger.test.sequence.KotlinPsiChainBuilderTestCase
import org.jetbrains.kotlin.idea.debugger.sequence.lib.collections.KotlinCollectionSupportProvider
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
import org.junit.runner.RunWith
@RunWith(JUnit3WithIdeaConfigurationRunner::class)
class PositiveCollectionBuildTest : KotlinPsiChainBuilderTestCase.Positive("collection/positive") {
override val kotlinChainBuilder: StreamChainBuilder = KotlinCollectionSupportProvider().chainBuilder
fun testIntermediateIsLastCall() = doTest()
fun testOnlyFilterCall() = doTest()
fun testTerminationCallUsed() = doTest()
fun testOnlyTerminationCallUsed() = doTest()
}
@@ -0,0 +1,56 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.sequence.psi.collection
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
import org.jetbrains.kotlin.idea.debugger.sequence.lib.collections.KotlinCollectionSupportProvider
import org.jetbrains.kotlin.idea.debugger.test.sequence.psi.TypedChainTestCase
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinSequenceTypes
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
import org.junit.runner.RunWith
@RunWith(JUnit3WithIdeaConfigurationRunner::class)
class TypedCollectionChainTest : TypedChainTestCase("collection/positive/types") {
override val kotlinChainBuilder: StreamChainBuilder = KotlinCollectionSupportProvider().chainBuilder
fun testAny() = doTest(KotlinSequenceTypes.ANY)
fun testNullableAny() = doTest(KotlinSequenceTypes.NULLABLE_ANY)
fun testBoolean() = doTest(KotlinSequenceTypes.BOOLEAN)
fun testNullableBoolean() = doTest(KotlinSequenceTypes.NULLABLE_ANY)
fun testByte() = doTest(KotlinSequenceTypes.BYTE)
fun testNullableByte() = doTest(KotlinSequenceTypes.NULLABLE_ANY)
fun testShort() = doTest(KotlinSequenceTypes.SHORT)
fun testNullableShort() = doTest(KotlinSequenceTypes.NULLABLE_ANY)
fun testInt() = doTest(KotlinSequenceTypes.INT)
fun testNullableInt() = doTest(KotlinSequenceTypes.NULLABLE_ANY)
fun testLong() = doTest(KotlinSequenceTypes.LONG)
fun testNullableLong() = doTest(KotlinSequenceTypes.NULLABLE_ANY)
fun testFloat() = doTest(KotlinSequenceTypes.FLOAT)
fun testNullableFloat() = doTest(KotlinSequenceTypes.NULLABLE_ANY)
fun testDouble() = doTest(KotlinSequenceTypes.DOUBLE)
fun testNullableDouble() = doTest(KotlinSequenceTypes.NULLABLE_ANY)
fun testChar() = doTest(KotlinSequenceTypes.CHAR)
fun testNullableChar() = doTest(KotlinSequenceTypes.NULLABLE_ANY)
fun testNullableAnyToPrimitive() = doTest(KotlinSequenceTypes.NULLABLE_ANY, KotlinSequenceTypes.BOOLEAN)
fun testPrimitiveToNullableAny() = doTest(KotlinSequenceTypes.INT, KotlinSequenceTypes.NULLABLE_ANY)
fun testAnyToPrimitive() = doTest(KotlinSequenceTypes.ANY, KotlinSequenceTypes.INT)
fun testPrimitiveToAny() = doTest(KotlinSequenceTypes.INT, KotlinSequenceTypes.ANY)
fun testNullableToNotNull() = doTest(KotlinSequenceTypes.NULLABLE_ANY, KotlinSequenceTypes.INT)
fun testNotNullToNullable() = doTest(KotlinSequenceTypes.DOUBLE, KotlinSequenceTypes.NULLABLE_ANY)
fun testFewTransitions1() = doTest(KotlinSequenceTypes.BYTE, KotlinSequenceTypes.ANY, KotlinSequenceTypes.NULLABLE_ANY, KotlinSequenceTypes.INT)
fun testFewTransitions2() = doTest(KotlinSequenceTypes.CHAR, KotlinSequenceTypes.BOOLEAN, KotlinSequenceTypes.DOUBLE, KotlinSequenceTypes.ANY)
}
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.sequence.psi.java
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
import org.junit.runner.RunWith
@RunWith(JUnit3WithIdeaConfigurationRunner::class)
class AmbiguousChainsTest : PositiveJavaStreamTest("ambiguous") {
fun testSimpleExpression() = doTest(2)
fun testNestedExpression() = doTest(3)
fun testSimpleFunctionParameter() = doTest(2)
fun testNestedFunctionParameters() = doTest(3)
fun testNestedFunctionParametersReversed() = doTest(3)
fun testStreamProducerParameter() = doTest(2)
fun testStreamIntermediateCallParameter() = doTest(2)
fun testStreamTerminatorParameter() = doTest(2)
fun testStreamAllPositions() = doTest(4)
fun testNestedStreamProducerParameter() = doTest(3)
fun testNestedStreamIntermediateCallParameter() = doTest(3)
fun testNestedStreamTerminatorCallParameter() = doTest(3)
fun testNestedCallInLambda() = doTest(2)
fun testNestedCallInAnonymous() = doTest(2)
fun testLinkedChain() = doTest(3)
private fun doTest(chainsCount: Int) {
val chains = buildChains()
assertEquals(chainsCount, chains.size)
}
}
@@ -0,0 +1,45 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.sequence.psi.java
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
import org.junit.runner.RunWith
@RunWith(JUnit3WithIdeaConfigurationRunner::class)
class LocationPositiveChainTest : PositiveJavaStreamTest("location") {
fun testAnonymousBody() = doTest()
fun testAssignExpression() = doTest()
fun testFirstParameterOfFunction() = doTest()
fun testLambdaBody() = doTest()
fun testParameterInAssignExpression() = doTest()
fun testParameterInReturnExpression() = doTest()
fun testReturnExpression() = doTest()
fun testSecondParameterOfFunction() = doTest()
fun testSingleExpression() = doTest()
fun testBeforeStatement() = doTest()
fun testBetweenChainCallsBeforeDot() = doTest()
fun testBetweenChainCallsAfterDot() = doTest()
fun testInEmptyParameterList() = doTest()
fun testBetweenParametersBeforeComma() = doTest()
fun testBetweenParametersAfterComma() = doTest()
fun testInAnyLambda() = doTest()
fun testInAnyAnonymous() = doTest()
fun testInString() = doTest()
fun testInVariableName() = doTest()
fun testInMethodReference() = doTest()
fun testAsMethodExpression() = doTest()
}
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.sequence.psi.java
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
import org.jetbrains.kotlin.idea.debugger.test.sequence.KotlinPsiChainBuilderTestCase
import org.jetbrains.kotlin.idea.debugger.sequence.lib.java.JavaStandardLibrarySupportProvider
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
import org.junit.runner.RunWith
@RunWith(JUnit3WithIdeaConfigurationRunner::class)
class NegativeJavaStreamTest : KotlinPsiChainBuilderTestCase.Negative("streams/negative") {
override val kotlinChainBuilder: StreamChainBuilder = JavaStandardLibrarySupportProvider().chainBuilder
fun testFakeStream() = doTest()
fun testWithoutTerminalOperation() = doTest()
fun testNoBreakpoint() = doTest()
fun testBreakpointOnMethod() = doTest()
fun testBreakpointOnIfCondition() = doTest()
fun testBreakpointOnNewScope() = doTest()
fun testBreakpointOnElseBranch() = doTest()
fun testInLambda() = doTest()
fun testInLambdaWithBody() = doTest()
fun testInAnonymous() = doTest()
fun testAfterStatement() = doTest()
fun testInPreviousStatement() = doTest()
fun testInNextStatement() = doTest()
fun testIdea173415() = doTest()
}
@@ -0,0 +1,13 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.sequence.psi.java
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
import org.jetbrains.kotlin.idea.debugger.test.sequence.KotlinPsiChainBuilderTestCase
import org.jetbrains.kotlin.idea.debugger.sequence.lib.java.JavaStandardLibrarySupportProvider
abstract class PositiveJavaStreamTest(subDirectory: String) : KotlinPsiChainBuilderTestCase.Positive("streams/positive/$subDirectory") {
override val kotlinChainBuilder: StreamChainBuilder = JavaStandardLibrarySupportProvider().chainBuilder
}
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.sequence.psi.java
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
import org.jetbrains.kotlin.idea.debugger.sequence.lib.java.JavaStandardLibrarySupportProvider
import org.jetbrains.kotlin.idea.debugger.test.sequence.psi.TypedChainTestCase
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinSequenceTypes.DOUBLE
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinSequenceTypes.INT
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinSequenceTypes.LONG
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinSequenceTypes.NULLABLE_ANY
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
import org.junit.runner.RunWith
@RunWith(JUnit3WithIdeaConfigurationRunner::class)
class TypedJavaChainTest : TypedChainTestCase("streams/positive/types") {
override val kotlinChainBuilder: StreamChainBuilder = JavaStandardLibrarySupportProvider().chainBuilder
fun testOneCall() = doTest(NULLABLE_ANY)
fun testMapToSame() = doTest(NULLABLE_ANY, NULLABLE_ANY)
fun testPrimitiveOneCall() = doTest(INT)
fun testPrimitiveMapToSame() = doTest(LONG, LONG)
fun testMapToPrimitive() = doTest(NULLABLE_ANY, DOUBLE)
fun testMapToObj() = doTest(DOUBLE, NULLABLE_ANY)
fun testMapPrimitiveToPrimitive() = doTest(LONG, INT)
fun testFewTransitions() = doTest(NULLABLE_ANY, INT, NULLABLE_ANY, LONG, DOUBLE)
}
@@ -0,0 +1,59 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.sequence.psi.sequence
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
import org.jetbrains.kotlin.idea.debugger.sequence.lib.sequence.KotlinSequenceSupportProvider
import org.jetbrains.kotlin.idea.debugger.test.sequence.psi.TypedChainTestCase
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinSequenceTypes
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
import org.junit.runner.RunWith
@RunWith(JUnit3WithIdeaConfigurationRunner::class)
class TypedSequenceChain : TypedChainTestCase("sequence/positive/types") {
override val kotlinChainBuilder: StreamChainBuilder = KotlinSequenceSupportProvider().chainBuilder
fun testAny() = doTest(KotlinSequenceTypes.ANY)
fun testNullableAny() = doTest(KotlinSequenceTypes.NULLABLE_ANY)
fun testBoolean() = doTest(KotlinSequenceTypes.BOOLEAN)
fun testNullableBoolean() = doTest(KotlinSequenceTypes.NULLABLE_ANY)
fun testByte() = doTest(KotlinSequenceTypes.BYTE)
fun testNullableByte() = doTest(KotlinSequenceTypes.NULLABLE_ANY)
fun testShort() = doTest(KotlinSequenceTypes.SHORT)
fun testNullableShort() = doTest(KotlinSequenceTypes.NULLABLE_ANY)
fun testInt() = doTest(KotlinSequenceTypes.INT)
fun testNullableInt() = doTest(KotlinSequenceTypes.NULLABLE_ANY)
fun testLong() = doTest(KotlinSequenceTypes.LONG)
fun testNullableLong() = doTest(KotlinSequenceTypes.NULLABLE_ANY)
fun testFloat() = doTest(KotlinSequenceTypes.FLOAT)
fun testNullableFloat() = doTest(KotlinSequenceTypes.NULLABLE_ANY)
fun testDouble() = doTest(KotlinSequenceTypes.DOUBLE)
fun testNullableDouble() = doTest(KotlinSequenceTypes.NULLABLE_ANY)
fun testChar() = doTest(KotlinSequenceTypes.CHAR)
fun testNullableChar() = doTest(KotlinSequenceTypes.NULLABLE_ANY)
fun testNullableAnyToPrimitive() = doTest(KotlinSequenceTypes.NULLABLE_ANY, KotlinSequenceTypes.BOOLEAN)
fun testPrimitiveToNullableAny() = doTest(KotlinSequenceTypes.INT, KotlinSequenceTypes.NULLABLE_ANY)
fun testAnyToPrimitive() = doTest(KotlinSequenceTypes.ANY, KotlinSequenceTypes.INT)
fun testPrimitiveToAny() = doTest(KotlinSequenceTypes.INT, KotlinSequenceTypes.ANY)
fun testNullableToNotNull() = doTest(KotlinSequenceTypes.NULLABLE_ANY, KotlinSequenceTypes.INT)
fun testNotNullToNullable() = doTest(KotlinSequenceTypes.DOUBLE, KotlinSequenceTypes.NULLABLE_ANY)
fun testFewTransitions1() =
doTest(KotlinSequenceTypes.BYTE, KotlinSequenceTypes.ANY, KotlinSequenceTypes.NULLABLE_ANY, KotlinSequenceTypes.INT)
fun testFewTransitions2() =
doTest(KotlinSequenceTypes.CHAR, KotlinSequenceTypes.BOOLEAN, KotlinSequenceTypes.DOUBLE, KotlinSequenceTypes.ANY)
}
@@ -0,0 +1,225 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.util
import org.jetbrains.kotlin.test.InTextDirectivesUtils.findLinesWithPrefixesRemoved
import com.intellij.debugger.DebuggerInvocationUtil
import com.intellij.openapi.application.ModalityState
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiManager
import com.intellij.psi.search.FilenameIndex
import com.intellij.xdebugger.XDebuggerManager
import org.jetbrains.kotlin.test.testFramework.runWriteAction
import org.jetbrains.kotlin.idea.util.application.runReadAction
import com.intellij.debugger.engine.evaluation.CodeFragmentKind
import com.intellij.debugger.engine.evaluation.TextWithImportsImpl
import com.intellij.debugger.ui.breakpoints.Breakpoint
import com.intellij.debugger.ui.breakpoints.BreakpointManager
import com.intellij.debugger.ui.breakpoints.LineBreakpoint
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiFile
import com.intellij.xdebugger.XDebuggerUtil
import com.intellij.xdebugger.breakpoints.XBreakpointManager
import com.intellij.xdebugger.breakpoints.XBreakpointProperties
import com.intellij.xdebugger.breakpoints.XBreakpointType
import com.intellij.xdebugger.breakpoints.XLineBreakpointType
import org.jetbrains.java.debugger.breakpoints.properties.JavaBreakpointProperties
import org.jetbrains.java.debugger.breakpoints.properties.JavaLineBreakpointProperties
import org.jetbrains.kotlin.idea.debugger.breakpoints.*
import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferenceKeys
import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferences
import javax.swing.SwingUtilities
internal class BreakpointCreator(
private val project: Project,
private val logger: (String) -> Unit,
private val preferences: DebuggerPreferences
) {
fun createBreakpoints(file: PsiFile) {
val document = runReadAction { PsiDocumentManager.getInstance(project).getDocument(file) } ?: return
val breakpointManager = XDebuggerManager.getInstance(project).breakpointManager
val kotlinFieldBreakpointType = findBreakpointType(KotlinFieldBreakpointType::class.java)
val virtualFile = file.virtualFile
val runnable = {
var offset = -1
while (true) {
val fileText = document.text
offset = fileText.indexOf("point!", offset + 1)
if (offset == -1) break
val commentLine = document.getLineNumber(offset)
val lineIndex = commentLine + 1
val comment = fileText
.substring(document.getLineStartOffset(commentLine), document.getLineEndOffset(commentLine))
.trim()
when {
@Suppress("SpellCheckingInspection") comment.startsWith("//FieldWatchpoint!") -> {
val javaBreakpoint = createBreakpointOfType(
breakpointManager,
kotlinFieldBreakpointType,
lineIndex,
virtualFile
)
(javaBreakpoint as? KotlinFieldBreakpoint)?.apply {
@Suppress("SpellCheckingInspection")
val fieldName = comment.substringAfter("//FieldWatchpoint! (").substringBefore(")")
setFieldName(fieldName)
setWatchAccess(preferences[DebuggerPreferenceKeys.WATCH_FIELD_ACCESS])
setWatchModification(preferences[DebuggerPreferenceKeys.WATCH_FIELD_MODIFICATION])
setWatchInitialization(preferences[DebuggerPreferenceKeys.WATCH_FIELD_INITIALISATION])
BreakpointManager.addBreakpoint(javaBreakpoint)
logger("KotlinFieldBreakpoint created at ${file.virtualFile.name}:${lineIndex + 1}")
}
}
comment.startsWith("//Breakpoint!") -> {
val ordinal = getPropertyFromComment(comment, "lambdaOrdinal")?.toInt()
val condition = getPropertyFromComment(comment, "condition")
createLineBreakpoint(breakpointManager, file, lineIndex, ordinal, condition)
}
comment.startsWith("//FunctionBreakpoint!") -> {
createFunctionBreakpoint(breakpointManager, file, lineIndex)
}
else -> throw AssertionError("Cannot create breakpoint at line ${lineIndex + 1}")
}
}
}
if (!SwingUtilities.isEventDispatchThread()) {
DebuggerInvocationUtil.invokeAndWait(project, runnable, ModalityState.defaultModalityState())
} else {
runnable.invoke()
}
}
fun createAdditionalBreakpoints(fileContents: String) {
val breakpoints = findLinesWithPrefixesRemoved(fileContents, "// ADDITIONAL_BREAKPOINT: ")
for (breakpoint in breakpoints) {
val position = breakpoint.split(".kt:")
assert(position.size == 2) { "Couldn't parse position from test directive: directive = $breakpoint" }
var lineMarker = position[1]
var ordinal: Int? = null
if (lineMarker.contains(":(") && lineMarker.endsWith(")")) {
val lineMarkerAndOrdinal = lineMarker.split(":(")
lineMarker = lineMarkerAndOrdinal[0]
ordinal = lineMarkerAndOrdinal[1].substringBefore(")").toInt()
}
createBreakpoint(position[0], lineMarker, ordinal)
}
}
private fun getPropertyFromComment(comment: String, propertyName: String): String? {
if (comment.contains("$propertyName = ")) {
val result = comment.substringAfter("$propertyName = ")
if (result.contains(", ")) {
return result.substringBefore(", ")
}
if (result.contains(")")) {
return result.substringBefore(")")
}
}
return null
}
private fun createBreakpoint(fileName: String, lineMarker: String, ordinal: Int?) {
val sourceFiles = runReadAction {
FilenameIndex.getAllFilesByExt(project, "kt")
.filter { it.name.contains(fileName) && it.contentsToByteArray().toString(Charsets.UTF_8).contains(lineMarker) }
}
assert(sourceFiles.size == 1) { "One source file should be found: name = $fileName, sourceFiles = $sourceFiles" }
val runnable = Runnable {
val psiSourceFile = PsiManager.getInstance(project).findFile(sourceFiles.first())!!
val breakpointManager = XDebuggerManager.getInstance(project).breakpointManager
val document = PsiDocumentManager.getInstance(project).getDocument(psiSourceFile)!!
val index = psiSourceFile.text!!.indexOf(lineMarker)
val lineNumber = document.getLineNumber(index) + 1 // lineMarker is for previous line
createLineBreakpoint(breakpointManager, psiSourceFile, lineNumber, ordinal, null)
}
DebuggerInvocationUtil.invokeAndWait(project, runnable, ModalityState.defaultModalityState())
}
private fun createFunctionBreakpoint(breakpointManager: XBreakpointManager, file: PsiFile, lineIndex: Int) {
val breakpointType = findBreakpointType(KotlinFunctionBreakpointType::class.java)
val breakpoint = createBreakpointOfType(breakpointManager, breakpointType, lineIndex, file.virtualFile)
if (breakpoint is KotlinFunctionBreakpoint) {
logger("FunctionBreakpoint created at ${file.virtualFile.name}:${lineIndex + 1}")
}
}
private fun createLineBreakpoint(
breakpointManager: XBreakpointManager,
file: PsiFile,
lineIndex: Int,
lambdaOrdinal: Int?,
condition: String?
) {
val kotlinLineBreakpointType = findBreakpointType(KotlinLineBreakpointType::class.java)
val javaBreakpoint = createBreakpointOfType(
breakpointManager,
kotlinLineBreakpointType,
lineIndex,
file.virtualFile
)
if (javaBreakpoint is LineBreakpoint<*>) {
val properties = javaBreakpoint.xBreakpoint.properties as? JavaLineBreakpointProperties ?: return
var suffix = ""
if (lambdaOrdinal != null) {
if (lambdaOrdinal != -1) {
properties.lambdaOrdinal = lambdaOrdinal - 1
} else {
properties.lambdaOrdinal = lambdaOrdinal
}
suffix += " lambdaOrdinal = $lambdaOrdinal"
}
if (condition != null) {
javaBreakpoint.setCondition(TextWithImportsImpl(CodeFragmentKind.EXPRESSION, condition))
suffix += " condition = $condition"
}
BreakpointManager.addBreakpoint(javaBreakpoint)
logger("LineBreakpoint created at ${file.virtualFile.name}:${lineIndex + 1}$suffix")
}
}
private fun createBreakpointOfType(
breakpointManager: XBreakpointManager,
breakpointType: XLineBreakpointType<XBreakpointProperties<*>>,
lineIndex: Int,
virtualFile: VirtualFile
): Breakpoint<out JavaBreakpointProperties<*>>? {
if (!breakpointType.canPutAt(virtualFile, lineIndex, project)) return null
val xBreakpoint = runWriteAction {
breakpointManager.addLineBreakpoint(
breakpointType,
virtualFile.url,
lineIndex,
breakpointType.createBreakpointProperties(virtualFile, lineIndex)
)
}
return BreakpointManager.getJavaBreakpoint(xBreakpoint)
}
@Suppress("UNCHECKED_CAST")
private inline fun <reified T : XBreakpointType<*, *>> findBreakpointType(javaClass: Class<T>): XLineBreakpointType<XBreakpointProperties<*>> {
return XDebuggerUtil.getInstance().findBreakpointType(javaClass) as XLineBreakpointType<XBreakpointProperties<*>>
}
}
@@ -0,0 +1,322 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.util
import com.intellij.debugger.SourcePosition
import com.intellij.debugger.engine.*
import com.intellij.debugger.engine.evaluation.CodeFragmentKind
import com.intellij.debugger.engine.evaluation.TextWithImports
import com.intellij.debugger.engine.evaluation.TextWithImportsImpl
import com.intellij.debugger.impl.DebuggerSession
import com.intellij.debugger.settings.NodeRendererSettings
import com.intellij.debugger.ui.impl.watch.*
import com.intellij.debugger.ui.tree.*
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.roots.JdkOrderEntry
import com.intellij.openapi.roots.libraries.LibraryUtil
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.io.FileUtil
import com.intellij.psi.PsiExpression
import com.intellij.xdebugger.impl.XDebugSessionImpl
import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl
import com.intellij.xdebugger.impl.frame.XDebugViewSessionListener
import com.intellij.xdebugger.impl.frame.XVariablesView
import com.intellij.xdebugger.impl.frame.XWatchesViewImpl
import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree
import com.intellij.xdebugger.impl.ui.tree.nodes.*
import org.jetbrains.kotlin.idea.debugger.KotlinFrameExtraVariablesProvider
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinCodeFragmentFactory
import org.jetbrains.kotlin.idea.debugger.invokeInManagerThread
import org.jetbrains.kotlin.idea.debugger.test.KOTLIN_LIBRARY_NAME
import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferenceKeys
import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferences
import org.jetbrains.kotlin.idea.debugger.test.util.PrinterConfig.DescriptorViewOptions
import org.jetbrains.kotlin.psi.KtFile
import java.io.Closeable
import javax.swing.tree.TreeNode
class FramePrinter(
debuggerSession: DebuggerSession,
private val delegate: FramePrinterDelegate,
private val preferences: DebuggerPreferences,
private val testRootDisposable: Disposable
) : Closeable {
private companion object {
fun getClassRenderer() = NodeRendererSettings.getInstance()!!.classRenderer!!
}
private lateinit var variablesView: XVariablesView
private lateinit var watchesView: XWatchesViewImpl
private val oldShowFqTypeNames: Boolean
init {
ApplicationManager.getApplication().invokeAndWait(
{
variablesView = createVariablesView(debuggerSession)
watchesView = createWatchesView(debuggerSession)
}, ModalityState.any()
)
getClassRenderer().let { renderer ->
oldShowFqTypeNames = renderer.SHOW_FQ_TYPE_NAMES
renderer.SHOW_FQ_TYPE_NAMES = true
}
}
override fun close() {
getClassRenderer().SHOW_FQ_TYPE_NAMES = oldShowFqTypeNames
}
fun printFrame(completion: () -> Unit) {
if (preferences[DebuggerPreferenceKeys.PRINT_FRAME]) {
doPrintFrame(completion)
} else {
completion()
}
}
private fun doPrintFrame(completion: () -> Unit) {
val tree = variablesView.tree
val config = getPrinterConfig()
fun processor() {
Printer(delegate, config).printTree(tree)
for (extra in getExtraVars()) {
watchesView.addWatchExpression(XExpressionImpl.fromText(extra.text), -1, false)
}
Printer(delegate, config).printTree(watchesView.tree)
completion()
}
// TODO why this is needed? Otherwise some tests are never ended
val filter: (TreeNode) -> Boolean = { it !is XValueNodeImpl || it.name != "cause" }
delegate.expandAll(tree, ::processor, filter, delegate.evaluationContext.suspendContext)
}
private fun getPrinterConfig(): PrinterConfig {
val skipInPrintFrame = preferences[DebuggerPreferenceKeys.SKIP].flatMap { it.split(',') }.map { it.trim() }
val viewOptions = DescriptorViewOptions.valueOf(preferences[DebuggerPreferenceKeys.DESCRIPTOR_VIEW_OPTIONS])
return PrinterConfig(skipInPrintFrame, viewOptions)
}
private fun createWatchesView(debuggerSession: DebuggerSession): XWatchesViewImpl {
val session = debuggerSession.xDebugSession as XDebugSessionImpl
val watchesView = XWatchesViewImpl(session, false)
Disposer.register(testRootDisposable, watchesView)
XDebugViewSessionListener.attach(watchesView, session)
return watchesView
}
private fun createVariablesView(debuggerSession: DebuggerSession): XVariablesView {
val session = debuggerSession.xDebugSession as XDebugSessionImpl
val variablesView = XVariablesView(session)
Disposer.register(testRootDisposable, variablesView)
XDebugViewSessionListener.attach(variablesView, session)
return variablesView
}
private fun getExtraVars(): Set<TextWithImports> {
return KotlinFrameExtraVariablesProvider()
.collectVariables(delegate.debuggerContext.sourcePosition, delegate.evaluationContext, hashSetOf())
}
}
private class PrinterConfig(
val variablesToSkipInPrintFrame: List<String> = emptyList(),
val viewOptions: DescriptorViewOptions = DescriptorViewOptions.FULL
) {
enum class DescriptorViewOptions {
FULL, NAME_EXPRESSION, NAME_EXPRESSION_RESULT
}
fun shouldRenderSourcesPosition(): Boolean {
return when (viewOptions) {
DescriptorViewOptions.FULL -> true
else -> false
}
}
fun shouldRenderExpression(): Boolean {
return when {
viewOptions.toString().contains("EXPRESSION") -> true
else -> false
}
}
fun renderLabel(node: TreeNode, descriptor: NodeDescriptorImpl): String {
return when {
descriptor is WatchItemDescriptor -> descriptor.calcValueName()
viewOptions.toString().contains("NAME") -> (node as? XValueNodeImpl)?.name ?: descriptor.name ?: descriptor.label
else -> descriptor.label
}
}
fun shouldComputeResultOfCreateExpression(): Boolean {
return viewOptions == DescriptorViewOptions.NAME_EXPRESSION_RESULT
}
}
private class Printer(private val delegate: FramePrinterDelegate, private val config: PrinterConfig) {
fun printTree(tree: XDebuggerTree) {
val root = tree.treeModel.root as TreeNode
printNode(root, 0)
}
private fun printNode(node: TreeNode, indent: Int) {
val project = delegate.debuggerContext.project
val descriptor = when (node) {
is DebuggerTreeNodeImpl -> node.descriptor
is XValueNodeImpl -> (node.valueContainer as? JavaValue)?.descriptor ?: MessageDescriptor(node.text.toString())
is XStackFrameNode -> (node.valueContainer as? JavaStackFrame)?.descriptor
is XValueGroupNodeImpl -> (node.valueContainer as? JavaStaticGroup)?.descriptor
is WatchesRootNode -> null
is WatchNodeImpl -> WatchItemDescriptor(project, TextWithImportsImpl(CodeFragmentKind.EXPRESSION, node.expression.expression))
is MessageTreeNode -> MessageDescriptor(node.text.toString())
else -> MessageDescriptor(node.toString())
}
if (descriptor != null && printDescriptor(node, descriptor, indent)) {
return
}
printChildren(node, indent + 2)
}
fun printDescriptor(node: TreeNode, descriptor: NodeDescriptorImpl, indent: Int): Boolean {
if (descriptor is DefaultNodeDescriptor || config.variablesToSkipInPrintFrame.contains(descriptor.name)) {
return true
}
val label = calculateLabel(node, descriptor) ?: return true
val project = delegate.debuggerContext.project
val debugProcess = delegate.debuggerContext.debugProcess ?: error("Debugger process is not launched")
val text = buildString {
append(" ".repeat(indent + 1))
append(getPrefix(descriptor))
append(label)
if (config.shouldRenderSourcesPosition() && hasSourcePosition(descriptor)) {
val sp = debugProcess.invokeInManagerThread {
SourcePositionProvider.getSourcePosition(descriptor, project, delegate.debuggerContext)
}
append(" (sp = ${render(sp)})")
}
if (config.shouldRenderExpression() && descriptor is ValueDescriptorImpl) {
val expression = debugProcess.invokeInManagerThread {
descriptor.getTreeEvaluation((node as XValueNodeImpl).valueContainer as JavaValue, it) as? PsiExpression
}
if (expression != null) {
val text = TextWithImportsImpl(expression)
val imports = expression.getUserData(DebuggerTreeNodeExpression.ADDITIONAL_IMPORTS_KEY)?.joinToString { it } ?: ""
val codeFragment = KotlinCodeFragmentFactory().createPresentationCodeFragment(
TextWithImportsImpl(text.kind, text.text, text.imports + imports, text.fileType),
delegate.debuggerContext.sourcePosition.elementAt, project
)
val codeFragmentText = codeFragment.text
if (config.shouldComputeResultOfCreateExpression()) {
debugProcess.invokeInManagerThread {
val suspendContext = it.suspendContext ?: error(SuspendContext::class.java.simpleName + " is not set")
val fragment = TextWithImportsImpl(text.kind, codeFragmentText, codeFragment.importsToString(), text.fileType)
delegate.evaluate(suspendContext, fragment)
}
}
append(" (expression = $codeFragmentText)")
}
}
append("\n")
}
delegate.logDescriptor(descriptor, text)
return false
}
private fun calculateLabel(node: TreeNode, descriptor: NodeDescriptorImpl): String? {
var label = config.renderLabel(node, descriptor)
// TODO: update presentation before calc label
if (label == NodeDescriptorImpl.UNKNOWN_VALUE_MESSAGE && descriptor is StaticDescriptor) {
label = "static = " + NodeRendererSettings.getInstance().classRenderer.renderTypeName(descriptor.type.name())
}
if (label.endsWith(XDebuggerUIConstants.COLLECTING_DATA_MESSAGE)) {
return null
}
return label
}
private fun getPrefix(descriptor: NodeDescriptorImpl): String {
val prefix = when (descriptor) {
is StackFrameDescriptor -> "frame"
is WatchItemDescriptor -> "extra"
is LocalVariableDescriptor -> "local"
is StaticDescriptor -> "static"
is ThisDescriptorImpl -> "this"
is FieldDescriptor -> "field"
is ArrayElementDescriptor -> "element"
is MessageDescriptor -> ""
else -> "unknown"
}
return prefix + " ".repeat("unknown ".length - prefix.length) + if (descriptor is MessageDescriptor) " - " else " = "
}
private fun hasSourcePosition(descriptor: NodeDescriptorImpl): Boolean {
return when (descriptor) {
is LocalVariableDescriptor,
is FieldDescriptor -> true
else -> false
}
}
private fun printChildren(node: TreeNode, indent: Int) {
val e = node.children()
while (e.hasMoreElements()) {
printNode(e.nextElement() as TreeNode, indent)
}
}
private fun render(sp: SourcePosition?): String {
return renderSourcePosition(sp).replace(":", ", ")
}
}
fun renderSourcePosition(sourcePosition: SourcePosition?): String {
if (sourcePosition == null) {
return "null"
}
val virtualFile = sourcePosition.file.originalFile.virtualFile ?: sourcePosition.file.viewProvider.virtualFile
val libraryEntry = LibraryUtil.findLibraryEntry(virtualFile, sourcePosition.file.project)
if (libraryEntry != null && (libraryEntry is JdkOrderEntry || libraryEntry.presentableName == KOTLIN_LIBRARY_NAME)) {
val suffix = if (sourcePosition.isInCompiledFile()) "COMPILED" else "EXT"
return FileUtil.getNameWithoutExtension(virtualFile.name) + ".!$suffix!"
}
return virtualFile.name + ":" + (sourcePosition.line + 1)
}
private fun SourcePosition.isInCompiledFile(): Boolean {
val ktFile = file as? KtFile ?: return false
return ktFile.isCompiled
}
@@ -0,0 +1,24 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.util
import com.intellij.debugger.engine.SuspendContextImpl
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
import com.intellij.debugger.engine.evaluation.TextWithImportsImpl
import com.intellij.debugger.impl.DebuggerContextImpl
import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl
import com.intellij.ui.treeStructure.Tree
import javax.swing.tree.TreeNode
interface FramePrinterDelegate {
val debuggerContext: DebuggerContextImpl
val evaluationContext: EvaluationContextImpl
fun evaluate(suspendContext: SuspendContextImpl, textWithImports: TextWithImportsImpl)
fun expandAll(tree: Tree, runnable: () -> Unit, filter: (TreeNode) -> Boolean, suspendContext: SuspendContextImpl)
fun logDescriptor(descriptor: NodeDescriptorImpl, text: String)
}
@@ -0,0 +1,129 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.util
import com.intellij.debugger.impl.OutputChecker
import com.intellij.idea.IdeaLogger
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.io.FileUtilRt
import com.intellij.openapi.util.text.StringUtilRt
import com.intellij.openapi.vfs.CharsetToolkit
import org.junit.Assert
import java.io.File
import kotlin.math.min
internal class KotlinOutputChecker(
private val testDir: String,
appPath: String,
outputPath: String
) : OutputChecker(appPath, outputPath) {
companion object {
@JvmStatic
private val LOG = Logger.getInstance(KotlinOutputChecker::class.java)
private const val CONNECT_PREFIX = "Connected to the target VM"
private const val DISCONNECT_PREFIX = "Disconnected from the target VM"
private const val RUN_JAVA = "Run Java"
//ERROR: JDWP Unable to get JNI 1.2 environment, jvm->GetEnv() return code = -2
private val JDI_BUG_OUTPUT_PATTERN_1 =
Regex("ERROR:\\s+JDWP\\s+Unable\\s+to\\s+get\\s+JNI\\s+1\\.2\\s+environment,\\s+jvm->GetEnv\\(\\)\\s+return\\s+code\\s+=\\s+-2")
//JDWP exit error AGENT_ERROR_NO_JNI_ENV(183): [../../../src/share/back/util.c:820]
private val JDI_BUG_OUTPUT_PATTERN_2 = Regex("JDWP\\s+exit\\s+error\\s+AGENT_ERROR_NO_JNI_ENV.*]")
}
private lateinit var myTestName: String
override fun init(testName: String) {
super.init(testName)
this.myTestName = Character.toLowerCase(testName[0]) + testName.substring(1)
}
// Copied from the base OutputChecker.checkValid(). Need to intercept call to base preprocessBuffer() method
override fun checkValid(jdk: Sdk, sortClassPath: Boolean) {
if (IdeaLogger.ourErrorsOccurred != null) {
throw IdeaLogger.ourErrorsOccurred
}
val actual = preprocessBuffer(buildOutputString())
val outDir = File(testDir)
var outFile = File(outDir, "$myTestName.out")
if (!outFile.exists()) {
if (SystemInfo.isWindows) {
val winOut = File(outDir, "$myTestName.win.out")
if (winOut.exists()) {
outFile = winOut
}
} else if (SystemInfo.isUnix) {
val unixOut = File(outDir, "$myTestName.unx.out")
if (unixOut.exists()) {
outFile = unixOut
}
}
}
if (!outFile.exists()) {
FileUtil.writeToFile(outFile, actual)
LOG.error("Test file created ${outFile.path}\n**************** Don't forget to put it into VCS! *******************")
} else {
val originalText = FileUtilRt.loadFile(outFile, CharsetToolkit.UTF8)
val expected = StringUtilRt.convertLineSeparators(originalText)
if (expected != actual) {
println("expected:")
println(originalText)
println("actual:")
println(actual)
val len = min(expected.length, actual.length)
if (expected.length != actual.length) {
println("Text sizes differ: expected " + expected.length + " but actual: " + actual.length)
}
if (expected.length > len) {
println("Rest from expected text is: \"" + expected.substring(len) + "\"")
} else if (actual.length > len) {
println("Rest from actual text is: \"" + actual.substring(len) + "\"")
}
Assert.assertEquals(originalText, actual)
}
}
}
private fun preprocessBuffer(buffer: String): String {
val lines = buffer.lines().toMutableList()
val connectedIndex = lines.indexOfFirst { it.startsWith(CONNECT_PREFIX) }
lines[connectedIndex] = CONNECT_PREFIX
val runCommandIndex = connectedIndex - 1
lines[runCommandIndex] = RUN_JAVA
val disconnectedIndex = lines.indexOfFirst { it.startsWith(DISCONNECT_PREFIX) }
lines[disconnectedIndex] = DISCONNECT_PREFIX
return lines.filter { !(it.matches(JDI_BUG_OUTPUT_PATTERN_1) || it.matches(
JDI_BUG_OUTPUT_PATTERN_2
)) }.joinToString("\n")
}
private fun buildOutputString(): String {
// Call base method with reflection
val m = OutputChecker::class.java.getDeclaredMethod("buildOutputString")!!
val isAccessible = m.isAccessible
try {
m.isAccessible = true
return m.invoke(this) as String
} finally {
m.isAccessible = isAccessible
}
}
}
@@ -0,0 +1,44 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.util
import org.apache.log4j.AppenderSkeleton
import org.apache.log4j.Level
import org.apache.log4j.Logger
import org.apache.log4j.spi.LoggingEvent
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches
internal class LogPropagator(val systemLogger: (String) -> Unit) {
private var oldLogLevel: Level? = null
private val logger = Logger.getLogger(KotlinDebuggerCaches::class.java)
private var appender: AppenderSkeleton? = null
fun attach() {
oldLogLevel = logger.level
logger.level = Level.DEBUG
appender = object : AppenderSkeleton() {
override fun append(event: LoggingEvent?) {
val message = event?.renderedMessage
if (message != null) {
systemLogger(message)
}
}
override fun close() {}
override fun requiresLayout() = false
}
logger.addAppender(appender)
}
fun detach() {
logger.removeAppender(appender)
appender = null
logger.level = oldLogLevel
}
}
@@ -0,0 +1,61 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.util
import org.jetbrains.kotlin.codegen.CodegenTestCase
enum class SteppingInstructionKind(val directiveName: String) {
StepInto("STEP_INTO"),
StepOut("STEP_OUT"),
StepOver("STEP_OVER"),
ForceStepOver("STEP_OVER_FORCE"),
SmartStepInto("SMART_STEP_INTO"),
SmartStepIntoByIndex("SMART_STEP_INTO_BY_INDEX"),
Resume("RESUME")
}
class SteppingInstruction(val kind: SteppingInstructionKind, val arg: Int) {
companion object {
fun parse(file: CodegenTestCase.TestFile): List<SteppingInstruction> {
return parse(file, Companion::parseLine)
}
fun parseSingle(file: CodegenTestCase.TestFile, kind: SteppingInstructionKind): SteppingInstruction? {
val instructions = parse(file) { line -> parseKind(line, kind) }
if (instructions.size > 1) {
error("Several instructions found for kind $kind")
}
return instructions.singleOrNull()
}
private fun parse(file: CodegenTestCase.TestFile, processor: (String) -> SteppingInstruction?): List<SteppingInstruction> {
return file.content.lineSequence()
.map { it.trimStart() }
.filter { it.startsWith("// ") }
.mapNotNullTo(mutableListOf(), processor)
}
private fun parseLine(line: String): SteppingInstruction? {
for (kind in SteppingInstructionKind.values()) {
parseKind(line, kind)?.let { return it }
}
return null
}
private fun parseKind(line: String, kind: SteppingInstructionKind): SteppingInstruction? {
val prefix = "// " + kind.directiveName + ": "
if (line.startsWith(prefix)) {
val rawValue = line.drop(prefix.length).trim()
val n = rawValue.toIntOrNull() ?: error("Int expected, got $rawValue")
return SteppingInstruction(kind, n)
}
return null
}
}
}
@@ -0,0 +1,62 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.debugger.test.util
import org.jetbrains.org.objectweb.asm.*
import java.io.File
import java.util.*
fun patchDexTests(classesDir: File) {
classesDir.walk()
.filter { it.isFile && it.nameWithoutExtension.endsWith("Dex") && it.extension == "class" }
.forEach(::applyDexLikePatch)
}
private fun applyDexLikePatch(file: File) {
val reader = ClassReader(file.readBytes())
val writer = ClassWriter(ClassWriter.COMPUTE_FRAMES)
val visitor = writer
.withRemoveSourceDebugExtensionVisitor()
.withRemoveSameLinesInLineTableVisitor()
reader.accept(visitor, 0)
file.writeBytes(writer.toByteArray())
}
private fun ClassVisitor.withRemoveSourceDebugExtensionVisitor(): ClassVisitor {
return object : ClassVisitor(Opcodes.API_VERSION, this) {
override fun visitSource(source: String?, debug: String?) {
super.visitSource(source, null)
}
}
}
private fun ClassVisitor.withRemoveSameLinesInLineTableVisitor(): ClassVisitor {
return object : ClassVisitor(Opcodes.API_VERSION, this) {
override fun visitMethod(
access: Int,
name: String?,
desc: String?,
signature: String?,
exceptions: Array<out String>?
): MethodVisitor? {
val methodVisitor = super.visitMethod(access, name, desc, signature, exceptions) ?: return null
return object : MethodVisitor(Opcodes.API_VERSION, methodVisitor) {
val labels = HashSet<String>()
override fun visitLineNumber(line: Int, start: Label?) {
val added = labels.add(start.toString())
if (added) {
super.visitLineNumber(line, start)
}
}
}
}
}
}
@@ -1,3 +1,4 @@
// FILE: text.kt
package isInsideInlineLambda
fun main(args: Array<String>) {
@@ -73,3 +74,46 @@ class A {
// ADDITIONAL_BREAKPOINT: isInsideInlineLambdaInLibrary.kt:Breakpoint5:(1)
// EXPRESSION: it + 15
// RESULT: 20: I
// FILE: isInsideInlineLambdaInLibrary.kt
package isInsideInlineLambdaInLibrary
public fun test() {
val a = A()
//Breakpoint1
a.foo(1) { 1 }
// inside other lambda
a.foo(100) {
//Breakpoint2
a.foo(2) { 1 }
1
}
// inside variable declaration
//Breakpoint3
val x = a.foo(3) { 1 }
// inside object declaration
val y = object {
fun foo() {
//Breakpoint4
a.foo(4) { 1 }
}
}
y.foo()
// inside local function
fun local() {
//Breakpoint5
a.foo(5) { 1 }
}
local()
}
class A {
inline fun foo(i: Int, f: (i: Int) -> Int): A {
f(i)
return this
}
}
@@ -1,34 +1,34 @@
LineBreakpoint created at isInsideInlineLambdaInLibrary.kt:6 lambdaOrdinal = 1
LineBreakpoint created at isInsideInlineLambdaInLibrary.kt:11 lambdaOrdinal = 1
LineBreakpoint created at isInsideInlineLambdaInLibrary.kt:17 lambdaOrdinal = 1
LineBreakpoint created at isInsideInlineLambdaInLibrary.kt:23 lambdaOrdinal = 1
LineBreakpoint created at isInsideInlineLambdaInLibrary.kt:31 lambdaOrdinal = 1
LineBreakpoint created at isInsideInlineLambda.kt:9 lambdaOrdinal = 1
LineBreakpoint created at isInsideInlineLambda.kt:17 lambdaOrdinal = 1
LineBreakpoint created at isInsideInlineLambda.kt:25 lambdaOrdinal = 1
LineBreakpoint created at isInsideInlineLambda.kt:33 lambdaOrdinal = 1
LineBreakpoint created at isInsideInlineLambda.kt:43 lambdaOrdinal = 1
LineBreakpoint created at isInsideInlineLambdaInLibrary.kt:7 lambdaOrdinal = 1
LineBreakpoint created at isInsideInlineLambdaInLibrary.kt:12 lambdaOrdinal = 1
LineBreakpoint created at isInsideInlineLambdaInLibrary.kt:18 lambdaOrdinal = 1
LineBreakpoint created at isInsideInlineLambdaInLibrary.kt:24 lambdaOrdinal = 1
LineBreakpoint created at isInsideInlineLambdaInLibrary.kt:32 lambdaOrdinal = 1
LineBreakpoint created at text.kt:10 lambdaOrdinal = 1
LineBreakpoint created at text.kt:18 lambdaOrdinal = 1
LineBreakpoint created at text.kt:26 lambdaOrdinal = 1
LineBreakpoint created at text.kt:34 lambdaOrdinal = 1
LineBreakpoint created at text.kt:44 lambdaOrdinal = 1
Run Java
Connected to the target VM
isInsideInlineLambda.kt:9
text.kt:10
Compile bytecode for it + 1
isInsideInlineLambda.kt:17
text.kt:18
Compile bytecode for it + 2
isInsideInlineLambda.kt:25
text.kt:26
Compile bytecode for it + 3
isInsideInlineLambda.kt:33
text.kt:34
Compile bytecode for it + 4
isInsideInlineLambda.kt:43
text.kt:44
Compile bytecode for it + 5
isInsideInlineLambdaInLibrary.kt:6
isInsideInlineLambdaInLibrary.kt:7
Compile bytecode for it + 11
isInsideInlineLambdaInLibrary.kt:11
isInsideInlineLambdaInLibrary.kt:12
Compile bytecode for it + 12
isInsideInlineLambdaInLibrary.kt:17
isInsideInlineLambdaInLibrary.kt:18
Compile bytecode for it + 13
isInsideInlineLambdaInLibrary.kt:23
isInsideInlineLambdaInLibrary.kt:24
Compile bytecode for it + 14
isInsideInlineLambdaInLibrary.kt:31
isInsideInlineLambdaInLibrary.kt:32
Compile bytecode for it + 15
Disconnected from the target VM
@@ -1,3 +1,4 @@
// FILE: customLibClassName.kt
package customLibClassName
fun main(args: Array<String>) {
@@ -26,4 +27,87 @@ fun main(args: Array<String>) {
// ADDITIONAL_BREAKPOINT: simpleLibFile.kt:public fun foo() {
// EXPRESSION: 1 + 5
// RESULT: 6: I
// RESULT: 6: I
// FILE: lib/oneFunSameClassName/1/a1.kt
@file:JvmName("SameNameOneFunSameFileName")
@file:JvmMultifileClass
package customLib.oneFunSameClassName
public fun oneFunSameFileNameFun(): Int {
return 1
}
// FILE: lib/oneFunSameClassName/2/a2.kt
@file:JvmName("SameNameOneFunSameFileName")
@file:JvmMultifileClass
package customLib.oneFunSameClassName
public fun oneFunSameFileNameFun2(): Int {
return 1
}
// FILE: lib/twoFunDifferentSignature/1/a1.kt
@file:JvmName("SameNameTwoFunDifferentSignature")
@file:JvmMultifileClass
package customLib.twoFunDifferentSignature
public fun twoFunDifferentSignatureFun(): Int {
return 1
}
// FILE: lib/twoFunDifferentSignature/2/a2.kt
@file:JvmName("SameNameTwoFunDifferentSignature")
@file:JvmMultifileClass
package customLib.twoFunDifferentSignature
public fun twoFunDifferentSignatureFun(i: Int): Int {
return 1
}
// FILE: lib/breakpointOnLocalProperty/1/a1.kt
@file:JvmName("SameNameBreakpointOnLocalProperty")
@file:JvmMultifileClass
package customLib.breakpointOnLocalProperty
public fun breakpointOnLocalPropertyFun(): Int {
val a = 1
return 1
}
// FILE: lib/breakpointOnLocalProperty/2/a2.kt
@file:JvmName("SameNameBreakpointOnLocalProperty")
@file:JvmMultifileClass
package customLib.breakpointOnLocalProperty
public fun breakpointOnLocalPropertyFun2(): Int {
return 1
}
// FILE: lib/property/1/a1.kt
@file:JvmName("SameNameProperty")
@file:JvmMultifileClass
package customLib.property
public val foo: Int =
1
// FILE: lib/property/2/a2.kt
@file:JvmName("SameNameProperty")
@file:JvmMultifileClass
package customLib.property
public fun someFun(): Int {
return 1
}
// FILE: lib/simpleLibFile/simpleLibFile.kt
package customLib.simpleLibFile
public fun foo() {
1 + 1
}
class B {
public var prop: Int = 1
}
@@ -1,19 +1,19 @@
LineBreakpoint created at a1.kt:6
LineBreakpoint created at a1.kt:6
LineBreakpoint created at a1.kt:6
LineBreakpoint created at a1.kt:6
LineBreakpoint created at simpleLibFile.kt:4
LineBreakpoint created at a1.kt:7
LineBreakpoint created at a1.kt:7
LineBreakpoint created at a1.kt:7
LineBreakpoint created at a1.kt:7
LineBreakpoint created at simpleLibFile.kt:5
Run Java
Connected to the target VM
a1.kt:6
a1.kt:7
Compile bytecode for 1 + 1
a1.kt:6
a1.kt:7
Compile bytecode for 1 + 2
a1.kt:6
a1.kt:7
Compile bytecode for 1 + 3
a1.kt:6
a1.kt:7
Compile bytecode for 1 + 4
simpleLibFile.kt:4
simpleLibFile.kt:5
Compile bytecode for 1 + 5
Disconnected from the target VM
@@ -1,3 +1,4 @@
// FILE: test.kt
package localFunInLibrary
fun main(args: Array<String>) {
@@ -6,4 +7,12 @@ fun main(args: Array<String>) {
// ADDITIONAL_BREAKPOINT: localFunCustomLib.kt:localFunInLibraryCustomLibProperty
// EXPRESSION: localFun()
// RESULT: 1: I
// RESULT: 1: I
// FILE: localFunCustomLib.kt
package customLib.localFunInLibraryCustomLib
public fun localFunInLibraryCustomLibMainFun() {
fun localFun() = 1
val localFunInLibraryCustomLibProperty = 1
}
@@ -1,7 +1,7 @@
LineBreakpoint created at localFunCustomLib.kt:6
LineBreakpoint created at localFunCustomLib.kt:7
Run Java
Connected to the target VM
localFunCustomLib.kt:6
localFunCustomLib.kt:7
Compile bytecode for localFun()
Disconnected from the target VM
@@ -1,3 +1,4 @@
// FILE: breakpointInInlineFun.kt
package breakpointInInlineFun
import customLib.inlineFunInLibrary.*
@@ -9,4 +10,19 @@ fun main(args: Array<String>) {
// RESUME: 2
// ADDITIONAL_BREAKPOINT: inlineFunInLibrary.kt:public inline fun inlineFun
// ADDITIONAL_BREAKPOINT: inlineFunInLibrary.kt: Breakpoint 2
// ADDITIONAL_BREAKPOINT: inlineFunInLibrary.kt: Breakpoint 2
// FILE: customLib/inlineFunInLibrary/inlineFunInLibrary.kt
package customLib.inlineFunInLibrary
public inline fun inlineFun(f: () -> Unit) {
1 + 1
inlineFunInner {
1 + 1
}
}
public inline fun inlineFunInner(f: () -> Unit) {
// Breakpoint 2
1 + 1
}
@@ -1,9 +1,9 @@
LineBreakpoint created at inlineFunInLibrary.kt:4
LineBreakpoint created at inlineFunInLibrary.kt:12
LineBreakpoint created at inlineFunInLibrary.kt:5
LineBreakpoint created at inlineFunInLibrary.kt:13
Run Java
Connected to the target VM
inlineFunInLibrary.kt:4
inlineFunInLibrary.kt:12
inlineFunInLibrary.kt:5
inlineFunInLibrary.kt:13
Disconnected from the target VM
Process finished with exit code 0
@@ -1,3 +1,4 @@
// FILE: classFromAnotherPackage.kt
package classFromAnotherPackage
import forTests.MyJavaClass
@@ -12,3 +13,7 @@ fun main(args: Array<String>) {
// EXPRESSION: forTests.MyJavaClass()
// RESULT: instance of forTests.MyJavaClass(id=ID): LforTests/MyJavaClass;
// FILE: forTests/MyJavaClass.java
package forTests;
public class MyJavaClass {}
@@ -1,7 +1,7 @@
LineBreakpoint created at classFromAnotherPackage.kt:7
LineBreakpoint created at classFromAnotherPackage.kt:8
Run Java
Connected to the target VM
classFromAnotherPackage.kt:7
classFromAnotherPackage.kt:8
Compile bytecode for MyJavaClass()
Compile bytecode for forTests.MyJavaClass()
Disconnected from the target VM
@@ -1,3 +1,4 @@
// FILE: createExpressionWithArray.kt
package createExpressionWithArray
import forTests.MyJavaClass
@@ -13,3 +14,28 @@ fun main(args: Array<String>) {
// PRINT_FRAME
// DESCRIPTOR_VIEW_OPTIONS: NAME_EXPRESSION_RESULT
// FILE: forTests/MyJavaClass.java
package forTests;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class MyJavaClass {
public static class BaseClass {
public final int i2 = 1;
}
public BaseClass getBaseClassValue() {
return new BaseClass();
}
public BaseClass getInnerClassValue() {
return new InnerClass();
}
public static class InnerClass extends BaseClass {
public final int i = 1;
}
public MyJavaClass() {}
}
@@ -1,7 +1,7 @@
LineBreakpoint created at createExpressionWithArray.kt:11
LineBreakpoint created at createExpressionWithArray.kt:12
Run Java
Connected to the target VM
createExpressionWithArray.kt:11
createExpressionWithArray.kt:12
Compile bytecode for args
Compile bytecode for baseArray
Compile bytecode for baseArray[0]
@@ -1,3 +1,4 @@
// FILE: delegatedPropertyInOtherFile.kt
package delegatedPropertyInOtherFile
import delegatedPropertyInOtherFileOther.*
@@ -11,3 +12,16 @@ fun main(a: Array<String>) {
// EXPRESSION: t.a
// RESULT: 12: I
// FILE: delegatedPropertyInOtherFile/delegatedPropertyInOtherFile2.kt
package delegatedPropertyInOtherFileOther
import kotlin.reflect.KProperty
class WithDelegate {
val a: Int by Id(12)
}
class Id(val v: Int) {
operator fun getValue(o: Any, property: KProperty<*>): Int = v
}
@@ -1,7 +1,7 @@
LineBreakpoint created at delegatedPropertyInOtherFile.kt:9
LineBreakpoint created at delegatedPropertyInOtherFile.kt:10
Run Java
Connected to the target VM
delegatedPropertyInOtherFile.kt:9
delegatedPropertyInOtherFile.kt:10
Compile bytecode for t.a
Disconnected from the target VM
@@ -2,7 +2,6 @@ LineBreakpoint created at evDelegatedProperty.kt:13
Run Java
Connected to the target VM
evDelegatedProperty.kt:13
Compile bytecode for a.prop
frame = main:13, EvDelegatedPropertyKt {evDelegatedProperty}
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = evDelegatedProperty.kt, 9)
local = a: evDelegatedProperty.A = {evDelegatedProperty.A@uniqueID} (sp = evDelegatedProperty.kt, 10)
@@ -1,3 +1,4 @@
// FILE: fieldGetters.kt
package fieldGetters
import forTests.FieldsGetters
@@ -30,8 +31,6 @@ class K2 {
// EXPRESSION: K2().a_field
// RESULT: 0: I
// EXPRESSION: PublicField().foo
// RESULT: "a": Ljava/lang/String;
@@ -102,4 +101,82 @@ class K2 {
// RESULT: "a": Ljava/lang/String;
// EXPRESSION: PublicFieldAndGetterInParent().foo_field
// RESULT: "b": Ljava/lang/String;
// RESULT: "b": Ljava/lang/String;
// FILE: forTests/FieldsGetters.java
package forTests;
public class FieldsGetters {
public static class PublicField {
public String foo = "a";
}
public static class PackagePrivateField {
String foo = "b";
}
public static class ProtectedField {
protected String foo = "c";
}
public static class PrivateField {
private String foo = "d";
}
public static class PublicFieldGetter {
public final String foo = "a";
public String getFoo() {
return "b";
}
}
public static class PrivateFieldPublicGetter {
private final String foo = "c";
public String getFoo() {
return "d";
}
}
public static class PrivateFieldPrivateGetter {
private final String foo = "e";
public String getFoo() {
return "f";
}
}
public static class PublicGetter1 extends PublicField {
public String getFoo() {
return "g";
}
}
public static class PublicGetter2 extends PackagePrivateField {
public String getFoo() {
return "h";
}
}
public static class PrivateGetter1 extends PrivateField {
private String getFoo() {
return "g";
}
}
public static class PublicGetterOnly {
public String getFoo() {
return "a";
}
}
public static class PublicFieldAndGetterInParent extends PublicGetterOnly {
public String foo = "b";
}
public abstract class AbstractGetter {
public String foo = "c";
public abstract String getFoo();
}
}
@@ -1,7 +1,7 @@
LineBreakpoint created at fieldGetters.kt:8
LineBreakpoint created at fieldGetters.kt:9
Run Java
Connected to the target VM
fieldGetters.kt:8
fieldGetters.kt:9
Compile bytecode for K1().a
Compile bytecode for K1().a_field
Compile bytecode for K2().a
@@ -1,3 +1,4 @@
// FILE: fileWithError.kt
package fileWithError
fun main(args: Array<String>) {
@@ -8,4 +9,17 @@ fun main(args: Array<String>) {
// ADDITIONAL_BREAKPOINT: fileWithInternal.kt:Breakpoint
// EXPRESSION: 1
// RESULT: 1: I
// RESULT: 1: I
// FILE: lib/fileWithInternal.kt
package fileWithInternal
fun test() {
// Breakpoint
val a = fileWithInternal2.MyInternal()
}
// FILE: lib/fileWithInternal2.kt
package fileWithInternal2
internal class MyInternal
@@ -1,7 +1,7 @@
LineBreakpoint created at fileWithInternal.kt:5
LineBreakpoint created at fileWithInternal.kt:6
Run Java
Connected to the target VM
fileWithInternal.kt:5
fileWithInternal.kt:6
Compile bytecode for 1
Disconnected from the target VM
@@ -1,3 +1,4 @@
// FILE: inlineFunInMultiFilePackage.kt
package inlineFunInMultiFilePackage
fun main(args: Array<String>) {
@@ -8,3 +9,9 @@ fun main(args: Array<String>) {
// EXPRESSION: multiFilePackage.foo { 1 }
// RESULT: 1: I
// FILE: multiFilePackage.kt
@file:JvmMultifileClass
@file:JvmName("NewName")
package multiFilePackage
inline fun foo(f: () -> Int) = f()
@@ -1,7 +1,7 @@
LineBreakpoint created at inlineFunInMultiFilePackage.kt:5
LineBreakpoint created at inlineFunInMultiFilePackage.kt:6
Run Java
Connected to the target VM
inlineFunInMultiFilePackage.kt:5
inlineFunInMultiFilePackage.kt:6
Compile bytecode for multiFilePackage.foo { 1 }
Disconnected from the target VM
@@ -1,3 +1,4 @@
// FILE: inlineFunction.kt
package inlineFunction
import inlineFunctionOtherPackage.*
@@ -13,4 +14,14 @@ inline fun foo() = 1
// RESULT: 1: I
// EXPRESSION: foo()
// RESULT: 1: I
// RESULT: 1: I
// FILE: lib.kt
package inlineFunctionOtherPackage
inline fun myFun(f: () -> Int): Int = f()
val String.prop: String
get() {
return "a"
}
@@ -1,7 +1,7 @@
LineBreakpoint created at inlineFunction.kt:7
LineBreakpoint created at inlineFunction.kt:8
Run Java
Connected to the target VM
inlineFunction.kt:7
inlineFunction.kt:8
Compile bytecode for myFun { 1 }
Compile bytecode for foo()
Disconnected from the target VM
@@ -1,3 +1,4 @@
// FILE: test.kt
package inlineFunctionBreakpointAnotherFile
fun main(args: Array<String>) {
@@ -10,4 +11,11 @@ fun main(args: Array<String>) {
}
}
// ADDITIONAL_BREAKPOINT: inlineFunctionWithBreakpoint.kt:inline fun myFun
// ADDITIONAL_BREAKPOINT: inlineFunctionWithBreakpoint.kt:inline fun myFun
// FILE: inlineFunctionWithBreakpoint.kt
package inlineFunctionWithBreakpoint
inline fun myFun(f: (Int) -> Unit) {
f(1)
}
@@ -1,7 +1,7 @@
LineBreakpoint created at inlineFunctionWithBreakpoint.kt:4
LineBreakpoint created at inlineFunctionWithBreakpoint.kt:5
Run Java
Connected to the target VM
inlineFunctionWithBreakpoint.kt:4
inlineFunctionWithBreakpoint.kt:5
Disconnected from the target VM
Process finished with exit code 0
@@ -1,3 +1,4 @@
// FILE: jcBlock.kt
package jcBlock
fun main(args: Array<String>) {
@@ -16,4 +17,20 @@ fun main(args: Array<String>) {
// RESULT: 1: I
// EXPRESSION: elseVal
// RESULT: Unresolved reference: elseVal
// RESULT: Unresolved reference: elseVal
// FILE: forTests/javaContext/JavaClass.java
package forTests.javaContext;
public class JavaClass {
public void block() {
int bodyVal = 1;
if (true) {
int thenVal = 1;
int breakpoint = 1;
}
else {
int elseVal = 1;
}
}
}
@@ -1,10 +1,10 @@
LineBreakpoint created at jcBlock.kt:6
LineBreakpoint created at jcBlock.kt:7
Run Java
Connected to the target VM
jcBlock.kt:6
JavaClass.java:16
JavaClass.java:18
JavaClass.java:19
jcBlock.kt:7
JavaClass.java:6
JavaClass.java:8
JavaClass.java:9
Compile bytecode for bodyVal
Compile bytecode for thenVal
Disconnected from the target VM
@@ -1,3 +1,4 @@
// FILE: jcImports.kt
package jcImports
fun main(args: Array<String>) {
@@ -10,4 +11,23 @@ fun main(args: Array<String>) {
// STEP_OVER: 1
// EXPRESSION: list.filter { it == 1 }.size
// RESULT: 1: I
// RESULT: 1: I
// FILE: forTests/javaContext/JavaClass.java
package forTests.javaContext;
import java.util.ArrayList;
public class JavaClass {
public void imports() {
ArrayList<Integer> list = createList();
int breakpoint = 1;
}
private ArrayList<Integer> createList() {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
return list;
}
}
@@ -1,9 +1,9 @@
LineBreakpoint created at jcImports.kt:6
LineBreakpoint created at jcImports.kt:7
Run Java
Connected to the target VM
jcImports.kt:6
JavaClass.java:27
JavaClass.java:28
jcImports.kt:7
JavaClass.java:8
JavaClass.java:9
Compile bytecode for list.filter { it == 1 }.size
Disconnected from the target VM
@@ -1,3 +1,4 @@
// FILE: jcLocalVariable.kt
package jcLocalVariable
fun main(args: Array<String>) {
@@ -10,4 +11,14 @@ fun main(args: Array<String>) {
// STEP_OVER: 1
// EXPRESSION: i
// RESULT: 1: I
// RESULT: 1: I
// FILE: forTests/javaContext/JavaClass.java
package forTests.javaContext;
public class JavaClass {
public void localVariable() {
int i = 1;
int breakpoint = 1;
}
}
@@ -1,9 +1,9 @@
LineBreakpoint created at jcLocalVariable.kt:6
LineBreakpoint created at jcLocalVariable.kt:7
Run Java
Connected to the target VM
jcLocalVariable.kt:6
JavaClass.java:11
JavaClass.java:12
jcLocalVariable.kt:7
JavaClass.java:6
JavaClass.java:7
Compile bytecode for i
Disconnected from the target VM
@@ -1,3 +1,4 @@
// FILE: test.kt
package jcMarkedObject
fun main(args: Array<String>) {
@@ -15,4 +16,14 @@ fun main(args: Array<String>) {
// EXPRESSION: i_DebugLabel
// RESULT: instance of java.lang.Integer(id=ID): Ljava/lang/Integer;
// DEBUG_LABEL: i = i
// DEBUG_LABEL: i = i
// FILE: forTests/javaContext/JavaClass.java
package forTests.javaContext;
public class JavaClass {
public void markObject() {
Integer i = 1;
int breakpoint = 1;
}
}
@@ -1,9 +1,9 @@
LineBreakpoint created at jcMarkedObject.kt:6
LineBreakpoint created at test.kt:7
Run Java
Connected to the target VM
jcMarkedObject.kt:6
JavaClass.java:39
JavaClass.java:40
test.kt:7
JavaClass.java:6
JavaClass.java:7
Compile bytecode for i
Compile bytecode for i_DebugLabel
Disconnected from the target VM
@@ -1,3 +1,4 @@
// FILE: test.kt
package jcProperty
fun main(args: Array<String>) {
@@ -15,4 +16,16 @@ fun main(args: Array<String>) {
// RESULT: 1: I
// EXPRESSION: javaPrivateProperty
// RESULT: 1: I
// RESULT: 1: I
// FILE: forTests/javaContext/JavaClass.java
package forTests.javaContext;
public class JavaClass {
public int javaProperty = 1;
private int javaPrivateProperty = 1;
public void property() {
int breakpoint = 1;
}
}
@@ -1,8 +1,8 @@
LineBreakpoint created at jcProperty.kt:6
LineBreakpoint created at test.kt:7
Run Java
Connected to the target VM
jcProperty.kt:6
JavaClass.java:47
test.kt:7
JavaClass.java:9
Compile bytecode for this.javaProperty
Compile bytecode for javaProperty
Compile bytecode for javaPrivateProperty
@@ -1,3 +1,4 @@
// FILE: jcSimple.kt
package jcSimple
fun main(args: Array<String>) {
@@ -9,4 +10,13 @@ fun main(args: Array<String>) {
// STEP_INTO: 1
// EXPRESSION: 1 + 1
// RESULT: 2: I
// RESULT: 2: I
// FILE: forTests/javaContext/JavaClass.java
package forTests.javaContext;
public class JavaClass {
public void simple() {
int breakpoint = 1;
}
}
@@ -1,8 +1,8 @@
LineBreakpoint created at jcSimple.kt:6
LineBreakpoint created at jcSimple.kt:7
Run Java
Connected to the target VM
jcSimple.kt:6
JavaClass.java:7
jcSimple.kt:7
JavaClass.java:6
Compile bytecode for 1 + 1
Disconnected from the target VM
@@ -1,3 +1,4 @@
// FILE: javaStaticMethods.kt
package javaStaticMethods
import forTests.javaContext.JavaClass.JavaStatic
@@ -9,3 +10,12 @@ fun main() {
// EXPRESSION: JavaStatic.state()
// RESULT: 1: I
// FILE: forTests/javaContext/JavaClass.java
package forTests.javaContext;
public class JavaClass {
public interface JavaStatic {
static int state() { return 1; }
}
}
@@ -1,7 +1,7 @@
LineBreakpoint created at javaStaticMethods.kt:7
LineBreakpoint created at javaStaticMethods.kt:8
Run Java
Connected to the target VM
javaStaticMethods.kt:7
javaStaticMethods.kt:8
Compile bytecode for JavaStatic.state()
Disconnected from the target VM
@@ -1,3 +1,4 @@
// FILE: privateClass.kt
package privateClass
fun main(args: Array<String>) {
@@ -32,3 +33,15 @@ class A {
// EXPRESSION: forTests.MyJavaClass.PrivateJavaClass().prop
// RESULT: 1: I
// FILE: forTests/MyJavaClass.java
package forTests;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class MyJavaClass {
private static class PrivateJavaClass {
public final int prop = 1;
}
}
@@ -1,7 +1,7 @@
LineBreakpoint created at privateClass.kt:5
LineBreakpoint created at privateClass.kt:6
Run Java
Connected to the target VM
privateClass.kt:5
privateClass.kt:6
Compile bytecode for A.PrivateClass()
Compile bytecode for A.PrivateClass().prop
Compile bytecode for A().PrivateInnerClass()
@@ -1,3 +1,4 @@
// FILE: rawTypeskt11831.kt
package rawTypeskt11831
fun main(args: Array<String>) {
@@ -8,4 +9,22 @@ fun main(args: Array<String>) {
}
// EXPRESSION: foo
// RESULT: 1: I
// RESULT: 1: I
// FILE: forTests/MyJavaClass.java
package forTests;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class MyJavaClass {
public static class RawA<T> {
public int foo(List<T> p) {
return 1;
}
}
public static class RawADerived extends RawA {
}
}
@@ -1,7 +1,7 @@
LineBreakpoint created at rawTypeskt11831.kt:7
LineBreakpoint created at rawTypeskt11831.kt:8
Run Java
Connected to the target VM
rawTypeskt11831.kt:7
rawTypeskt11831.kt:8
Compile bytecode for foo
Disconnected from the target VM
@@ -0,0 +1,37 @@
package forTests
import kotlin.coroutines.Continuation
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.startCoroutine
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation()
override fun resumeWith(result: Result<Any?>) { result.getOrThrow() }
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
class WaitFinish(
private val timeout: Long = 5,
private val unit: TimeUnit = TimeUnit.SECONDS
) {
private val cdl = CountDownLatch(1)
fun finish() {
cdl.countDown()
}
fun waitEnd() {
if (!cdl.await(timeout, unit)) {
throw java.lang.IllegalStateException("Too long wait in debugger test!")
}
Thread.sleep(10)
}
}
@@ -3,4 +3,6 @@ package streams.sequence.sort
fun main(args: Array<String>) {
//Breakpoint!
arrayOf(Person("Bob", 42), Person("Alice", 27)).asSequence().sortedByDescending { it.age }.count()
}
}
data class Person(val name: String, val age: Int)

Some files were not shown because too many files have changed in this diff Show More