All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.junit.jupiter.engine.discovery.JavaElementsResolver Maven / Gradle / Ivy

There is a newer version: 5.11.0
Show newest version
/*
 * 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);
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy