/* * Copyright 2015-2017 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.platform.runner; import static java.util.stream.Collectors.toCollection; import static java.util.stream.Collectors.toSet; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Optional; import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; import org.junit.platform.commons.util.StringUtils; import org.junit.platform.engine.TestSource; import org.junit.platform.engine.support.descriptor.ClassSource; import org.junit.platform.engine.support.descriptor.MethodSource; import org.junit.platform.launcher.TestIdentifier; import org.junit.platform.launcher.TestPlan; import org.junit.platform.suite.api.UseTechnicalNames; import org.junit.runner.Description; import org.junit.runner.manipulation.Filter; /** * @since 1.0 */ class JUnitPlatformTestTree { private final Map<TestIdentifier, Description> descriptions = new HashMap<>(); private final TestPlan plan; private final Function<TestIdentifier, String> nameExtractor; private final Description suiteDescription; JUnitPlatformTestTree(TestPlan plan, Class<?> testClass) { this.plan = plan; this.nameExtractor = useTechnicalNames(testClass) ? this::getTechnicalName : TestIdentifier::getDisplayName; this.suiteDescription = generateSuiteDescription(plan, testClass); } private static boolean useTechnicalNames(Class<?> testClass) { return testClass.isAnnotationPresent(UseTechnicalNames.class); } Description getSuiteDescription() { return this.suiteDescription; } Description getDescription(TestIdentifier identifier) { return this.descriptions.get(identifier); } private Description generateSuiteDescription(TestPlan testPlan, Class<?> testClass) { Description suiteDescription = Description.createSuiteDescription(testClass.getName()); buildDescriptionTree(suiteDescription, testPlan); return suiteDescription; } private void buildDescriptionTree(Description suiteDescription, TestPlan testPlan) { testPlan.getRoots().forEach(testIdentifier -> buildDescription(testIdentifier, suiteDescription, testPlan)); } void addDynamicDescription(TestIdentifier newIdentifier, String parentId) { Description parent = getDescription(this.plan.getTestIdentifier(parentId)); this.plan.add(newIdentifier); buildDescription(newIdentifier, parent, this.plan); } private void buildDescription(TestIdentifier identifier, Description parent, TestPlan testPlan) { Description newDescription = createJUnit4Description(identifier, testPlan); parent.addChild(newDescription); this.descriptions.put(identifier, newDescription); testPlan.getChildren(identifier).forEach( testIdentifier -> buildDescription(testIdentifier, newDescription, testPlan)); } private Description createJUnit4Description(TestIdentifier identifier, TestPlan testPlan) { String name = nameExtractor.apply(identifier); if (identifier.isTest()) { String containerName = testPlan.getParent(identifier).map(nameExtractor).orElse("<unrooted>"); return Description.createTestDescription(containerName, name, identifier.getUniqueId()); } return Description.createSuiteDescription(name, identifier.getUniqueId()); } private String getTechnicalName(TestIdentifier testIdentifier) { Optional<TestSource> optionalSource = testIdentifier.getSource(); if (optionalSource.isPresent()) { TestSource source = optionalSource.get(); if (source instanceof ClassSource) { return ((ClassSource) source).getJavaClass().getName(); } else if (source instanceof MethodSource) { MethodSource methodSource = (MethodSource) source; String methodParameterTypes = methodSource.getMethodParameterTypes(); if (StringUtils.isBlank(methodParameterTypes)) { return methodSource.getMethodName(); } else { return String.format("%s(%s)", methodSource.getMethodName(), methodParameterTypes); } } } // Else fall back to display name return testIdentifier.getDisplayName(); } Set<TestIdentifier> getTestsInSubtree(TestIdentifier ancestor) { // @formatter:off return plan.getDescendants(ancestor).stream() .filter(TestIdentifier::isTest) .collect(toCollection(LinkedHashSet::new)); // @formatter:on } Set<TestIdentifier> getFilteredLeaves(Filter filter) { Set<TestIdentifier> identifiers = applyFilterToDescriptions(filter); return removeNonLeafIdentifiers(identifiers); } private Set<TestIdentifier> removeNonLeafIdentifiers(Set<TestIdentifier> identifiers) { return identifiers.stream().filter(isALeaf(identifiers)).collect(toSet()); } private Predicate<? super TestIdentifier> isALeaf(Set<TestIdentifier> identifiers) { return testIdentifier -> { Set<TestIdentifier> descendants = plan.getDescendants(testIdentifier); return identifiers.stream().noneMatch(descendants::contains); }; } private Set<TestIdentifier> applyFilterToDescriptions(Filter filter) { // @formatter:off return descriptions.entrySet() .stream() .filter(entry -> filter.shouldRun(entry.getValue())) .map(Entry::getKey) .collect(toSet()); // @formatter:on } }