Skip to content

Commit 1f1556a

Browse files
committed
Report discovery issues for invalid test classes
Issue: #242
1 parent b514c5b commit 1f1556a

File tree

17 files changed

+742
-658
lines changed

17 files changed

+742
-658
lines changed

junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassTemplateTestDescriptor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
@API(status = INTERNAL, since = "5.13")
5252
public class ClassTemplateTestDescriptor extends ClassBasedTestDescriptor implements Filterable {
5353

54-
public static final String STATIC_CLASS_SEGMENT_TYPE = "class-template";
54+
public static final String STANDALONE_CLASS_SEGMENT_TYPE = "class-template";
5555
public static final String NESTED_CLASS_SEGMENT_TYPE = "nested-class-template";
5656

5757
private final Map<Integer, Collection<? extends TestDescriptor>> childrenPrototypesByIndex = new HashMap<>();

junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/ClassSelectorResolver.java

Lines changed: 42 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import static java.util.stream.Collectors.toCollection;
1616
import static java.util.stream.Collectors.toSet;
1717
import static org.junit.jupiter.engine.descriptor.NestedClassTestDescriptor.getEnclosingTestClasses;
18-
import static org.junit.platform.commons.support.AnnotationSupport.isAnnotated;
1918
import static org.junit.platform.commons.support.HierarchyTraversalMode.TOP_DOWN;
2019
import static org.junit.platform.commons.support.ReflectionSupport.findMethods;
2120
import static org.junit.platform.commons.support.ReflectionSupport.streamNestedClasses;
@@ -34,7 +33,6 @@
3433
import java.util.function.Supplier;
3534
import java.util.stream.Stream;
3635

37-
import org.junit.jupiter.api.ClassTemplate;
3836
import org.junit.jupiter.api.extension.ClassTemplateInvocationContext;
3937
import org.junit.jupiter.engine.config.JupiterConfiguration;
4038
import org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor;
@@ -44,7 +42,7 @@
4442
import org.junit.jupiter.engine.descriptor.Filterable;
4543
import org.junit.jupiter.engine.descriptor.NestedClassTestDescriptor;
4644
import org.junit.jupiter.engine.descriptor.TestClassAware;
47-
import org.junit.jupiter.engine.discovery.predicates.IsTestClassWithTests;
45+
import org.junit.jupiter.engine.discovery.predicates.TestClassPredicates;
4846
import org.junit.platform.commons.support.ReflectionSupport;
4947
import org.junit.platform.engine.DiscoverySelector;
5048
import org.junit.platform.engine.TestDescriptor;
@@ -62,41 +60,45 @@
6260
*/
6361
class ClassSelectorResolver implements SelectorResolver {
6462

65-
private static final Predicate<Class<?>> isAnnotatedWithClassTemplate = testClass -> isAnnotated(testClass,
66-
ClassTemplate.class);
67-
68-
private final IsTestClassWithTests isTestClassWithTests;
69-
7063
private final Predicate<String> classNameFilter;
7164
private final JupiterConfiguration configuration;
65+
private final TestClassPredicates predicates;
7266

7367
ClassSelectorResolver(Predicate<String> classNameFilter, JupiterConfiguration configuration,
7468
DiscoveryIssueReporter issueReporter) {
7569
this.classNameFilter = classNameFilter;
7670
this.configuration = configuration;
77-
this.isTestClassWithTests = new IsTestClassWithTests(issueReporter);
71+
this.predicates = new TestClassPredicates(issueReporter);
7872
}
7973

8074
@Override
8175
public Resolution resolve(ClassSelector selector, Context context) {
8276
Class<?> testClass = selector.getJavaClass();
83-
if (this.isTestClassWithTests.test(testClass)) {
84-
// Nested tests are never filtered out
85-
if (classNameFilter.test(testClass.getName())) {
77+
78+
if (this.predicates.isAnnotatedWithNested.test(testClass)) {
79+
// Class name filter is not applied to nested test classes
80+
if (this.predicates.isValidNestedTestClass(testClass)) {
8681
return toResolution(
87-
context.addToParent(parent -> Optional.of(newStaticClassTestDescriptor(parent, testClass))));
82+
context.addToParent(() -> DiscoverySelectors.selectClass(testClass.getEnclosingClass()),
83+
parent -> Optional.of(newMemberClassTestDescriptor(parent, testClass))));
8884
}
8985
}
90-
else if (this.isTestClassWithTests.isNestedTestClass.test(testClass)) {
91-
return toResolution(context.addToParent(() -> DiscoverySelectors.selectClass(testClass.getEnclosingClass()),
92-
parent -> Optional.of(newMemberClassTestDescriptor(parent, testClass))));
86+
else if (isAcceptedStandaloneTestClass(testClass)) {
87+
return toResolution(
88+
context.addToParent(parent -> Optional.of(newStandaloneClassTestDescriptor(parent, testClass))));
9389
}
9490
return unresolved();
9591
}
9692

93+
private boolean isAcceptedStandaloneTestClass(Class<?> testClass) {
94+
return this.classNameFilter.test(testClass.getName()) //
95+
&& this.predicates.looksLikeIntendedTestClass(testClass) //
96+
&& this.predicates.isValidStandaloneTestClass(testClass);
97+
}
98+
9799
@Override
98100
public Resolution resolve(NestedClassSelector selector, Context context) {
99-
if (this.isTestClassWithTests.isNestedTestClass.test(selector.getNestedClass())) {
101+
if (this.predicates.isAnnotatedWithNestedAndValid.test(selector.getNestedClass())) {
100102
return toResolution(context.addToParent(() -> selectClass(selector.getEnclosingClasses()),
101103
parent -> Optional.of(newMemberClassTestDescriptor(parent, selector.getNestedClass()))));
102104
}
@@ -108,17 +110,17 @@ public Resolution resolve(UniqueIdSelector selector, Context context) {
108110
UniqueId uniqueId = selector.getUniqueId();
109111
UniqueId.Segment lastSegment = uniqueId.getLastSegment();
110112
if (ClassTestDescriptor.SEGMENT_TYPE.equals(lastSegment.getType())) {
111-
return resolveStaticClassUniqueId(context, lastSegment, __ -> true, this::newClassTestDescriptor);
113+
return resolveStandaloneClassUniqueId(context, lastSegment, __ -> true, this::newClassTestDescriptor);
112114
}
113-
if (ClassTemplateTestDescriptor.STATIC_CLASS_SEGMENT_TYPE.equals(lastSegment.getType())) {
114-
return resolveStaticClassUniqueId(context, lastSegment, isAnnotatedWithClassTemplate,
115-
this::newStaticClassTemplateTestDescriptor);
115+
if (ClassTemplateTestDescriptor.STANDALONE_CLASS_SEGMENT_TYPE.equals(lastSegment.getType())) {
116+
return resolveStandaloneClassUniqueId(context, lastSegment, this.predicates.isAnnotatedWithClassTemplate,
117+
this::newClassTemplateTestDescriptor);
116118
}
117119
if (NestedClassTestDescriptor.SEGMENT_TYPE.equals(lastSegment.getType())) {
118120
return resolveNestedClassUniqueId(context, uniqueId, __ -> true, this::newNestedClassTestDescriptor);
119121
}
120122
if (ClassTemplateTestDescriptor.NESTED_CLASS_SEGMENT_TYPE.equals(lastSegment.getType())) {
121-
return resolveNestedClassUniqueId(context, uniqueId, isAnnotatedWithClassTemplate,
123+
return resolveNestedClassUniqueId(context, uniqueId, this.predicates.isAnnotatedWithClassTemplate,
122124
this::newNestedClassTemplateTestDescriptor);
123125
}
124126
if (ClassTemplateInvocationTestDescriptor.SEGMENT_TYPE.equals(lastSegment.getType())) {
@@ -138,11 +140,11 @@ public Resolution resolve(UniqueIdSelector selector, Context context) {
138140
public Resolution resolve(IterationSelector selector, Context context) {
139141
DiscoverySelector parentSelector = selector.getParentSelector();
140142
if (parentSelector instanceof ClassSelector
141-
&& isAnnotatedWithClassTemplate.test(((ClassSelector) parentSelector).getJavaClass())) {
143+
&& this.predicates.isAnnotatedWithClassTemplate.test(((ClassSelector) parentSelector).getJavaClass())) {
142144
return resolveIterations(selector, context);
143145
}
144-
if (parentSelector instanceof NestedClassSelector
145-
&& isAnnotatedWithClassTemplate.test(((NestedClassSelector) parentSelector).getNestedClass())) {
146+
if (parentSelector instanceof NestedClassSelector && this.predicates.isAnnotatedWithClassTemplate.test(
147+
((NestedClassSelector) parentSelector).getNestedClass())) {
146148
return resolveIterations(selector, context);
147149
}
148150
return unresolved();
@@ -160,13 +162,13 @@ private Resolution resolveIterations(IterationSelector selector, Context context
160162
return matches.isEmpty() ? unresolved() : Resolution.matches(matches);
161163
}
162164

163-
private Resolution resolveStaticClassUniqueId(Context context, UniqueId.Segment lastSegment,
165+
private Resolution resolveStandaloneClassUniqueId(Context context, UniqueId.Segment lastSegment,
164166
Predicate<? super Class<?>> condition,
165167
BiFunction<TestDescriptor, Class<?>, ClassBasedTestDescriptor> factory) {
166168

167169
String className = lastSegment.getValue();
168170
return ReflectionSupport.tryToLoadClass(className).toOptional() //
169-
.filter(this.isTestClassWithTests) //
171+
.filter(this.predicates::isValidStandaloneTestClass) //
170172
.filter(condition) //
171173
.map(testClass -> toResolution(
172174
context.addToParent(parent -> Optional.of(factory.apply(parent, testClass))))) //
@@ -180,8 +182,9 @@ private Resolution resolveNestedClassUniqueId(Context context, UniqueId uniqueId
180182
String simpleClassName = uniqueId.getLastSegment().getValue();
181183
return toResolution(context.addToParent(() -> selectUniqueId(uniqueId.removeLastSegment()), parent -> {
182184
Class<?> parentTestClass = ((TestClassAware) parent).getTestClass();
183-
return ReflectionSupport.findNestedClasses(parentTestClass, this.isTestClassWithTests.isNestedTestClass.and(
184-
where(Class::getSimpleName, isEqual(simpleClassName)))).stream() //
185+
return ReflectionSupport.findNestedClasses(parentTestClass,
186+
this.predicates.isAnnotatedWithNestedAndValid.and(
187+
where(Class::getSimpleName, isEqual(simpleClassName)))).stream() //
185188
.findFirst() //
186189
.filter(condition) //
187190
.map(testClass -> factory.apply(parent, testClass));
@@ -196,15 +199,14 @@ private ClassTemplateInvocationTestDescriptor newDummyClassTemplateInvocationTes
196199
DummyClassTemplateInvocationContext.INSTANCE, index, parent.getSource().orElse(null), configuration);
197200
}
198201

199-
private ClassBasedTestDescriptor newStaticClassTestDescriptor(TestDescriptor parent, Class<?> testClass) {
200-
return isAnnotatedWithClassTemplate.test(testClass) //
201-
? newStaticClassTemplateTestDescriptor(parent, testClass) //
202+
private ClassBasedTestDescriptor newStandaloneClassTestDescriptor(TestDescriptor parent, Class<?> testClass) {
203+
return this.predicates.isAnnotatedWithClassTemplate.test(testClass) //
204+
? newClassTemplateTestDescriptor(parent, testClass) //
202205
: newClassTestDescriptor(parent, testClass);
203206
}
204207

205-
private ClassTemplateTestDescriptor newStaticClassTemplateTestDescriptor(TestDescriptor parent,
206-
Class<?> testClass) {
207-
return newClassTemplateTestDescriptor(parent, ClassTemplateTestDescriptor.STATIC_CLASS_SEGMENT_TYPE,
208+
private ClassTemplateTestDescriptor newClassTemplateTestDescriptor(TestDescriptor parent, Class<?> testClass) {
209+
return newClassTemplateTestDescriptor(parent, ClassTemplateTestDescriptor.STANDALONE_CLASS_SEGMENT_TYPE,
208210
newClassTestDescriptor(parent, testClass));
209211
}
210212

@@ -215,7 +217,7 @@ private ClassTestDescriptor newClassTestDescriptor(TestDescriptor parent, Class<
215217
}
216218

217219
private ClassBasedTestDescriptor newMemberClassTestDescriptor(TestDescriptor parent, Class<?> testClass) {
218-
return isAnnotatedWithClassTemplate.test(testClass) //
220+
return this.predicates.isAnnotatedWithClassTemplate.test(testClass) //
219221
? newNestedClassTemplateTestDescriptor(parent, testClass) //
220222
: newNestedClassTestDescriptor(parent, testClass);
221223
}
@@ -273,11 +275,11 @@ private Supplier<Set<? extends DiscoverySelector>> expansionCallback(TestDescrip
273275
List<Class<?>> testClasses = testClassesSupplier.get();
274276
Class<?> testClass = testClasses.get(testClasses.size() - 1);
275277
Stream<DiscoverySelector> methods = findMethods(testClass,
276-
this.isTestClassWithTests.isTestOrTestFactoryOrTestTemplateMethod, TOP_DOWN).stream().map(
277-
method -> selectMethod(testClasses, method));
278+
this.predicates.isTestOrTestFactoryOrTestTemplateMethod, TOP_DOWN).stream() //
279+
.map(method -> selectMethod(testClasses, method));
278280
Stream<NestedClassSelector> nestedClasses = streamNestedClasses(testClass,
279-
this.isTestClassWithTests.isNestedTestClass).map(
280-
nestedClass -> DiscoverySelectors.selectNestedClass(testClasses, nestedClass));
281+
this.predicates.isAnnotatedWithNestedAndValid) //
282+
.map(nestedClass -> DiscoverySelectors.selectNestedClass(testClasses, nestedClass));
281283
return Stream.concat(methods, nestedClasses).collect(
282284
toCollection((Supplier<Set<DiscoverySelector>>) LinkedHashSet::new));
283285
};

junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/DiscoverySelectorResolver.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import org.junit.jupiter.engine.config.JupiterConfiguration;
1717
import org.junit.jupiter.engine.descriptor.JupiterEngineDescriptor;
1818
import org.junit.jupiter.engine.descriptor.Validatable;
19-
import org.junit.jupiter.engine.discovery.predicates.IsTestClassWithTests;
19+
import org.junit.jupiter.engine.discovery.predicates.TestClassPredicates;
2020
import org.junit.platform.engine.EngineDiscoveryRequest;
2121
import org.junit.platform.engine.TestDescriptor;
2222
import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter;
@@ -38,7 +38,8 @@
3838
public class DiscoverySelectorResolver {
3939

4040
private static final EngineDiscoveryRequestResolver<JupiterEngineDescriptor> resolver = EngineDiscoveryRequestResolver.<JupiterEngineDescriptor> builder() //
41-
.addClassContainerSelectorResolverWithContext(ctx -> new IsTestClassWithTests(ctx.getIssueReporter())) //
41+
.addClassContainerSelectorResolverWithContext(
42+
ctx -> new TestClassPredicates(ctx.getIssueReporter()).looksLikeNestedOrStandaloneTestClass) //
4243
.addSelectorResolver(ctx -> new ClassSelectorResolver(ctx.getClassNameFilter(), getConfiguration(ctx),
4344
ctx.getIssueReporter())) //
4445
.addSelectorResolver(ctx -> new MethodSelectorResolver(getConfiguration(ctx), ctx.getIssueReporter())) //

junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/MethodSelectorResolver.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@
3636
import org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor;
3737
import org.junit.jupiter.engine.descriptor.TestTemplateInvocationTestDescriptor;
3838
import org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor;
39-
import org.junit.jupiter.engine.discovery.predicates.IsTestClassWithTests;
4039
import org.junit.jupiter.engine.discovery.predicates.IsTestFactoryMethod;
4140
import org.junit.jupiter.engine.discovery.predicates.IsTestMethod;
4241
import org.junit.jupiter.engine.discovery.predicates.IsTestTemplateMethod;
42+
import org.junit.jupiter.engine.discovery.predicates.TestClassPredicates;
4343
import org.junit.platform.commons.util.ClassUtils;
4444
import org.junit.platform.engine.DiscoveryIssue;
4545
import org.junit.platform.engine.DiscoveryIssue.Severity;
@@ -71,8 +71,7 @@ class MethodSelectorResolver implements SelectorResolver {
7171
this.configuration = configuration;
7272
this.issueReporter = issueReporter;
7373
this.methodTypes = MethodType.allPossibilities(issueReporter);
74-
IsTestClassWithTests classPredicate = new IsTestClassWithTests(issueReporter);
75-
this.testClassPredicate = classPredicate.or(classPredicate.isNestedTestClass);
74+
this.testClassPredicate = new TestClassPredicates(issueReporter).looksLikeNestedOrStandaloneTestClass;
7675
}
7776

7877
@Override

junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsInnerClass.java

Lines changed: 0 additions & 42 deletions
This file was deleted.

junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsNestedTestClass.java

Lines changed: 0 additions & 43 deletions
This file was deleted.

junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/discovery/predicates/IsPotentialTestContainer.java

Lines changed: 0 additions & 49 deletions
This file was deleted.

0 commit comments

Comments
 (0)