/* * 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.params; import static org.junit.platform.commons.util.AnnotationUtils.findAnnotation; import static org.junit.platform.commons.util.AnnotationUtils.findRepeatableAnnotations; import static org.junit.platform.commons.util.AnnotationUtils.isAnnotated; import java.lang.reflect.Method; import java.util.logging.Logger; import java.util.stream.Stream; 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.params.provider.Arguments; import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsSource; import org.junit.jupiter.params.support.AnnotationInitializer; import org.junit.platform.commons.util.AnnotationUtils; import org.junit.platform.commons.util.ExceptionUtils; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.commons.util.StringUtils; /** * @since 5.0 */ class ParameterizedTestExtension implements TestTemplateInvocationContextProvider { private static final Logger logger = Logger.getLogger(ParameterizedTestExtension.class.getName()); @Override public boolean supportsTestTemplate(ContainerExtensionContext context) { return isAnnotated(context.getTestMethod(), ParameterizedTest.class); } @Override public Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts( ContainerExtensionContext context) { Method templateMethod = Preconditions.notNull(context.getTestMethod().orElse(null), "test method must not be null"); ParameterizedTestNameFormatter formatter = createNameFormatter(templateMethod); // @formatter:off return findRepeatableAnnotations(templateMethod, ArgumentsSource.class) .stream() .map(ArgumentsSource::value) .map(ReflectionUtils::newInstance) .map(provider -> AnnotationInitializer.initialize(templateMethod, provider)) .flatMap(provider -> arguments(provider, context)) .map(Arguments::get) .map(arguments -> new ParameterizedTestInvocationContext(formatter, arguments)); // @formatter:on } private ParameterizedTestNameFormatter createNameFormatter(Method templateMethod) { ParameterizedTest parameterizedTest = findAnnotation(templateMethod, ParameterizedTest.class).get(); String name = parameterizedTest.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(name)) { logger.warning(String.format( "Configuration error: @ParameterizedTest on method [%s] must be declared with a non-empty name.", templateMethod)); name = AnnotationUtils.getDefaultValue(parameterizedTest, "name", String.class).get(); } return new ParameterizedTestNameFormatter(name); } protected static Stream<? extends Arguments> arguments(ArgumentsProvider provider, ContainerExtensionContext context) { try { return provider.provideArguments(context); } catch (Exception e) { throw ExceptionUtils.throwAsUncheckedException(e); } } }