diff --git a/platform/platform-tests/testSrc/com/intellij/ide/plugins/ClassLoaderConfiguratorTest.kt b/platform/platform-tests/testSrc/com/intellij/ide/plugins/ClassLoaderConfiguratorTest.kt
index aaf4679809e2..46ab99297695 100644
--- a/platform/platform-tests/testSrc/com/intellij/ide/plugins/ClassLoaderConfiguratorTest.kt
+++ b/platform/platform-tests/testSrc/com/intellij/ide/plugins/ClassLoaderConfiguratorTest.kt
@@ -178,7 +178,7 @@ internal class ClassLoaderConfiguratorTest {
}
}
-private fun loadDescriptors(dir: Path): PluginLoadingResult {
+internal fun loadDescriptors(dir: Path): PluginLoadingResult {
val result = PluginLoadingResult()
val context = DescriptorListLoadingContext(customDisabledPlugins = emptySet(),
customBrokenPluginVersions = emptyMap(),
diff --git a/platform/platform-tests/testSrc/com/intellij/ide/plugins/KotlinK1andK2ModesTest.kt b/platform/platform-tests/testSrc/com/intellij/ide/plugins/KotlinK1andK2ModesTest.kt
new file mode 100644
index 000000000000..5d5eb09b7592
--- /dev/null
+++ b/platform/platform-tests/testSrc/com/intellij/ide/plugins/KotlinK1andK2ModesTest.kt
@@ -0,0 +1,151 @@
+// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.ide.plugins
+
+import com.intellij.testFramework.assertions.Assertions.assertThat
+import com.intellij.testFramework.rules.InMemoryFsRule
+import kotlinx.coroutines.runBlocking
+import org.junit.Rule
+import org.junit.Test
+import org.junit.jupiter.api.parallel.Execution
+import org.junit.jupiter.api.parallel.ExecutionMode
+import java.nio.file.Path
+
+// The system property `idea.kotlin.plugin.use.k2` is changed so tests should be sequential
+@Execution(ExecutionMode.SAME_THREAD)
+class KotlinK1andK2ModesTest {
+ @Rule
+ @JvmField
+ val inMemoryFs = InMemoryFsRule()
+
+ private val rootDir: Path get() = inMemoryFs.fs.getPath("/")
+
+ @Test
+ fun `plugin depending on kotlin disabled by default in K2 mode`() = withKotlinPluginMode(isK2 = true) {
+ plugin(rootDir, """
+
+ foo
+ org.jetbrains.kotlin
+
+ """)
+
+ assertThat(getSinglePlugin(rootDir).isEnabled).isFalse()
+ }
+
+ @Test
+ fun `explicitly incompatible plugin depending on kotlin disabled in K2 Mode`() = withKotlinPluginMode(isK2 = true) {
+ plugin(rootDir, """
+
+ foo
+ org.jetbrains.kotlin
+
+
+
+
+
+ """)
+
+ assertThat(getSinglePlugin(rootDir).isEnabled).isFalse()
+ }
+
+ @Test
+ fun `explicitly incompatible plugin depending on kotlin disabled in K1 Mode`() = withKotlinPluginMode(isK2 = false) {
+ plugin(rootDir, """
+
+ foo
+ org.jetbrains.kotlin
+
+
+
+
+
+ """)
+
+ assertThat(getSinglePlugin(rootDir).isEnabled).isFalse()
+ }
+
+ @Test
+ fun `plugin depending on kotlin is enabled when with supportsK2`() = withKotlinPluginMode(isK2 = true) {
+ plugin(rootDir, """
+
+ foo
+ org.jetbrains.kotlin
+
+
+
+
+
+
+ """)
+
+ assertThat(getSinglePlugin(rootDir).isEnabled).isTrue()
+ }
+
+
+ @Test
+ fun `plugin optionally depending on kotlin plugin is not disabled by default in K2 mode and optional dependency is disabled`() = withKotlinPluginMode(isK2 = true) {
+ plugin(rootDir, """
+
+ foo
+ org.jetbrains.kotlin
+
+ """)
+
+ dependencyXml(rootDir, "foo", "kt.xml", """
+
+
+ """)
+
+ val plugin = getSinglePlugin(rootDir)
+ assertThat(plugin.isEnabled).isTrue()
+
+ val dependency = plugin.pluginDependencies.single()
+ assertThat(dependency.subDescriptor).isNull()
+ }
+
+ @Test
+ fun `plugin optionally depending on kotlin plugin is not disabled by default in K2 mode and optional dependency is not disabled`() = withKotlinPluginMode(isK2 = true) {
+ plugin(rootDir, """
+
+ foo
+
+
+
+ org.jetbrains.kotlin
+
+ """)
+
+ dependencyXml(rootDir, "foo", "kt.xml", """
+
+
+ """)
+
+ val plugin = getSinglePlugin(rootDir)
+ assertThat(plugin.isEnabled).isTrue()
+
+ val dependency = plugin.pluginDependencies.single()
+ assertThat(dependency.subDescriptor).isNotNull()
+ }
+}
+
+private fun getSinglePlugin(rootDir: Path): IdeaPluginDescriptorImpl {
+ val pluginResult = runBlocking { loadDescriptors(rootDir) }
+ val allPlugins = pluginResult.getIncompleteIdMap().values + pluginResult.enabledPlugins
+ val plugin = allPlugins.single()
+ return plugin
+}
+
+private inline fun withKotlinPluginMode(isK2: Boolean, action: () -> Unit) {
+ val current = System.getProperty("idea.kotlin.plugin.use.k2")
+ System.setProperty("idea.kotlin.plugin.use.k2", isK2.toString())
+ try {
+ action()
+ }
+ finally {
+ if (current == null) {
+ System.clearProperty("idea.kotlin.plugin.use.k2")
+ }
+ else {
+ System.setProperty("idea.kotlin.plugin.use.k2", current)
+ }
+ }
+}
\ No newline at end of file
diff --git a/platform/platform-tests/testSrc/com/intellij/ide/plugins/PluginBuilder.kt b/platform/platform-tests/testSrc/com/intellij/ide/plugins/PluginBuilder.kt
index e971a9da61ae..2ef4a7ec75c7 100644
--- a/platform/platform-tests/testSrc/com/intellij/ide/plugins/PluginBuilder.kt
+++ b/platform/platform-tests/testSrc/com/intellij/ide/plugins/PluginBuilder.kt
@@ -23,6 +23,16 @@ fun plugin(outDir: Path, @Language("XML") descriptor: String) {
outDir.resolve("${rawDescriptor.id!!}/${PluginManagerCore.PLUGIN_XML_PATH}").write(descriptor.trimIndent())
}
+fun dependencyXml(outDir: Path, ownerId: String, filename: String, @Language("XML") descriptor: String) {
+ try {
+ readModuleDescriptorForTest(descriptor.toByteArray())
+ }
+ catch (e: Throwable) {
+ throw RuntimeException("Cannot parse:\n ${descriptor.trimIndent().prependIndent(" ")}", e)
+ }
+ outDir.resolve("${ownerId}/${PluginManagerCore.META_INF}${filename}").write(descriptor.trimIndent())
+}
+
fun module(outDir: Path, ownerId: String, moduleId: String, @Language("XML") descriptor: String) {
try {
readModuleDescriptorForTest(descriptor.toByteArray())