diff --git a/idea/testData/debugger/sequence/exec/java/outs/simple.out b/idea/testData/debugger/sequence/exec/java/outs/simple.out new file mode 100644 index 00000000000..0818ed7757a --- /dev/null +++ b/idea/testData/debugger/sequence/exec/java/outs/simple.out @@ -0,0 +1,21 @@ +LineBreakpoint created at Simple.kt:5 +Run Java +Connected to the target VM +Simple.kt:5 +Stream.of(1, 2, 3) +.toArray() +toArray + before: 1,2,3 + after: 4,5,6 +mappings for toArray + direct: + 1 -> 4 + 2 -> 5 + 3 -> 6 + reverse: + 1 <- 4 + 2 <- 5 + 3 <- 6 +Disconnected from the target VM + +Process finished with exit code 0 diff --git a/idea/testData/debugger/sequence/exec/java/src/Simple.kt b/idea/testData/debugger/sequence/exec/java/src/Simple.kt new file mode 100644 index 00000000000..7a5ddd22c42 --- /dev/null +++ b/idea/testData/debugger/sequence/exec/java/src/Simple.kt @@ -0,0 +1,6 @@ +import java.util.stream.Stream + +fun main(args: Array) { + // Breakpoint! + Stream.of(1, 2, 3).toArray() +} diff --git a/idea/tests/com/intellij/debugger/streams/kotlin/exec/KotlinEvaluationTestCase.kt b/idea/tests/com/intellij/debugger/streams/kotlin/exec/KotlinEvaluationTestCase.kt new file mode 100644 index 00000000000..e7d80b73dcf --- /dev/null +++ b/idea/tests/com/intellij/debugger/streams/kotlin/exec/KotlinEvaluationTestCase.kt @@ -0,0 +1,78 @@ +package com.intellij.debugger.streams.kotlin.exec + +import com.intellij.debugger.impl.OutputChecker +import com.intellij.debugger.streams.kotlin.LibraryManager +import com.intellij.debugger.streams.lib.LibrarySupportProvider +import com.intellij.debugger.streams.test.TraceExecutionTestCase +import com.intellij.execution.configurations.JavaParameters +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.util.Computable +import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess +import com.intellij.psi.JavaPsiFacade +import com.intellij.psi.PsiClass +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.testFramework.PsiTestUtil +import org.jetbrains.kotlin.asJava.classes.FakeLightClassForFileOfPackage +import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade +import java.io.File +import java.nio.file.Paths + +/** + * @author Vitaliy.Bibaev + */ +abstract class KotlinEvaluationTestCase : TraceExecutionTestCase() { + private companion object { + val STDLIB_JAR_NAME = "kotlin-stdlib.jar" + } + + abstract val appName: String + abstract val librarySupport: LibrarySupportProvider + + override final fun getLibrarySupportProvider(): LibrarySupportProvider = librarySupport + + override fun setUpModule() { + super.setUpModule() + ApplicationManager.getApplication().runWriteAction { + VfsRootAccess.allowRootAccess(LibraryManager.LIBRARIES_DIRECTORY) + PsiTestUtil.addLibrary(myModule, "${LibraryManager.LIBRARIES_DIRECTORY}/$STDLIB_JAR_NAME") + } + } + + override fun createJavaParameters(mainClass: String?): JavaParameters { + val javaParameters = super.createJavaParameters(mainClass) + javaParameters.classPath.add("${LibraryManager.LIBRARIES_DIRECTORY}/$STDLIB_JAR_NAME") + return javaParameters + } + + override fun initOutputChecker(): OutputChecker { + return KotlinOutputChecker(testAppPath, appOutputPath) + } + + override fun createLocalProcess(className: String?) { + super.createLocalProcess(className + "Kt") + } + + override fun createBreakpoints(className: String) { + val psiClasses = ApplicationManager.getApplication().runReadAction(Computable> { + JavaPsiFacade.getInstance(myProject) + .findClasses(className, GlobalSearchScope.allScope(myProject)) + }) + + for (psiClass in psiClasses) { + if (psiClass is KtLightClassForFacade) { + val files = psiClass.files + for (jetFile in files) { + createBreakpoints(jetFile) + } + } else if (psiClass is FakeLightClassForFileOfPackage) { + // skip, because we already create breakpoints using KotlinLightClassForPackage + } else { + createBreakpoints(psiClass.containingFile) + } + } + } + + override fun getTestAppPath(): String { + return Paths.get(File("").absolutePath, "/testData/exec/$appName").toString() + } +} diff --git a/idea/tests/com/intellij/debugger/streams/kotlin/exec/KotlinOutputChecker.kt b/idea/tests/com/intellij/debugger/streams/kotlin/exec/KotlinOutputChecker.kt new file mode 100644 index 00000000000..c9cec871dde --- /dev/null +++ b/idea/tests/com/intellij/debugger/streams/kotlin/exec/KotlinOutputChecker.kt @@ -0,0 +1,129 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.intellij.debugger.streams.kotlin.exec + +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 + +/** + * Copied with minor changes from the kotlin repo + * TODO: use org.jetbrains.kotlin.idea.debugger.KotlinOutputChecker instead + * @author Vitaliy.Bibaev + */ +internal class KotlinOutputChecker(appPath: String, outputPath: String) : OutputChecker(appPath, outputPath) { + companion object { + @JvmStatic + private val LOG = Logger.getInstance(KotlinOutputChecker::class.java) + + private val CONNECT_PREFIX = "Connected to the target VM" + private val DISCONNECT_PREFIX = "Disconnected from the target VM" + private 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.*]") + } + + // 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(myAppPath + File.separator + "outs") + 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 = Math.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 + } + } +} diff --git a/idea/tests/com/intellij/debugger/streams/kotlin/exec/java/JavaStreamTest.kt b/idea/tests/com/intellij/debugger/streams/kotlin/exec/java/JavaStreamTest.kt new file mode 100644 index 00000000000..5d217836765 --- /dev/null +++ b/idea/tests/com/intellij/debugger/streams/kotlin/exec/java/JavaStreamTest.kt @@ -0,0 +1,18 @@ +package com.intellij.debugger.streams.kotlin.exec.java + +import com.intellij.debugger.streams.kotlin.exec.KotlinEvaluationTestCase +import com.intellij.debugger.streams.kotlin.lib.JavaStandardLibrarySupportProvider +import com.intellij.debugger.streams.lib.LibrarySupportProvider + + +/** + * @author Vitaliy.Bibaev + */ +class JavaStreamTest : KotlinEvaluationTestCase() { + override val appName: String = "java" + override val librarySupport: LibrarySupportProvider = JavaStandardLibrarySupportProvider() + + fun testSimple() { + doTest(false) + } +} \ No newline at end of file