blob: 43befc5a52cc737dd3f70f1200d6ef1e5a3244d0 [file]
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.execution;
import com.intellij.execution.junit.JUnitUtil;
import com.intellij.execution.junit.TestClassFilter;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.application.ReadActionProcessor;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiShortNamesCache;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.search.searches.ClassesWithAnnotatedMembersSearch;
import com.intellij.psi.util.PsiUtilCore;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
import java.util.Set;
public class ConfigurationUtil {
// return true if there is JUnit4 test
public static boolean findAllTestClasses(final TestClassFilter testClassFilter,
@Nullable final Module module,
final Set<? super PsiClass> found) {
final PsiManager manager = testClassFilter.getPsiManager();
final Project project = manager.getProject();
GlobalSearchScope projectScopeWithoutLibraries = GlobalSearchScope.projectScope(project);
final GlobalSearchScope scope = projectScopeWithoutLibraries.intersectWith(testClassFilter.getScope());
final PsiClass base = testClassFilter.getBase();
if (base != null) {
ClassInheritorsSearch.search(base, scope, true, true, false).forEach(new ReadActionProcessor<PsiClass>() {
@Override
public boolean processInReadAction(PsiClass aClass) {
if (testClassFilter.isAccepted(aClass)) found.add(aClass);
return true;
}
});
}
// classes having suite() method
final PsiMethod[] suiteMethods =
ReadAction.compute(() -> PsiShortNamesCache.getInstance(project).getMethodsByName(JUnitUtil.SUITE_METHOD_NAME, scope));
for (final PsiMethod method : suiteMethods) {
ApplicationManager.getApplication().runReadAction(() -> {
final PsiClass containingClass = method.getContainingClass();
if (containingClass == null) return;
if (containingClass instanceof PsiAnonymousClass) return;
if (containingClass.hasModifierProperty(PsiModifier.ABSTRACT)) return;
if (containingClass.getContainingClass() != null && !containingClass.hasModifierProperty(PsiModifier.STATIC)) return;
if (JUnitUtil.isSuiteMethod(method) && testClassFilter.isAccepted(containingClass)) {
found.add(containingClass);
}
});
}
Set<PsiClass> processed = new HashSet<>();
boolean hasJunit4 = addAnnotatedMethodsAnSubclasses(scope, testClassFilter, module, found, processed, JUnitUtil.TEST_ANNOTATION,
manager.getProject());
hasJunit4 |= addAnnotatedMethodsAnSubclasses(scope, testClassFilter, module, found, processed, JUnitUtil.RUN_WITH, manager.getProject());
return hasJunit4;
}
private static boolean addAnnotatedMethodsAnSubclasses(final GlobalSearchScope scope,
final TestClassFilter testClassFilter,
@Nullable final Module module,
final Set<? super PsiClass> found,
final Set<? super PsiClass> processed,
final String annotation,
final Project project) {
final Ref<Boolean> isJUnit4 = new Ref<>(Boolean.FALSE);
// annotated with @Test
final PsiClass testAnnotation = ReadAction.compute(() -> JavaPsiFacade.getInstance(project).findClass(annotation, GlobalSearchScope.allScope(project)));
if (testAnnotation != null) {
//allScope is used to find all abstract test cases which probably have inheritors in the current 'scope'
GlobalSearchScope allScope = module == null ? GlobalSearchScope.allScope(project)
: module.getModuleRuntimeScope(true);
ClassesWithAnnotatedMembersSearch.search(testAnnotation, allScope).forEach(annotated -> {
boolean success = ReadAction.compute(()-> {
if (!processed.add(annotated)) { // don't process the same class twice regardless of it being in the scope
return false;
}
final VirtualFile file = PsiUtilCore.getVirtualFile(annotated);
if (file != null && scope.contains(file) && testClassFilter.isAccepted(annotated)) {
if (!found.add(annotated)) {
return false;
}
isJUnit4.set(Boolean.TRUE);
}
return true;
});
if (!success) return true;
ClassInheritorsSearch.search(annotated, scope, true, true, false).forEach(new ReadActionProcessor<PsiClass>() {
@Override
public boolean processInReadAction(PsiClass aClass) {
if (testClassFilter.isAccepted(aClass)) {
found.add(aClass);
processed.add(aClass);
isJUnit4.set(Boolean.TRUE);
}
return true;
}
});
return true;
});
}
return isJUnit4.get().booleanValue();
}
}