/*
* 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.extension;
import static org.junit.platform.commons.util.AnnotationUtils.isAnnotated;
import java.lang.reflect.Method;
import java.util.logging.Logger;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.extension.ContainerExtensionContext;
import org.junit.jupiter.api.extension.TestTemplateInvocationContext;
import org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider;
import org.junit.platform.commons.util.AnnotationUtils;
import org.junit.platform.commons.util.Preconditions;
import org.junit.platform.commons.util.StringUtils;
/**
* {@code TestTemplateInvocationContextProvider} that supports the
* {@link RepeatedTest @RepeatedTest} annotation.
*
* @since 5.0
*/
class RepeatedTestExtension implements TestTemplateInvocationContextProvider {
private static final Logger logger = Logger.getLogger(RepeatedTestExtension.class.getName());
@Override
public boolean supportsTestTemplate(ContainerExtensionContext context) {
return isAnnotated(context.getTestMethod(), RepeatedTest.class);
}
@Override
public Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts(
ContainerExtensionContext context) {
Method testMethod = Preconditions.notNull(context.getTestMethod().orElse(null), "test method must not be null");
String displayName = context.getDisplayName();
RepeatedTest repeatedTest = AnnotationUtils.findAnnotation(testMethod, RepeatedTest.class).get();
int totalRepetitions = totalRepetitions(repeatedTest, testMethod);
RepeatedTestDisplayNameFormatter formatter = displayNameFormatter(repeatedTest, testMethod, displayName);
// @formatter:off
return IntStream
.rangeClosed(1, totalRepetitions)
.mapToObj(repetition -> new RepeatedTestInvocationContext(repetition, totalRepetitions, formatter));
// @formatter:on
}
private int totalRepetitions(RepeatedTest repeatedTest, Method method) {
int repetitions = repeatedTest.value();
// TODO [#242] Replace logging with precondition check once we have a proper mechanism for
// handling validation exceptions during the TestEngine discovery phase.
if (repetitions < 1) {
String message = "Configuration error: @RepeatedTest on method [%s] must be declared with a positive 'value'. Defaulting to 1 repetition.";
logger.warning(String.format(message, method));
repetitions = 1;
}
return repetitions;
}
private RepeatedTestDisplayNameFormatter displayNameFormatter(RepeatedTest repeatedTest, Method method,
String displayName) {
String pattern = repeatedTest.name().trim();
// TODO [#242] Replace logging with precondition check once we have a proper mechanism for
// handling validation exceptions during the TestEngine discovery phase.
if (StringUtils.isBlank(pattern)) {
logger.warning(String.format(
"Configuration error: @RepeatedTest on method [%s] must be declared with a non-empty name.", method));
pattern = AnnotationUtils.getDefaultValue(repeatedTest, "name", String.class).get();
}
return new RepeatedTestDisplayNameFormatter(pattern, displayName);
}
}