| /* |
| * Copyright 2015-2022 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.jupiter.api; |
| |
| import static java.util.Spliterator.ORDERED; |
| import static java.util.Spliterators.spliteratorUnknownSize; |
| import static org.apiguardian.api.API.Status.MAINTAINED; |
| |
| import java.net.URI; |
| import java.util.Iterator; |
| import java.util.function.Function; |
| import java.util.stream.Stream; |
| import java.util.stream.StreamSupport; |
| |
| import org.apiguardian.api.API; |
| import org.junit.jupiter.api.function.Executable; |
| import org.junit.jupiter.api.function.ThrowingConsumer; |
| import org.junit.platform.commons.util.Preconditions; |
| |
| /** |
| * A {@code DynamicTest} is a test case generated at runtime. |
| * |
| * <p>It is composed of a {@linkplain DynamicNode#getDisplayName display name} |
| * and an {@link #getExecutable Executable}. |
| * |
| * <p>Instances of {@code DynamicTest} must be generated by factory methods |
| * annotated with {@link TestFactory @TestFactory}. |
| * |
| * <p>Note that dynamic tests are quite different from standard {@link Test @Test} |
| * cases since callbacks such as {@link BeforeEach @BeforeEach} and |
| * {@link AfterEach @AfterEach} methods are not executed for dynamic tests. |
| * |
| * @since 5.0 |
| * @see #dynamicTest(String, Executable) |
| * @see #stream(Iterator, Function, ThrowingConsumer) |
| * @see Test |
| * @see TestFactory |
| * @see DynamicContainer |
| * @see Executable |
| */ |
| @API(status = MAINTAINED, since = "5.3") |
| public class DynamicTest extends DynamicNode { |
| |
| /** |
| * Factory for creating a new {@code DynamicTest} for the supplied display |
| * name and executable code block. |
| * |
| * @param displayName the display name for the dynamic test; never |
| * {@code null} or blank |
| * @param executable the executable code block for the dynamic test; |
| * never {@code null} |
| * @see #stream(Iterator, Function, ThrowingConsumer) |
| */ |
| public static DynamicTest dynamicTest(String displayName, Executable executable) { |
| return new DynamicTest(displayName, null, executable); |
| } |
| |
| /** |
| * Factory for creating a new {@code DynamicTest} for the supplied display |
| * name, custom test source {@link URI}, and executable code block. |
| * |
| * @param displayName the display name for the dynamic test; never |
| * {@code null} or blank |
| * @param testSourceUri a custom test source URI for the dynamic test; may |
| * be {@code null} if the framework should generate the test source based on |
| * the {@code @TestFactory} method |
| * @param executable the executable code block for the dynamic test; |
| * never {@code null} |
| * @since 5.3 |
| * @see #stream(Iterator, Function, ThrowingConsumer) |
| */ |
| public static DynamicTest dynamicTest(String displayName, URI testSourceUri, Executable executable) { |
| return new DynamicTest(displayName, testSourceUri, executable); |
| } |
| |
| /** |
| * Generate a stream of dynamic tests based on the given generator and test |
| * executor. |
| * |
| * <p>Use this method when the set of dynamic tests is nondeterministic in |
| * nature or when the input comes from an existing {@link Iterator}. See |
| * {@link #stream(Stream, Function, ThrowingConsumer)} as an alternative. |
| * |
| * <p>The given {@code inputGenerator} is responsible for generating |
| * input values. A {@link DynamicTest} will be added to the resulting |
| * stream for each dynamically generated input value, using the given |
| * {@code displayNameGenerator} and {@code testExecutor}. |
| * |
| * @param inputGenerator an {@code Iterator} that serves as a dynamic |
| * <em>input generator</em>; never {@code null} |
| * @param displayNameGenerator a function that generates a display name |
| * based on an input value; never {@code null} |
| * @param testExecutor a consumer that executes a test based on an input |
| * value; never {@code null} |
| * @param <T> the type of <em>input</em> generated by the {@code inputGenerator} |
| * and used by the {@code displayNameGenerator} and {@code testExecutor} |
| * @return a stream of dynamic tests based on the given generator and |
| * executor; never {@code null} |
| * @see #dynamicTest(String, Executable) |
| * @see #stream(Stream, Function, ThrowingConsumer) |
| */ |
| public static <T> Stream<DynamicTest> stream(Iterator<T> inputGenerator, |
| Function<? super T, String> displayNameGenerator, ThrowingConsumer<? super T> testExecutor) { |
| |
| Preconditions.notNull(inputGenerator, "inputGenerator must not be null"); |
| |
| return stream(StreamSupport.stream(spliteratorUnknownSize(inputGenerator, ORDERED), false), |
| displayNameGenerator, testExecutor); |
| } |
| |
| /** |
| * Generate a stream of dynamic tests based on the given input stream and |
| * test executor. |
| * |
| * <p>Use this method when the set of dynamic tests is nondeterministic in |
| * nature or when the input comes from an existing {@link Stream}. See |
| * {@link #stream(Iterator, Function, ThrowingConsumer)} as an alternative. |
| * |
| * <p>The given {@code inputStream} is responsible for supplying input values. |
| * A {@link DynamicTest} will be added to the resulting stream for each |
| * dynamically supplied input value, using the given {@code displayNameGenerator} |
| * and {@code testExecutor}. |
| * |
| * @param inputStream a {@code Stream} that supplies dynamic input values; |
| * never {@code null} |
| * @param displayNameGenerator a function that generates a display name |
| * based on an input value; never {@code null} |
| * @param testExecutor a consumer that executes a test based on an input |
| * value; never {@code null} |
| * @param <T> the type of <em>input</em> supplied by the {@code inputStream} |
| * and used by the {@code displayNameGenerator} and {@code testExecutor} |
| * @return a stream of dynamic tests based on the given generator and |
| * executor; never {@code null} |
| * @since 5.7 |
| * @see #dynamicTest(String, Executable) |
| * @see #stream(Iterator, Function, ThrowingConsumer) |
| */ |
| @API(status = MAINTAINED, since = "5.7") |
| public static <T> Stream<DynamicTest> stream(Stream<T> inputStream, |
| Function<? super T, String> displayNameGenerator, ThrowingConsumer<? super T> testExecutor) { |
| |
| Preconditions.notNull(inputStream, "inputStream must not be null"); |
| Preconditions.notNull(displayNameGenerator, "displayNameGenerator must not be null"); |
| Preconditions.notNull(testExecutor, "testExecutor must not be null"); |
| |
| return inputStream // |
| .map(input -> dynamicTest(displayNameGenerator.apply(input), () -> testExecutor.accept(input))); |
| } |
| |
| /** |
| * Generate a stream of dynamic tests based on the given generator and test |
| * executor. |
| * |
| * <p>Use this method when the set of dynamic tests is nondeterministic in |
| * nature or when the input comes from an existing {@link Iterator}. See |
| * {@link #stream(Stream, ThrowingConsumer)} as an alternative. |
| * |
| * <p>The given {@code inputGenerator} is responsible for generating |
| * input values and display names. A {@link DynamicTest} will be added to |
| * the resulting stream for each dynamically generated input value, |
| * using the given {@code testExecutor}. |
| * |
| * @param inputGenerator an {@code Iterator} with {@code Named} values |
| * that serves as a dynamic <em>input generator</em>; never {@code null} |
| * @param testExecutor a consumer that executes a test based on an input |
| * value; never {@code null} |
| * @param <T> the type of <em>input</em> generated by the {@code inputGenerator} |
| * and used by the {@code testExecutor} |
| * @return a stream of dynamic tests based on the given generator and |
| * executor; never {@code null} |
| * @since 5.8 |
| * |
| * @see #dynamicTest(String, Executable) |
| * @see #stream(Stream, ThrowingConsumer) |
| * @see Named |
| */ |
| @API(status = MAINTAINED, since = "5.8") |
| public static <T> Stream<DynamicTest> stream(Iterator<? extends Named<T>> inputGenerator, |
| ThrowingConsumer<? super T> testExecutor) { |
| Preconditions.notNull(inputGenerator, "inputGenerator must not be null"); |
| |
| return stream(StreamSupport.stream(spliteratorUnknownSize(inputGenerator, ORDERED), false), testExecutor); |
| } |
| |
| /** |
| * Generate a stream of dynamic tests based on the given input stream and |
| * test executor. |
| * |
| * <p>Use this method when the set of dynamic tests is nondeterministic in |
| * nature or when the input comes from an existing {@link Stream}. See |
| * {@link #stream(Iterator, ThrowingConsumer)} as an alternative. |
| * |
| * <p>The given {@code inputStream} is responsible for supplying input values |
| * and display names. A {@link DynamicTest} will be added to the resulting stream for |
| * each dynamically supplied input value, using the given {@code testExecutor}. |
| * |
| * @param inputStream a {@code Stream} that supplies dynamic {@code Named} |
| * input values; never {@code null} |
| * @param testExecutor a consumer that executes a test based on an input |
| * value; never {@code null} |
| * @param <T> the type of <em>input</em> supplied by the {@code inputStream} |
| * and used by the {@code displayNameGenerator} and {@code testExecutor} |
| * @return a stream of dynamic tests based on the given generator and |
| * executor; never {@code null} |
| * @since 5.8 |
| * |
| * @see #dynamicTest(String, Executable) |
| * @see #stream(Iterator, ThrowingConsumer) |
| * @see Named |
| */ |
| @API(status = MAINTAINED, since = "5.8") |
| public static <T> Stream<DynamicTest> stream(Stream<? extends Named<T>> inputStream, |
| ThrowingConsumer<? super T> testExecutor) { |
| Preconditions.notNull(inputStream, "inputStream must not be null"); |
| Preconditions.notNull(testExecutor, "testExecutor must not be null"); |
| |
| return inputStream // |
| .map(input -> dynamicTest(input.getName(), () -> testExecutor.accept(input.getPayload()))); |
| } |
| |
| private final Executable executable; |
| |
| private DynamicTest(String displayName, URI testSourceUri, Executable executable) { |
| super(displayName, testSourceUri); |
| this.executable = Preconditions.notNull(executable, "executable must not be null"); |
| } |
| |
| /** |
| * Get the {@code executable} code block associated with this {@code DynamicTest}. |
| */ |
| public Executable getExecutable() { |
| return this.executable; |
| } |
| |
| } |