Run configuration producer for Gradle tests (KT-10700)
This commit is contained in:
@@ -30,5 +30,8 @@
|
|||||||
language="Groovy"
|
language="Groovy"
|
||||||
hasStaticDescription="true"
|
hasStaticDescription="true"
|
||||||
level="WARNING"/>
|
level="WARNING"/>
|
||||||
|
|
||||||
|
<runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinTestClassGradleConfigurationProducer"/>
|
||||||
|
<runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinTestMethodGradleConfigurationProducer"/>
|
||||||
</extensions>
|
</extensions>
|
||||||
</idea-plugin>
|
</idea-plugin>
|
||||||
|
|||||||
@@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jetbrains.kotlin.idea.run
|
||||||
|
|
||||||
|
import com.intellij.execution.JavaRunConfigurationExtensionManager
|
||||||
|
import com.intellij.execution.actions.ConfigurationContext
|
||||||
|
import com.intellij.execution.actions.RunConfigurationProducer
|
||||||
|
import com.intellij.execution.junit.PatternConfigurationProducer
|
||||||
|
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration
|
||||||
|
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
||||||
|
import com.intellij.openapi.util.Ref
|
||||||
|
import com.intellij.psi.PsiClass
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiMethod
|
||||||
|
import org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer
|
||||||
|
import org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer
|
||||||
|
import org.jetbrains.plugins.gradle.util.GradleConstants
|
||||||
|
|
||||||
|
class KotlinTestClassGradleConfigurationProducer : TestClassGradleConfigurationProducer() {
|
||||||
|
|
||||||
|
override fun doSetupConfigurationFromContext(configuration: ExternalSystemRunConfiguration,
|
||||||
|
context: ConfigurationContext,
|
||||||
|
sourceElement: Ref<PsiElement>): Boolean {
|
||||||
|
val contextLocation = context.location ?: return false
|
||||||
|
val module = context.module ?: return false
|
||||||
|
|
||||||
|
if (RunConfigurationProducer.getInstance(PatternConfigurationProducer::class.java).isMultipleElementsSelected(context)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
val leaf = context.location?.psiElement ?: return false
|
||||||
|
val testClass = KotlinJUnitRunConfigurationProducer.getTestClass(leaf) ?: return false
|
||||||
|
sourceElement.set(testClass)
|
||||||
|
|
||||||
|
if (!ExternalSystemApiUtil.isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, module)) return false
|
||||||
|
|
||||||
|
val projectPath = resolveProjectPath(module) ?: return false
|
||||||
|
|
||||||
|
val tasksToRun = getTasksToRun(module)
|
||||||
|
if (tasksToRun.isEmpty()) return false
|
||||||
|
|
||||||
|
configuration.settings.externalProjectPath = projectPath
|
||||||
|
configuration.settings.taskNames = tasksToRun
|
||||||
|
configuration.settings.scriptParameters = String.format("--tests %s", testClass.qualifiedName)
|
||||||
|
configuration.name = testClass.name
|
||||||
|
|
||||||
|
JavaRunConfigurationExtensionManager.getInstance().extendCreatedConfiguration(configuration, contextLocation)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun doIsConfigurationFromContext(configuration: ExternalSystemRunConfiguration, context: ConfigurationContext): Boolean {
|
||||||
|
val leaf = context.location?.psiElement ?: return false
|
||||||
|
if (context.module == null) return false
|
||||||
|
|
||||||
|
if (RunConfigurationProducer.getInstance(PatternConfigurationProducer::class.java).isMultipleElementsSelected(context)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val methodLocation = KotlinJUnitRunConfigurationProducer.getTestMethodLocation(leaf)
|
||||||
|
if (methodLocation != null) return false
|
||||||
|
|
||||||
|
val testClass = KotlinJUnitRunConfigurationProducer.getTestClass(leaf)
|
||||||
|
if (testClass == null || testClass.qualifiedName == null) return false
|
||||||
|
|
||||||
|
|
||||||
|
val projectPath = resolveProjectPath(context.module) ?: return false
|
||||||
|
if (projectPath != configuration.settings.externalProjectPath) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (!configuration.settings.taskNames.containsAll(getTasksToRun(context.module))) return false
|
||||||
|
|
||||||
|
val scriptParameters = configuration.settings.scriptParameters + ' '
|
||||||
|
val i = scriptParameters.indexOf("--tests ")
|
||||||
|
if (i == -1) return false
|
||||||
|
|
||||||
|
val str = scriptParameters.substringAfter("--tests ").trim() + ' '
|
||||||
|
return str.startsWith(testClass.qualifiedName + ' ') && !str.contains("--tests")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KotlinTestMethodGradleConfigurationProducer
|
||||||
|
: TestMethodGradleConfigurationProducer() {
|
||||||
|
|
||||||
|
override fun doSetupConfigurationFromContext(configuration: ExternalSystemRunConfiguration,
|
||||||
|
context: ConfigurationContext,
|
||||||
|
sourceElement: Ref<PsiElement>): Boolean {
|
||||||
|
val contextLocation = context.location ?: return false
|
||||||
|
if (context.module == null) return false
|
||||||
|
|
||||||
|
if (RunConfigurationProducer.getInstance(PatternConfigurationProducer::class.java).isMultipleElementsSelected(context)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val methodLocation = KotlinJUnitRunConfigurationProducer.getTestMethodLocation(contextLocation.psiElement) ?: return false
|
||||||
|
val psiMethod = methodLocation.psiElement
|
||||||
|
sourceElement.set(psiMethod)
|
||||||
|
|
||||||
|
val containingClass = psiMethod.containingClass ?: return false
|
||||||
|
|
||||||
|
|
||||||
|
if (!applyTestMethodConfiguration(configuration, context, psiMethod, containingClass)) return false
|
||||||
|
|
||||||
|
JavaRunConfigurationExtensionManager.getInstance().extendCreatedConfiguration(configuration, contextLocation)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun doIsConfigurationFromContext(configuration: ExternalSystemRunConfiguration, context: ConfigurationContext): Boolean {
|
||||||
|
if (RunConfigurationProducer.getInstance(PatternConfigurationProducer::class.java).isMultipleElementsSelected(context)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val contextLocation = context.location ?: return false
|
||||||
|
val module = context.module ?: return false
|
||||||
|
|
||||||
|
val methodLocation = KotlinJUnitRunConfigurationProducer.getTestMethodLocation(contextLocation.psiElement) ?: return false
|
||||||
|
val psiMethod = methodLocation.psiElement
|
||||||
|
|
||||||
|
val containingClass = psiMethod.containingClass ?: return false
|
||||||
|
|
||||||
|
|
||||||
|
val projectPath = resolveProjectPath(module) ?: return false
|
||||||
|
|
||||||
|
if (projectPath != configuration.settings.externalProjectPath) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (!configuration.settings.taskNames.containsAll(getTasksToRun(module))) return false
|
||||||
|
|
||||||
|
val scriptParameters = configuration.settings.scriptParameters + ' '
|
||||||
|
val testFilter = createTestFilter(containingClass, psiMethod)
|
||||||
|
return scriptParameters.contains(testFilter!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun applyTestMethodConfiguration(configuration: ExternalSystemRunConfiguration,
|
||||||
|
context: ConfigurationContext,
|
||||||
|
psiMethod: PsiMethod,
|
||||||
|
vararg containingClasses: PsiClass): Boolean {
|
||||||
|
val module = context.module ?: return false
|
||||||
|
|
||||||
|
if (!ExternalSystemApiUtil.isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, module)) return false
|
||||||
|
|
||||||
|
val projectPath = resolveProjectPath(module) ?: return false
|
||||||
|
|
||||||
|
val tasksToRun = getTasksToRun(module)
|
||||||
|
if (tasksToRun.isEmpty()) return false
|
||||||
|
|
||||||
|
configuration.settings.externalProjectPath = projectPath
|
||||||
|
configuration.settings.taskNames = tasksToRun
|
||||||
|
|
||||||
|
val params = containingClasses.joinToString("") { aClass -> createTestFilter(aClass, psiMethod) ?: "" }
|
||||||
|
|
||||||
|
configuration.settings.scriptParameters = params.trim()
|
||||||
|
configuration.name = (if (containingClasses.size == 1) containingClasses[0].name + "." else "") + psiMethod.name
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private fun createTestFilter(aClass: PsiClass, psiMethod: PsiMethod): String? {
|
||||||
|
return createTestFilter(aClass.qualifiedName, psiMethod.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createTestFilter(aClass: String?, method: String?): String? {
|
||||||
|
if (aClass == null) return null
|
||||||
|
val testFilterPattern = aClass + if (method == null) "" else '.' + method
|
||||||
|
return "--tests \"$testFilterPattern\" "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -137,33 +137,35 @@ class KotlinJUnitRunConfigurationProducer : RunConfigurationProducer<JUnitConfig
|
|||||||
super.onFirstRun(fromContext, context, performRunnable)
|
super.onFirstRun(fromContext, context, performRunnable)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getTestMethodLocation(leaf: PsiElement): Location<PsiMethod>? {
|
companion object {
|
||||||
val function = leaf.getParentOfType<KtNamedFunction>(false) ?: return null
|
fun getTestClass(leaf: PsiElement): PsiClass? {
|
||||||
val owner = PsiTreeUtil.getParentOfType(function, KtFunction::class.java, KtClass::class.java)
|
val containingFile = leaf.containingFile as? KtFile ?: return null
|
||||||
|
var ktClass = leaf.getParentOfType<KtClass>(false)
|
||||||
if (owner is KtClass) {
|
if (!ktClass.isJUnitTestClass()) {
|
||||||
val delegate = owner.toLightClass() ?: return null
|
ktClass = getTestClassInFile(containingFile)
|
||||||
val method = delegate.methods.firstOrNull() { it.navigationElement == function } ?: return null
|
|
||||||
val methodLocation = PsiLocation.fromPsiElement(method)
|
|
||||||
if (JUnitUtil.isTestMethod(methodLocation, false)) {
|
|
||||||
return methodLocation
|
|
||||||
}
|
}
|
||||||
|
return ktClass?.toLightClass()
|
||||||
}
|
}
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getTestClass(leaf: PsiElement): PsiClass? {
|
fun getTestMethodLocation(leaf: PsiElement): Location<PsiMethod>? {
|
||||||
val containingFile = leaf.containingFile as? KtFile ?: return null
|
val function = leaf.getParentOfType<KtNamedFunction>(false) ?: return null
|
||||||
var jetClass = leaf.getParentOfType<KtClass>(false)
|
val owner = PsiTreeUtil.getParentOfType(function, KtFunction::class.java, KtClass::class.java)
|
||||||
if (!jetClass.isJUnitTestClass()) {
|
|
||||||
jetClass = getTestClassInFile(containingFile)
|
if (owner is KtClass) {
|
||||||
|
val delegate = owner.toLightClass() ?: return null
|
||||||
|
val method = delegate.methods.firstOrNull() { it.navigationElement == function } ?: return null
|
||||||
|
val methodLocation = PsiLocation.fromPsiElement(method)
|
||||||
|
if (JUnitUtil.isTestMethod(methodLocation, false)) {
|
||||||
|
return methodLocation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
return jetClass?.toLightClass()
|
|
||||||
|
private fun KtClass?.isJUnitTestClass() =
|
||||||
|
this?.toLightClass()?.let { JUnitUtil.isTestClass(it, false, true) } ?: false
|
||||||
|
|
||||||
|
private fun getTestClassInFile(ktFile: KtFile) =
|
||||||
|
ktFile.declarations.filterIsInstance<KtClass>().singleOrNull { it.isJUnitTestClass() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KtClass?.isJUnitTestClass() =
|
|
||||||
this?.toLightClass()?.let { JUnitUtil.isTestClass(it, false, true) } ?: false
|
|
||||||
|
|
||||||
private fun getTestClassInFile(jetFile: KtFile) =
|
|
||||||
jetFile.declarations.filterIsInstance<KtClass>().singleOrNull { it.isJUnitTestClass() }
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user