/*
* 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.jupiter.engine.descriptor;
import static java.util.stream.Collectors.toList;
import static org.junit.platform.commons.meta.API.Usage.Internal;
import java.lang.reflect.Method;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.jupiter.api.extension.ContainerExtensionContext;
import org.junit.jupiter.api.extension.TestTemplateInvocationContext;
import org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider;
import org.junit.jupiter.engine.execution.JupiterEngineExecutionContext;
import org.junit.jupiter.engine.extension.ExtensionRegistry;
import org.junit.platform.commons.meta.API;
import org.junit.platform.commons.util.Preconditions;
import org.junit.platform.engine.TestDescriptor;
import org.junit.platform.engine.UniqueId;
import org.opentest4j.TestAbortedException;
/**
* {@link TestDescriptor} for {@link org.junit.jupiter.api.TestTemplate @TestTemplate}
* methods.
*
* @since 5.0
*/
@API(Internal)
public class TestTemplateTestDescriptor extends MethodBasedTestDescriptor {
public TestTemplateTestDescriptor(UniqueId uniqueId, Class<?> testClass, Method templateMethod) {
super(uniqueId, testClass, templateMethod);
}
@Override
public Type getType() {
return Type.CONTAINER;
}
@Override
public boolean hasTests() {
return true;
}
// --- Node ----------------------------------------------------------------
@Override
public JupiterEngineExecutionContext prepare(JupiterEngineExecutionContext context) throws Exception {
ExtensionRegistry registry = populateNewExtensionRegistryFromExtendWith(getTestMethod(),
context.getExtensionRegistry());
ContainerExtensionContext testExtensionContext = new TestTemplateContainerExtensionContext(
context.getExtensionContext(), context.getExecutionListener(), this);
// @formatter:off
return context.extend()
.withExtensionRegistry(registry)
.withExtensionContext(testExtensionContext)
.build();
// @formatter:on
}
@Override
public SkipResult shouldBeSkipped(JupiterEngineExecutionContext context) throws Exception {
return shouldContainerBeSkipped(context);
}
@Override
public JupiterEngineExecutionContext execute(JupiterEngineExecutionContext context,
DynamicTestExecutor dynamicTestExecutor) throws Exception {
ContainerExtensionContext containerExtensionContext = (ContainerExtensionContext) context.getExtensionContext();
List<TestTemplateInvocationContextProvider> providers = validateProviders(containerExtensionContext,
context.getExtensionRegistry());
AtomicInteger invocationIndex = new AtomicInteger();
// @formatter:off
providers.stream()
.flatMap(provider -> provider.provideTestTemplateInvocationContexts(containerExtensionContext))
.map(invocationContext -> createInvocationTestDescriptor(invocationContext, invocationIndex.incrementAndGet()))
.forEach(invocationTestDescriptor -> execute(dynamicTestExecutor, invocationTestDescriptor));
// @formatter:on
validateWasAtLeastInvokedOnce(invocationIndex.get());
return context;
}
private List<TestTemplateInvocationContextProvider> validateProviders(
ContainerExtensionContext containerExtensionContext, ExtensionRegistry extensionRegistry) {
// @formatter:off
List<TestTemplateInvocationContextProvider> providers = extensionRegistry.stream(TestTemplateInvocationContextProvider.class)
.filter(provider -> provider.supportsTestTemplate(containerExtensionContext))
.collect(toList());
// @formatter:on
Preconditions.notEmpty(providers,
() -> String.format("You must register at least one %s that supports @TestTemplate method [%s]",
TestTemplateInvocationContextProvider.class.getSimpleName(), getTestMethod()));
return providers;
}
private TestDescriptor createInvocationTestDescriptor(TestTemplateInvocationContext invocationContext, int index) {
UniqueId uniqueId = getUniqueId().append(TestTemplateInvocationTestDescriptor.SEGMENT_TYPE, "#" + index);
return new TestTemplateInvocationTestDescriptor(uniqueId, getTestClass(), getTestMethod(), invocationContext,
index);
}
private void execute(DynamicTestExecutor dynamicTestExecutor, TestDescriptor testDescriptor) {
addChild(testDescriptor);
dynamicTestExecutor.execute(testDescriptor);
}
private void validateWasAtLeastInvokedOnce(int invocationIndex) {
if (invocationIndex == 0) {
throw new TestAbortedException("No supporting "
+ TestTemplateInvocationContextProvider.class.getSimpleName() + " provided an invocation context");
}
}
}