PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/junit/src/com/intellij/execution/junit/TestPackage.java

http://github.com/JetBrains/intellij-community
Java | 287 lines | 255 code | 31 blank | 1 comment | 42 complexity | cb229daa37607a51db8ef277b7cafeed MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, MPL-2.0-no-copyleft-exception, MIT, EPL-1.0, AGPL-1.0
  1. // Copyright 2000-2020 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.
  2. package com.intellij.execution.junit;
  3. import com.intellij.execution.*;
  4. import com.intellij.execution.configurations.JavaParameters;
  5. import com.intellij.execution.configurations.RuntimeConfigurationException;
  6. import com.intellij.execution.configurations.RuntimeConfigurationWarning;
  7. import com.intellij.execution.junit2.info.MethodLocation;
  8. import com.intellij.execution.runners.ExecutionEnvironment;
  9. import com.intellij.execution.testframework.SearchForTestsTask;
  10. import com.intellij.execution.testframework.SourceScope;
  11. import com.intellij.execution.testframework.TestSearchScope;
  12. import com.intellij.openapi.application.ReadAction;
  13. import com.intellij.openapi.module.Module;
  14. import com.intellij.openapi.project.DumbService;
  15. import com.intellij.openapi.project.IndexNotReadyException;
  16. import com.intellij.openapi.project.Project;
  17. import com.intellij.openapi.util.Condition;
  18. import com.intellij.openapi.util.registry.Registry;
  19. import com.intellij.psi.*;
  20. import com.intellij.psi.search.GlobalSearchScope;
  21. import com.intellij.psi.search.PackageScope;
  22. import com.intellij.psi.util.ClassUtil;
  23. import com.intellij.refactoring.listeners.RefactoringElementListener;
  24. import com.intellij.rt.junit.JUnitStarter;
  25. import com.intellij.util.Function;
  26. import com.intellij.util.containers.JBTreeTraverser;
  27. import org.jetbrains.annotations.NotNull;
  28. import org.jetbrains.annotations.Nullable;
  29. import org.jetbrains.annotations.TestOnly;
  30. import java.io.File;
  31. import java.util.LinkedHashSet;
  32. import java.util.List;
  33. import java.util.Objects;
  34. import java.util.Set;
  35. public class TestPackage extends TestObject {
  36. protected static final Function<Location<?>, String> CLASS_NAME_FUNCTION = location -> {
  37. if (location instanceof MethodLocation) {
  38. PsiClass containingClass = ((MethodLocation)location).getContainingClass();
  39. if (containingClass == null) return null;
  40. return ClassUtil.getJVMClassName(containingClass) + "," + ((MethodLocation)location).getPsiElement().getName();
  41. }
  42. PsiElement psiElement = location.getPsiElement();
  43. return psiElement instanceof PsiClass ? ClassUtil.getJVMClassName((PsiClass)psiElement) : null;
  44. };
  45. public TestPackage(JUnitConfiguration configuration, ExecutionEnvironment environment) {
  46. super(configuration, environment);
  47. }
  48. @Nullable
  49. @Override
  50. public SourceScope getSourceScope() {
  51. final JUnitConfiguration.Data data = getConfiguration().getPersistentData();
  52. return data.getScope().getSourceScope(getConfiguration());
  53. }
  54. @Override
  55. public SearchForTestsTask createSearchingForTestsTask() throws ExecutionException {
  56. final JUnitConfiguration.Data data = getConfiguration().getPersistentData();
  57. final Module module = getConfiguration().getConfigurationModule().getModule();
  58. final TestClassFilter classFilter = computeFilter(data);
  59. return new SearchForTestsTask(getConfiguration().getProject(), myServerSocket) {
  60. private final Set<Location<?>> myClasses = new LinkedHashSet<>();
  61. @Override
  62. protected void search() {
  63. myClasses.clear();
  64. final SourceScope sourceScope = getSourceScope();
  65. if (sourceScope != null) {
  66. try {
  67. if (JUnitStarter.JUNIT5_PARAMETER.equals(getRunner())) {
  68. searchTests5(module, classFilter, myClasses);
  69. }
  70. else {
  71. searchTests(module, classFilter, myClasses);
  72. }
  73. }
  74. catch (CantRunException ignored) {}
  75. }
  76. }
  77. @Override
  78. protected void onFound() {
  79. try {
  80. String packageName = getPackageName(data);
  81. String filters = getFilters(myClasses, packageName);
  82. if (JUnitStarter.JUNIT5_PARAMETER.equals(getRunner()) && module != null && filterOutputByDirectoryForJunit5(myClasses)) {
  83. JUnitStarter.printClassesList(composeDirectoryFilter(module), packageName, "", filters, myTempFile);
  84. }
  85. else {
  86. addClassesListToJavaParameters(myClasses, CLASS_NAME_FUNCTION, packageName, createTempFiles(), getJavaParameters(), filters);
  87. }
  88. }
  89. catch (Exception ignored) {}
  90. }
  91. @Override
  92. protected boolean requiresSmartMode() {
  93. return TestPackage.this.requiresSmartMode();
  94. }
  95. };
  96. }
  97. @Nullable
  98. private TestClassFilter computeFilter(JUnitConfiguration.Data data) throws ExecutionException {
  99. final TestClassFilter classFilter;
  100. try {
  101. classFilter =
  102. DumbService.getInstance(getConfiguration().getProject()).computeWithAlternativeResolveEnabled(() -> getClassFilter(data));
  103. LOG.assertTrue(classFilter.getBase() != null);
  104. return classFilter;
  105. }
  106. catch (JUnitUtil.NoJUnitException e) {
  107. return null;
  108. }
  109. catch (IndexNotReadyException e) {
  110. throw new ExecutionException("Running tests is disabled during index update");
  111. }
  112. }
  113. protected boolean requiresSmartMode() {
  114. return !JUnitStarter.JUNIT5_PARAMETER.equals(getRunner());
  115. }
  116. protected boolean filterOutputByDirectoryForJunit5(final Set<Location<?>> classNames) {
  117. return getConfiguration().getTestSearchScope() == TestSearchScope.SINGLE_MODULE;
  118. }
  119. protected String getFilters(Set<Location<?>> foundClasses, String packageName) {
  120. return foundClasses.isEmpty() ? packageName.isEmpty() ? ".*" : packageName + "\\..*" : "";
  121. }
  122. protected void searchTests5(Module module, TestClassFilter classFilter, Set<Location<?>> classes) throws CantRunException { }
  123. protected void searchTests(Module module, TestClassFilter classFilter, Set<Location<?>> classes) throws CantRunException {
  124. if (Registry.is("junit4.search.4.tests.all.in.scope", true)) {
  125. Condition<PsiClass> acceptClassCondition = aClass -> ReadAction.compute(() -> aClass.isValid() && classFilter.isAccepted(aClass));
  126. collectClassesRecursively(classFilter, acceptClassCondition, classes);
  127. }
  128. else {
  129. LinkedHashSet<PsiClass> psiClasses = new LinkedHashSet<>();
  130. ConfigurationUtil.findAllTestClasses(classFilter, module, psiClasses);
  131. psiClasses.stream().map(PsiLocation::fromPsiElement).forEach(classes::add);
  132. }
  133. }
  134. protected boolean createTempFiles() {
  135. return false;
  136. }
  137. @NotNull
  138. protected String getPackageName(JUnitConfiguration.Data data) throws CantRunException {
  139. PsiPackage aPackage = getPackage(data);
  140. return aPackage != null ? aPackage.getQualifiedName() : "";
  141. }
  142. protected void collectClassesRecursively(TestClassFilter classFilter,
  143. Condition<? super PsiClass> acceptClassCondition,
  144. Set<Location<?>> classes) throws CantRunException {
  145. PsiPackage aPackage = getPackage(getConfiguration().getPersistentData());
  146. if (aPackage != null) {
  147. GlobalSearchScope scope = GlobalSearchScope.projectScope(getConfiguration().getProject()).intersectWith(classFilter.getScope());
  148. collectClassesRecursively(aPackage, scope, acceptClassCondition, classes);
  149. }
  150. }
  151. private static void collectClassesRecursively(PsiPackage aPackage,
  152. GlobalSearchScope scope,
  153. Condition<? super PsiClass> acceptAsTest,
  154. Set<Location<?>> classes) {
  155. PsiPackage[] psiPackages = ReadAction.compute(() -> aPackage.getSubPackages(scope));
  156. for (PsiPackage psiPackage : psiPackages) {
  157. collectClassesRecursively(psiPackage, scope, acceptAsTest, classes);
  158. }
  159. PsiClass[] psiClasses = ReadAction.compute(() -> aPackage.getClasses(scope));
  160. for (PsiClass aClass : psiClasses) {
  161. collectInnerClasses(aClass, acceptAsTest, classes);
  162. }
  163. }
  164. protected static void collectInnerClasses(PsiClass aClass, Condition<? super PsiClass> acceptAsTest, Set<Location<?>> classes) {
  165. if (Registry.is("junit4.accept.inner.classes", true)) {
  166. classes.addAll(ReadAction.compute(() -> JBTreeTraverser.of(PsiClass::getInnerClasses)
  167. .withRoot(aClass).filter(acceptAsTest).map(psiClass -> PsiLocation.fromPsiElement(psiClass))
  168. .toList()));
  169. }
  170. else if (acceptAsTest.value(aClass)) {
  171. classes.add(PsiLocation.fromPsiElement(aClass));
  172. }
  173. }
  174. @Override
  175. protected JavaParameters createJavaParameters() throws ExecutionException {
  176. final JavaParameters javaParameters = super.createJavaParameters();
  177. final JUnitConfiguration.Data data = getConfiguration().getPersistentData();
  178. final Project project = getConfiguration().getProject();
  179. final SourceScope sourceScope = data.getScope().getSourceScope(getConfiguration());
  180. if (sourceScope == null || !JUnitStarter.JUNIT5_PARAMETER.equals(getRunner())) { //check for junit 5
  181. JUnitUtil.checkTestCase(sourceScope, project);
  182. }
  183. createTempFiles(javaParameters);
  184. createServerSocket(javaParameters);
  185. return javaParameters;
  186. }
  187. @Override
  188. protected void collectPackagesToOpen(List<String> options) {
  189. try {
  190. SourceScope sourceScope = getSourceScope();
  191. if (sourceScope != null) {
  192. collectSubPackages(options,
  193. getPackage(getConfiguration().getPersistentData()),
  194. sourceScope.getGlobalSearchScope());
  195. }
  196. }
  197. catch (CantRunException ignored) {
  198. }
  199. }
  200. @Override
  201. protected boolean configureByModule(Module module) {
  202. return super.configureByModule(module) && getConfiguration().getPersistentData().getScope() != TestSearchScope.WHOLE_PROJECT;
  203. }
  204. protected TestClassFilter getClassFilter(final JUnitConfiguration.Data data) throws CantRunException {
  205. Module module = getConfiguration().getConfigurationModule().getModule();
  206. if (getConfiguration().getPersistentData().getScope() == TestSearchScope.WHOLE_PROJECT){
  207. module = null;
  208. }
  209. final TestClassFilter classFilter = TestClassFilter.create(getSourceScope(), module);
  210. return classFilter.intersectionWith(filterScope(data));
  211. }
  212. protected GlobalSearchScope filterScope(final JUnitConfiguration.Data data) throws CantRunException {
  213. return ReadAction.compute(() -> PackageScope.packageScope(getPackage(data), true));
  214. }
  215. protected PsiPackage getPackage(JUnitConfiguration.Data data) throws CantRunException {
  216. final String packageName = data.getPackageName();
  217. final PsiPackage aPackage = JavaPsiFacade.getInstance(getConfiguration().getProject()).findPackage(packageName);
  218. if (aPackage == null) throw CantRunException.packageNotFound(packageName);
  219. return aPackage;
  220. }
  221. @Override
  222. public String suggestActionName() {
  223. final JUnitConfiguration.Data data = getConfiguration().getPersistentData();
  224. return data.getPackageName().trim().length() > 0
  225. ? ExecutionBundle.message("test.in.scope.presentable.text", data.getPackageName())
  226. : JUnitBundle.message("all.tests.scope.presentable.text");
  227. }
  228. @Override
  229. public RefactoringElementListener getListener(final PsiElement element, final JUnitConfiguration configuration) {
  230. return element instanceof PsiPackage ? RefactoringListeners.getListener((PsiPackage)element, configuration.myPackage) : null;
  231. }
  232. @Override
  233. public boolean isConfiguredByElement(JUnitConfiguration configuration,
  234. PsiClass testClass,
  235. PsiMethod testMethod,
  236. PsiPackage testPackage,
  237. PsiDirectory testDir) {
  238. return testPackage != null && Objects.equals(testPackage.getQualifiedName(), configuration.getPersistentData().getPackageName());
  239. }
  240. @Override
  241. public void checkConfiguration() throws RuntimeConfigurationException {
  242. super.checkConfiguration();
  243. final String packageName = getConfiguration().getPersistentData().getPackageName();
  244. final PsiPackage aPackage = JavaPsiFacade.getInstance(getConfiguration().getProject()).findPackage(packageName);
  245. if (aPackage == null) {
  246. throw new RuntimeConfigurationWarning(JUnitBundle.message("package.does.not.exist.error.message", packageName));
  247. }
  248. if (getSourceScope() == null) {
  249. getConfiguration().getConfigurationModule().checkForWarning();
  250. }
  251. }
  252. @TestOnly
  253. public File getWorkingDirsFile() {
  254. return myWorkingDirsFile;
  255. }
  256. }