diff --git a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index bfeb71f6b3e..22c22b3532b 100755 --- a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -735,8 +735,9 @@ fun main(args: Array) { } testClass { - model("scratch", extension = "kts", testMethod = "doCompilingTest", testClassName = "Compiling") - model("scratch", extension = "kts", testMethod = "doReplTest", testClassName = "Repl") + model("scratch", extension = "kts", testMethod = "doCompilingTest", testClassName = "Compiling", recursive = false) + model("scratch", extension = "kts", testMethod = "doReplTest", testClassName = "Repl", recursive = false) + model("scratch/multiFile", extension = null, testMethod = "doMultiFileTest", recursive = false) } } diff --git a/idea/testData/scratch/generics.comp.after b/idea/testData/scratch/generics.comp.after new file mode 100644 index 00000000000..992dcb85498 --- /dev/null +++ b/idea/testData/scratch/generics.comp.after @@ -0,0 +1,8 @@ +class GClass { // RESULT: class GClass + fun foo(t: T): T { + return t + } +} + +val g = GClass() // RESULT: val g: Generics.GClass +g.foo(1) // RESULT: 1 diff --git a/idea/testData/scratch/generics.kts b/idea/testData/scratch/generics.kts new file mode 100644 index 00000000000..417bc24a399 --- /dev/null +++ b/idea/testData/scratch/generics.kts @@ -0,0 +1,8 @@ +class GClass { + fun foo(t: T): T { + return t + } +} + +val g = GClass() +g.foo(1) \ No newline at end of file diff --git a/idea/testData/scratch/generics.repl.after b/idea/testData/scratch/generics.repl.after new file mode 100644 index 00000000000..458340348a2 --- /dev/null +++ b/idea/testData/scratch/generics.repl.after @@ -0,0 +1,8 @@ +class GClass { + fun foo(t: T): T { + return t + } +} + +val g = GClass() +g.foo(1) // RESULT: 1 diff --git a/idea/testData/scratch/klass.comp.after b/idea/testData/scratch/klass.comp.after new file mode 100644 index 00000000000..4c0cce5fc74 --- /dev/null +++ b/idea/testData/scratch/klass.comp.after @@ -0,0 +1,14 @@ +class MyClass { // RESULT: class MyClass + fun foo() = 1 +} + +MyClass().foo() // RESULT: 1 + +interface I { // RESULT: interface I + fun foo(): Int +} + +val i = object: I { // RESULT: val i: Klass.I + override fun foo(): Int = 1 +} +i.foo() // RESULT: 1 diff --git a/idea/testData/scratch/klass.kts b/idea/testData/scratch/klass.kts new file mode 100644 index 00000000000..01ddaa3a871 --- /dev/null +++ b/idea/testData/scratch/klass.kts @@ -0,0 +1,14 @@ +class MyClass { + fun foo() = 1 +} + +MyClass().foo() + +interface I { + fun foo(): Int +} + +val i = object: I { + override fun foo(): Int = 1 +} +i.foo() diff --git a/idea/testData/scratch/klass.repl.after b/idea/testData/scratch/klass.repl.after new file mode 100644 index 00000000000..978e2377824 --- /dev/null +++ b/idea/testData/scratch/klass.repl.after @@ -0,0 +1,14 @@ +class MyClass { + fun foo() = 1 +} + +MyClass().foo() // RESULT: 1 + +interface I { + fun foo(): Int +} + +val i = object: I { + override fun foo(): Int = 1 +} +i.foo() // RESULT: 1 diff --git a/idea/testData/scratch/multiFile/inlineFun/inlineFun.comp.after b/idea/testData/scratch/multiFile/inlineFun/inlineFun.comp.after new file mode 100644 index 00000000000..ce195685d49 --- /dev/null +++ b/idea/testData/scratch/multiFile/inlineFun/inlineFun.comp.after @@ -0,0 +1,3 @@ +import inlineFun.* + +foo { 1 + 3 } // RESULT: 4 \ No newline at end of file diff --git a/idea/testData/scratch/multiFile/inlineFun/inlineFun.kts b/idea/testData/scratch/multiFile/inlineFun/inlineFun.kts new file mode 100644 index 00000000000..6b957dd293e --- /dev/null +++ b/idea/testData/scratch/multiFile/inlineFun/inlineFun.kts @@ -0,0 +1,3 @@ +import inlineFun.* + +foo { 1 + 3 } \ No newline at end of file diff --git a/idea/testData/scratch/multiFile/inlineFun/inlineFun.repl.after b/idea/testData/scratch/multiFile/inlineFun/inlineFun.repl.after new file mode 100644 index 00000000000..ce195685d49 --- /dev/null +++ b/idea/testData/scratch/multiFile/inlineFun/inlineFun.repl.after @@ -0,0 +1,3 @@ +import inlineFun.* + +foo { 1 + 3 } // RESULT: 4 \ No newline at end of file diff --git a/idea/testData/scratch/multiFile/inlineFun/myFun.kt b/idea/testData/scratch/multiFile/inlineFun/myFun.kt new file mode 100644 index 00000000000..0ac3f202b13 --- /dev/null +++ b/idea/testData/scratch/multiFile/inlineFun/myFun.kt @@ -0,0 +1,3 @@ +package inlineFun + +inline fun foo(f: () -> Int): Int = f() \ No newline at end of file diff --git a/idea/testData/scratch/multiFile/javaDep/javaDep.comp.after b/idea/testData/scratch/multiFile/javaDep/javaDep.comp.after new file mode 100644 index 00000000000..03c7977c6c4 --- /dev/null +++ b/idea/testData/scratch/multiFile/javaDep/javaDep.comp.after @@ -0,0 +1,3 @@ +import myTest.MyJavaClass + +MyJavaClass().test() // RESULT: 1 \ No newline at end of file diff --git a/idea/testData/scratch/multiFile/javaDep/javaDep.kts b/idea/testData/scratch/multiFile/javaDep/javaDep.kts new file mode 100644 index 00000000000..bb1c8939884 --- /dev/null +++ b/idea/testData/scratch/multiFile/javaDep/javaDep.kts @@ -0,0 +1,3 @@ +import myTest.MyJavaClass + +MyJavaClass().test() \ No newline at end of file diff --git a/idea/testData/scratch/multiFile/javaDep/javaDep.repl.after b/idea/testData/scratch/multiFile/javaDep/javaDep.repl.after new file mode 100644 index 00000000000..03c7977c6c4 --- /dev/null +++ b/idea/testData/scratch/multiFile/javaDep/javaDep.repl.after @@ -0,0 +1,3 @@ +import myTest.MyJavaClass + +MyJavaClass().test() // RESULT: 1 \ No newline at end of file diff --git a/idea/testData/scratch/custom/MyJavaClass.java b/idea/testData/scratch/multiFile/javaDep/myTest/MyJavaClass.java similarity index 100% rename from idea/testData/scratch/custom/MyJavaClass.java rename to idea/testData/scratch/multiFile/javaDep/myTest/MyJavaClass.java diff --git a/idea/testData/scratch/var.comp.after b/idea/testData/scratch/var.comp.after new file mode 100644 index 00000000000..2d45cf954c4 --- /dev/null +++ b/idea/testData/scratch/var.comp.after @@ -0,0 +1,3 @@ +var a = 1 // RESULT: var a: Int +a++ // RESULT: 1 +a // RESULT: 2 diff --git a/idea/testData/scratch/var.kts b/idea/testData/scratch/var.kts new file mode 100644 index 00000000000..8da9de9c877 --- /dev/null +++ b/idea/testData/scratch/var.kts @@ -0,0 +1,3 @@ +var a = 1 +a++ +a \ No newline at end of file diff --git a/idea/testData/scratch/var.repl.after b/idea/testData/scratch/var.repl.after new file mode 100644 index 00000000000..8300ee454f8 --- /dev/null +++ b/idea/testData/scratch/var.repl.after @@ -0,0 +1,3 @@ +var a = 1 +a++ // RESULT: 1 +a // RESULT: 2 diff --git a/idea/testData/scratch/when.comp.after b/idea/testData/scratch/when.comp.after new file mode 100644 index 00000000000..bd4a5b18c0f --- /dev/null +++ b/idea/testData/scratch/when.comp.after @@ -0,0 +1,19 @@ +val a = 1 // RESULT: val a: Int +when(a) { // OUTPUT: 1 + 1 -> println("1") + else -> println("2") +} + +when(a) { // OUTPUT: 1 + 1 -> println("1") +} + +when(a) { // OUTPUT: 1 + 2 -> println("2") + else -> println("1") +} + +when(a) { // RESULT: 11 + 1 -> 11 + else -> 12 +} \ No newline at end of file diff --git a/idea/testData/scratch/when.kts b/idea/testData/scratch/when.kts new file mode 100644 index 00000000000..4a71c00159a --- /dev/null +++ b/idea/testData/scratch/when.kts @@ -0,0 +1,19 @@ +val a = 1 +when(a) { + 1 -> println("1") + else -> println("2") +} + +when(a) { + 1 -> println("1") +} + +when(a) { + 2 -> println("2") + else -> println("1") +} + +when(a) { + 1 -> 11 + else -> 12 +} \ No newline at end of file diff --git a/idea/testData/scratch/when.repl.after b/idea/testData/scratch/when.repl.after new file mode 100644 index 00000000000..bc920f19830 --- /dev/null +++ b/idea/testData/scratch/when.repl.after @@ -0,0 +1,19 @@ +val a = 1 +when(a) { // OUTPUT: 1 + 1 -> println("1") + else -> println("2") +} + +when(a) { // OUTPUT: 1 + 1 -> println("1") +} + +when(a) { // OUTPUT: 1 + 2 -> println("2") + else -> println("1") +} + +when(a) { + 1 -> 11 + else -> 12 +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/scratch/AbstractScratchRunActionTest.kt b/idea/tests/org/jetbrains/kotlin/idea/scratch/AbstractScratchRunActionTest.kt index 33ceb53ccea..3431232a875 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/scratch/AbstractScratchRunActionTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/scratch/AbstractScratchRunActionTest.kt @@ -20,25 +20,30 @@ import com.intellij.ide.scratch.ScratchFileService import com.intellij.ide.scratch.ScratchRootType import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.CommonDataKeys -import com.intellij.openapi.fileEditor.FileEditorManager -import com.intellij.openapi.fileEditor.TextEditor import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.CompilerModuleExtension +import com.intellij.openapi.roots.ModuleRootModificationUtil +import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.PsiManager import com.intellij.testFramework.FileEditorManagerTestCase import com.intellij.testFramework.MapDataContext +import com.intellij.testFramework.PsiTestUtil import com.intellij.testFramework.TestActionEvent import com.intellij.util.ui.UIUtil import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.idea.scratch.actions.RunScratchAction import org.jetbrains.kotlin.idea.scratch.output.InlayScratchOutputHandler -import org.jetbrains.kotlin.idea.scratch.ui.scratchTopPanel import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor import org.jetbrains.kotlin.test.KotlinTestUtils +import org.jetbrains.kotlin.test.MockLibraryUtil import org.junit.Assert import java.io.File +import java.util.* abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() { + fun doReplTest(fileName: String) { doTest(fileName, true) } @@ -47,6 +52,40 @@ abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() { doTest(fileName, false) } + fun doMultiFileTest(dirName: String) { + val javaFiles = arrayListOf() + val kotlinFiles = arrayListOf() + val baseDir = File(testDataPath, dirName) + baseDir.walk().forEach { + if (it.isFile) { + if (it.extension == "java") javaFiles.add(it) + if (it.extension == "kt") kotlinFiles.add(it) + } + } + + javaFiles.forEach { myFixture.copyFileToProject(it.path, FileUtil.getRelativePath(baseDir, it)!!) } + kotlinFiles.forEach { myFixture.copyFileToProject(it.path, FileUtil.getRelativePath(baseDir, it)!!) } + + val outputDir = myFixture.tempDirFixture.findOrCreateDir("out1") + + MockLibraryUtil.compileKotlin(baseDir.path, File(outputDir.path)) + + if (javaFiles.isNotEmpty()) { + val options = Arrays.asList("-d", outputDir.path) + KotlinTestUtils.compileJavaFiles(javaFiles, options) + } + + PsiTestUtil.setCompilerOutputPath(myModule, outputDir.url, false) + + val mainFileName = "$dirName/${getTestName(true)}.kts" + doCompilingTest(mainFileName) + doReplTest(mainFileName) + + ModuleRootModificationUtil.updateModel(myModule) { model -> + model.getModuleExtension(CompilerModuleExtension::class.java).inheritCompilerOutputPath(true) + } + } + fun doTest(fileName: String, isRepl: Boolean) { val sourceFile = File(testDataPath, fileName) val fileText = sourceFile.readText() @@ -61,9 +100,11 @@ abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() { myFixture.openFileInEditor(scratchFile) - ScratchFileLanguageProvider.createFile(myFixture.file)?.scratchTopPanel?.setReplMode(isRepl) + val psiFile = PsiManager.getInstance(project).findFile(scratchFile) ?: error("Couldn't find psi file ${sourceFile.path}") + val (editor, scratchPanel) = getEditorWithScratchPanel(project, scratchFile)?: error("Couldn't find scratch panel") + scratchPanel.setReplMode(isRepl) - val event = getActionEvent(myFixture.file.virtualFile, RunScratchAction()) + val event = getActionEvent(scratchFile, RunScratchAction()) launchAction(event, RunScratchAction()) UIUtil.dispatchAllInvocationEvents() @@ -71,29 +112,32 @@ abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() { val start = System.currentTimeMillis() // wait until output is displayed in editor or for 1 minute while (!event.presentation.isEnabled && (System.currentTimeMillis() - start) < 60000) { - Thread.sleep(5000) + Thread.sleep(100) } UIUtil.dispatchAllInvocationEvents() - val editors = FileEditorManager.getInstance(project).getEditors(scratchFile).filterIsInstance() - val doc = PsiDocumentManager.getInstance(project).getDocument(myFixture.file) ?: error("Document for ${myFixture.file.name} is null") + val doc = PsiDocumentManager.getInstance(project).getDocument(psiFile) ?: error("Document for ${psiFile.name} is null") - val actualOutput = StringBuilder(myFixture.file.text) + val actualOutput = StringBuilder(psiFile.text) for (line in doc.lineCount - 1 downTo 0) { - editors.flatMap { it.editor.inlayModel.getInlineElementsInRange(doc.getLineStartOffset(line), doc.getLineEndOffset(line)) } - .map { it.renderer } + editor.editor.inlayModel.getInlineElementsInRange( + doc.getLineStartOffset(line), + doc.getLineEndOffset(line) + ).map { it.renderer } .filterIsInstance() .forEach { val str = it.toString() - - val offset = doc.getLineEndOffset(line) - actualOutput.insert(offset, " // $str") + val offset = doc.getLineEndOffset(line); actualOutput.insert(offset, " // $str") } } - val expectedFileName = if (isRepl) fileName.replace(".kts", ".repl.after") else fileName.replace(".kts", ".comp.after") - val expectedFile = File("$testDataPath/$expectedFileName") + val expectedFileName = if (isRepl) { + fileName.replace(".kts", ".repl.after") + } else { + fileName.replace(".kts", ".comp.after") + } + val expectedFile = File(testDataPath, expectedFileName) KotlinTestUtils.assertEqualsToFile(expectedFile, actualOutput.toString()) } @@ -106,7 +150,7 @@ abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() { private fun getActionEvent(virtualFile: VirtualFile, action: AnAction): TestActionEvent { val context = MapDataContext() context.put(CommonDataKeys.VIRTUAL_FILE_ARRAY, arrayOf(virtualFile)) - context.put(CommonDataKeys.PROJECT, myFixture.project) + context.put(CommonDataKeys.PROJECT, project) return TestActionEvent(context, action) } diff --git a/idea/tests/org/jetbrains/kotlin/idea/scratch/ScratchRunActionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/scratch/ScratchRunActionTestGenerated.java index c4fa01943ac..9dc90b25b1c 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/scratch/ScratchRunActionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/scratch/ScratchRunActionTestGenerated.java @@ -24,7 +24,7 @@ public class ScratchRunActionTestGenerated extends AbstractScratchRunActionTest @RunWith(JUnit3RunnerWithInners.class) public static class Compiling extends AbstractScratchRunActionTest { public void testAllFilesPresentInCompiling() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/scratch"), Pattern.compile("^(.+)\\.kts$"), TargetBackend.ANY, true); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/scratch"), Pattern.compile("^(.+)\\.kts$"), TargetBackend.ANY, false); } @TestMetadata("for.kts") @@ -33,6 +33,18 @@ public class ScratchRunActionTestGenerated extends AbstractScratchRunActionTest doCompilingTest(fileName); } + @TestMetadata("generics.kts") + public void testGenerics() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/scratch/generics.kts"); + doCompilingTest(fileName); + } + + @TestMetadata("klass.kts") + public void testKlass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/scratch/klass.kts"); + doCompilingTest(fileName); + } + @TestMetadata("simple.kts") public void testSimple() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/scratch/simple.kts"); @@ -62,6 +74,18 @@ public class ScratchRunActionTestGenerated extends AbstractScratchRunActionTest String fileName = KotlinTestUtils.navigationMetadata("idea/testData/scratch/userOutput.kts"); doCompilingTest(fileName); } + + @TestMetadata("var.kts") + public void testVar() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/scratch/var.kts"); + doCompilingTest(fileName); + } + + @TestMetadata("when.kts") + public void testWhen() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/scratch/when.kts"); + doCompilingTest(fileName); + } } @TestMetadata("idea/testData/scratch") @@ -69,7 +93,7 @@ public class ScratchRunActionTestGenerated extends AbstractScratchRunActionTest @RunWith(JUnit3RunnerWithInners.class) public static class Repl extends AbstractScratchRunActionTest { public void testAllFilesPresentInRepl() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/scratch"), Pattern.compile("^(.+)\\.kts$"), TargetBackend.ANY, true); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/scratch"), Pattern.compile("^(.+)\\.kts$"), TargetBackend.ANY, false); } @TestMetadata("for.kts") @@ -78,6 +102,18 @@ public class ScratchRunActionTestGenerated extends AbstractScratchRunActionTest doReplTest(fileName); } + @TestMetadata("generics.kts") + public void testGenerics() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/scratch/generics.kts"); + doReplTest(fileName); + } + + @TestMetadata("klass.kts") + public void testKlass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/scratch/klass.kts"); + doReplTest(fileName); + } + @TestMetadata("simple.kts") public void testSimple() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/scratch/simple.kts"); @@ -107,5 +143,38 @@ public class ScratchRunActionTestGenerated extends AbstractScratchRunActionTest String fileName = KotlinTestUtils.navigationMetadata("idea/testData/scratch/userOutput.kts"); doReplTest(fileName); } + + @TestMetadata("var.kts") + public void testVar() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/scratch/var.kts"); + doReplTest(fileName); + } + + @TestMetadata("when.kts") + public void testWhen() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/scratch/when.kts"); + doReplTest(fileName); + } + } + + @TestMetadata("idea/testData/scratch/multiFile") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class MultiFile extends AbstractScratchRunActionTest { + public void testAllFilesPresentInMultiFile() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/scratch/multiFile"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, false); + } + + @TestMetadata("inlineFun") + public void testInlineFun() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/scratch/multiFile/inlineFun/"); + doMultiFileTest(fileName); + } + + @TestMetadata("javaDep") + public void testJavaDep() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/scratch/multiFile/javaDep/"); + doMultiFileTest(fileName); + } } }