Cleanup: NotNull/Nullable
[idea/community.git] / java / execution / impl / src / com / intellij / execution / testDiscovery / TestDiscoveryProducer.java
1 // 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.
2 package com.intellij.execution.testDiscovery;
3
4 import com.intellij.openapi.diagnostic.Logger;
5 import com.intellij.openapi.extensions.ExtensionPointName;
6 import com.intellij.openapi.project.Project;
7 import com.intellij.openapi.util.Couple;
8 import com.intellij.psi.PsiClass;
9 import com.intellij.psi.PsiMethod;
10 import com.intellij.util.Consumer;
11 import com.intellij.util.containers.ContainerUtil;
12 import com.intellij.util.containers.MultiMap;
13 import gnu.trove.THashSet;
14 import org.jetbrains.annotations.ApiStatus;
15 import org.jetbrains.annotations.NotNull;
16 import org.jetbrains.annotations.Nullable;
17
18 import java.io.IOException;
19 import java.util.Collection;
20 import java.util.List;
21 import java.util.Map;
22
23 @ApiStatus.Experimental
24 public interface TestDiscoveryProducer {
25   ExtensionPointName<TestDiscoveryProducer> EP = ExtensionPointName.create("com.intellij.testDiscoveryProducer");
26
27   Logger LOG = Logger.getInstance(LocalTestDiscoveryProducer.class);
28
29   @NotNull
30   MultiMap<String, String> getDiscoveredTests(@NotNull Project project,
31                                               @NotNull List<Couple<String>> classesAndMethods,
32                                               byte frameworkId);
33
34   @NotNull
35   MultiMap<String, String> getDiscoveredTestsForFiles(@NotNull Project project,
36                                                       @NotNull List<String> paths,
37                                                       byte frameworkId);
38
39   boolean isRemote();
40
41   static void consumeDiscoveredTests(@NotNull Project project,
42                                      @NotNull List<Couple<String>> classesAndMethods,
43                                      byte frameworkId,
44                                      @NotNull List<String> filePaths,
45                                      @NotNull TestProcessor processor) {
46     MultiMap<String, String> visitedTests = new MultiMap<String, String>() {
47       @NotNull
48       @Override
49       protected Collection<String> createCollection() {
50         return new THashSet<>();
51       }
52     };
53     for (TestDiscoveryProducer producer : EP.getExtensionList()) {
54       for (Map.Entry<String, Collection<String>> entry : ContainerUtil.concat(
55         producer.getDiscoveredTests(project, classesAndMethods, frameworkId).entrySet(),
56         producer.getDiscoveredTestsForFiles(project, filePaths, frameworkId).entrySet())) {
57         String className = entry.getKey();
58         for (String methodRawName : entry.getValue()) {
59           if (!visitedTests.get(className).contains(methodRawName)) {
60             visitedTests.putValue(className, methodRawName);
61             Couple<String> couple = extractParameter(methodRawName);
62             if (!processor.process(className, couple.first, couple.second)) return;
63           }
64         }
65       }
66     }
67   }
68
69   @NotNull
70   List<String> getAffectedFilePaths(@NotNull Project project, @NotNull List<Couple<String>> testFqns, byte frameworkId) throws IOException;
71
72   @NotNull
73   List<String> getAffectedFilePathsByClassName(@NotNull Project project, @NotNull String testClassNames, byte frameworkId) throws IOException;
74
75   @NotNull
76   List<String> getFilesWithoutTests(@NotNull Project project, @NotNull Collection<String> paths) throws IOException;
77
78   // testFqn - (className, methodName)
79   static void consumeAffectedPaths(@NotNull Project project, @NotNull List<Couple<String>> testFqns, @NotNull Consumer<? super String> pathsConsumer, byte frameworkId) throws IOException {
80     for (TestDiscoveryProducer extension : EP.getExtensionList()) {
81       for (String path : extension.getAffectedFilePaths(project, testFqns, frameworkId)) {
82         pathsConsumer.consume(path);
83       }
84     }
85   }
86
87   static void consumeAffectedPaths(@NotNull Project project, @NotNull String testClassName, @NotNull Consumer<? super String> pathsConsumer, byte frameworkId) throws IOException {
88     for (TestDiscoveryProducer extension : EP.getExtensionList()) {
89       for (String path : extension.getAffectedFilePathsByClassName(project, testClassName, frameworkId)) {
90         pathsConsumer.consume(path);
91       }
92     }
93   }
94
95   @NotNull
96   static Couple<String> extractParameter(@NotNull String rawName) {
97     int idx = rawName.indexOf('[');
98     return idx == -1 ?
99            Couple.of(rawName, null) :
100            Couple.of(rawName.substring(0, idx), rawName.substring(idx));
101   }
102
103
104   @FunctionalInterface
105   interface TestProcessor {
106     boolean process(@NotNull String className, @NotNull String methodName, @Nullable String parameter);
107   }
108
109   @FunctionalInterface
110   interface PsiTestProcessor {
111     boolean process(@NotNull PsiClass clazz, @Nullable PsiMethod method, @Nullable String parameter);
112   }
113 }