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
if (ApplicationManager.getApplication().isUnitTestMode) {
listener.documentChanged(file, updater)
}
scriptsQueue.cancelAllRequests()
scriptsQueue.addRequest(
{ listener.documentChanged(file, updater) },
@@ -53,4 +53,6 @@ class TestingBackgroundExecutor internal constructor(
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.project.Project
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.idea.core.script.configuration.cache.ScriptConfigurationCacheScope
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.ScriptConfigurationUpdater
import org.jetbrains.plugins.gradle.GradleManager
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
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) {
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
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.psi.PsiDocumentManager
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.idea.core.script.IdeScriptReportSink
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
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
abstract class AbstractScriptConfigurationLoadingTest : AbstractScriptConfigurationTest() {
val ktFile: KtFile get() = myFile as KtFile
val virtualFile get() = myFile.virtualFile
lateinit var scriptConfigurationManager: ScriptConfigurationManager
companion object {
@@ -41,14 +40,6 @@ abstract class AbstractScriptConfigurationLoadingTest : AbstractScriptConfigurat
super.setUp()
testScriptConfigurationNotification = true
addExtensionPointInTest(
DefaultScriptConfigurationManagerExtensions.LOADER,
project,
FileContentsDependentConfigurationLoader(project),
testRootDisposable
)
configureScriptFile("idea/testData/script/definition/loading/async/")
scriptConfigurationManager = ServiceManager.getService(project, ScriptConfigurationManager::class.java)
}
@@ -59,6 +50,17 @@ abstract class AbstractScriptConfigurationLoadingTest : AbstractScriptConfigurat
currentLoadingScriptConfigurationCallback = null
}
override fun setUpTestProject() {
addExtensionPointInTest(
DefaultScriptConfigurationManagerExtensions.LOADER,
project,
FileContentsDependentConfigurationLoader(project),
testRootDisposable
)
configureScriptFile("idea/testData/script/definition/loading/async/")
}
override fun loadScriptConfigurationSynchronously(script: VirtualFile) {
// do nothings
}
@@ -80,8 +82,12 @@ abstract class AbstractScriptConfigurationLoadingTest : AbstractScriptConfigurat
}
}
protected fun assertAppliedConfiguration(contents: String) {
val secondConfiguration = scriptConfigurationManager.getConfiguration(ktFile)!!
protected fun assertNoBackgroundTasks() {
assertTrue(scriptConfigurationManager.testingBackgroundExecutor.noBackgroundTasks())
}
protected fun assertAppliedConfiguration(contents: String, file: KtFile = myFile as KtFile) {
val secondConfiguration = scriptConfigurationManager.getConfiguration(file)!!
assertEquals(
contents,
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)
scriptConfigurationManager.updater.ensureUpToDatedConfigurationSuggested(ktFile)
scriptConfigurationManager.updater.ensureUpToDatedConfigurationSuggested(file)
}
protected fun changeContents(contents: String) {
protected fun changeContents(contents: String, file: PsiFile = myFile) {
runWriteAction {
val fileDocumentManager = FileDocumentManager.getInstance()
fileDocumentManager.reloadFiles(virtualFile)
val document = fileDocumentManager.getDocument(virtualFile)!!
document.setText(contents)
fileDocumentManager.saveDocument(document)
psiManager.reloadFromDisk(myFile)
myFile = psiManager.findFile(virtualFile)
VfsUtil.saveText(file.virtualFile, contents)
PsiDocumentManager.getInstance(project).commitAllDocuments()
myFile = psiManager.findFile(file.virtualFile)
}
}
protected fun assertReports(expected: String) {
val actual = IdeScriptReportSink.getReports(virtualFile).single().message
protected fun assertReports(expected: String, file: KtFile = myFile as KtFile) {
val actual = IdeScriptReportSink.getReports(file.virtualFile).single().message
assertEquals(expected, actual)
}
protected fun assertSuggestedConfiguration() {
assertTrue(virtualFile.hasSuggestedScriptConfiguration(project))
protected fun assertSuggestedConfiguration(file: KtFile = myFile as KtFile) {
assertTrue(file.virtualFile.hasSuggestedScriptConfiguration(project))
}
protected fun assertAndApplySuggestedConfiguration() {
assertTrue(virtualFile.applySuggestedScriptConfiguration(project))
protected fun assertAndApplySuggestedConfiguration(file: KtFile = myFile as KtFile) {
assertTrue(file.virtualFile.applySuggestedScriptConfiguration(project))
}
protected fun assertNoSuggestedConfiguration() {
assertFalse(virtualFile.applySuggestedScriptConfiguration(project))
protected fun assertNoSuggestedConfiguration(file: KtFile = myFile as KtFile) {
assertFalse(file.virtualFile.applySuggestedScriptConfiguration(project))
}
protected fun assertNoLoading() {
@@ -136,12 +138,12 @@ abstract class AbstractScriptConfigurationLoadingTest : AbstractScriptConfigurat
occurredLoadings = 0
}
protected fun assertAndLoadInitialConfiguration() {
assertNull(scriptConfigurationManager.getConfiguration(ktFile))
protected fun assertAndLoadInitialConfiguration(file: KtFile = myFile as KtFile) {
assertNull(scriptConfigurationManager.getConfiguration(file))
assertAndDoAllBackgroundTasks()
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.PsiTestUtil
import com.intellij.util.ui.UIUtil
import org.jdom.Element
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
import org.jetbrains.kotlin.idea.completion.test.KotlinCompletionTestCase
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.ScriptDefinitionsManager
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.test.PluginTestCaseBase
import org.jetbrains.kotlin.idea.util.application.runWriteAction
@@ -86,6 +88,10 @@ abstract class AbstractScriptConfigurationTest : KotlinCompletionTestCase() {
protected fun configureScriptFile(path: String) {
val mainScriptFile = findMainScript(path)
configureScriptFile(path, mainScriptFile)
}
protected fun configureScriptFile(path: String, mainScriptFile: File) {
val environment = createScriptEnvironment(mainScriptFile)
registerScriptTemplateProvider(environment)
@@ -137,9 +143,23 @@ abstract class AbstractScriptConfigurationTest : KotlinCompletionTestCase() {
private val oldScripClasspath: String? = System.getProperty("kotlin.script.classpath")
private var settings: Element? = null
override fun setUp() {
super.setUp()
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() {
@@ -147,6 +167,10 @@ abstract class AbstractScriptConfigurationTest : KotlinCompletionTestCase() {
System.setProperty("kotlin.script.classpath", oldScripClasspath ?: "")
settings?.let {
KotlinScriptingSettings.getInstance(project).loadState(it)
}
super.tearDown()
}
@@ -250,7 +274,7 @@ abstract class AbstractScriptConfigurationTest : KotlinCompletionTestCase() {
}
}
private fun createFileAndSyncDependencies(scriptFile: File) {
protected fun createFileAndSyncDependencies(scriptFile: File) {
var script: VirtualFile? = null
if (module != null) {
script = module.moduleFile?.parent?.findChild(scriptFile.name)
@@ -278,14 +302,13 @@ abstract class AbstractScriptConfigurationTest : KotlinCompletionTestCase() {
checkHighlighting()
}
protected fun checkHighlighting() {
val ktFile = myFile as KtFile
val reports = IdeScriptReportSink.getReports(ktFile)
protected fun checkHighlighting(file: KtFile = myFile as KtFile) {
val reports = IdeScriptReportSink.getReports(file)
val isFatalErrorPresent = reports.any { it.severity == ScriptDiagnostic.Severity.FATAL }
assert(isFatalErrorPresent || KotlinHighlightingUtil.shouldHighlight(myFile)) {
"Highlighting is switched off for ${myFile.virtualFile.path}\n" +
assert(isFatalErrorPresent || KotlinHighlightingUtil.shouldHighlight(file)) {
"Highlighting is switched off for ${file.virtualFile.path}\n" +
"reports=$reports\n" +
"scriptDefinition=${ktFile.findScriptDefinition()}"
"scriptDefinition=${file.findScriptDefinition()}"
}
}
@@ -5,6 +5,8 @@
package org.jetbrains.kotlin.idea.script
import org.jetbrains.kotlin.psi.KtFile
class ScriptConfigurationLoadingTest : AbstractScriptConfigurationLoadingTest() {
fun testSimple() {
assertAndLoadInitialConfiguration()
@@ -158,10 +160,10 @@ class ScriptConfigurationLoadingTest : AbstractScriptConfigurationLoadingTest()
fun testLoadingForUsagesSearch() {
assertAndLoadInitialConfiguration()
assertTrue(scriptConfigurationManager.updater.ensureConfigurationUpToDate(listOf(ktFile)))
assertTrue(scriptConfigurationManager.updater.ensureConfigurationUpToDate(listOf(myFile as KtFile)))
changeContents("A")
assertFalse(scriptConfigurationManager.updater.ensureConfigurationUpToDate(listOf(ktFile)))
assertFalse(scriptConfigurationManager.updater.ensureConfigurationUpToDate(listOf(myFile as KtFile)))
}
fun testReportsOnAutoApply() {