[REVERT/172] Test Support: Implement proper detection of existing TestNG configurations
This commit is contained in:
+233
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.Location;
|
||||
import com.intellij.execution.PsiLocation;
|
||||
import com.intellij.execution.actions.ConfigurationContext;
|
||||
import com.intellij.execution.actions.ConfigurationFromContext;
|
||||
import com.intellij.execution.junit.InheritorChooser;
|
||||
import com.intellij.execution.junit2.info.MethodLocation;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiClassUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
|
||||
import com.theoryinpractice.testng.configuration.TestNGConfigurationProducer;
|
||||
import com.theoryinpractice.testng.util.TestNGUtil;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.asJava.LightClassUtilsKt;
|
||||
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector;
|
||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.kotlin.asJava.LightClassUtilsKt.toLightClass;
|
||||
|
||||
public class KotlinTestNgConfigurationProducer extends TestNGConfigurationProducer {
|
||||
@Override
|
||||
public boolean shouldReplace(ConfigurationFromContext self, ConfigurationFromContext other) {
|
||||
return other.isProducedBy(TestNGConfigurationProducer.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean setupConfigurationFromContext(
|
||||
TestNGConfiguration configuration, ConfigurationContext context, Ref<PsiElement> sourceElement
|
||||
) {
|
||||
// TODO: check TestNG Pattern running first, before method/class (see TestNGInClassConfigurationProducer for logic)
|
||||
// TODO: and PsiClassOwner not handled, which is in TestNGInClassConfigurationProducer
|
||||
|
||||
Location location = context.getLocation();
|
||||
if (location == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Project project = context.getProject();
|
||||
PsiElement leaf = location.getPsiElement();
|
||||
|
||||
if (!ProjectRootsUtil.isInProjectOrLibSource(leaf)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(leaf.getContainingFile() instanceof KtFile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
KtFile ktFile = (KtFile) leaf.getContainingFile();
|
||||
|
||||
if (TargetPlatformDetector.getPlatform(ktFile) != JvmPlatform.INSTANCE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
KtNamedDeclaration declarationToRun = getDeclarationToRun(leaf);
|
||||
|
||||
if (declarationToRun instanceof KtNamedFunction) {
|
||||
KtNamedFunction function = (KtNamedFunction) declarationToRun;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
KtElement owner = PsiTreeUtil.getParentOfType(function, KtFunction.class, KtClass.class);
|
||||
|
||||
if (owner instanceof KtClass) {
|
||||
PsiClass delegate = toLightClass((KtClass) owner);
|
||||
if (delegate != null) {
|
||||
for (PsiMethod method : delegate.getMethods()) {
|
||||
if (method.getNavigationElement() == function) {
|
||||
if (TestNGUtil.hasTest(method)) {
|
||||
return configure(configuration, location, context, project, delegate, method);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (declarationToRun instanceof KtClass) {
|
||||
PsiClass delegate = toLightClass((KtClassOrObject) declarationToRun);
|
||||
if (!isTestNGClass(delegate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return configure(configuration, location, context, project, delegate, null);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFirstRun(ConfigurationFromContext configuration, ConfigurationContext context, Runnable startRunnable) {
|
||||
KtNamedDeclaration declarationToRun = getDeclarationToRun(configuration.getSourceElement());
|
||||
final PsiNamedElement lightElement = CollectionsKt.firstOrNull(LightClassUtilsKt.toLightElements(declarationToRun));
|
||||
|
||||
// Copied from TestNGInClassConfigurationProducer.onFirstRun()
|
||||
if (lightElement instanceof PsiMethod || lightElement instanceof PsiClass) {
|
||||
PsiMethod psiMethod;
|
||||
PsiClass containingClass;
|
||||
|
||||
if (lightElement instanceof PsiMethod) {
|
||||
psiMethod = (PsiMethod)lightElement;
|
||||
containingClass = psiMethod.getContainingClass();
|
||||
} else {
|
||||
psiMethod = null;
|
||||
containingClass = (PsiClass)lightElement;
|
||||
}
|
||||
|
||||
InheritorChooser inheritorChooser = new InheritorChooser() {
|
||||
@Override
|
||||
protected void runForClasses(List<PsiClass> classes, PsiMethod method, ConfigurationContext context, Runnable performRunnable) {
|
||||
((TestNGConfiguration)context.getConfiguration().getConfiguration()).bePatternConfiguration(classes, method);
|
||||
super.runForClasses(classes, method, context, performRunnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runForClass(PsiClass aClass,
|
||||
PsiMethod psiMethod,
|
||||
ConfigurationContext context,
|
||||
Runnable performRunnable) {
|
||||
if (lightElement instanceof PsiMethod) {
|
||||
Project project = psiMethod.getProject();
|
||||
MethodLocation methodLocation = new MethodLocation(project, psiMethod, PsiLocation.fromPsiElement(aClass));
|
||||
((TestNGConfiguration)context.getConfiguration().getConfiguration()).setMethodConfiguration(methodLocation);
|
||||
} else {
|
||||
((TestNGConfiguration)context.getConfiguration().getConfiguration()).setClassConfiguration(aClass);
|
||||
}
|
||||
super.runForClass(aClass, psiMethod, context, performRunnable);
|
||||
}
|
||||
};
|
||||
if (inheritorChooser.runMethodInAbstractClass(context,
|
||||
startRunnable,
|
||||
psiMethod,
|
||||
containingClass,
|
||||
new Condition<PsiClass>() {
|
||||
@Override
|
||||
public boolean value(PsiClass aClass) {
|
||||
return aClass.hasModifierProperty(PsiModifier.ABSTRACT) &&
|
||||
TestNGUtil.hasTest(aClass);
|
||||
}
|
||||
})) return;
|
||||
}
|
||||
|
||||
super.onFirstRun(configuration, context, startRunnable);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static KtNamedDeclaration getDeclarationToRun(@NotNull PsiElement leaf) {
|
||||
if (!(leaf.getContainingFile() instanceof KtFile)) return null;
|
||||
KtFile jetFile = (KtFile) leaf.getContainingFile();
|
||||
|
||||
KtNamedFunction function = PsiTreeUtil.getParentOfType(leaf, KtNamedFunction.class, false);
|
||||
if (function != null) return function;
|
||||
|
||||
KtClass ktClass = PsiTreeUtil.getParentOfType(leaf, KtClass.class, false);
|
||||
if (ktClass != null) return ktClass;
|
||||
|
||||
return getClassDeclarationInFile(jetFile);
|
||||
}
|
||||
|
||||
private boolean configure(
|
||||
TestNGConfiguration configuration, Location location, ConfigurationContext context, Project project,
|
||||
@Nullable PsiClass delegate, @Nullable PsiMethod method
|
||||
) {
|
||||
if (delegate == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
setupConfigurationModule(context, configuration);
|
||||
Module originalModule = configuration.getConfigurationModule().getModule();
|
||||
configuration.setClassConfiguration(delegate);
|
||||
if (method != null) {
|
||||
configuration.setMethodConfiguration(PsiLocation.fromPsiElement(project, method));
|
||||
}
|
||||
configuration.restoreOriginalModule(originalModule);
|
||||
configuration.setName(configuration.getName());
|
||||
JavaRunConfigurationExtensionManager.getInstance().extendCreatedConfiguration(configuration, location);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isTestNGClass(PsiClass psiClass) {
|
||||
return psiClass != null && PsiClassUtil.isRunnableClass(psiClass, true, false) && TestNGUtil.hasTest(psiClass);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static KtClass getClassDeclarationInFile(KtFile jetFile) {
|
||||
KtClass tempSingleDeclaration = null;
|
||||
|
||||
for (KtDeclaration ktDeclaration : jetFile.getDeclarations()) {
|
||||
if (ktDeclaration instanceof KtClass) {
|
||||
KtClass declaration = (KtClass) ktDeclaration;
|
||||
|
||||
if (tempSingleDeclaration == null) {
|
||||
tempSingleDeclaration = declaration;
|
||||
}
|
||||
else {
|
||||
// There are several class declarations in file
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tempSingleDeclaration;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user