Run configuration producer for Gradle tests (KT-10700)
This commit is contained in:
@@ -30,5 +30,8 @@
|
||||
language="Groovy"
|
||||
hasStaticDescription="true"
|
||||
level="WARNING"/>
|
||||
|
||||
<runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinTestClassGradleConfigurationProducer"/>
|
||||
<runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinTestMethodGradleConfigurationProducer"/>
|
||||
</extensions>
|
||||
</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)
|
||||
}
|
||||
|
||||
private fun getTestMethodLocation(leaf: PsiElement): Location<PsiMethod>? {
|
||||
val function = leaf.getParentOfType<KtNamedFunction>(false) ?: return null
|
||||
val owner = PsiTreeUtil.getParentOfType(function, KtFunction::class.java, KtClass::class.java)
|
||||
|
||||
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
|
||||
companion object {
|
||||
fun getTestClass(leaf: PsiElement): PsiClass? {
|
||||
val containingFile = leaf.containingFile as? KtFile ?: return null
|
||||
var ktClass = leaf.getParentOfType<KtClass>(false)
|
||||
if (!ktClass.isJUnitTestClass()) {
|
||||
ktClass = getTestClassInFile(containingFile)
|
||||
}
|
||||
return ktClass?.toLightClass()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getTestClass(leaf: PsiElement): PsiClass? {
|
||||
val containingFile = leaf.containingFile as? KtFile ?: return null
|
||||
var jetClass = leaf.getParentOfType<KtClass>(false)
|
||||
if (!jetClass.isJUnitTestClass()) {
|
||||
jetClass = getTestClassInFile(containingFile)
|
||||
fun getTestMethodLocation(leaf: PsiElement): Location<PsiMethod>? {
|
||||
val function = leaf.getParentOfType<KtNamedFunction>(false) ?: return null
|
||||
val owner = PsiTreeUtil.getParentOfType(function, KtFunction::class.java, KtClass::class.java)
|
||||
|
||||
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