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

org.junit.platform.launcher.TestPlan Maven / Gradle / Ivy

/*
 * Copyright 2015-2019 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 v2.0 which
 * accompanies this distribution and is available at
 *
 * https://www.eclipse.org/legal/epl-v20.html
 */

package org.junit.platform.launcher;

import static java.util.Collections.emptySet;
import static java.util.Collections.unmodifiableSet;
import static org.apiguardian.api.API.Status.DEPRECATED;
import static org.apiguardian.api.API.Status.INTERNAL;
import static org.apiguardian.api.API.Status.STABLE;

import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;

import org.apiguardian.api.API;
import org.junit.platform.commons.PreconditionViolationException;
import org.junit.platform.commons.util.Preconditions;
import org.junit.platform.engine.TestDescriptor;
import org.junit.platform.engine.TestDescriptor.Visitor;

/**
 * {@code TestPlan} describes the tree of tests and containers as discovered
 * by a {@link Launcher}.
 *
 * 

Tests and containers are represented by {@link TestIdentifier} instances. * The complete set of identifiers comprises a tree-like structure. However, * each identifier only stores the unique ID of its parent. This class provides * a number of helpful methods to retrieve the * {@linkplain #getParent(TestIdentifier) parent}, * {@linkplain #getChildren(TestIdentifier) children}, and * {@linkplain #getDescendants(TestIdentifier) descendants} of an identifier. * *

While the contained instances of {@link TestIdentifier} are immutable, * instances of this class contain mutable state. For example, when a dynamic * test is registered at runtime, it is added to the original test plan and * reported to {@link TestExecutionListener} implementations. * *

This class is not intended to be extended by clients. * * @since 1.0 * @see Launcher * @see TestExecutionListener */ @API(status = STABLE, since = "1.0") public class TestPlan { private final Set roots = Collections.synchronizedSet(new LinkedHashSet<>(4)); private final Map> children = new ConcurrentHashMap<>(32); private final Map allIdentifiers = new ConcurrentHashMap<>(32); private final boolean containsTests; /** * Construct a new {@code TestPlan} from the supplied collection of * {@link TestDescriptor TestDescriptors}. * *

Each supplied {@code TestDescriptor} is expected to be a descriptor * for a {@link org.junit.platform.engine.TestEngine TestEngine}. * * @param engineDescriptors the engine test descriptors from which the test * plan should be created; never {@code null} * @return a new test plan */ @API(status = INTERNAL, since = "1.0") public static TestPlan from(Collection engineDescriptors) { Preconditions.notNull(engineDescriptors, "Cannot create TestPlan from a null collection of TestDescriptors"); TestPlan testPlan = new TestPlan(engineDescriptors.stream().anyMatch(TestDescriptor::containsTests)); Visitor visitor = descriptor -> testPlan.add(TestIdentifier.from(descriptor)); engineDescriptors.forEach(engineDescriptor -> engineDescriptor.accept(visitor)); return testPlan; } @API(status = INTERNAL, since = "1.4") protected TestPlan(boolean containsTests) { this.containsTests = containsTests; } /** * Add the supplied {@link TestIdentifier} to this test plan. * * @param testIdentifier the identifier to add; never {@code null} * @deprecated without replacement since this method was intended to be internal. */ @Deprecated @API(status = DEPRECATED, since = "1.4") public void add(TestIdentifier testIdentifier) { Preconditions.notNull(testIdentifier, "testIdentifier must not be null"); allIdentifiers.put(testIdentifier.getUniqueId(), testIdentifier); if (testIdentifier.getParentId().isPresent()) { String parentId = testIdentifier.getParentId().get(); Set directChildren = children.computeIfAbsent(parentId, key -> Collections.synchronizedSet(new LinkedHashSet<>(16))); directChildren.add(testIdentifier); } else { roots.add(testIdentifier); } } /** * Get the root {@link TestIdentifier TestIdentifiers} for this test plan. * * @return an unmodifiable set of the root identifiers */ public Set getRoots() { return unmodifiableSet(roots); } /** * Get the parent of the supplied {@link TestIdentifier}. * * @param child the identifier to look up the parent for; never {@code null} * @return an {@code Optional} containing the parent, if present */ public Optional getParent(TestIdentifier child) { Preconditions.notNull(child, "child must not be null"); return child.getParentId().map(this::getTestIdentifier); } /** * Get the children of the supplied {@link TestIdentifier}. * * @param parent the identifier to look up the children for; never {@code null} * @return an unmodifiable set of the parent's children, potentially empty * @see #getChildren(String) */ public Set getChildren(TestIdentifier parent) { Preconditions.notNull(parent, "parent must not be null"); return getChildren(parent.getUniqueId()); } /** * Get the children of the supplied unique ID. * * @param parentId the unique ID to look up the children for; never * {@code null} or blank * @return an unmodifiable set of the parent's children, potentially empty * @see #getChildren(TestIdentifier) */ public Set getChildren(String parentId) { Preconditions.notBlank(parentId, "parent ID must not be null or blank"); return children.containsKey(parentId) ? unmodifiableSet(children.get(parentId)) : emptySet(); } /** * Get the {@link TestIdentifier} with the supplied unique ID. * * @param uniqueId the unique ID to look up the identifier for; never * {@code null} or blank * @return the identifier with the supplied unique ID; never {@code null} * @throws PreconditionViolationException if no {@code TestIdentifier} * with the supplied unique ID is present in this test plan */ public TestIdentifier getTestIdentifier(String uniqueId) throws PreconditionViolationException { Preconditions.notBlank(uniqueId, "unique ID must not be null or blank"); Preconditions.condition(allIdentifiers.containsKey(uniqueId), () -> "No TestIdentifier with unique ID [" + uniqueId + "] has been added to this TestPlan."); return allIdentifiers.get(uniqueId); } /** * Count all {@link TestIdentifier TestIdentifiers} that satisfy the * given {@linkplain Predicate predicate}. * * @param predicate a predicate which returns {@code true} for identifiers * to be counted; never {@code null} * @return the number of identifiers that satisfy the supplied predicate */ public long countTestIdentifiers(Predicate predicate) { Preconditions.notNull(predicate, "Predicate must not be null"); return allIdentifiers.values().stream().filter(predicate).count(); } /** * Get all descendants of the supplied {@link TestIdentifier} (i.e., * all of its children and their children, recursively). * * @param parent the identifier to look up the descendants for; never {@code null} * @return an unmodifiable set of the parent's descendants, potentially empty */ public Set getDescendants(TestIdentifier parent) { Preconditions.notNull(parent, "parent must not be null"); Set result = new LinkedHashSet<>(16); Set children = getChildren(parent); result.addAll(children); for (TestIdentifier child : children) { result.addAll(getDescendants(child)); } return unmodifiableSet(result); } /** * Return whether this test plan contains any tests. * *

A test plan contains tests, if at least one of the contained engine * descriptors {@linkplain TestDescriptor#containsTests(TestDescriptor) * contains tests}. * * @return {@code true} if this test plan contains tests * @see TestDescriptor#containsTests(TestDescriptor) */ public boolean containsTests() { return containsTests; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy