Skip to content

Commit

Permalink
Change TestTemplateInvocationContextProvider#provide to return Stream
Browse files Browse the repository at this point in the history
While Iterators cannot be closed, Streams can. Since providers now
return Streams we close them after consumption. Thus, providers may
now read directly from files etc. and can register a hook using
Stream.onClose() to close their resources.
  • Loading branch information
marcphilipp committed Mar 11, 2017
1 parent acabb9a commit 410b47d
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import static org.junit.platform.commons.meta.API.Usage.Experimental;

import java.util.Iterator;
import java.util.stream.Stream;

import org.junit.platform.commons.meta.API;

Expand Down Expand Up @@ -67,15 +68,19 @@ public interface TestTemplateInvocationContextProvider extends Extension {
* <p>This method is only called by the framework if {@link #supports} has
* previously returned {@code true} for the same
* {@link ContainerExtensionContext}. Thus, it must not return an empty
* {@code Iterator}.
* {@code Stream}.
*
* <p>The returned {@code Stream} will be properly closed by calling
* {@link Stream#close()}, making it safe to use a resource such as
* {@link java.nio.file.Files#lines(java.nio.file.Path) Files.lines()}.
*
* @param context the container extension context for the test template
* method about to be invoked; never {@code null}
* @return an Iterator of TestTemplateInvocationContext instances for the
* @return a Stream of TestTemplateInvocationContext instances for the
* invocation of the test template method; never {@code null} or empty
* @see #supports
* @see ContainerExtensionContext
*/
Iterator<TestTemplateInvocationContext> provide(ContainerExtensionContext context);
Stream<TestTemplateInvocationContext> provide(ContainerExtensionContext context);

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import static org.junit.platform.commons.meta.API.Usage.Internal;

import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

Expand Down Expand Up @@ -91,15 +90,12 @@ public JupiterEngineExecutionContext execute(JupiterEngineExecutionContext conte
List<TestTemplateInvocationContextProvider> providers = validateProviders(containerExtensionContext,
context.getExtensionRegistry());
AtomicInteger invocationIndex = new AtomicInteger();
providers.forEach(provider -> {
Iterator<TestTemplateInvocationContext> contextIterator = provider.provide(containerExtensionContext);
contextIterator.forEachRemaining(invocationContext -> {
int index = invocationIndex.incrementAndGet();
TestDescriptor invocationTestDescriptor = createInvocationTestDescriptor(invocationContext, index);
addChild(invocationTestDescriptor);
dynamicTestExecutor.execute(invocationTestDescriptor);
});
});
// @formatter:off
providers.stream()
.flatMap(provider -> provider.provide(containerExtensionContext))
.map(invocationContext -> createInvocationTestDescriptor(invocationContext, invocationIndex.incrementAndGet()))
.forEach(invocationTestDescriptor -> execute(dynamicTestExecutor, invocationTestDescriptor));
// @formatter:on
validateWasAtLeastInvokedOnce(invocationIndex);
return context;
}
Expand All @@ -126,6 +122,11 @@ private TestDescriptor createInvocationTestDescriptor(TestTemplateInvocationCont
invocationContext, index);
}

private void execute(DynamicTestExecutor dynamicTestExecutor, TestDescriptor testDescriptor) {
addChild(testDescriptor);
dynamicTestExecutor.execute(testDescriptor);
}

private void validateWasAtLeastInvokedOnce(AtomicInteger invocationIndex) {
if (invocationIndex.get() == 0) {
throw new TestAbortedException("No supporting "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
package org.junit.jupiter.engine;

import static java.util.Arrays.asList;
import static java.util.Collections.emptyIterator;
import static java.util.Collections.singleton;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
Expand All @@ -38,8 +37,8 @@
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;
import java.util.stream.Stream;

Expand Down Expand Up @@ -77,7 +76,7 @@
/**
* @since 5.0
*/
public class TestTemplateInvocationTests extends AbstractJupiterTestEngineTests {
class TestTemplateInvocationTests extends AbstractJupiterTestEngineTests {

@Test
void templateWithoutRegisteredExtensionReportsFailure() {
Expand Down Expand Up @@ -311,6 +310,25 @@ void templateWithSupportingProviderButNoInvocationsReportsAbortedTest() {
message("No supporting TestTemplateInvocationContextProvider provided an invocation context")))));
}

@Test
void templateWithCloseableStream() {
LauncherDiscoveryRequest request = request().selectors(
selectMethod(MyTestTemplateTestCase.class, "templateWithCloseableStream")).build();

ExecutionEventRecorder eventRecorder = executeTests(request);

assertThat(InvocationContextProviderWithCloseableStream.streamClosed.get()).describedAs(
"streamClosed").isTrue();

assertRecordedExecutionEventsContainsExactly(eventRecorder.getExecutionEvents(), //
wrappedInContainerEvents(MyTestTemplateTestCase.class, //
event(container("templateWithCloseableStream"), started()), //
event(dynamicTestRegistered("test-template-invocation:#1")), //
event(test("test-template-invocation:#1"), started()), //
event(test("test-template-invocation:#1"), finishedSuccessfully()), //
event(container("templateWithCloseableStream"), finishedSuccessfully())));
}

private TestDescriptor findTestDescriptor(ExecutionEventRecorder eventRecorder,
Condition<ExecutionEvent> condition) {
// @formatter:off
Expand Down Expand Up @@ -338,10 +356,6 @@ private final Condition<? super ExecutionEvent>[] wrappedInContainerEvents(Class

static class MyTestTemplateTestCase {

@Test
void foo() {
}

@TestTemplate
void templateWithoutRegisteredExtension() {
}
Expand Down Expand Up @@ -392,10 +406,10 @@ void templateWithDynamicParameterResolver(String parameter) {
@ExtendWith(StringParameterResolvingInvocationContextProvider.class)
@TestTemplate
void templateWithWrongParameterType(int parameter) {
fail("never called");
fail("never called: " + parameter);
}

private String parameterInstanceVariable;
String parameterInstanceVariable;

@ExtendWith(StringParameterInjectingInvocationContextProvider.class)
@TestTemplate
Expand All @@ -409,6 +423,10 @@ void templateWithSupportingProviderButNoInvocations() {
fail("never called");
}

@ExtendWith(InvocationContextProviderWithCloseableStream.class)
@TestTemplate
void templateWithCloseableStream() {
}
}

static class TestTemplateTestClassWithBeforeAndAfterEach {
Expand Down Expand Up @@ -452,8 +470,8 @@ public boolean supports(ContainerExtensionContext context) {
}

@Override
public Iterator<TestTemplateInvocationContext> provide(ContainerExtensionContext context) {
return singleton(emptyTestTemplateInvocationContext()).iterator();
public Stream<TestTemplateInvocationContext> provide(ContainerExtensionContext context) {
return Stream.of(emptyTestTemplateInvocationContext());
}
}

Expand All @@ -466,8 +484,8 @@ public boolean supports(ContainerExtensionContext context) {
}

@Override
public Iterator<TestTemplateInvocationContext> provide(ContainerExtensionContext context) {
return singleton(emptyTestTemplateInvocationContext()).iterator();
public Stream<TestTemplateInvocationContext> provide(ContainerExtensionContext context) {
return Stream.of(emptyTestTemplateInvocationContext());
}
}

Expand All @@ -479,8 +497,8 @@ public boolean supports(ContainerExtensionContext context) {
}

@Override
public Iterator<TestTemplateInvocationContext> provide(ContainerExtensionContext context) {
return asList(emptyTestTemplateInvocationContext(), emptyTestTemplateInvocationContext()).iterator();
public Stream<TestTemplateInvocationContext> provide(ContainerExtensionContext context) {
return Stream.of(emptyTestTemplateInvocationContext(), emptyTestTemplateInvocationContext());
}
}

Expand All @@ -507,13 +525,13 @@ public boolean supports(ContainerExtensionContext context) {
}

@Override
public Iterator<TestTemplateInvocationContext> provide(ContainerExtensionContext context) {
public Stream<TestTemplateInvocationContext> provide(ContainerExtensionContext context) {
return Stream.<TestTemplateInvocationContext> generate(() -> new TestTemplateInvocationContext() {
@Override
public String getDisplayName(int invocationIndex) {
return invocationIndex + " --> " + context.getDisplayName();
}
}).limit(1).iterator();
}).limit(1);
}
}

Expand All @@ -532,8 +550,8 @@ public boolean supports(ContainerExtensionContext context) {
}

@Override
public Iterator<TestTemplateInvocationContext> provide(ContainerExtensionContext context) {
return asList(createContext("foo"), createContext("bar")).iterator();
public Stream<TestTemplateInvocationContext> provide(ContainerExtensionContext context) {
return Stream.of(createContext("foo"), createContext("bar"));
}

private TestTemplateInvocationContext createContext(String argument) {
Expand Down Expand Up @@ -572,8 +590,8 @@ public boolean supports(ContainerExtensionContext context) {
}

@Override
public Iterator<TestTemplateInvocationContext> provide(ContainerExtensionContext context) {
return asList(createContext("foo"), createContext("bar")).iterator();
public Stream<TestTemplateInvocationContext> provide(ContainerExtensionContext context) {
return Stream.of(createContext("foo"), createContext("bar"));
}

private TestTemplateInvocationContext createContext(String argument) {
Expand Down Expand Up @@ -604,8 +622,8 @@ public boolean supports(ContainerExtensionContext context) {
}

@Override
public Iterator<TestTemplateInvocationContext> provide(ContainerExtensionContext context) {
return asList(createContext("foo"), createContext("bar")).iterator();
public Stream<TestTemplateInvocationContext> provide(ContainerExtensionContext context) {
return Stream.of(createContext("foo"), createContext("bar"));
}

private TestTemplateInvocationContext createContext(String argument) {
Expand Down Expand Up @@ -639,7 +657,7 @@ public void beforeTestExecution(TestExtensionContext context) throws Exception {
public void handleTestExecutionException(TestExtensionContext context, Throwable throwable)
throws Throwable {
TestTemplateTestClassWithDynamicLifecycleCallbacks.lifecycleEvents.add("handleTestExecutionException");
throw throwable;
throw new AssertionError(throwable);
}

@Override
Expand All @@ -663,8 +681,23 @@ public boolean supports(ContainerExtensionContext context) {
}

@Override
public Iterator<TestTemplateInvocationContext> provide(ContainerExtensionContext context) {
return emptyIterator();
public Stream<TestTemplateInvocationContext> provide(ContainerExtensionContext context) {
return Stream.empty();
}
}

private static class InvocationContextProviderWithCloseableStream implements TestTemplateInvocationContextProvider {

private static AtomicBoolean streamClosed = new AtomicBoolean(false);

@Override
public boolean supports(ContainerExtensionContext context) {
return true;
}

@Override
public Stream<TestTemplateInvocationContext> provide(ContainerExtensionContext context) {
return Stream.of(emptyTestTemplateInvocationContext()).onClose(() -> streamClosed.set(true));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import java.util.Spliterator;
import java.util.Spliterators;
Expand Down Expand Up @@ -52,7 +51,7 @@ public boolean supports(ContainerExtensionContext context) {
}

@Override
public Iterator<TestTemplateInvocationContext> provide(ContainerExtensionContext context) {
public Stream<TestTemplateInvocationContext> provide(ContainerExtensionContext context) {
Method templateMethod = Preconditions.notNull(context.getTestMethod().orElse(null),
"test method must not be null");
ParameterizedTestNameFormatter formatter = createNameFormatter(templateMethod);
Expand All @@ -64,8 +63,7 @@ public Iterator<TestTemplateInvocationContext> provide(ContainerExtensionContext
.peek(provider -> initialize(templateMethod, provider))
.flatMap(ParameterizedTestExtension::toArgumentsStream)
.map(Arguments::getArguments)
.map(arguments -> toTestTemplateInvocationContext(formatter, arguments))
.iterator();
.map(arguments -> toTestTemplateInvocationContext(formatter, arguments));
// @formatter:on
}

Expand Down

0 comments on commit 410b47d

Please sign in to comment.