| /* |
| * Copyright 2021 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
| * in compliance with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software distributed under the License |
| * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
| * or implied. See the License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| |
| package com.google.testing.junit.testparameterinjector; |
| |
| import static com.google.common.base.Preconditions.checkState; |
| import static java.lang.annotation.ElementType.CONSTRUCTOR; |
| import static java.lang.annotation.ElementType.METHOD; |
| import static java.lang.annotation.RetentionPolicy.RUNTIME; |
| import static java.util.Collections.unmodifiableMap; |
| |
| import com.google.auto.value.AutoValue; |
| import com.google.common.collect.ImmutableList; |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.Target; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import javax.annotation.Nullable; |
| |
| /** |
| * Annotation that can be placed on @Test-methods or a test constructor to indicate the sets of |
| * parameters that it should be invoked with. |
| * |
| * <p>For @Test-methods, the method will be invoked for every set of parameters that is specified. |
| * For constructors, all the tests in the test class will be invoked on a class instance that was |
| * constructed by each set of parameters. |
| * |
| * <p>Note: If this annotation is used in a test class, the other methods in that class can use |
| * other types of parameterization, such as {@linkplain TestParameter @TestParameter}. |
| * |
| * <p>See {@link #value()} for simple examples. |
| */ |
| @Retention(RUNTIME) |
| @Target({CONSTRUCTOR, METHOD}) |
| public @interface TestParameters { |
| |
| /** |
| * Array of stringified set of parameters in YAML format. Each element corresponds to a single |
| * invocation of a test method. |
| * |
| * <p>Each element in this array is a full parameter set, formatted as a YAML mapping. The mapping |
| * keys must match the parameter names and the mapping values will be converted to the parameter |
| * type if possible. See yaml.org for the YAML syntax. Parameter types that are supported: |
| * |
| * <ul> |
| * <li>YAML primitives: |
| * <ul> |
| * <li>String: Specified as YAML string |
| * <li>boolean: Specified as YAML boolean |
| * <li>long and int: Specified as YAML integer |
| * <li>float and double: Specified as YAML floating point or integer |
| * </ul> |
| * <li> |
| * <li>Parsed types: |
| * <ul> |
| * <li>Enum value: Specified as a String that can be parsed by {@code Enum.valueOf()} |
| * <li>Byte array or com.google.protobuf.ByteString: Specified as an UTF8 String or YAML |
| * bytes (example: "!!binary 'ZGF0YQ=='") |
| * </ul> |
| * <li> |
| * </ul> |
| * |
| * <p>For dynamic sets of parameters or parameter types that are not supported here, use {@link |
| * #valuesProvider()} and leave this field empty. |
| * |
| * <p><b>Examples</b> |
| * |
| * <pre> |
| * {@literal @}Test |
| * {@literal @}TestParameters({ |
| * "{age: 17, expectIsAdult: false}", |
| * "{age: 22, expectIsAdult: true}", |
| * }) |
| * public void personIsAdult(int age, boolean expectIsAdult) { ... } |
| * |
| * {@literal @}Test |
| * {@literal @}TestParameters({ |
| * "{updateRequest: {name: 'Hermione'}, expectedResultType: SUCCESS}", |
| * "{updateRequest: {name: '---'}, expectedResultType: FAILURE}", |
| * }) |
| * public void update(UpdateRequest updateRequest, ResultType expectedResultType) { ... } |
| * </pre> |
| */ |
| String[] value() default {}; |
| |
| /** |
| * Sets a provider that will return a list of parameter sets. Each element in the returned list |
| * corresponds to a single invocation of a test method. |
| * |
| * <p>If this field is set, {@link #value()} must be empty and vice versa. |
| * |
| * <p><b>Example</b> |
| * |
| * <pre> |
| * {@literal @}Test |
| * {@literal @}TestParameters(valuesProvider = IsAdultValueProvider.class) |
| * public void personIsAdult(int age, boolean expectIsAdult) { ... } |
| * |
| * private static final class IsAdultValueProvider implements TestParametersValuesProvider { |
| * {@literal @}Override public {@literal List<TestParametersValues>} provideValues() { |
| * return ImmutableList.of( |
| * TestParametersValues.builder() |
| * .name("teenager") |
| * .addParameter("age", 17) |
| * .addParameter("expectIsAdult", false) |
| * .build(), |
| * TestParametersValues.builder() |
| * .name("young adult") |
| * .addParameter("age", 22) |
| * .addParameter("expectIsAdult", true) |
| * .build() |
| * ); |
| * } |
| * } |
| * </pre> |
| */ |
| Class<? extends TestParametersValuesProvider> valuesProvider() default |
| DefaultTestParametersValuesProvider.class; |
| |
| /** Interface for custom providers of test parameter values. */ |
| interface TestParametersValuesProvider { |
| List<TestParametersValues> provideValues(); |
| } |
| |
| /** A set of parameters for a single method invocation. */ |
| @AutoValue |
| abstract class TestParametersValues { |
| |
| /** |
| * A name for this set of parameters that will be used for describing this test. |
| * |
| * <p>Example: If a test method is called "personIsAdult" and this name is "teenager", the name |
| * of the resulting test will be "personIsAdult[teenager]". |
| */ |
| public abstract String name(); |
| |
| /** A map, mapping parameter names to their values. */ |
| @SuppressWarnings("AutoValueImmutableFields") // intentional to allow null values |
| public abstract Map<String, Object> parametersMap(); |
| |
| public static Builder builder() { |
| return new Builder(); |
| } |
| |
| // Avoid instantiations other than the AutoValue one. |
| TestParametersValues() {} |
| |
| /** Builder for {@link TestParametersValues}. */ |
| public static final class Builder { |
| private String name; |
| private final LinkedHashMap<String, Object> parametersMap = new LinkedHashMap<>(); |
| |
| /** |
| * Sets a name for this set of parameters that will be used for describing this test. |
| * |
| * <p>Example: If a test method is called "personIsAdult" and this name is "teenager", the |
| * name of the resulting test will be "personIsAdult[teenager]". |
| */ |
| public Builder name(String name) { |
| this.name = name.replaceAll("\\s+", " "); |
| return this; |
| } |
| |
| /** |
| * Adds a parameter by its name. |
| * |
| * @param parameterName The name of the parameter of the test method |
| * @param value A value of the same type as the method parameter |
| */ |
| public Builder addParameter(String parameterName, @Nullable Object value) { |
| this.parametersMap.put(parameterName, value); |
| return this; |
| } |
| |
| /** Adds parameters by thris names. */ |
| public Builder addParameters(Map<String, Object> parameterNameToValueMap) { |
| this.parametersMap.putAll(parameterNameToValueMap); |
| return this; |
| } |
| |
| public TestParametersValues build() { |
| checkState(name != null, "This set of parameters needs a name (%s)", parametersMap); |
| return new AutoValue_TestParameters_TestParametersValues( |
| name, unmodifiableMap(new LinkedHashMap<>(parametersMap))); |
| } |
| } |
| } |
| |
| /** Default {@link TestParametersValuesProvider} implementation that does nothing. */ |
| class DefaultTestParametersValuesProvider implements TestParametersValuesProvider { |
| @Override |
| public List<TestParametersValues> provideValues() { |
| return ImmutableList.of(); |
| } |
| } |
| } |