diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/run/AbstractKotlinTestClassGradleConfigurationProducer.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/run/AbstractKotlinTestClassGradleConfigurationProducer.kt index 864e1d91c9f..e6c40c0af8f 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/run/AbstractKotlinTestClassGradleConfigurationProducer.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/run/AbstractKotlinTestClassGradleConfigurationProducer.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.idea.run import com.intellij.execution.Location import com.intellij.execution.actions.ConfigurationContext import com.intellij.execution.actions.ConfigurationFromContext +import com.intellij.execution.configurations.ConfigurationFactory import com.intellij.execution.junit.InheritorChooser import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration import com.intellij.openapi.module.Module @@ -40,12 +41,12 @@ abstract class AbstractKotlinMultiplatformTestClassGradleConfigurationProducer : return isApplicable(module, platform) } - override fun isPreferredConfiguration(self: ConfigurationFromContext?, other: ConfigurationFromContext): Boolean { - return other.isJpsJunitConfiguration() + override fun isPreferredConfiguration(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean { + return other.isJpsJunitConfiguration() || super.isPreferredConfiguration(self, other) } override fun shouldReplace(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean { - return other.isJpsJunitConfiguration() + return other.isJpsJunitConfiguration() || super.shouldReplace(self, other) } override fun onFirstRun(fromContext: ConfigurationFromContext, context: ConfigurationContext, performRunnable: Runnable) { @@ -94,6 +95,10 @@ abstract class AbstractKotlinMultiplatformTestClassGradleConfigurationProducer : abstract class AbstractKotlinTestClassGradleConfigurationProducer : TestClassGradleConfigurationProducer(), KotlinGradleConfigurationProducer { + override fun getConfigurationFactory(): ConfigurationFactory { + return KotlinGradleExternalTaskConfigurationType.instance.factory + } + override fun isConfigurationFromContext(configuration: ExternalSystemRunConfiguration, context: ConfigurationContext): Boolean { if (!context.check()) { return false @@ -133,4 +138,20 @@ abstract class AbstractKotlinTestClassGradleConfigurationProducer override fun getPsiClassForLocation(contextLocation: Location<*>) = getTestClassForKotlinTest(contextLocation) override fun getPsiMethodForLocation(contextLocation: Location<*>) = getTestMethodForKotlinTest(contextLocation) -} + + override fun isPreferredConfiguration(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean { + return checkShouldReplace(self, other) || super.isPreferredConfiguration(self, other) + } + + override fun shouldReplace(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean { + return checkShouldReplace(self, other) || super.shouldReplace(self, other) + } + + private fun checkShouldReplace(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean { + if (self.isProducedBy(javaClass) && other.isProducedBy(TestClassGradleConfigurationProducer::class.java)) { + return true + } + + return false + } +} \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/run/AbstractKotlinTestMethodGradleConfigurationProducer.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/run/AbstractKotlinTestMethodGradleConfigurationProducer.kt index 95fa15aa53c..2951233b0ef 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/run/AbstractKotlinTestMethodGradleConfigurationProducer.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/run/AbstractKotlinTestMethodGradleConfigurationProducer.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.idea.run import com.intellij.execution.Location import com.intellij.execution.actions.ConfigurationContext import com.intellij.execution.actions.ConfigurationFromContext +import com.intellij.execution.configurations.ConfigurationFactory import com.intellij.execution.junit.InheritorChooser import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration import com.intellij.openapi.module.Module @@ -41,12 +42,12 @@ abstract class AbstractKotlinMultiplatformTestMethodGradleConfigurationProducer return isApplicable(module, platform) } - override fun isPreferredConfiguration(self: ConfigurationFromContext?, other: ConfigurationFromContext): Boolean { - return other.isJpsJunitConfiguration() + override fun isPreferredConfiguration(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean { + return other.isJpsJunitConfiguration() || super.isPreferredConfiguration(self, other) } override fun shouldReplace(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean { - return other.isJpsJunitConfiguration() + return other.isJpsJunitConfiguration() || super.shouldReplace(self, other) } override fun onFirstRun(fromContext: ConfigurationFromContext, context: ConfigurationContext, performRunnable: Runnable) { @@ -97,6 +98,10 @@ abstract class AbstractKotlinMultiplatformTestMethodGradleConfigurationProducer abstract class AbstractKotlinTestMethodGradleConfigurationProducer : TestMethodGradleConfigurationProducer(), KotlinGradleConfigurationProducer { + override fun getConfigurationFactory(): ConfigurationFactory { + return KotlinGradleExternalTaskConfigurationType.instance.factory + } + override fun isConfigurationFromContext(configuration: ExternalSystemRunConfiguration, context: ConfigurationContext): Boolean { if (!context.check()) { return false @@ -135,4 +140,24 @@ abstract class AbstractKotlinTestMethodGradleConfigurationProducer } override fun getPsiMethodForLocation(contextLocation: Location<*>) = getTestMethodForKotlinTest(contextLocation) + + override fun isPreferredConfiguration(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean { + return checkShouldReplace(self, other) || super.isPreferredConfiguration(self, other) + } + + override fun shouldReplace(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean { + return checkShouldReplace(self, other) || super.shouldReplace(self, other) + } + + private fun checkShouldReplace(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean { + if (self.isProducedBy(javaClass)) { + if (other.isProducedBy(TestMethodGradleConfigurationProducer::class.java) || + other.isProducedBy(AbstractKotlinTestClassGradleConfigurationProducer::class.java) + ) { + return true + } + } + + return false + } } diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/run/KotlinGradleExternalTaskConfigurationType.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/run/KotlinGradleExternalTaskConfigurationType.kt new file mode 100644 index 00000000000..628d1540ca4 --- /dev/null +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/run/KotlinGradleExternalTaskConfigurationType.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.run + +import com.intellij.execution.configurations.ConfigurationFactory +import com.intellij.execution.configurations.ConfigurationType +import com.intellij.execution.configurations.ConfigurationTypeUtil +import com.intellij.openapi.externalSystem.model.ProjectSystemId +import com.intellij.openapi.externalSystem.service.execution.AbstractExternalSystemTaskConfigurationType +import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration +import com.intellij.openapi.project.Project +import org.jetbrains.plugins.gradle.service.execution.GradleRunConfiguration +import org.jetbrains.plugins.gradle.util.GradleConstants + +class KotlinGradleExternalTaskConfigurationType : AbstractExternalSystemTaskConfigurationType(GradleConstants.SYSTEM_ID) { + companion object { + val instance: KotlinGradleExternalTaskConfigurationType + get() = ConfigurationTypeUtil.findConfigurationType(KotlinGradleExternalTaskConfigurationType::class.java) + } + + override fun getId() = "Kotlin" + externalSystemId.readableName + "RunConfiguration" + + @Suppress("SpellCheckingInspection") + override fun getHelpTopic() = "reference.dialogs.rundebug.GradleRunConfiguration" + + override fun doCreateConfiguration( + externalSystemId: ProjectSystemId, + project: Project, + factory: ConfigurationFactory, + name: String + ): ExternalSystemRunConfiguration { + return KotlinGradleRunConfiguration(project, factory, name) + } +} + +class KotlinGradleRunConfiguration(project: Project?, factory: ConfigurationFactory?, name: String?) : + GradleRunConfiguration(project, factory, name) \ No newline at end of file diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleTestRunConfigurationTest.kt b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleTestRunConfigurationTest.kt new file mode 100644 index 00000000000..c7c7a863e2a --- /dev/null +++ b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleTestRunConfigurationTest.kt @@ -0,0 +1,70 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.codeInsight.gradle + +import com.intellij.execution.PsiLocation +import com.intellij.execution.actions.ConfigurationContext +import com.intellij.execution.actions.ConfigurationFromContext +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiManager +import org.junit.Test +import com.intellij.testFramework.runInEdtAndWait +import com.intellij.util.PlatformUtils +import org.jetbrains.kotlin.idea.run.KotlinGradleRunConfiguration +import org.jetbrains.kotlin.idea.run.KotlinJvmTestClassGradleConfigurationProducer +import org.jetbrains.kotlin.idea.run.KotlinJvmTestMethodGradleConfigurationProducer +import org.jetbrains.kotlin.idea.util.application.runReadAction +import org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer +import org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer +import org.jetbrains.plugins.gradle.tooling.annotation.TargetVersions + +class GradleTestRunConfigurationTest : GradleImportingTestCase() { + @Test + @TargetVersions("4.7+") + fun testPreferredConfigurations() { + if (!PlatformUtils.isIntelliJ()) { + return + } + + val files = importProjectFromTestData() + + runInEdtAndWait { + runReadAction { + val javaFile = files.first { it.name == "MyTest.java" } + val kotlinFile = files.first { it.name == "MyKotlinTest.kt" } + + val javaClassConfiguration = getConfiguration(javaFile, "MyTest") + javaClassConfiguration.isProducedBy(TestClassGradleConfigurationProducer::class.java) + assert(javaClassConfiguration.configuration !is KotlinGradleRunConfiguration) + + val javaMethodConfiguration = getConfiguration(javaFile, "testA") + javaMethodConfiguration.isProducedBy(TestMethodGradleConfigurationProducer::class.java) + assert(javaMethodConfiguration.configuration !is KotlinGradleRunConfiguration) + + val kotlinClassConfiguration = getConfiguration(kotlinFile, "MyKotlinTest") + kotlinClassConfiguration.isProducedBy(KotlinJvmTestClassGradleConfigurationProducer::class.java) + assert(kotlinClassConfiguration.configuration is KotlinGradleRunConfiguration) + + val kotlinFunctionConfiguration = getConfiguration(kotlinFile, "testA") + kotlinFunctionConfiguration.isProducedBy(KotlinJvmTestMethodGradleConfigurationProducer::class.java) + assert(kotlinFunctionConfiguration.configuration is KotlinGradleRunConfiguration) + } + } + } + + private fun getConfiguration(file: VirtualFile, pattern: String): ConfigurationFromContext { + val psiFile = PsiManager.getInstance(myTestFixture.project).findFile(file) ?: error("PsiFile not found for $file") + val offset = psiFile.text.indexOf(pattern) + val psiElement = psiFile.findElementAt(offset) + val location = PsiLocation(psiElement) + val context = ConfigurationContext.createEmptyContextForLocation(location) + return context.configurationsFromContext.orEmpty().singleOrNull() ?: error("Configuration not found for pattern $pattern") + } + + override fun testDataDirName(): String { + return "testRunConfigurations" + } +} \ No newline at end of file diff --git a/idea/resources/META-INF/gradle.xml b/idea/resources/META-INF/gradle.xml index 8b4e960055b..025b6755fbd 100644 --- a/idea/resources/META-INF/gradle.xml +++ b/idea/resources/META-INF/gradle.xml @@ -19,6 +19,7 @@ + diff --git a/idea/testData/gradle/testRunConfigurations/preferredConfigurations/build.gradle b/idea/testData/gradle/testRunConfigurations/preferredConfigurations/build.gradle new file mode 100755 index 00000000000..ca38f7ade59 --- /dev/null +++ b/idea/testData/gradle/testRunConfigurations/preferredConfigurations/build.gradle @@ -0,0 +1,15 @@ +plugins { + id 'java' + id 'org.jetbrains.kotlin.jvm' version '1.3.50' +} + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + testCompile "junit:junit:4.12" +} \ No newline at end of file diff --git a/idea/testData/gradle/testRunConfigurations/preferredConfigurations/src/test/java/MyTest.java b/idea/testData/gradle/testRunConfigurations/preferredConfigurations/src/test/java/MyTest.java new file mode 100755 index 00000000000..9e00d244c4a --- /dev/null +++ b/idea/testData/gradle/testRunConfigurations/preferredConfigurations/src/test/java/MyTest.java @@ -0,0 +1,9 @@ +import org.junit.Test; + +public class MyTest { + @Test + public void testA() {} + + @Test + public void testB() {} +} diff --git a/idea/testData/gradle/testRunConfigurations/preferredConfigurations/src/test/kotlin/MyKotlinTest.kt b/idea/testData/gradle/testRunConfigurations/preferredConfigurations/src/test/kotlin/MyKotlinTest.kt new file mode 100755 index 00000000000..b716ac97ded --- /dev/null +++ b/idea/testData/gradle/testRunConfigurations/preferredConfigurations/src/test/kotlin/MyKotlinTest.kt @@ -0,0 +1,11 @@ +import org.junit.Test + +class MyKotlinTest { + @Test + fun testA() { + } + + @Test + fun testB() { + } +} \ No newline at end of file