org.junit.jupiter.engine.discovery.JavaElementsResolver Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of junit-jupiter-engine Show documentation
Show all versions of junit-jupiter-engine Show documentation
Module "junit-jupiter-engine" of JUnit 5.
/*
* Copyright 2015-2016 the original author or authors.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.junit.jupiter.engine.discovery;
import static java.lang.String.format;
import static org.junit.platform.commons.meta.API.Usage.Experimental;
import static org.junit.platform.commons.util.ReflectionUtils.findMethods;
import static org.junit.platform.commons.util.ReflectionUtils.findNestedClasses;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.junit.jupiter.engine.descriptor.ClassTestDescriptor;
import org.junit.jupiter.engine.discovery.predicates.IsInnerClass;
import org.junit.platform.commons.meta.API;
import org.junit.platform.commons.util.ReflectionUtils;
import org.junit.platform.engine.TestDescriptor;
import org.junit.platform.engine.UniqueId;
/**
* @since 5.0
*/
@API(Experimental)
class JavaElementsResolver {
private static final Logger LOG = Logger.getLogger(JavaElementsResolver.class.getName());
private static final IsInnerClass isInnerClass = new IsInnerClass();
private final TestDescriptor engineDescriptor;
private final Set resolvers;
JavaElementsResolver(TestDescriptor engineDescriptor, Set resolvers) {
this.engineDescriptor = engineDescriptor;
this.resolvers = resolvers;
}
void resolveClass(Class testClass) {
Set resolvedDescriptors = resolveContainerWithParents(testClass);
resolvedDescriptors.forEach(this::resolveChildren);
if (resolvedDescriptors.isEmpty()) {
LOG.warning(() -> format("Class '%s' could not be resolved", testClass.getName()));
}
}
void resolveMethod(Class testClass, Method testMethod) {
Set potentialParents = resolveContainerWithParents(testClass);
Set resolvedDescriptors = resolveForAllParents(testMethod, potentialParents);
if (resolvedDescriptors.isEmpty()) {
LOG.warning(() -> format("Method '%s' could not be resolved", testMethod.toGenericString()));
}
}
private Set resolveContainerWithParents(Class testClass) {
if (isInnerClass.test(testClass)) {
Set potentialParents = resolveContainerWithParents(testClass.getDeclaringClass());
return resolveForAllParents(testClass, potentialParents);
}
else {
return resolveForAllParents(testClass, Collections.singleton(engineDescriptor));
}
}
void resolveUniqueId(UniqueId uniqueId) {
List segments = uniqueId.getSegments();
segments.remove(0); // Ignore engine unique ID
if (!resolveUniqueId(this.engineDescriptor, segments)) {
LOG.warning(() -> format("Unique ID '%s' could not be resolved", uniqueId));
}
}
/**
* Return true if all segments of unique ID could be resolved
*/
private boolean resolveUniqueId(TestDescriptor parent, List remainingSegments) {
if (remainingSegments.isEmpty()) {
resolveChildren(parent);
return true;
}
UniqueId.Segment head = remainingSegments.remove(0);
for (ElementResolver resolver : resolvers) {
Optional resolvedDescriptor = resolver.resolveUniqueId(head, parent);
if (!resolvedDescriptor.isPresent())
continue;
Optional foundTestDescriptor = findTestDescriptorByUniqueId(
resolvedDescriptor.get().getUniqueId());
TestDescriptor descriptor = foundTestDescriptor.orElseGet(() -> {
TestDescriptor newDescriptor = resolvedDescriptor.get();
parent.addChild(newDescriptor);
return newDescriptor;
});
return resolveUniqueId(descriptor, remainingSegments);
}
return false;
}
private Set resolveContainerWithChildren(Class containerClass,
Set potentialParents) {
Set resolvedDescriptors = resolveForAllParents(containerClass, potentialParents);
resolvedDescriptors.forEach(this::resolveChildren);
return resolvedDescriptors;
}
private Set resolveForAllParents(AnnotatedElement element, Set potentialParents) {
Set resolvedDescriptors = new HashSet<>();
potentialParents.forEach(parent -> {
resolvedDescriptors.addAll(resolve(element, parent));
});
return resolvedDescriptors;
}
private void resolveChildren(TestDescriptor descriptor) {
if (descriptor instanceof ClassTestDescriptor) {
Class testClass = ((ClassTestDescriptor) descriptor).getTestClass();
resolveContainedMethods(descriptor, testClass);
resolveContainedNestedClasses(descriptor, testClass);
}
}
private void resolveContainedNestedClasses(TestDescriptor containerDescriptor, Class clazz) {
List> nestedClassesCandidates = findNestedClasses(clazz, isInnerClass);
nestedClassesCandidates.forEach(
nestedClass -> resolveContainerWithChildren(nestedClass, Collections.singleton(containerDescriptor)));
}
private void resolveContainedMethods(TestDescriptor containerDescriptor, Class testClass) {
List testMethodCandidates = findMethods(testClass, method -> !ReflectionUtils.isPrivate(method),
ReflectionUtils.MethodSortOrder.HierarchyDown);
testMethodCandidates.forEach(method -> resolve(method, containerDescriptor));
}
private Set resolve(AnnotatedElement element, TestDescriptor parent) {
return this.resolvers.stream() //
.map(resolver -> tryToResolveWithResolver(element, parent, resolver)) //
.filter(testDescriptors -> !testDescriptors.isEmpty()) //
.flatMap(Collection::stream) //
.collect(Collectors.toSet());
}
private Set tryToResolveWithResolver(AnnotatedElement element, TestDescriptor parent,
ElementResolver resolver) {
Set resolvedDescriptors = resolver.resolveElement(element, parent);
resolvedDescriptors.forEach(testDescriptor -> {
Optional existingTestDescriptor = findTestDescriptorByUniqueId(
testDescriptor.getUniqueId());
if (!existingTestDescriptor.isPresent()) {
parent.addChild(testDescriptor);
}
});
return resolvedDescriptors;
}
@SuppressWarnings("unchecked")
private Optional findTestDescriptorByUniqueId(UniqueId uniqueId) {
return (Optional) this.engineDescriptor.findByUniqueId(uniqueId);
}
}