mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[kotlin] Implement 'AddKotlinTestQuickFixProvider' alongside the 'AddKotlinCoroutinesQuickFixProvider'
^KTIJ-23814 Verification Pending ^KTIJ-31125 Verification Pending GitOrigin-RevId: a79570cebf7c77dc5904177c4e034e589ae0a554
This commit is contained in:
committed by
intellij-monorepo-bot
parent
5cf2c1c66b
commit
3c9dfaea46
@@ -1750,6 +1750,7 @@ put.expressions.on.separate.lines=Put expressions on separate lines
|
||||
put.calls.on.separate.lines=Put calls on separate lines
|
||||
add.kotlin.coroutines=Add Kotlin coroutines library
|
||||
add.kotlin.coroutines.description=Add Kotlin Coroutines Library
|
||||
add.0.library=Add ''{0}'' library
|
||||
demorgan.law=DeMorgan Law
|
||||
replace.with.end.of.line.comment=Replace with end of line comment
|
||||
convert.collection.constructor.to.function=Convert Collection constructor to function
|
||||
|
||||
+1
@@ -53,5 +53,6 @@
|
||||
<orderEntry type="module" module-name="kotlin.base.facet" />
|
||||
<orderEntry type="module" module-name="intellij.platform.core" />
|
||||
<orderEntry type="module" module-name="kotlin.base.analysis" />
|
||||
<orderEntry type="module" module-name="kotlin.base.indices" />
|
||||
</component>
|
||||
</module>
|
||||
+4
@@ -334,6 +334,10 @@
|
||||
|
||||
<codeInsight.unresolvedReferenceQuickFixProvider
|
||||
implementation="org.jetbrains.kotlin.idea.codeInsight.inspections.shared.libraries.AddKotlinCoroutinesQuickFixProvider"/>
|
||||
|
||||
<codeInsight.unresolvedReferenceQuickFixProvider
|
||||
implementation="org.jetbrains.kotlin.idea.codeInsight.inspections.shared.libraries.AddKotlinTestLibraryQuickFixProvider"/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.codeInsight.inspections.shared.InfixCallToOrdinaryInspection"
|
||||
groupPath="Kotlin"
|
||||
groupBundle="messages.KotlinBundle" groupKey="group.names.code.migration"
|
||||
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.idea.codeInsight.inspections.shared.libraries
|
||||
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.impl.scopes.ModulesScope
|
||||
import com.intellij.psi.JavaPsiFacade
|
||||
|
||||
internal class AddKotlinCoroutinesQuickFixProvider : SimpleAddKotlinLibraryQuickFixProvider(
|
||||
libraryGroupId = "org.jetbrains.kotlinx",
|
||||
libraryArtifactId = "kotlinx-coroutines-core",
|
||||
namesToCheck = setOf("runBlocking", "CoroutineScope")
|
||||
) {
|
||||
override fun hasLibrary(module: Module): Boolean {
|
||||
val scope = ModulesScope.moduleWithDependenciesAndLibrariesScope(module)
|
||||
return JavaPsiFacade.getInstance(module.project).findClasses("kotlinx.coroutines.CoroutineScope", scope).isNotEmpty()
|
||||
}
|
||||
}
|
||||
+10
-3
@@ -4,6 +4,9 @@ package org.jetbrains.kotlin.idea.codeInsight.inspections.shared.libraries
|
||||
import com.intellij.codeInsight.intention.HighPriorityAction
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.codeInspection.util.IntentionName
|
||||
import com.intellij.openapi.application.Application
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.writeAction
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.project.Project
|
||||
@@ -21,18 +24,22 @@ internal class AddKotlinLibraryQuickFix(
|
||||
) : IntentionAction, HighPriorityAction {
|
||||
override fun getText(): String = quickFixText
|
||||
override fun getFamilyName(): String = quickFixText
|
||||
override fun startInWriteAction(): Boolean = true
|
||||
override fun startInWriteAction(): Boolean = false
|
||||
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile?): Boolean {
|
||||
val module = file?.module ?: return false
|
||||
return dependencyManager.isApplicable(module) && !dependencyManager.isProjectSyncPendingOrInProgress()
|
||||
}
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: PsiFile?) {
|
||||
if (editor == null || file == null) return
|
||||
if (editor == null && !ApplicationManager.getApplication().isHeadlessEnvironment) return
|
||||
if (file == null) return
|
||||
val psiFile = file.originalFile
|
||||
val module = psiFile.module ?: return
|
||||
|
||||
dependencyManager.addDependency(module, libraryDescriptor)
|
||||
ApplicationManager.getApplication().runWriteAction {
|
||||
dependencyManager.addDependency(module, libraryDescriptor)
|
||||
}
|
||||
|
||||
dependencyManager.startProjectSync()
|
||||
|
||||
val buildScriptFile = dependencyManager.getBuildScriptFile(module)
|
||||
|
||||
+77
-25
@@ -3,57 +3,76 @@ package org.jetbrains.kotlin.idea.codeInsight.inspections.shared.libraries
|
||||
|
||||
import com.intellij.codeInsight.daemon.QuickFixActionRegistrar
|
||||
import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider
|
||||
import com.intellij.codeInspection.util.IntentionName
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.impl.scopes.ModulesScope
|
||||
import com.intellij.openapi.roots.DependencyScope
|
||||
import com.intellij.openapi.roots.ExternalLibraryDescriptor
|
||||
import com.intellij.openapi.roots.ProjectFileIndex
|
||||
import com.intellij.psi.JavaPsiFacade
|
||||
import com.intellij.psi.PsiReference
|
||||
import org.jetbrains.kotlin.config.toKotlinVersion
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.languageVersionSettings
|
||||
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.base.util.module
|
||||
import org.jetbrains.kotlin.idea.configuration.KotlinBuildSystemDependencyManager
|
||||
import org.jetbrains.kotlin.idea.configuration.KotlinLibraryVersionProvider
|
||||
import org.jetbrains.kotlin.idea.configuration.isProjectSyncPendingOrInProgress
|
||||
import org.jetbrains.kotlin.idea.configuration.withScope
|
||||
import org.jetbrains.kotlin.idea.codeInsight.inspections.shared.libraries.AddKotlinLibraryQuickFixProvider.LibraryAvailabilityTester
|
||||
import org.jetbrains.kotlin.idea.codeInsight.inspections.shared.libraries.AddKotlinLibraryQuickFixProvider.LibraryDescriptorProvider
|
||||
import org.jetbrains.kotlin.idea.codeInsight.inspections.shared.libraries.AddKotlinLibraryQuickFixProvider.LibraryReferenceTester
|
||||
import org.jetbrains.kotlin.idea.configuration.*
|
||||
import org.jetbrains.kotlin.idea.stubindex.KotlinFullClassNameIndex
|
||||
import org.jetbrains.kotlin.psi.KtQualifiedExpression
|
||||
import org.jetbrains.kotlin.psi.KtReferenceExpression
|
||||
|
||||
/**
|
||||
* A quick fix provider allowing for Kotlin libraries to be added when an unresolved element was detected.
|
||||
* [libraryGroupId] and [libraryArtifactId] are the maven coordinates that will be added by this quick-fix.
|
||||
*/
|
||||
abstract class AddKotlinLibraryQuickFixProvider(
|
||||
open class AddKotlinLibraryQuickFixProvider(
|
||||
private val libraryGroupId: String,
|
||||
private val libraryArtifactId: String
|
||||
private val libraryArtifactId: String,
|
||||
private val libraryDescriptorProvider: LibraryDescriptorProvider,
|
||||
private val libraryAvailabilityTester: LibraryAvailabilityTester,
|
||||
private val libraryReferenceTester: LibraryReferenceTester,
|
||||
@IntentionName
|
||||
private val quickFixText: String = KotlinBundle.message("add.0.library", "$libraryGroupId:$libraryArtifactId")
|
||||
) : UnresolvedReferenceQuickFixProvider<PsiReference>() {
|
||||
/**
|
||||
* Returns whether the library that will be added by this quick-fix is already present in the module.
|
||||
*/
|
||||
protected abstract fun hasLibrary(module: Module): Boolean
|
||||
|
||||
/**
|
||||
* Checks if the reference is a reference to a definition of the library belonging to this quick-fix.
|
||||
*/
|
||||
protected abstract fun isLibraryReference(ref: PsiReference): Boolean
|
||||
fun interface LibraryAvailabilityTester {
|
||||
/**
|
||||
* Returns whether the library that will be added by this quick-fix is already present in the module.
|
||||
*/
|
||||
fun isAvailable(module: Module): Boolean
|
||||
|
||||
private fun PsiReference.getKotlinVersion(): KotlinVersion {
|
||||
return element.languageVersionSettings.languageVersion.toKotlinVersion()
|
||||
companion object
|
||||
}
|
||||
|
||||
private fun getLibraryDescriptor(kotlinVersion: KotlinVersion): ExternalLibraryDescriptor? {
|
||||
val versionProvider = KotlinLibraryVersionProvider.EP_NAME.extensionList.firstOrNull() ?: return null
|
||||
return versionProvider.getVersion(libraryGroupId, libraryArtifactId, kotlinVersion)
|
||||
fun interface LibraryReferenceTester {
|
||||
/**
|
||||
* Checks if the reference is a reference to a definition of the library belonging to this quick-fix.
|
||||
*/
|
||||
fun isLibraryReference(ref: PsiReference): Boolean
|
||||
|
||||
companion object
|
||||
}
|
||||
|
||||
fun interface LibraryDescriptorProvider {
|
||||
fun getLibraryDescriptor(libraryGroupId: String, libraryArtifactId: String, psiReference: PsiReference): ExternalLibraryDescriptor?
|
||||
|
||||
companion object
|
||||
}
|
||||
|
||||
override fun registerFixes(ref: PsiReference, registrar: QuickFixActionRegistrar) {
|
||||
if (!isLibraryReference(ref)) return
|
||||
if (!libraryReferenceTester.isLibraryReference(ref)) return
|
||||
val module = ref.element.module ?: return
|
||||
|
||||
val extensionList = ref.element.project.extensionArea.getExtensionPoint(KotlinBuildSystemDependencyManager.EP_NAME).extensionList
|
||||
val dependencyManager = extensionList.firstOrNull { it.isApplicable(module) } ?: return
|
||||
if (dependencyManager.isProjectSyncPendingOrInProgress()) return
|
||||
|
||||
if (hasLibrary(module)) return
|
||||
val libraryVersionToUse = getLibraryDescriptor(ref.getKotlinVersion()) ?: return
|
||||
if (libraryAvailabilityTester.isAvailable(module)) return
|
||||
|
||||
val libraryDescriptor = libraryDescriptorProvider.getLibraryDescriptor(
|
||||
libraryGroupId, libraryArtifactId, ref
|
||||
) ?: return
|
||||
|
||||
val scope = if (ProjectFileIndex.getInstance(module.project).isInTestSourceContent(ref.element.containingFile.virtualFile)) {
|
||||
DependencyScope.TEST
|
||||
@@ -64,11 +83,44 @@ abstract class AddKotlinLibraryQuickFixProvider(
|
||||
registrar.register(
|
||||
AddKotlinLibraryQuickFix(
|
||||
dependencyManager = dependencyManager,
|
||||
libraryDescriptor = libraryVersionToUse.withScope(scope),
|
||||
quickFixText = KotlinBundle.message("add.kotlin.coroutines")
|
||||
libraryDescriptor = libraryDescriptor.withScope(scope),
|
||||
quickFixText = quickFixText
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getReferenceClass(): Class<PsiReference> = PsiReference::class.java
|
||||
}
|
||||
|
||||
/**
|
||||
* Will use the [KotlinLibraryVersionProvider] to look up the version
|
||||
*/
|
||||
fun LibraryDescriptorProvider.Companion.default() = LibraryDescriptorProvider { libraryGroupId, libraryArtifactId, psiRef ->
|
||||
val module = psiRef.element.module ?: return@LibraryDescriptorProvider null
|
||||
val libraryVersion = KotlinLibraryVersionProvider.EP_NAME.extensionList.firstNotNullOfOrNull { provider ->
|
||||
provider.getVersion(module, libraryGroupId, libraryArtifactId)
|
||||
}
|
||||
|
||||
ExternalLibraryDescriptor(libraryGroupId, libraryArtifactId, libraryVersion, libraryVersion, libraryVersion)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A simple [LibraryReferenceTester] that determines if an unresolved reference belongs to the library if they
|
||||
* are contained in the [names].
|
||||
* The names that are checked are references or function calls that are not part of a dot qualified expression.
|
||||
*/
|
||||
fun LibraryReferenceTester.Companion.knownNames(vararg names: String) = LibraryReferenceTester { ref ->
|
||||
val referenceExpression = ref.element as? KtReferenceExpression ?: return@LibraryReferenceTester false
|
||||
if (referenceExpression.parent is KtQualifiedExpression) return@LibraryReferenceTester false
|
||||
referenceExpression.text in names
|
||||
}
|
||||
|
||||
/**
|
||||
* Will check if the provided [fqn] is available as class in the given module
|
||||
*/
|
||||
fun LibraryAvailabilityTester.Companion.knownClassFqn(fqn: String) = LibraryAvailabilityTester { module ->
|
||||
val scope = ModulesScope.moduleWithDependenciesAndLibrariesScope(module)
|
||||
JavaPsiFacade.getInstance(module.project).findClasses(fqn, scope).isNotEmpty() ||
|
||||
KotlinFullClassNameIndex[fqn, module.project, scope].isNotEmpty()
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.idea.codeInsight.inspections.shared.libraries
|
||||
|
||||
import com.intellij.psi.PsiReference
|
||||
import org.jetbrains.kotlin.psi.KtQualifiedExpression
|
||||
import org.jetbrains.kotlin.psi.KtReferenceExpression
|
||||
|
||||
/**
|
||||
* A simple [AddKotlinLibraryQuickFixProvider] that determines if an unresolved reference belongs to the library if they
|
||||
* are contained in the [namesToCheck].
|
||||
* The names that are checked are references or function calls that are not part of a dot qualified expression.
|
||||
*/
|
||||
abstract class SimpleAddKotlinLibraryQuickFixProvider(
|
||||
libraryGroupId: String,
|
||||
libraryArtifactId: String,
|
||||
private val namesToCheck: Set<String>,
|
||||
) : AddKotlinLibraryQuickFixProvider(libraryGroupId, libraryArtifactId) {
|
||||
override fun isLibraryReference(ref: PsiReference): Boolean {
|
||||
val referenceExpression = ref.element as? KtReferenceExpression ?: return false
|
||||
if (!namesToCheck.contains(referenceExpression.text)) return false
|
||||
return referenceExpression.parent !is KtQualifiedExpression
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.idea.codeInsight.inspections.shared.libraries
|
||||
|
||||
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
|
||||
|
||||
internal class AddKotlinCoroutinesQuickFixProvider : AddKotlinLibraryQuickFixProvider(
|
||||
libraryGroupId = "org.jetbrains.kotlinx",
|
||||
libraryArtifactId = "kotlinx-coroutines-core",
|
||||
libraryDescriptorProvider = LibraryDescriptorProvider.default(),
|
||||
libraryAvailabilityTester = LibraryAvailabilityTester.knownClassFqn("kotlinx.coroutines.CoroutineScope"),
|
||||
libraryReferenceTester = LibraryReferenceTester.knownNames(
|
||||
"runBlocking", "CoroutineScope", "Dispatchers", "launch", "GlobalScope",
|
||||
"MainScope", "async", "await", "withContext", "cancel", "isActive", "Job",
|
||||
),
|
||||
quickFixText = KotlinBundle.message("add.kotlin.coroutines")
|
||||
)
|
||||
|
||||
|
||||
internal class AddKotlinTestLibraryQuickFixProvider : AddKotlinLibraryQuickFixProvider(
|
||||
libraryGroupId = "org.jetbrains.kotlin",
|
||||
libraryArtifactId = "kotlin-test",
|
||||
libraryDescriptorProvider = LibraryDescriptorProvider.default(),
|
||||
libraryAvailabilityTester = LibraryAvailabilityTester.knownClassFqn("kotlin.test.Asserter"),
|
||||
libraryReferenceTester = LibraryReferenceTester.knownNames("Test", "assertEquals", "assertTrue", "assertFalse", "assertFailsWith"),
|
||||
)
|
||||
+1
-1
@@ -153,7 +153,7 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator {
|
||||
}
|
||||
|
||||
private fun Project.isGradleSyncPending(module: Module): Boolean {
|
||||
return KotlinProjectConfigurationService.getInstance(this).isSyncPending(module)
|
||||
return KotlinProjectConfigurationService.getInstance(this).isSyncDesired(module)
|
||||
}
|
||||
|
||||
private fun Project.isGradleSyncInProgress(): Boolean {
|
||||
|
||||
@@ -41,6 +41,10 @@
|
||||
<kotlinBuildSystemFacade implementation="org.jetbrains.kotlin.idea.gradleJava.KotlinGradleBuildSystemFacade"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||
<libraryVersionProvider implementation="org.jetbrains.kotlin.idea.gradleJava.KotlinGradlePluginLibraryVersionProvider"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
|
||||
|
||||
<frameworkSupport implementation="org.jetbrains.kotlin.idea.gradleJava.configuration.GradleKotlinMPPSourceSetsFrameworkSupportProvider"/>
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.idea.gradleJava
|
||||
|
||||
import com.intellij.openapi.module.Module
|
||||
import org.jetbrains.kotlin.idea.configuration.KotlinLibraryVersionProvider
|
||||
|
||||
/**
|
||||
* Returns the modules 'Kotlin Gradle Plugin version' as the version for libraries
|
||||
* which originate from the Kotlin monorepo. Libraries (such as the kotlin stdlib, kotlin-test, ...) are expected
|
||||
* to have the same version as the Kotlin Gradle Plugin.
|
||||
*/
|
||||
class KotlinGradlePluginLibraryVersionProvider : KotlinLibraryVersionProvider {
|
||||
companion object {
|
||||
const val STDLIB_GROUP_ID = "org.jetbrains.kotlin"
|
||||
}
|
||||
|
||||
override fun getVersion(module: Module, groupId: String, artifactId: String): String? {
|
||||
if (groupId != STDLIB_GROUP_ID) return null
|
||||
return module.kotlinGradlePluginVersion?.versionString
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -14,6 +14,7 @@ import com.intellij.psi.util.childrenOfType
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.idea.base.codeInsight.CliArgumentStringBuilder.buildArgumentString
|
||||
import org.jetbrains.kotlin.idea.base.codeInsight.CliArgumentStringBuilder.replaceLanguageFeature
|
||||
import org.jetbrains.kotlin.idea.base.facet.isMultiPlatformModule
|
||||
import org.jetbrains.kotlin.idea.base.util.module
|
||||
import org.jetbrains.kotlin.idea.compiler.configuration.IdeKotlinVersion
|
||||
import org.jetbrains.kotlin.idea.configuration.*
|
||||
@@ -219,7 +220,7 @@ class KotlinBuildScriptManipulator(
|
||||
libraryDescriptor.libraryGroupId,
|
||||
libraryDescriptor.libraryArtifactId,
|
||||
libraryDescriptor.preferredVersion ?: libraryDescriptor.maxVersion ?: libraryDescriptor.minVersion,
|
||||
scope.toGradleCompileScope(scriptFile.module?.buildSystemType == BuildSystemType.AndroidGradle)
|
||||
scope.toGradleCompileScope(targetModule)
|
||||
)
|
||||
|
||||
if (targetModule != null && usesNewMultiplatform()) {
|
||||
|
||||
+65
-27
@@ -2,29 +2,62 @@
|
||||
package org.jetbrains.kotlin.idea.codeInsight.gradle
|
||||
|
||||
import com.intellij.codeInsight.daemon.quickFix.ActionHint
|
||||
import com.intellij.openapi.application.runReadAction
|
||||
import com.intellij.openapi.application.*
|
||||
import com.intellij.openapi.externalSystem.autoimport.AutoImportProjectTracker
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.testFramework.IndexingTestUtil
|
||||
import com.intellij.testFramework.PlatformTestUtil
|
||||
import com.intellij.testFramework.UsefulTestCase
|
||||
import com.intellij.testFramework.runInEdtAndWait
|
||||
import com.intellij.testFramework.*
|
||||
import com.intellij.testFramework.common.timeoutRunBlocking
|
||||
import com.intellij.testFramework.utils.vfs.refreshAndGetVirtualDirectory
|
||||
import kotlinx.coroutines.*
|
||||
import org.jetbrains.kotlin.idea.configuration.KotlinProjectConfigurationService
|
||||
import org.jetbrains.kotlin.idea.core.util.toPsiFile
|
||||
import org.jetbrains.kotlin.idea.test.DirectiveBasedActionUtils
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import kotlin.io.path.isRegularFile
|
||||
import kotlin.io.path.pathString
|
||||
import kotlin.io.path.readText
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.*
|
||||
import kotlin.streams.asSequence
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
|
||||
abstract class AbstractGradleMultiFileQuickFixTest : MultiplePluginVersionGradleImportingCodeInsightTestCase() {
|
||||
override fun testDataDirName() = "fixes"
|
||||
final override fun testDataDirectory(): File = super.testDataDirectory().resolve("before")
|
||||
|
||||
open val afterDirectory get() = testDataDirectory().parentFile.resolve("after")
|
||||
open val afterTestDataDirectory get() = testDataDirectory().parentFile.resolve("after")
|
||||
|
||||
private lateinit var afterDirectory: Path
|
||||
|
||||
@OptIn(ExperimentalPathApi::class)
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
|
||||
/* Setup 'after' directory: Ensure that we process it similar to the 'before', by also replacing test properties */
|
||||
afterDirectory = TemporaryDirectory.generateTemporaryPath("${testDataDirName()}.after")
|
||||
afterTestDataDirectory.toPath().copyToRecursively(afterDirectory, followLinks = true, copyAction = { source, target ->
|
||||
if (source.isDirectory()) {
|
||||
target.createDirectory()
|
||||
}
|
||||
|
||||
if (source.isRegularFile()) {
|
||||
target.writeText(configureKotlinVersionAndProperties(source.readText()))
|
||||
}
|
||||
|
||||
CopyActionResult.CONTINUE
|
||||
})
|
||||
|
||||
/* Some quick fix (e.g. AddKotlinLibraryQuickFix) will modify build scripts *and* re-sync the project */
|
||||
AutoImportProjectTracker.enableAutoReloadInTests(testRootDisposable)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalPathApi::class)
|
||||
override fun tearDown() {
|
||||
RunAll.runAll(
|
||||
{ afterDirectory.deleteRecursively() },
|
||||
{ super.tearDown() },
|
||||
)
|
||||
}
|
||||
|
||||
protected fun doMultiFileQuickFixTest(
|
||||
ignoreChangesInBuildScriptFiles: Boolean = true,
|
||||
@@ -49,43 +82,48 @@ abstract class AbstractGradleMultiFileQuickFixTest : MultiplePluginVersionGradle
|
||||
val actionHint = ActionHint.parse(ktFile, mainFileText)
|
||||
codeInsightTestFixture.configureFromExistingVirtualFile(ktFile.virtualFile)
|
||||
|
||||
runInEdtAndWait {
|
||||
timeoutRunBlocking(3.minutes) {
|
||||
val actions = codeInsightTestFixture.availableIntentions
|
||||
val action = actionHint.findAndCheck(actions) { "Test file: ${projectPath.relativize(mainFilePath).pathString}" }
|
||||
if (action != null) {
|
||||
action.invoke(myProject, null, ktFile)
|
||||
codeInsightTestFixture.launchAction(action)
|
||||
KotlinProjectConfigurationService.getInstance(project).awaitSyncFinished()
|
||||
|
||||
IndexingTestUtil.waitUntilIndexesAreReady(myProject)
|
||||
|
||||
val expected = afterDirectory.toPath().refreshAndGetVirtualDirectory()
|
||||
|
||||
val expected = afterDirectory.refreshAndGetVirtualDirectory()
|
||||
val projectVFile = projectPath.refreshAndGetVirtualDirectory()
|
||||
|
||||
UsefulTestCase.refreshRecursively(expected)
|
||||
UsefulTestCase.refreshRecursively(projectVFile)
|
||||
|
||||
PlatformTestUtil.assertDirectoriesEqual(
|
||||
expected,
|
||||
projectVFile,
|
||||
fun(vFile: VirtualFile): Boolean {
|
||||
if (vFile.parent == projectVFile) {
|
||||
when (vFile.name) {
|
||||
".gradle", "gradle", "build", "gradle.properties", "gradlew", "gradlew.bat", ".kotlin" -> return false
|
||||
withContext(Dispatchers.EDT) {
|
||||
PlatformTestUtil.assertDirectoriesEqual(
|
||||
expected,
|
||||
projectVFile,
|
||||
fun(vFile: VirtualFile): Boolean {
|
||||
if (vFile.parent == projectVFile) {
|
||||
when (vFile.name) {
|
||||
".gradle", "gradle", "build", "gradle.properties", "gradlew", "gradlew.bat", ".kotlin" -> return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ignoreChangesInBuildScriptFiles && ".gradle" in vFile.name) return false
|
||||
if (ignoreChangesInBuildScriptFiles && ".gradle" in vFile.name) return false
|
||||
|
||||
return additionalResultFileFilter(vFile)
|
||||
},
|
||||
)
|
||||
return additionalResultFileFilter(vFile)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
IndexingTestUtil.waitUntilIndexesAreReady(myProject)
|
||||
|
||||
codeInsightTestFixture.doHighlighting()
|
||||
DirectiveBasedActionUtils.checkAvailableActionsAreExpected(ktFile, action?.let { actions - it } ?: actions)
|
||||
DirectiveBasedActionUtils.checkForUnexpectedErrors(ktFile)
|
||||
|
||||
readActionBlocking {
|
||||
DirectiveBasedActionUtils.checkAvailableActionsAreExpected(ktFile, action?.let { actions - it } ?: actions)
|
||||
DirectiveBasedActionUtils.checkForUnexpectedErrors(ktFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+14
@@ -53,4 +53,18 @@ class GradleQuickFixTest : AbstractGradleMultiFileQuickFixTest() {
|
||||
@Test
|
||||
@PluginTargetVersions(pluginVersion = "1.5.31+")
|
||||
fun testCreateActualForGranularSourceSetTarget() = doMultiFileQuickFixTest()
|
||||
|
||||
@Test
|
||||
@PluginTargetVersions(pluginVersion = "2.0+")
|
||||
fun testAddKotlinTestLibraryJvm() = doMultiFileQuickFixTest(
|
||||
ignoreChangesInBuildScriptFiles = false,
|
||||
additionalResultFileFilter = { file -> file.name != "settings.gradle.kts" }
|
||||
)
|
||||
|
||||
@Test
|
||||
@PluginTargetVersions(pluginVersion = "1.5.31+")
|
||||
fun testAddKotlinTestLibraryKmp() = doMultiFileQuickFixTest(
|
||||
ignoreChangesInBuildScriptFiles = false,
|
||||
additionalResultFileFilter = { file -> file.name != "settings.gradle.kts" }
|
||||
)
|
||||
}
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
}
|
||||
dependencies {
|
||||
testImplementation(kotlin("test"))
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Add 'org.jetbrains.kotlin:kotlin-test' library" "true"
|
||||
// ERROR: Unresolved reference: Test
|
||||
|
||||
class MyTest {
|
||||
@Test
|
||||
fun testFoo() {
|
||||
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
{{kts_kotlin_plugin_repositories}}
|
||||
}
|
||||
|
||||
plugins {
|
||||
kotlin("jvm") version "{{kotlin_plugin_version}}"
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Add 'org.jetbrains.kotlin:kotlin-test' library" "true"
|
||||
// ERROR: Unresolved reference: Test
|
||||
|
||||
class MyTest {
|
||||
@Test<caret>
|
||||
fun testFoo() {
|
||||
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
plugins {
|
||||
kotlin("multiplatform")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvm()
|
||||
linuxX64()
|
||||
sourceSets {
|
||||
getByName("commonTest") {
|
||||
dependencies {
|
||||
implementation(kotlin("test"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
{{kts_kotlin_plugin_repositories}}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Add 'org.jetbrains.kotlin:kotlin-test' library" "true"
|
||||
import kotlin.test.Test
|
||||
|
||||
class MyTest {
|
||||
@Test
|
||||
fun testFoo() {
|
||||
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
plugins {
|
||||
kotlin("multiplatform")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvm()
|
||||
linuxX64()
|
||||
}
|
||||
|
||||
repositories {
|
||||
{{kts_kotlin_plugin_repositories}}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
{{kts_kotlin_plugin_repositories}}
|
||||
}
|
||||
|
||||
plugins {
|
||||
kotlin("multiplatform") version "{{kotlin_plugin_version}}"
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Add 'org.jetbrains.kotlin:kotlin-test' library" "true"
|
||||
import kotlin.test.Test
|
||||
|
||||
class MyTest {
|
||||
@Test<caret>
|
||||
fun testFoo() {
|
||||
|
||||
}
|
||||
}
|
||||
+10
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||
import org.jetbrains.kotlin.config.KotlinFacetSettingsProvider
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.idea.base.facet.isMultiPlatformModule
|
||||
import org.jetbrains.kotlin.idea.base.facet.platform.platform
|
||||
import org.jetbrains.kotlin.idea.base.indices.KotlinPackageIndexUtils
|
||||
import org.jetbrains.kotlin.idea.base.platforms.*
|
||||
@@ -103,6 +104,7 @@ const val KOTLIN_GROUP_ID = "org.jetbrains.kotlin"
|
||||
fun isRepositoryConfigured(repositoriesBlockText: String): Boolean =
|
||||
repositoriesBlockText.contains(MAVEN_CENTRAL) || repositoriesBlockText.contains(JCENTER)
|
||||
|
||||
@Deprecated("Use 'toGradleCompileScope(Module) instead")
|
||||
fun DependencyScope.toGradleCompileScope(isAndroidModule: Boolean) = when (this) {
|
||||
DependencyScope.COMPILE -> "implementation"
|
||||
// TODO: We should add testCompile or androidTestCompile
|
||||
@@ -112,6 +114,14 @@ fun DependencyScope.toGradleCompileScope(isAndroidModule: Boolean) = when (this)
|
||||
else -> "implementation"
|
||||
}
|
||||
|
||||
fun DependencyScope.toGradleCompileScope(targetModule: Module? = null) = when (this) {
|
||||
DependencyScope.COMPILE -> "implementation"
|
||||
DependencyScope.TEST -> if (targetModule?.isMultiPlatformModule == true) "implementation" else "testImplementation"
|
||||
DependencyScope.RUNTIME -> "runtime"
|
||||
DependencyScope.PROVIDED -> "implementation"
|
||||
else -> "implementation"
|
||||
}
|
||||
|
||||
fun RepositoryDescription.toGroovyRepositorySnippet() = "maven { url '$url' }"
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
package org.jetbrains.kotlin.idea.configuration
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.roots.ExternalLibraryDescriptor
|
||||
import com.intellij.openapi.module.Module
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
@@ -16,5 +16,5 @@ interface KotlinLibraryVersionProvider {
|
||||
* Returns a version of the library identified by the [groupId] and [artifactId] compatible with the [projectKotlinVersion].
|
||||
* Returns null if the [KotlinLibraryVersionProvider] does not manage the given library or no compatible version could be found.
|
||||
*/
|
||||
fun getVersion(groupId: String, artifactId: String, projectKotlinVersion: KotlinVersion): ExternalLibraryDescriptor?
|
||||
fun getVersion(module: Module, groupId: String, artifactId: String): String?
|
||||
}
|
||||
+116
-20
@@ -5,19 +5,19 @@ import com.intellij.model.SideEffectGuard
|
||||
import com.intellij.openapi.application.readAction
|
||||
import com.intellij.openapi.components.Service
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.externalSystem.autoimport.ExternalSystemProjectId
|
||||
import com.intellij.openapi.externalSystem.autoimport.ExternalSystemProjectTracker
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.platform.ide.progress.withBackgroundProgress
|
||||
import com.intellij.ui.EditorNotifications
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.*
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.kotlin.idea.projectConfiguration.KotlinProjectConfigurationBundle
|
||||
import org.jetbrains.kotlin.idea.statistics.KotlinJ2KOnboardingFUSCollector
|
||||
import org.jetbrains.kotlin.idea.util.isKotlinFileType
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
@Service(Service.Level.PROJECT)
|
||||
class KotlinProjectConfigurationService(private val project: Project, private val coroutineScope: CoroutineScope) {
|
||||
@@ -27,6 +27,35 @@ class KotlinProjectConfigurationService(private val project: Project, private va
|
||||
}
|
||||
}
|
||||
|
||||
private data class SyncState(
|
||||
val level: Level,
|
||||
|
||||
/**
|
||||
* Jobs waiting for a sync to finish (aka transition back to 'idle' again)
|
||||
*/
|
||||
val onFinishedListeners: List<CompletableJob>
|
||||
) {
|
||||
enum class Level {
|
||||
/**
|
||||
* No sync is requested, nor currently in-progress running
|
||||
*/
|
||||
Idle,
|
||||
|
||||
/**
|
||||
* A sync is enqueued but not yet actually running on the external system, or
|
||||
* a previous sync is already running, but a new one has been requested already
|
||||
*/
|
||||
SyncQueued,
|
||||
|
||||
/**
|
||||
* The sync is currently running by the external system
|
||||
*/
|
||||
SyncInProgress,
|
||||
}
|
||||
}
|
||||
|
||||
private val syncState = AtomicReference(SyncState(SyncState.Level.Idle, emptyList()))
|
||||
|
||||
@Volatile
|
||||
private var checkingAndPerformingAutoConfig: Boolean = false
|
||||
|
||||
@@ -36,16 +65,13 @@ class KotlinProjectConfigurationService(private val project: Project, private va
|
||||
|
||||
fun shouldShowNotConfiguredDialog(module: Module): Boolean {
|
||||
if (!findApplicableConfigurator(module).shouldShowNotConfiguredDialog()) return false
|
||||
if (isSyncPending(module)) return false
|
||||
if (isSyncDesired(module)) return false
|
||||
if (checkingAndPerformingAutoConfig) return false
|
||||
// If notificationCooldownEnd wasn't set, then the autoconfiguration didn't take place
|
||||
val cooldownEnd = notificationCooldownEnd ?: return true
|
||||
return System.currentTimeMillis() >= cooldownEnd
|
||||
}
|
||||
|
||||
fun isSyncPending(module: Module): Boolean {
|
||||
return KotlinBuildSystemDependencyManager.findApplicableConfigurator(module)?.isProjectSyncPending() == true
|
||||
}
|
||||
|
||||
fun refreshEditorNotifications() {
|
||||
// We want to remove the "Kotlin not configured" notification banner as fast as possible
|
||||
@@ -60,14 +86,61 @@ class KotlinProjectConfigurationService(private val project: Project, private va
|
||||
}
|
||||
}
|
||||
|
||||
@Volatile
|
||||
private var syncInProgress: Boolean = false
|
||||
/**
|
||||
* @return true if the build configuration is 'dirty' and the user is shown a button to re-sync.
|
||||
* @see isSyncing
|
||||
* @see isSyncInProgress
|
||||
* @see KotlinBuildSystemDependencyManager.isProjectSyncPending
|
||||
*/
|
||||
fun isSyncDesired(module: Module): Boolean {
|
||||
return KotlinBuildSystemDependencyManager.findApplicableConfigurator(module)?.isProjectSyncPending() == true
|
||||
}
|
||||
|
||||
@Volatile
|
||||
private var syncQueued: Boolean = false
|
||||
/**
|
||||
* @return true if the sync is already enqueued or actually in progress by the underlying external system.
|
||||
*/
|
||||
fun isSyncing(): Boolean {
|
||||
return syncState.get().run {
|
||||
level == SyncState.Level.SyncQueued || level == SyncState.Level.SyncInProgress
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the sync is currently in-progress by the underlying external system.
|
||||
* Also see [isSyncing] for checking if the sync is queued or in progress.
|
||||
*/
|
||||
fun isSyncInProgress(): Boolean {
|
||||
return syncInProgress
|
||||
return syncState.get().level == SyncState.Level.SyncInProgress
|
||||
}
|
||||
|
||||
/**
|
||||
* Will suspend until all queued or 'in progress' syncs are completed.
|
||||
* @return true if the method suspended and had to wait for a sync
|
||||
* @return false if no sync was queued or in progress and the method was able to return without suspending.
|
||||
*/
|
||||
suspend fun awaitSyncFinished(): Boolean {
|
||||
val job = Job()
|
||||
|
||||
val state = syncState.updateAndGet { state ->
|
||||
/* Idle: Nothing to do */
|
||||
if (state.level == SyncState.Level.Idle) return@updateAndGet state
|
||||
state.copy(onFinishedListeners = state.onFinishedListeners + job)
|
||||
}
|
||||
|
||||
if (state.level != SyncState.Level.Idle) {
|
||||
job.join()
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers a sync ([queueSync]) and will suspend until it completes.
|
||||
*/
|
||||
suspend fun sync() {
|
||||
queueSync()
|
||||
awaitSyncFinished()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,24 +150,47 @@ class KotlinProjectConfigurationService(private val project: Project, private va
|
||||
fun queueSync() {
|
||||
// prevents this side effect from being actually run from quickfix previews (e.g. in Fleet)
|
||||
SideEffectGuard.checkSideEffectAllowed(SideEffectGuard.EffectType.PROJECT_MODEL)
|
||||
|
||||
if (syncInProgress) {
|
||||
syncQueued = true
|
||||
} else {
|
||||
val previousState = syncState.getAndUpdate { state -> state.copy(level = SyncState.Level.SyncQueued) }
|
||||
if (previousState.level < SyncState.Level.SyncInProgress) {
|
||||
ExternalSystemProjectTracker.getInstance(project).scheduleProjectRefresh()
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
fun onSyncStarted() {
|
||||
syncInProgress = true
|
||||
syncState.updateAndGet { state ->
|
||||
state.copy(level = SyncState.Level.SyncInProgress)
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
fun onSyncFinished() {
|
||||
syncInProgress = false
|
||||
if (syncQueued) {
|
||||
syncQueued = false
|
||||
val previousState = syncState.getAndUpdate { state ->
|
||||
/*
|
||||
Only if the previous state was actually 'SyncInProgress', then we can
|
||||
consider the job to be done and reset the state. If the state is already 'SyncQueued' again, this means
|
||||
that another queueSync call happened and we should start one more sync.
|
||||
*/
|
||||
if (state.level == SyncState.Level.SyncInProgress) {
|
||||
SyncState(level = SyncState.Level.Idle, emptyList())
|
||||
} else {
|
||||
state
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
We previously were in 'StateInProgress', which means the job now has finished.
|
||||
Therefore, its time to complete the waiting coroutines.
|
||||
*/
|
||||
if (previousState.level == SyncState.Level.SyncInProgress) {
|
||||
previousState.onFinishedListeners.forEach { job -> job.complete() }
|
||||
}
|
||||
|
||||
/*
|
||||
During the current sync, we received another call into 'queueSync', which means
|
||||
that the currently finished sync is 'dirty' and we should start another one!
|
||||
*/
|
||||
if (previousState.level == SyncState.Level.SyncQueued) {
|
||||
ExternalSystemProjectTracker.getInstance(project).scheduleProjectRefresh()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,5 +33,6 @@
|
||||
<orderEntry type="module" module-name="intellij.java.psi" />
|
||||
<orderEntry type="module" module-name="intellij.java.impl" />
|
||||
<orderEntry type="module" module-name="kotlin.project-configuration" />
|
||||
<orderEntry type="module" module-name="kotlin.base.project-structure" />
|
||||
</component>
|
||||
</module>
|
||||
+7
-5
@@ -1,15 +1,17 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.tools.projectWizard.compatibility
|
||||
|
||||
import com.intellij.openapi.roots.ExternalLibraryDescriptor
|
||||
import com.intellij.openapi.module.Module
|
||||
import org.jetbrains.kotlin.config.toKotlinVersion
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.languageVersionSettings
|
||||
import org.jetbrains.kotlin.idea.configuration.KotlinLibraryVersionProvider
|
||||
|
||||
class DefaultKotlinLibraryVersionProvider : KotlinLibraryVersionProvider {
|
||||
override fun getVersion(groupId: String, artifactId: String, projectKotlinVersion: KotlinVersion): ExternalLibraryDescriptor? {
|
||||
override fun getVersion(module: Module, groupId: String, artifactId: String): String? {
|
||||
val projectKotlinVersion = module.languageVersionSettings.languageVersion.toKotlinVersion()
|
||||
|
||||
val versions = KotlinLibrariesCompatibilityStore.getInstance().getVersions(groupId, artifactId).orEmpty()
|
||||
val kotlinShortVersion = "${projectKotlinVersion.major}.${projectKotlinVersion.minor}"
|
||||
val versionToUse = versions[kotlinShortVersion] ?: return null
|
||||
|
||||
return ExternalLibraryDescriptor(groupId, artifactId, versionToUse, versionToUse, versionToUse)
|
||||
return versions[kotlinShortVersion]
|
||||
}
|
||||
}
|
||||
@@ -50,5 +50,6 @@
|
||||
<orderEntry type="module" module-name="intellij.maven.tests" scope="TEST" />
|
||||
<orderEntry type="module" module-name="kotlin.gradle.gradle-java.tests.shared" scope="TEST" />
|
||||
<orderEntry type="module" module-name="kotlin.project-configuration" scope="TEST" />
|
||||
<orderEntry type="module" module-name="kotlin.base.project-structure" scope="TEST" />
|
||||
</component>
|
||||
</module>
|
||||
+14
-23
@@ -1,9 +1,11 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.tools.projectWizard.compatibility
|
||||
|
||||
import com.intellij.openapi.roots.ExternalLibraryDescriptor
|
||||
import com.intellij.testFramework.fixtures.BasePlatformTestCase
|
||||
import org.jetbrains.kotlin.config.LanguageVersion
|
||||
import org.jetbrains.kotlin.idea.configuration.KotlinLibraryVersionProvider
|
||||
import org.jetbrains.kotlin.idea.facet.setLanguageAndApiVersionInKotlinFacet
|
||||
import org.jetbrains.kotlin.idea.test.createFacet
|
||||
|
||||
class DefaultKotlinLibraryVersionProviderTest : BasePlatformTestCase() {
|
||||
private lateinit var provider: DefaultKotlinLibraryVersionProvider
|
||||
@@ -11,46 +13,35 @@ class DefaultKotlinLibraryVersionProviderTest : BasePlatformTestCase() {
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
provider = DefaultKotlinLibraryVersionProvider()
|
||||
module.createFacet(useProjectSettings = false)
|
||||
}
|
||||
|
||||
private fun getCoroutinesVersion(kotlinVersion: KotlinVersion): ExternalLibraryDescriptor? {
|
||||
private fun getCoroutinesVersion(version: LanguageVersion): String? {
|
||||
val groupId = "org.jetbrains.kotlinx"
|
||||
val artifactId = "kotlinx-coroutines-core"
|
||||
val descriptor = provider.getVersion(groupId, artifactId, kotlinVersion)
|
||||
if (descriptor != null) {
|
||||
assertEquals(groupId, descriptor.libraryGroupId)
|
||||
assertEquals(artifactId, descriptor.libraryArtifactId)
|
||||
assertNotNull(descriptor.preferredVersion)
|
||||
assertEquals(descriptor.preferredVersion, descriptor.minVersion)
|
||||
assertEquals(descriptor.preferredVersion, descriptor.maxVersion)
|
||||
}
|
||||
return descriptor
|
||||
|
||||
myFixture.module.setLanguageAndApiVersionInKotlinFacet(version.toString(), version.toString())
|
||||
|
||||
return provider.getVersion(myFixture.module, groupId, artifactId)
|
||||
}
|
||||
|
||||
fun testDefaultVersionProviderRegistered() {
|
||||
assertTrue(KotlinLibraryVersionProvider.Companion.EP_NAME.extensionList.any { it is DefaultKotlinLibraryVersionProvider })
|
||||
assertTrue(KotlinLibraryVersionProvider.EP_NAME.extensionList.any { it is DefaultKotlinLibraryVersionProvider })
|
||||
}
|
||||
|
||||
fun testKnownVersion() {
|
||||
val returnedVersion = getCoroutinesVersion(KotlinVersion(1, 9))
|
||||
val returnedVersion = getCoroutinesVersion(LanguageVersion.KOTLIN_1_9)
|
||||
assertNotNull(returnedVersion)
|
||||
}
|
||||
|
||||
fun testPatchedKotlinVersion() {
|
||||
val returnedVersion = getCoroutinesVersion(KotlinVersion(1, 9, 23))
|
||||
val nonPatchedVersion = getCoroutinesVersion(KotlinVersion(1, 9))
|
||||
assertNotNull(returnedVersion?.preferredVersion)
|
||||
assertEquals(returnedVersion?.preferredVersion, nonPatchedVersion?.preferredVersion)
|
||||
}
|
||||
|
||||
fun testUnknownKotlin() {
|
||||
assertNull(getCoroutinesVersion(KotlinVersion(0, 3)))
|
||||
assertNull(getCoroutinesVersion(LanguageVersion.KOTLIN_1_0))
|
||||
}
|
||||
|
||||
fun testSpecificCoroutinesVersions() {
|
||||
// Here we test that versions for old Kotlin versions (which will not receive new updates)
|
||||
// return the correct exact values
|
||||
assertEquals("1.6.4", getCoroutinesVersion(KotlinVersion(1, 6))?.preferredVersion)
|
||||
assertEquals("1.5.2", getCoroutinesVersion(KotlinVersion(1, 5))?.preferredVersion)
|
||||
assertEquals("1.6.4", getCoroutinesVersion(LanguageVersion.KOTLIN_1_6))
|
||||
assertEquals("1.5.2", getCoroutinesVersion(LanguageVersion.KOTLIN_1_5))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user