From 4fa5160a6a1c1a897964f9d7044e45786627c570 Mon Sep 17 00:00:00 2001 From: mobounya Date: Fri, 19 Jan 2024 20:45:15 +0100 Subject: [PATCH] Simplify the generation of DynamicTests stream Introduce two methods in the class DynamicTest to generate a stream of DynamicTests from a Stream/Iterator of NamedExecutables. Instead of passing an inputStream, a displayNameGenerator and a testExecutor separately, these two additional methods will allow you to pass one Iterator/Stream of a NamedExecutable. Unlike the Named interface, the NamedExecutable can colocate assertion callbacks in one container using the execute method. Issue: #3261 --- .../org/junit/jupiter/api/DynamicTest.java | 59 +++++++++++++++++++ .../junit/jupiter/api/DynamicTestTests.java | 52 ++++++++++++++++ 2 files changed, 111 insertions(+) diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DynamicTest.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DynamicTest.java index 87f4aeae166..b656c1bdeba 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DynamicTest.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/DynamicTest.java @@ -226,6 +226,65 @@ public static Stream stream(Stream> inputStr .map(input -> dynamicTest(input.getName(), () -> testExecutor.accept(input.getPayload()))); } + /** + * Generate a stream of dynamic tests based on the given input stream. + * + *

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)} as an alternative. + * + *

The given {@code inputGenerator} is responsible for supplying input values, + * display names, and an executor that executes a test. A {@link DynamicTest} will be + * added to the resulting stream for each dynamically supplied input value. + * + * @param inputGenerator an {@code Iterator} with {@code NamedExecutable} values + * that serves as a dynamic input generator; never {@code null} + * @param the type of input supplied by the {@code inputStream} + * @return a stream of dynamic tests based on the given generator; never {@code null} + * @since 5.11 + * + * @see #dynamicTest(String, Executable) + * @see #stream(Stream) + * @see NamedExecutable + */ + + public static > Stream stream( + Iterator> inputGenerator) { + Preconditions.notNull(inputGenerator, "inputGenerator must not be null"); + + return stream(StreamSupport.stream(spliteratorUnknownSize(inputGenerator, ORDERED), false)); + } + + /** + * Generate a stream of dynamic tests based on the given input stream. + * + *

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)} as an alternative. + * + *

The given {@code inputStream} is responsible for supplying input values, + * display names, and an executor that executes a test. A {@link DynamicTest} will be + * added to the resulting stream for each dynamically supplied input value. + * + * @param inputStream a {@code Stream} that supplies dynamic {@code NamedExecutable} + * input values; never {@code null} + * @param the type of input supplied by the {@code inputStream} + * @return a stream of dynamic tests based on the given generator; never {@code null} + * @since 5.11 + * + * @see #dynamicTest(String, Executable) + * @see #stream(Iterator) + * @see NamedExecutable + */ + + public static > Stream stream( + Stream> inputStream) { + Preconditions.notNull(inputStream, "inputStream must not be null"); + + return inputStream. // + map((input) -> dynamicTest(input.getName(), input)); + } + private final Executable executable; private DynamicTest(String displayName, URI testSourceUri, Executable executable) { diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/api/DynamicTestTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/api/DynamicTestTests.java index 4fc95d19ca0..cc28108d2fe 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/api/DynamicTestTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/api/DynamicTestTests.java @@ -37,6 +37,28 @@ */ class DynamicTestTests { + record DummyNamedExecutableForTests(String name, ThrowingConsumer consumer) implements NamedExecutable { + + @Override + public String toString() { + return getName().toLowerCase(); + } + + @Override + public String getName() { + return name; + } + + @Override + public DummyNamedExecutableForTests getPayload() { + return this; + } + + @Override + public void execute() throws Throwable { + consumer.accept(getPayload().toString()); + }} + private static final Executable nix = () -> { }; @@ -90,6 +112,18 @@ void streamFromIteratorWithNamesPreconditions() { assertThrows(PreconditionViolationException.class, () -> DynamicTest.stream(emptyIterator(), null)); } + @Test + void streamFromStreamWithNamedExecutablesPreconditions() { + assertThrows(PreconditionViolationException.class, + () -> DynamicTest.stream((Stream>)null)); + } + + @Test + void streamFromIteratorWithNamedExecutablesPreconditions() { + assertThrows(PreconditionViolationException.class, + () -> DynamicTest.stream((Iterator)null)); + } + @Test void streamFromStream() throws Throwable { Stream stream = DynamicTest.stream(Stream.of("foo", "bar", "baz"), String::toUpperCase, @@ -119,6 +153,24 @@ void streamFromIteratorWithNames() throws Throwable { assertStream(stream); } + @Test + void streamFromStreamWithNamedExecutables() throws Throwable { + Stream stream = DynamicTest.stream( + Stream.of(new DummyNamedExecutableForTests("FOO", this::throwingConsumer), new DummyNamedExecutableForTests("BAR", this::throwingConsumer), new DummyNamedExecutableForTests("BAZ", this::throwingConsumer)) + ); + + assertStream(stream); + } + + @Test + void streamFromIteratorWithNamedExecutables() throws Throwable { + Stream stream = DynamicTest.stream( + List.of(new DummyNamedExecutableForTests("FOO", this::throwingConsumer), new DummyNamedExecutableForTests("BAR", this::throwingConsumer), new DummyNamedExecutableForTests("BAZ", this::throwingConsumer)).iterator() + ); + + assertStream(stream); + } + private void assertStream(Stream stream) throws Throwable { List dynamicTests = stream.collect(Collectors.toList());