9dec0623d01bedf6b34964369b6d204d2208f881
[idea/community.git] / python / src / com / jetbrains / python / testing / PythonUnitTestUtil.java
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.jetbrains.python.testing;
3
4 import com.intellij.execution.Location;
5 import com.intellij.execution.PsiLocation;
6 import com.intellij.openapi.progress.ProgressManager;
7 import com.intellij.openapi.project.Project;
8 import com.intellij.openapi.util.io.FileUtilRt;
9 import com.intellij.openapi.vfs.LocalFileSystem;
10 import com.intellij.openapi.vfs.VirtualFile;
11 import com.intellij.psi.PsiFile;
12 import com.intellij.psi.PsiManager;
13 import com.intellij.util.ThreeState;
14 import com.jetbrains.python.psi.PyClass;
15 import com.jetbrains.python.psi.PyFunction;
16 import com.jetbrains.python.psi.stubs.PyClassNameIndex;
17 import com.jetbrains.python.psi.stubs.PyFunctionNameIndex;
18 import com.jetbrains.python.psi.types.TypeEvalContext;
19 import org.jetbrains.annotations.ApiStatus;
20 import org.jetbrains.annotations.NotNull;
21 import org.jetbrains.annotations.Nullable;
22
23 import java.util.ArrayList;
24 import java.util.List;
25
26 public final class PythonUnitTestUtil {
27   private PythonUnitTestUtil() {}
28
29   public static List<Location> findLocations(@NotNull final Project project,
30                                              @NotNull String fileName,
31                                              @Nullable String className,
32                                              @Nullable String methodName) {
33     if (fileName.contains("%")) {
34       fileName = fileName.substring(0, fileName.lastIndexOf("%"));
35     }
36     final List<Location> locations = new ArrayList<>();
37     if (methodName == null && className == null) {
38       final VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByPath(fileName);
39       if (virtualFile == null) return locations;
40       final PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile);
41       if (psiFile != null) {
42         locations.add(new PsiLocation<>(project, psiFile));
43       }
44     }
45
46     if (className != null) {
47       for (PyClass cls : PyClassNameIndex.find(className, project, false)) {
48         ProgressManager.checkCanceled();
49
50         final PsiFile containingFile = cls.getContainingFile();
51         final VirtualFile virtualFile = containingFile.getVirtualFile();
52         final String clsFileName = virtualFile == null ? containingFile.getName() : virtualFile.getPath();
53         final String clsFileNameWithoutExt = FileUtilRt.getNameWithoutExtension(clsFileName);
54         if (!clsFileNameWithoutExt.endsWith(fileName) && !fileName.equals(clsFileName)) {
55           continue;
56         }
57         if (methodName == null) {
58           locations.add(new PsiLocation<>(project, cls));
59         }
60         else {
61           final PyFunction method = cls.findMethodByName(methodName, true, null);
62           if (method == null) {
63             continue;
64           }
65
66           locations.add(new PyPsiLocationWithFixedClass(project, method, cls));
67         }
68       }
69     }
70     else if (methodName != null) {
71       for (PyFunction function : PyFunctionNameIndex.find(methodName, project)) {
72         ProgressManager.checkCanceled();
73         if (function.getContainingClass() == null) {
74           final PsiFile containingFile = function.getContainingFile();
75           final VirtualFile virtualFile = containingFile.getVirtualFile();
76           final String clsFileName = virtualFile == null ? containingFile.getName() : virtualFile.getPath();
77           final String clsFileNameWithoutExt = FileUtilRt.getNameWithoutExtension(clsFileName);
78           if (!clsFileNameWithoutExt.endsWith(fileName)) {
79             continue;
80           }
81           locations.add(new PsiLocation<>(project, function));
82         }
83       }
84     }
85     return locations;
86   }
87
88   /**
89    * @deprecated use {@link PythonUnitTestDetectorsKt#isUnitTestCaseClass(PyClass, TypeEvalContext)}
90    */
91   @Deprecated
92   @ApiStatus.ScheduledForRemoval(inVersion = "2021.1")
93   public static boolean isUnitTestCaseClass(@NotNull PyClass pyClass) {
94     return PythonUnitTestDetectorsKt.isUnitTestCaseClass(pyClass, TypeEvalContext.codeInsightFallback(pyClass.getProject()));
95   }
96
97   /**
98    * @deprecated use {@link PythonUnitTestDetectorsBasedOnSettings#isTestClass(PyClass, ThreeState, TypeEvalContext)}
99    */
100   @Deprecated
101   @ApiStatus.ScheduledForRemoval(inVersion = "2021.1")
102   public static boolean isTestClass(@NotNull final PyClass cls,
103                                     @NotNull final ThreeState testCaseClassRequired,
104                                     @Nullable TypeEvalContext context) {
105     return PythonUnitTestDetectorsBasedOnSettings.isTestClass(cls, testCaseClassRequired, context);
106   }
107 }