as42: Remove clearing scratchesMapping in tests

This commit is contained in:
Nikolay Krasko
2020-09-01 20:47:08 +03:00
committed by Konstantin Tskhovrebov
parent c5b70797e2
commit fa9368125f
2 changed files with 454 additions and 0 deletions
@@ -0,0 +1,380 @@
/*
* 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.scratch
import com.intellij.ide.scratch.ScratchFileService
import com.intellij.ide.scratch.ScratchRootType
import com.intellij.lang.Language
import com.intellij.lang.PerFileMappingsEx
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.module.Module
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.openapi.vfs.newvfs.impl.VfsRootAccess
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.codegen.forTestCompile.ForTestCompileRuntime
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.actions.KOTLIN_WORKSHEET_EXTENSION
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingUtil
import org.jetbrains.kotlin.idea.scratch.actions.ClearScratchAction
import org.jetbrains.kotlin.idea.scratch.actions.RunScratchAction
import org.jetbrains.kotlin.idea.scratch.actions.ScratchCompilationSupport
import org.jetbrains.kotlin.idea.scratch.output.InlayScratchFileRenderer
import org.jetbrains.kotlin.idea.scratch.ui.KtScratchFileEditorWithPreview
import org.jetbrains.kotlin.idea.test.KotlinLightProjectDescriptor
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.parsing.KotlinParserDefinition.Companion.STD_SCRIPT_SUFFIX
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.MockLibraryUtil
import org.jetbrains.kotlin.utils.PathUtil
import org.junit.Assert
import java.io.File
abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() {
fun doRightPreviewPanelOutputTest(fileName: String) {
doRightPreviewPanelOutputTest(fileName = fileName, isRepl = false)
}
fun doWorksheetReplTest(fileName: String) {
doInlayOutputTest(fileName = fileName, isRepl = true, isWorksheet = true)
}
fun doScratchReplTest(fileName: String) {
doInlayOutputTest(fileName = fileName, isRepl = true, isWorksheet = false)
}
fun doWorksheetCompilingTest(fileName: String) {
doInlayOutputTest(fileName = fileName, isRepl = false, isWorksheet = true)
}
fun doScratchCompilingTest(fileName: String) {
doInlayOutputTest(fileName = fileName, isRepl = false, isWorksheet = false)
}
fun doWorksheetMultiFileTest(dirName: String) {
doMultiFileTest(dirName, isWorksheet = true)
}
fun doScratchMultiFileTest(dirName: String) {
doMultiFileTest(dirName, isWorksheet = false)
}
private fun doMultiFileTest(dirName: String, isWorksheet: Boolean) {
val mainFileExtension = if (isWorksheet) KOTLIN_WORKSHEET_EXTENSION else STD_SCRIPT_SUFFIX
val javaFiles = arrayListOf<File>()
val kotlinFiles = arrayListOf<File>()
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)
}
}
val testDataPathFile = File(myFixture.testDataPath)
javaFiles.forEach {
myFixture.copyFileToProject(
FileUtil.getRelativePath(testDataPathFile, it)!!,
FileUtil.getRelativePath(baseDir, it)!!
)
}
kotlinFiles.forEach {
myFixture.copyFileToProject(
FileUtil.getRelativePath(testDataPathFile, it)!!,
FileUtil.getRelativePath(baseDir, it)!!
)
}
val outputDir = FileUtil.createTempDirectory(dirName, "")
if (javaFiles.isNotEmpty()) {
val options = listOf("-d", outputDir.path)
KotlinTestUtils.compileJavaFiles(javaFiles, options)
}
MockLibraryUtil.compileKotlin(baseDir.path, outputDir)
PsiTestUtil.setCompilerOutputPath(myFixture.module, outputDir.path, false)
val mainFileName = "$dirName/${getTestName(true)}.$mainFileExtension"
doInlayOutputTest(mainFileName, isRepl = false, isWorksheet = isWorksheet)
launchAction(ClearScratchAction())
doInlayOutputTest(mainFileName, isRepl = true, isWorksheet = isWorksheet)
ModuleRootModificationUtil.updateModel(myFixture.module) { model ->
model.getModuleExtension(CompilerModuleExtension::class.java).inheritCompilerOutputPath(true)
}
}
private fun doInlayOutputTest(fileName: String, isRepl: Boolean, isWorksheet: Boolean) {
configureAndLaunchScratch(fileName = fileName, isRepl = isRepl, isWorksheet = isWorksheet)
val actualOutput = getFileTextWithInlays()
val expectedFile = getExpectedFile(fileName, isRepl, suffix = "after")
KotlinTestUtils.assertEqualsToFile(expectedFile, actualOutput)
}
private fun doRightPreviewPanelOutputTest(fileName: String, isRepl: Boolean) {
configureAndLaunchScratch(fileName = fileName, isRepl = isRepl, isWorksheet = false)
val previewTextWithFoldings = getPreviewTextWithFoldings()
val expectedFile = getExpectedFile(fileName, isRepl, suffix = "preview")
KotlinTestUtils.assertEqualsToFile(expectedFile, previewTextWithFoldings)
}
private fun configureAndLaunchScratch(fileName: String, isRepl: Boolean, isWorksheet: Boolean) {
val sourceFile = File(testDataPath, fileName)
val fileText = sourceFile.readText().inlinePropertiesValues(isRepl)
if (isWorksheet) {
configureWorksheetByText(sourceFile.name, fileText)
} else {
configureScratchByText(sourceFile.name, fileText)
}
if (!KotlinHighlightingUtil.shouldHighlight(myFixture.file)) error("Highlighting for scratch file is switched off")
launchScratch()
waitUntilScratchFinishes(isRepl)
}
private fun getExpectedFile(fileName: String, isRepl: Boolean, suffix: String): File {
val expectedFileName = if (isRepl) {
fileName.replace(".kts", ".repl.$suffix")
} else {
fileName.replace(".kts", ".comp.$suffix")
}
return File(testDataPath, expectedFileName)
}
protected fun String.inlinePropertiesValues(
isRepl: Boolean = false,
isInteractiveMode: Boolean = false
): String {
return replace("~REPL_MODE~", isRepl.toString()).replace("~INTERACTIVE_MODE~", isInteractiveMode.toString())
}
protected fun getFileTextWithInlays(): String {
val doc = myFixture.getDocument(myFixture.file) ?: error("Document for ${myFixture.file.name} is null")
val actualOutput = StringBuilder(myFixture.file.text)
for (line in doc.lineCount - 1 downTo 0) {
getInlays(doc.getLineStartOffset(line), doc.getLineEndOffset(line))
.forEach { inlay ->
val str = inlay.toString()
val offset = doc.getLineEndOffset(line)
actualOutput.insert(
offset,
"${str.takeWhile { it.isWhitespace() }}// ${str.trim()}"
)
}
}
return actualOutput.toString().trim()
}
private fun getPreviewTextWithFoldings(): String {
val scratchFileEditor = getScratchEditorForSelectedFile(myManager, myFixture.file.virtualFile)
?: error("Couldn't find scratch panel")
val previewEditor = scratchFileEditor.getPreviewEditor()
return getFoldingData(previewEditor.editor, withCollapseStatus = false)
}
protected fun getInlays(start: Int = 0, end: Int = myFixture.file.textLength): List<InlayScratchFileRenderer> {
val inlineElementsInRange = myFixture.editor.inlayModel
.getAfterLineEndElementsInRange(start, end)
.filter { it.renderer is InlayScratchFileRenderer }
return inlineElementsInRange.map { it.renderer as InlayScratchFileRenderer }
}
protected fun configureScratchByText(name: String, text: String): ScratchFile {
val scratchVirtualFile = ScratchRootType.getInstance().createScratchFile(
project,
name,
KotlinLanguage.INSTANCE,
text,
ScratchFileService.Option.create_if_missing
) ?: error("Couldn't create scratch file")
myFixture.openFileInEditor(scratchVirtualFile)
ScriptConfigurationManager.updateScriptDependenciesSynchronously(myFixture.file)
val scratchFileEditor = getScratchEditorForSelectedFile(myManager, myFixture.file.virtualFile)
?: error("Couldn't find scratch file")
configureOptions(scratchFileEditor, text, myFixture.module)
return scratchFileEditor.scratchFile
}
protected fun configureWorksheetByText(name: String, text: String): ScratchFile {
val worksheetFile = myFixture.configureByText(name, text).virtualFile
ScriptConfigurationManager.updateScriptDependenciesSynchronously(myFixture.file)
val scratchFileEditor = getScratchEditorForSelectedFile(myManager, myFixture.file.virtualFile)
?: error("Couldn't find scratch panel")
// We want to check that correct module is selected automatically,
// that's why we set `module` to null so it wouldn't be changed
configureOptions(scratchFileEditor, text, null)
return scratchFileEditor.scratchFile
}
protected fun launchScratch() {
val action = RunScratchAction()
launchAction(action)
}
protected fun launchAction(action: AnAction) {
val e = getActionEvent(myFixture.file.virtualFile, action)
action.beforeActionPerformedUpdate(e)
Assert.assertTrue(e.presentation.isEnabled && e.presentation.isVisible)
action.actionPerformed(e)
}
protected fun waitUntilScratchFinishes(shouldStopRepl: Boolean = true) {
UIUtil.dispatchAllInvocationEvents()
val start = System.currentTimeMillis()
// wait until output is displayed in editor or for 1 minute
while (ScratchCompilationSupport.isAnyInProgress()) {
if ((System.currentTimeMillis() - start) > TIME_OUT) {
LOG.warn("Waiting timeout $TIME_OUT ms is exceed")
break
}
Thread.sleep(100)
}
if (shouldStopRepl) stopReplProcess()
UIUtil.dispatchAllInvocationEvents()
}
protected fun stopReplProcess() {
if (myFixture.file != null) {
val scratchFile = getScratchEditorForSelectedFile(myManager, myFixture.file.virtualFile)?.scratchFile
?: error("Couldn't find scratch panel")
scratchFile.replScratchExecutor?.stopAndWait()
}
UIUtil.dispatchAllInvocationEvents()
}
private fun getActionEvent(virtualFile: VirtualFile, action: AnAction): TestActionEvent {
val context = MapDataContext()
context.put(CommonDataKeys.VIRTUAL_FILE_ARRAY, arrayOf(virtualFile))
context.put(CommonDataKeys.PROJECT, project)
context.put(CommonDataKeys.EDITOR, myFixture.editor)
return TestActionEvent(context, action)
}
protected fun testScratchText(): String {
return File(testDataPath, "idea/scripting-support/testData/scratch/custom/test_scratch.kts").readText()
}
override fun getTestDataPath() = KotlinTestUtils.getHomeDirectory()
override fun getProjectDescriptor(): com.intellij.testFramework.LightProjectDescriptor {
val testName = getTestName(false)
return when {
testName.endsWith("WithKotlinTest") -> INSTANCE_WITH_KOTLIN_TEST
testName.endsWith("NoRuntime") -> INSTANCE_WITHOUT_RUNTIME
testName.endsWith("ScriptRuntime") -> INSTANCE_WITH_SCRIPT_RUNTIME
else -> KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE_FULL_JDK
}
}
override fun setUp() {
super.setUp()
VfsRootAccess.allowRootAccess(KotlinTestUtils.getHomeDirectory())
PluginTestCaseBase.addJdk(myFixture.projectDisposable) { PluginTestCaseBase.fullJdk() }
}
override fun tearDown() {
super.tearDown()
VfsRootAccess.disallowRootAccess(KotlinTestUtils.getHomeDirectory())
// (ScratchFileService.getInstance().scratchesMapping as PerFileMappingsEx<Language>).mappings.forEach { (file, _) ->
// runWriteAction { file.delete(this) }
// }
}
companion object {
private const val TIME_OUT = 60000 // 1 min
private val INSTANCE_WITH_KOTLIN_TEST = object : KotlinWithJdkAndRuntimeLightProjectDescriptor(
arrayListOf(
ForTestCompileRuntime.runtimeJarForTests(),
PathUtil.kotlinPathsForDistDirectory.kotlinTestPath
)
) {
override fun getSdk() = PluginTestCaseBase.fullJdk()
}
private val INSTANCE_WITHOUT_RUNTIME = object : KotlinLightProjectDescriptor() {
override fun getSdk() = PluginTestCaseBase.fullJdk()
}
private val INSTANCE_WITH_SCRIPT_RUNTIME = object : KotlinWithJdkAndRuntimeLightProjectDescriptor(
arrayListOf(
ForTestCompileRuntime.runtimeJarForTests(),
ForTestCompileRuntime.scriptRuntimeJarForTests()
)
) {
override fun getSdk() = PluginTestCaseBase.fullJdk()
}
fun configureOptions(
scratchFileEditor: KtScratchFileEditorWithPreview,
fileText: String,
module: Module?
) {
val scratchFile = scratchFileEditor.scratchFile
if (InTextDirectivesUtils.getPrefixedBoolean(fileText, "// INTERACTIVE_MODE: ") != true) {
scratchFile.saveOptions { copy(isInteractiveMode = false) }
}
if (InTextDirectivesUtils.getPrefixedBoolean(fileText, "// REPL_MODE: ") == true) {
scratchFile.saveOptions { copy(isRepl = true) }
}
if (module != null && !InTextDirectivesUtils.isDirectiveDefined(fileText, "// NO_MODULE")) {
scratchFile.setModule(module)
}
val isPreviewEnabled = InTextDirectivesUtils.getPrefixedBoolean(fileText, "// PREVIEW_ENABLED: ") == true
scratchFileEditor.setPreviewEnabled(isPreviewEnabled)
}
}
}
@@ -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.scratch
import com.intellij.codeInsight.daemon.LineMarkerInfo
import com.intellij.ide.scratch.ScratchFileService
import com.intellij.ide.scratch.ScratchRootType
import com.intellij.openapi.editor.Document
import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.util.io.FileUtil
import com.intellij.psi.PsiDocumentManager
import com.intellij.testFramework.ExpectedHighlightingData
import com.intellij.testFramework.FileEditorManagerTestCase
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.codeInsight.AbstractLineMarkersTest
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
import org.jetbrains.kotlin.idea.scratch.AbstractScratchRunActionTest.Companion.configureOptions
import org.jetbrains.kotlin.psi.KtFile
import java.io.File
abstract class AbstractScratchLineMarkersTest : FileEditorManagerTestCase() {
fun doScratchTest(path: String) {
val fileText = FileUtil.loadFile(File(path))
val scratchVirtualFile = ScratchRootType.getInstance().createScratchFile(
project,
"scratch.kts",
KotlinLanguage.INSTANCE,
fileText,
ScratchFileService.Option.create_if_missing
) ?: error("Couldn't create scratch file")
myFixture.openFileInEditor(scratchVirtualFile)
ScriptConfigurationManager.updateScriptDependenciesSynchronously(myFixture.file)
val scratchFileEditor = getScratchEditorForSelectedFile(FileEditorManager.getInstance(project), myFixture.file.virtualFile)
?: error("Couldn't find scratch panel")
configureOptions(scratchFileEditor, fileText, null)
val project = myFixture.project
val document = myFixture.editor.document
val data = ExpectedHighlightingData(document, false, false, false)
data.init()
PsiDocumentManager.getInstance(project).commitAllDocuments()
val markers = doAndCheckHighlighting(document, data, File(path))
AbstractLineMarkersTest.assertNavigationElements(myFixture.project, myFixture.file as KtFile, markers)
}
override fun tearDown() {
super.tearDown()
// (ScratchFileService.getInstance().scratchesMapping as PerFileMappingsEx<Language>).mappings.forEach { file, _ ->
// runWriteAction { file.delete(this) }
// }
}
private fun doAndCheckHighlighting(
documentToAnalyze: Document, expectedHighlighting: ExpectedHighlightingData, expectedFile: File
): List<LineMarkerInfo<*>> {
myFixture.doHighlighting()
return AbstractLineMarkersTest.checkHighlighting(myFixture.file, documentToAnalyze, expectedHighlighting, expectedFile)
}
}