Scripting: add test for loading configuration for gradle scripts

This commit is contained in:
Natalia Selezneva
2019-12-10 09:13:44 +03:00
parent 424a2c72b2
commit d68c3584f2
12 changed files with 261 additions and 47 deletions
@@ -52,6 +52,10 @@ internal class ScriptChangesNotifier(
val listener = getListener(project, file) ?: return val listener = getListener(project, file) ?: return
if (ApplicationManager.getApplication().isUnitTestMode) {
listener.documentChanged(file, updater)
}
scriptsQueue.cancelAllRequests() scriptsQueue.cancelAllRequests()
scriptsQueue.addRequest( scriptsQueue.addRequest(
{ listener.documentChanged(file, updater) }, { listener.documentChanged(file, updater) },
@@ -53,4 +53,6 @@ class TestingBackgroundExecutor internal constructor(
return copy.isNotEmpty() return copy.isNotEmpty()
} }
fun noBackgroundTasks(): Boolean = backgroundQueue.isEmpty()
} }
@@ -8,15 +8,15 @@ package org.jetbrains.kotlin.idea.scripting.gradle
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.idea.core.script.configuration.cache.ScriptConfigurationCacheScope
import com.intellij.util.io.systemIndependentPath import com.intellij.util.io.systemIndependentPath
import org.jetbrains.kotlin.idea.core.script.configuration.cache.ScriptConfigurationCacheScope
import org.jetbrains.kotlin.idea.core.script.configuration.listener.ScriptChangeListener import org.jetbrains.kotlin.idea.core.script.configuration.listener.ScriptChangeListener
import org.jetbrains.kotlin.idea.core.script.configuration.listener.ScriptConfigurationUpdater import org.jetbrains.kotlin.idea.core.script.configuration.listener.ScriptConfigurationUpdater
import org.jetbrains.plugins.gradle.GradleManager import org.jetbrains.plugins.gradle.GradleManager
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
import org.jetbrains.plugins.gradle.util.GradleConstants import org.jetbrains.plugins.gradle.util.GradleConstants
class GradleScriptListener(project: Project) : ScriptChangeListener(project) { open class GradleScriptListener(project: Project) : ScriptChangeListener(project) {
override fun editorActivated(vFile: VirtualFile, updater: ScriptConfigurationUpdater) { override fun editorActivated(vFile: VirtualFile, updater: ScriptConfigurationUpdater) {
if (!isGradleKotlinScript(vFile)) return if (!isGradleKotlinScript(vFile)) return
@@ -0,0 +1,116 @@
/*
* 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.scripting.gradle
import com.intellij.openapi.application.ApplicationManager
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.idea.core.script.configuration.listener.ScriptChangeListener
import org.jetbrains.kotlin.idea.core.script.isScriptChangesNotifierDisabled
import org.jetbrains.kotlin.idea.script.AbstractScriptConfigurationLoadingTest
import org.jetbrains.kotlin.idea.script.addExtensionPointInTest
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.plugins.gradle.util.GradleConstants
import java.io.File
private const val outsidePlaceholder = "// OUTSIDE_SECTIONS"
private const val insidePlaceholder = "// INSIDE_SECTIONS"
class GradleScriptInputsWatcherTest : AbstractScriptConfigurationLoadingTest() {
private lateinit var testFiles: TestFiles
data class TestFiles(val buildKts: KtFile, val settings: KtFile, val prop: PsiFile)
override fun setUp() {
super.setUp()
ApplicationManager.getApplication().isScriptChangesNotifierDisabled = false
}
override fun setUpTestProject() {
addExtensionPointInTest(
ScriptChangeListener.LISTENER,
project,
TestGradleScriptListener(project),
testRootDisposable
)
val rootDir = "idea/testData/script/definition/loading/gradle/"
val settings: KtFile = addFileToProject(rootDir + GradleConstants.KOTLIN_DSL_SETTINGS_FILE_NAME)
val prop: PsiFile = addFileToProject(rootDir + "gradle.properties")
val buildGradleKts = File(rootDir).walkTopDown().find { it.name == GradleConstants.KOTLIN_DSL_SCRIPT_NAME }
?: error("Couldn't find main script")
configureScriptFile(rootDir, buildGradleKts)
val build = (myFile as? KtFile) ?: error("")
testFiles = TestFiles(build, settings, prop)
}
private inline fun <reified T : Any> addFileToProject(file: String): T {
createFileAndSyncDependencies(File(file))
return (myFile as? T) ?: error("Couldn't configure project by $file")
}
fun testSectionChange() {
assertAndLoadInitialConfiguration(testFiles.buildKts)
changeBuildKtsInsideSections()
assertConfigurationUpdateWasDone(testFiles.buildKts)
}
fun testOutsideSectionChange() {
assertAndLoadInitialConfiguration(testFiles.buildKts)
changeBuildKtsOutsideSections()
assertConfigurationUpToDate(testFiles.buildKts)
}
private fun assertConfigurationUpToDate(file: KtFile) {
scriptConfigurationManager.updater.ensureUpToDatedConfigurationSuggested(file)
assertNoBackgroundTasks()
assertNoLoading()
}
private fun assertConfigurationUpdateWasDone(file: KtFile) {
scriptConfigurationManager.updater.ensureUpToDatedConfigurationSuggested(file)
assertAndDoAllBackgroundTasks()
assertSingleLoading()
}
private fun changeBuildKtsInsideSections(text: String = "application") {
changeBuildKts(insidePlaceholder, text)
}
private fun changeBuildKtsOutsideSections() {
changeBuildKts(outsidePlaceholder, "compile(\"\")")
}
private fun changeSettingsKtsInsideSections() {
changeSettingsKts(insidePlaceholder, "mavenCentral()")
}
private fun changeSettingsKtsOutsideSections() {
changeSettingsKts(outsidePlaceholder, "include: 'aaa'")
}
private fun changeBuildKts(placeHolder: String, text: String) {
changeContents(testFiles.buildKts.text.replace(placeHolder, text), testFiles.buildKts)
testFiles = testFiles.copy(buildKts = myFile as KtFile)
}
private fun changeSettingsKts(placeHolder: String, text: String) {
changeContents(testFiles.settings.text.replace(placeHolder, text), testFiles.settings)
testFiles = testFiles.copy(settings = myFile as KtFile)
}
private fun changePropertiesFile() {
changeContents(testFiles.prop.text.replace(outsidePlaceholder.replace("//", "#"), "myProp = true"), testFiles.prop)
testFiles = testFiles.copy(prop = myFile)
}
}
@@ -0,0 +1,15 @@
/*
* 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.scripting.gradle
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
internal class TestGradleScriptListener(project: Project) : GradleScriptListener(project) {
override fun isApplicable(vFile: VirtualFile): Boolean {
return true
}
}
@@ -0,0 +1,7 @@
plugins {
// INSIDE_SECTIONS
}
dependencies {
// OUTSIDE_SECTIONS
}
@@ -0,0 +1 @@
# OUTSIDE_SECTIONS
@@ -0,0 +1,5 @@
pluginManagement {
// INSIDE_SECTIONS
}
// OUTSIDE_SECTIONS
@@ -0,0 +1,37 @@
package custom.scriptDefinition
import kotlin.script.dependencies.*
import kotlin.script.experimental.dependencies.*
import kotlin.script.templates.*
import java.io.File
import kotlin.script.experimental.location.*
class TestDependenciesResolver : AsyncDependenciesResolver {
suspend override fun resolveAsync(scriptContents: ScriptContents, environment: Environment): DependenciesResolver.ResolveResult {
val text = scriptContents.text as String
val result = when {
text.startsWith("#BAD:") -> DependenciesResolver.ResolveResult.Failure(
reports = listOf(ScriptReport(text))
)
else -> DependenciesResolver.ResolveResult.Success(
dependencies = ScriptDependencies(
classpath = listOf(environment["template-classes"] as File),
imports = listOf("x_" + text.replace(Regex("#IGNORE_IN_CONFIGURATION"), ""))
),
reports = listOf(ScriptReport(text))
)
}
javaClass.classLoader
.loadClass("org.jetbrains.kotlin.idea.script.AbstractScriptConfigurationLoadingTest")
.methods.single { it.name == "loadingScriptConfigurationCallback" }
.invoke(null)
return result
}
}
@ScriptExpectedLocations([ScriptExpectedLocation.Everywhere])
@ScriptTemplateDefinition(TestDependenciesResolver::class, scriptFilePattern = ".*\\.gradle\\.kts")
class Template
@@ -6,8 +6,10 @@
package org.jetbrains.kotlin.idea.script package org.jetbrains.kotlin.idea.script
import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.idea.core.script.IdeScriptReportSink import org.jetbrains.kotlin.idea.core.script.IdeScriptReportSink
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
import org.jetbrains.kotlin.idea.core.script.applySuggestedScriptConfiguration import org.jetbrains.kotlin.idea.core.script.applySuggestedScriptConfiguration
@@ -20,9 +22,6 @@ import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
abstract class AbstractScriptConfigurationLoadingTest : AbstractScriptConfigurationTest() { abstract class AbstractScriptConfigurationLoadingTest : AbstractScriptConfigurationTest() {
val ktFile: KtFile get() = myFile as KtFile
val virtualFile get() = myFile.virtualFile
lateinit var scriptConfigurationManager: ScriptConfigurationManager lateinit var scriptConfigurationManager: ScriptConfigurationManager
companion object { companion object {
@@ -41,14 +40,6 @@ abstract class AbstractScriptConfigurationLoadingTest : AbstractScriptConfigurat
super.setUp() super.setUp()
testScriptConfigurationNotification = true testScriptConfigurationNotification = true
addExtensionPointInTest(
DefaultScriptConfigurationManagerExtensions.LOADER,
project,
FileContentsDependentConfigurationLoader(project),
testRootDisposable
)
configureScriptFile("idea/testData/script/definition/loading/async/")
scriptConfigurationManager = ServiceManager.getService(project, ScriptConfigurationManager::class.java) scriptConfigurationManager = ServiceManager.getService(project, ScriptConfigurationManager::class.java)
} }
@@ -59,6 +50,17 @@ abstract class AbstractScriptConfigurationLoadingTest : AbstractScriptConfigurat
currentLoadingScriptConfigurationCallback = null currentLoadingScriptConfigurationCallback = null
} }
override fun setUpTestProject() {
addExtensionPointInTest(
DefaultScriptConfigurationManagerExtensions.LOADER,
project,
FileContentsDependentConfigurationLoader(project),
testRootDisposable
)
configureScriptFile("idea/testData/script/definition/loading/async/")
}
override fun loadScriptConfigurationSynchronously(script: VirtualFile) { override fun loadScriptConfigurationSynchronously(script: VirtualFile) {
// do nothings // do nothings
} }
@@ -80,8 +82,12 @@ abstract class AbstractScriptConfigurationLoadingTest : AbstractScriptConfigurat
} }
} }
protected fun assertAppliedConfiguration(contents: String) { protected fun assertNoBackgroundTasks() {
val secondConfiguration = scriptConfigurationManager.getConfiguration(ktFile)!! assertTrue(scriptConfigurationManager.testingBackgroundExecutor.noBackgroundTasks())
}
protected fun assertAppliedConfiguration(contents: String, file: KtFile = myFile as KtFile) {
val secondConfiguration = scriptConfigurationManager.getConfiguration(file)!!
assertEquals( assertEquals(
contents, contents,
secondConfiguration.defaultImports.single().let { secondConfiguration.defaultImports.single().let {
@@ -91,39 +97,35 @@ abstract class AbstractScriptConfigurationLoadingTest : AbstractScriptConfigurat
) )
} }
protected fun makeChanges(contents: String) { protected fun makeChanges(contents: String, file: KtFile = myFile as KtFile) {
changeContents(contents) changeContents(contents)
scriptConfigurationManager.updater.ensureUpToDatedConfigurationSuggested(ktFile) scriptConfigurationManager.updater.ensureUpToDatedConfigurationSuggested(file)
} }
protected fun changeContents(contents: String) { protected fun changeContents(contents: String, file: PsiFile = myFile) {
runWriteAction { runWriteAction {
val fileDocumentManager = FileDocumentManager.getInstance() VfsUtil.saveText(file.virtualFile, contents)
fileDocumentManager.reloadFiles(virtualFile) PsiDocumentManager.getInstance(project).commitAllDocuments()
val document = fileDocumentManager.getDocument(virtualFile)!! myFile = psiManager.findFile(file.virtualFile)
document.setText(contents)
fileDocumentManager.saveDocument(document)
psiManager.reloadFromDisk(myFile)
myFile = psiManager.findFile(virtualFile)
} }
} }
protected fun assertReports(expected: String) { protected fun assertReports(expected: String, file: KtFile = myFile as KtFile) {
val actual = IdeScriptReportSink.getReports(virtualFile).single().message val actual = IdeScriptReportSink.getReports(file.virtualFile).single().message
assertEquals(expected, actual) assertEquals(expected, actual)
} }
protected fun assertSuggestedConfiguration() { protected fun assertSuggestedConfiguration(file: KtFile = myFile as KtFile) {
assertTrue(virtualFile.hasSuggestedScriptConfiguration(project)) assertTrue(file.virtualFile.hasSuggestedScriptConfiguration(project))
} }
protected fun assertAndApplySuggestedConfiguration() { protected fun assertAndApplySuggestedConfiguration(file: KtFile = myFile as KtFile) {
assertTrue(virtualFile.applySuggestedScriptConfiguration(project)) assertTrue(file.virtualFile.applySuggestedScriptConfiguration(project))
} }
protected fun assertNoSuggestedConfiguration() { protected fun assertNoSuggestedConfiguration(file: KtFile = myFile as KtFile) {
assertFalse(virtualFile.applySuggestedScriptConfiguration(project)) assertFalse(file.virtualFile.applySuggestedScriptConfiguration(project))
} }
protected fun assertNoLoading() { protected fun assertNoLoading() {
@@ -136,12 +138,12 @@ abstract class AbstractScriptConfigurationLoadingTest : AbstractScriptConfigurat
occurredLoadings = 0 occurredLoadings = 0
} }
protected fun assertAndLoadInitialConfiguration() { protected fun assertAndLoadInitialConfiguration(file: KtFile = myFile as KtFile) {
assertNull(scriptConfigurationManager.getConfiguration(ktFile)) assertNull(scriptConfigurationManager.getConfiguration(file))
assertAndDoAllBackgroundTasks() assertAndDoAllBackgroundTasks()
assertSingleLoading() assertSingleLoading()
assertAppliedConfiguration("initial") assertAppliedConfiguration(file.text, file)
checkHighlighting() checkHighlighting(file)
} }
} }
@@ -19,6 +19,7 @@ import com.intellij.openapi.vfs.VirtualFile
import com.intellij.testFramework.PlatformTestCase import com.intellij.testFramework.PlatformTestCase
import com.intellij.testFramework.PsiTestUtil import com.intellij.testFramework.PsiTestUtil
import com.intellij.util.ui.UIUtil import com.intellij.util.ui.UIUtil
import org.jdom.Element
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
import org.jetbrains.kotlin.idea.completion.test.KotlinCompletionTestCase import org.jetbrains.kotlin.idea.completion.test.KotlinCompletionTestCase
import org.jetbrains.kotlin.idea.core.script.IdeScriptReportSink import org.jetbrains.kotlin.idea.core.script.IdeScriptReportSink
@@ -26,6 +27,7 @@ import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager.Companio
import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionContributor import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionContributor
import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionsManager import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionsManager
import org.jetbrains.kotlin.idea.core.script.isScriptChangesNotifierDisabled import org.jetbrains.kotlin.idea.core.script.isScriptChangesNotifierDisabled
import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings
import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingUtil import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingUtil
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.idea.util.application.runWriteAction
@@ -86,6 +88,10 @@ abstract class AbstractScriptConfigurationTest : KotlinCompletionTestCase() {
protected fun configureScriptFile(path: String) { protected fun configureScriptFile(path: String) {
val mainScriptFile = findMainScript(path) val mainScriptFile = findMainScript(path)
configureScriptFile(path, mainScriptFile)
}
protected fun configureScriptFile(path: String, mainScriptFile: File) {
val environment = createScriptEnvironment(mainScriptFile) val environment = createScriptEnvironment(mainScriptFile)
registerScriptTemplateProvider(environment) registerScriptTemplateProvider(environment)
@@ -137,9 +143,23 @@ abstract class AbstractScriptConfigurationTest : KotlinCompletionTestCase() {
private val oldScripClasspath: String? = System.getProperty("kotlin.script.classpath") private val oldScripClasspath: String? = System.getProperty("kotlin.script.classpath")
private var settings: Element? = null
override fun setUp() { override fun setUp() {
super.setUp() super.setUp()
ApplicationManager.getApplication().isScriptChangesNotifierDisabled = true ApplicationManager.getApplication().isScriptChangesNotifierDisabled = true
settings = KotlinScriptingSettings.getInstance(project).state
ScriptDefinitionsManager.getInstance(project).getAllDefinitions().forEach {
KotlinScriptingSettings.getInstance(project).setEnabled(it, false)
}
setUpTestProject()
}
open fun setUpTestProject() {
} }
override fun tearDown() { override fun tearDown() {
@@ -147,6 +167,10 @@ abstract class AbstractScriptConfigurationTest : KotlinCompletionTestCase() {
System.setProperty("kotlin.script.classpath", oldScripClasspath ?: "") System.setProperty("kotlin.script.classpath", oldScripClasspath ?: "")
settings?.let {
KotlinScriptingSettings.getInstance(project).loadState(it)
}
super.tearDown() super.tearDown()
} }
@@ -250,7 +274,7 @@ abstract class AbstractScriptConfigurationTest : KotlinCompletionTestCase() {
} }
} }
private fun createFileAndSyncDependencies(scriptFile: File) { protected fun createFileAndSyncDependencies(scriptFile: File) {
var script: VirtualFile? = null var script: VirtualFile? = null
if (module != null) { if (module != null) {
script = module.moduleFile?.parent?.findChild(scriptFile.name) script = module.moduleFile?.parent?.findChild(scriptFile.name)
@@ -278,14 +302,13 @@ abstract class AbstractScriptConfigurationTest : KotlinCompletionTestCase() {
checkHighlighting() checkHighlighting()
} }
protected fun checkHighlighting() { protected fun checkHighlighting(file: KtFile = myFile as KtFile) {
val ktFile = myFile as KtFile val reports = IdeScriptReportSink.getReports(file)
val reports = IdeScriptReportSink.getReports(ktFile)
val isFatalErrorPresent = reports.any { it.severity == ScriptDiagnostic.Severity.FATAL } val isFatalErrorPresent = reports.any { it.severity == ScriptDiagnostic.Severity.FATAL }
assert(isFatalErrorPresent || KotlinHighlightingUtil.shouldHighlight(myFile)) { assert(isFatalErrorPresent || KotlinHighlightingUtil.shouldHighlight(file)) {
"Highlighting is switched off for ${myFile.virtualFile.path}\n" + "Highlighting is switched off for ${file.virtualFile.path}\n" +
"reports=$reports\n" + "reports=$reports\n" +
"scriptDefinition=${ktFile.findScriptDefinition()}" "scriptDefinition=${file.findScriptDefinition()}"
} }
} }
@@ -5,6 +5,8 @@
package org.jetbrains.kotlin.idea.script package org.jetbrains.kotlin.idea.script
import org.jetbrains.kotlin.psi.KtFile
class ScriptConfigurationLoadingTest : AbstractScriptConfigurationLoadingTest() { class ScriptConfigurationLoadingTest : AbstractScriptConfigurationLoadingTest() {
fun testSimple() { fun testSimple() {
assertAndLoadInitialConfiguration() assertAndLoadInitialConfiguration()
@@ -158,10 +160,10 @@ class ScriptConfigurationLoadingTest : AbstractScriptConfigurationLoadingTest()
fun testLoadingForUsagesSearch() { fun testLoadingForUsagesSearch() {
assertAndLoadInitialConfiguration() assertAndLoadInitialConfiguration()
assertTrue(scriptConfigurationManager.updater.ensureConfigurationUpToDate(listOf(ktFile))) assertTrue(scriptConfigurationManager.updater.ensureConfigurationUpToDate(listOf(myFile as KtFile)))
changeContents("A") changeContents("A")
assertFalse(scriptConfigurationManager.updater.ensureConfigurationUpToDate(listOf(ktFile))) assertFalse(scriptConfigurationManager.updater.ensureConfigurationUpToDate(listOf(myFile as KtFile)))
} }
fun testReportsOnAutoApply() { fun testReportsOnAutoApply() {