diff --git a/plugins/kotlin/base/resources/resources-en/messages/KotlinBundle.properties b/plugins/kotlin/base/resources/resources-en/messages/KotlinBundle.properties
index 7eb5ff812439..1211f7fda5f6 100644
--- a/plugins/kotlin/base/resources/resources-en/messages/KotlinBundle.properties
+++ b/plugins/kotlin/base/resources/resources-en/messages/KotlinBundle.properties
@@ -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
diff --git a/plugins/kotlin/code-insight/inspections-shared/kotlin.code-insight.inspections.shared.iml b/plugins/kotlin/code-insight/inspections-shared/kotlin.code-insight.inspections.shared.iml
index 8c11abd19996..da09f1312f75 100644
--- a/plugins/kotlin/code-insight/inspections-shared/kotlin.code-insight.inspections.shared.iml
+++ b/plugins/kotlin/code-insight/inspections-shared/kotlin.code-insight.inspections.shared.iml
@@ -53,5 +53,6 @@
+
\ No newline at end of file
diff --git a/plugins/kotlin/code-insight/inspections-shared/resources/kotlin.code-insight.inspections.shared.xml b/plugins/kotlin/code-insight/inspections-shared/resources/kotlin.code-insight.inspections.shared.xml
index 05c5d43a0664..493db847e8b8 100644
--- a/plugins/kotlin/code-insight/inspections-shared/resources/kotlin.code-insight.inspections.shared.xml
+++ b/plugins/kotlin/code-insight/inspections-shared/resources/kotlin.code-insight.inspections.shared.xml
@@ -334,6 +334,10 @@
+
+
+
() {
- /**
- * 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::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()
}
\ No newline at end of file
diff --git a/plugins/kotlin/code-insight/inspections-shared/src/org/jetbrains/kotlin/idea/codeInsight/inspections/shared/libraries/SimpleAddKotlinLibraryQuickFixProvider.kt b/plugins/kotlin/code-insight/inspections-shared/src/org/jetbrains/kotlin/idea/codeInsight/inspections/shared/libraries/SimpleAddKotlinLibraryQuickFixProvider.kt
deleted file mode 100644
index ada57dbc9e55..000000000000
--- a/plugins/kotlin/code-insight/inspections-shared/src/org/jetbrains/kotlin/idea/codeInsight/inspections/shared/libraries/SimpleAddKotlinLibraryQuickFixProvider.kt
+++ /dev/null
@@ -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,
-) : 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
- }
-}
\ No newline at end of file
diff --git a/plugins/kotlin/code-insight/inspections-shared/src/org/jetbrains/kotlin/idea/codeInsight/inspections/shared/libraries/defaultLibraryQuickFixProviders.kt b/plugins/kotlin/code-insight/inspections-shared/src/org/jetbrains/kotlin/idea/codeInsight/inspections/shared/libraries/defaultLibraryQuickFixProviders.kt
new file mode 100644
index 000000000000..7d8e8b48111c
--- /dev/null
+++ b/plugins/kotlin/code-insight/inspections-shared/src/org/jetbrains/kotlin/idea/codeInsight/inspections/shared/libraries/defaultLibraryQuickFixProviders.kt
@@ -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"),
+)
diff --git a/plugins/kotlin/gradle/code-insight-common/src/org/jetbrains/kotlin/idea/gradleCodeInsightCommon/KotlinWithGradleConfigurator.kt b/plugins/kotlin/gradle/code-insight-common/src/org/jetbrains/kotlin/idea/gradleCodeInsightCommon/KotlinWithGradleConfigurator.kt
index ce27d2cc5850..0c10ee828474 100644
--- a/plugins/kotlin/gradle/code-insight-common/src/org/jetbrains/kotlin/idea/gradleCodeInsightCommon/KotlinWithGradleConfigurator.kt
+++ b/plugins/kotlin/gradle/code-insight-common/src/org/jetbrains/kotlin/idea/gradleCodeInsightCommon/KotlinWithGradleConfigurator.kt
@@ -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 {
diff --git a/plugins/kotlin/gradle/gradle-java/resources/kotlin.gradle.gradle-java.xml b/plugins/kotlin/gradle/gradle-java/resources/kotlin.gradle.gradle-java.xml
index b9add8f9eb6c..cdb7a1a980bb 100644
--- a/plugins/kotlin/gradle/gradle-java/resources/kotlin.gradle.gradle-java.xml
+++ b/plugins/kotlin/gradle/gradle-java/resources/kotlin.gradle.gradle-java.xml
@@ -41,6 +41,10 @@
+
+
+
+
diff --git a/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/KotlinGradlePluginLibraryVersionProvider.kt b/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/KotlinGradlePluginLibraryVersionProvider.kt
new file mode 100644
index 000000000000..9e0c88f13d7e
--- /dev/null
+++ b/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/KotlinGradlePluginLibraryVersionProvider.kt
@@ -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
+ }
+}
diff --git a/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/configuration/KotlinBuildScriptManipulator.kt b/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/configuration/KotlinBuildScriptManipulator.kt
index c59496783999..803bf9f8c395 100644
--- a/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/configuration/KotlinBuildScriptManipulator.kt
+++ b/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/configuration/KotlinBuildScriptManipulator.kt
@@ -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()) {
diff --git a/plugins/kotlin/gradle/gradle-java/tests.shared/test/org/jetbrains/kotlin/idea/codeInsight/gradle/AbstractGradleMultiFileQuickFixTest.kt b/plugins/kotlin/gradle/gradle-java/tests.shared/test/org/jetbrains/kotlin/idea/codeInsight/gradle/AbstractGradleMultiFileQuickFixTest.kt
index b1c8e8d33492..a52fb9433a80 100644
--- a/plugins/kotlin/gradle/gradle-java/tests.shared/test/org/jetbrains/kotlin/idea/codeInsight/gradle/AbstractGradleMultiFileQuickFixTest.kt
+++ b/plugins/kotlin/gradle/gradle-java/tests.shared/test/org/jetbrains/kotlin/idea/codeInsight/gradle/AbstractGradleMultiFileQuickFixTest.kt
@@ -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)
+ }
}
}
}
diff --git a/plugins/kotlin/gradle/gradle-java/tests.shared/test/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleQuickFixTest.kt b/plugins/kotlin/gradle/gradle-java/tests.shared/test/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleQuickFixTest.kt
index 42f1292cf8c7..ca289e0c605f 100644
--- a/plugins/kotlin/gradle/gradle-java/tests.shared/test/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleQuickFixTest.kt
+++ b/plugins/kotlin/gradle/gradle-java/tests.shared/test/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleQuickFixTest.kt
@@ -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" }
+ )
}
diff --git a/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryJvm/after/build.gradle.kts b/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryJvm/after/build.gradle.kts
new file mode 100644
index 000000000000..47b875873906
--- /dev/null
+++ b/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryJvm/after/build.gradle.kts
@@ -0,0 +1,6 @@
+plugins {
+ kotlin("jvm")
+}
+dependencies {
+ testImplementation(kotlin("test"))
+}
\ No newline at end of file
diff --git a/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryJvm/after/src/test/kotlin/MyTest.kt b/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryJvm/after/src/test/kotlin/MyTest.kt
new file mode 100644
index 000000000000..925f8a40ea33
--- /dev/null
+++ b/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryJvm/after/src/test/kotlin/MyTest.kt
@@ -0,0 +1,9 @@
+// "Add 'org.jetbrains.kotlin:kotlin-test' library" "true"
+// ERROR: Unresolved reference: Test
+
+class MyTest {
+ @Test
+ fun testFoo() {
+
+ }
+}
diff --git a/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryJvm/before/build.gradle.kts b/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryJvm/before/build.gradle.kts
new file mode 100644
index 000000000000..9bc450610cef
--- /dev/null
+++ b/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryJvm/before/build.gradle.kts
@@ -0,0 +1,3 @@
+plugins {
+ kotlin("jvm")
+}
\ No newline at end of file
diff --git a/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryJvm/before/settings.gradle.kts b/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryJvm/before/settings.gradle.kts
new file mode 100644
index 000000000000..bc3dbfcd1d2d
--- /dev/null
+++ b/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryJvm/before/settings.gradle.kts
@@ -0,0 +1,9 @@
+pluginManagement {
+ repositories {
+ {{kts_kotlin_plugin_repositories}}
+ }
+
+ plugins {
+ kotlin("jvm") version "{{kotlin_plugin_version}}"
+ }
+}
\ No newline at end of file
diff --git a/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryJvm/before/src/test/kotlin/MyTest.kt b/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryJvm/before/src/test/kotlin/MyTest.kt
new file mode 100644
index 000000000000..9799272c1bc6
--- /dev/null
+++ b/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryJvm/before/src/test/kotlin/MyTest.kt
@@ -0,0 +1,9 @@
+// "Add 'org.jetbrains.kotlin:kotlin-test' library" "true"
+// ERROR: Unresolved reference: Test
+
+class MyTest {
+ @Test
+ fun testFoo() {
+
+ }
+}
diff --git a/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryKmp/after/build.gradle.kts b/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryKmp/after/build.gradle.kts
new file mode 100644
index 000000000000..588e045f2ba5
--- /dev/null
+++ b/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryKmp/after/build.gradle.kts
@@ -0,0 +1,19 @@
+plugins {
+ kotlin("multiplatform")
+}
+
+kotlin {
+ jvm()
+ linuxX64()
+ sourceSets {
+ getByName("commonTest") {
+ dependencies {
+ implementation(kotlin("test"))
+ }
+ }
+ }
+}
+
+repositories {
+ {{kts_kotlin_plugin_repositories}}
+}
\ No newline at end of file
diff --git a/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryKmp/after/src/commonTest/kotlin/MyTest.kt b/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryKmp/after/src/commonTest/kotlin/MyTest.kt
new file mode 100644
index 000000000000..2dd50aca5b9c
--- /dev/null
+++ b/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryKmp/after/src/commonTest/kotlin/MyTest.kt
@@ -0,0 +1,9 @@
+// "Add 'org.jetbrains.kotlin:kotlin-test' library" "true"
+import kotlin.test.Test
+
+class MyTest {
+ @Test
+ fun testFoo() {
+
+ }
+}
diff --git a/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryKmp/before/build.gradle.kts b/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryKmp/before/build.gradle.kts
new file mode 100644
index 000000000000..89697bf472ac
--- /dev/null
+++ b/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryKmp/before/build.gradle.kts
@@ -0,0 +1,12 @@
+plugins {
+ kotlin("multiplatform")
+}
+
+kotlin {
+ jvm()
+ linuxX64()
+}
+
+repositories {
+ {{kts_kotlin_plugin_repositories}}
+}
\ No newline at end of file
diff --git a/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryKmp/before/settings.gradle.kts b/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryKmp/before/settings.gradle.kts
new file mode 100644
index 000000000000..5baa7cf4f647
--- /dev/null
+++ b/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryKmp/before/settings.gradle.kts
@@ -0,0 +1,9 @@
+pluginManagement {
+ repositories {
+ {{kts_kotlin_plugin_repositories}}
+ }
+
+ plugins {
+ kotlin("multiplatform") version "{{kotlin_plugin_version}}"
+ }
+}
\ No newline at end of file
diff --git a/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryKmp/before/src/commonTest/kotlin/MyTest.kt b/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryKmp/before/src/commonTest/kotlin/MyTest.kt
new file mode 100644
index 000000000000..fa982ab4e3c1
--- /dev/null
+++ b/plugins/kotlin/idea/tests/testData/gradle/fixes/addKotlinTestLibraryKmp/before/src/commonTest/kotlin/MyTest.kt
@@ -0,0 +1,9 @@
+// "Add 'org.jetbrains.kotlin:kotlin-test' library" "true"
+import kotlin.test.Test
+
+class MyTest {
+ @Test
+ fun testFoo() {
+
+ }
+}
diff --git a/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInProjectUtils.kt b/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInProjectUtils.kt
index 4436cc736aab..ec424522f066 100644
--- a/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInProjectUtils.kt
+++ b/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInProjectUtils.kt
@@ -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' }"
/**
diff --git a/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/KotlinLibraryVersionProvider.kt b/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/KotlinLibraryVersionProvider.kt
index b24894ca29a7..08b63cfcd123 100644
--- a/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/KotlinLibraryVersionProvider.kt
+++ b/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/KotlinLibraryVersionProvider.kt
@@ -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?
}
\ No newline at end of file
diff --git a/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/KotlinProjectConfigurationService.kt b/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/KotlinProjectConfigurationService.kt
index 70d73627f72e..cc10c2444309 100644
--- a/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/KotlinProjectConfigurationService.kt
+++ b/plugins/kotlin/project-configuration/src/org/jetbrains/kotlin/idea/configuration/KotlinProjectConfigurationService.kt
@@ -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
+ ) {
+ 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()
}
}
diff --git a/plugins/kotlin/project-wizard/core/kotlin.project-wizard.core.iml b/plugins/kotlin/project-wizard/core/kotlin.project-wizard.core.iml
index 9d37b1d88926..d95a7d70e896 100644
--- a/plugins/kotlin/project-wizard/core/kotlin.project-wizard.core.iml
+++ b/plugins/kotlin/project-wizard/core/kotlin.project-wizard.core.iml
@@ -33,5 +33,6 @@
+
\ No newline at end of file
diff --git a/plugins/kotlin/project-wizard/core/src/org/jetbrains/kotlin/tools/projectWizard/compatibility/DefaultKotlinLibraryVersionProvider.kt b/plugins/kotlin/project-wizard/core/src/org/jetbrains/kotlin/tools/projectWizard/compatibility/DefaultKotlinLibraryVersionProvider.kt
index 63d8606323ac..f98d36b6f4e2 100644
--- a/plugins/kotlin/project-wizard/core/src/org/jetbrains/kotlin/tools/projectWizard/compatibility/DefaultKotlinLibraryVersionProvider.kt
+++ b/plugins/kotlin/project-wizard/core/src/org/jetbrains/kotlin/tools/projectWizard/compatibility/DefaultKotlinLibraryVersionProvider.kt
@@ -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]
}
}
\ No newline at end of file
diff --git a/plugins/kotlin/project-wizard/tests/kotlin.project-wizard.tests.iml b/plugins/kotlin/project-wizard/tests/kotlin.project-wizard.tests.iml
index 4126442bb818..717f0d780df1 100644
--- a/plugins/kotlin/project-wizard/tests/kotlin.project-wizard.tests.iml
+++ b/plugins/kotlin/project-wizard/tests/kotlin.project-wizard.tests.iml
@@ -50,5 +50,6 @@
+
\ No newline at end of file
diff --git a/plugins/kotlin/project-wizard/tests/test/org/jetbrains/kotlin/tools/projectWizard/compatibility/DefaultKotlinLibraryVersionProviderTest.kt b/plugins/kotlin/project-wizard/tests/test/org/jetbrains/kotlin/tools/projectWizard/compatibility/DefaultKotlinLibraryVersionProviderTest.kt
index 8789f36d3893..bd44d271919a 100644
--- a/plugins/kotlin/project-wizard/tests/test/org/jetbrains/kotlin/tools/projectWizard/compatibility/DefaultKotlinLibraryVersionProviderTest.kt
+++ b/plugins/kotlin/project-wizard/tests/test/org/jetbrains/kotlin/tools/projectWizard/compatibility/DefaultKotlinLibraryVersionProviderTest.kt
@@ -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))
}
}
\ No newline at end of file