001/*
002 * Copyright 2002-2017 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.test.context.junit4.statements;
018
019import java.lang.annotation.Annotation;
020import java.lang.reflect.Method;
021
022import org.junit.AssumptionViolatedException;
023import org.junit.runners.model.Statement;
024
025import org.springframework.core.annotation.AnnotatedElementUtils;
026import org.springframework.lang.Nullable;
027import org.springframework.test.annotation.IfProfileValue;
028import org.springframework.test.annotation.ProfileValueUtils;
029import org.springframework.util.Assert;
030
031/**
032 * {@code ProfileValueChecker} is a custom JUnit {@link Statement} that checks
033 * whether a test class or test method is enabled in the current environment
034 * via Spring's {@link IfProfileValue @IfProfileValue} annotation.
035 *
036 * @author Sam Brannen
037 * @author Philippe Marschall
038 * @since 4.2
039 * @see #evaluate()
040 * @see IfProfileValue
041 * @see ProfileValueUtils
042 */
043public class ProfileValueChecker extends Statement {
044
045        private final Statement next;
046
047        private final Class<?> testClass;
048
049        @Nullable
050        private final Method testMethod;
051
052
053        /**
054         * Construct a new {@code ProfileValueChecker} statement.
055         * @param next the next {@code Statement} in the execution chain;
056         * never {@code null}
057         * @param testClass the test class to check; never {@code null}
058         * @param testMethod the test method to check; may be {@code null} if
059         * this {@code ProfileValueChecker} is being applied at the class level
060         */
061        public ProfileValueChecker(Statement next, Class<?> testClass, @Nullable Method testMethod) {
062                Assert.notNull(next, "The next statement must not be null");
063                Assert.notNull(testClass, "The test class must not be null");
064                this.next = next;
065                this.testClass = testClass;
066                this.testMethod = testMethod;
067        }
068
069
070        /**
071         * Determine if the test specified by arguments to the
072         * {@linkplain #ProfileValueChecker constructor} is <em>enabled</em> in
073         * the current environment, as configured via the {@link IfProfileValue
074         * &#064;IfProfileValue} annotation.
075         * <p>If the test is not annotated with {@code @IfProfileValue} it is
076         * considered enabled.
077         * <p>If a test is not enabled, this method will abort further evaluation
078         * of the execution chain with a failed assumption; otherwise, this method
079         * will simply evaluate the next {@link Statement} in the execution chain.
080         * @see ProfileValueUtils#isTestEnabledInThisEnvironment(Class)
081         * @see ProfileValueUtils#isTestEnabledInThisEnvironment(Method, Class)
082         * @throws AssumptionViolatedException if the test is disabled
083         * @throws Throwable if evaluation of the next statement fails
084         */
085        @Override
086        public void evaluate() throws Throwable {
087                if (this.testMethod == null) {
088                        if (!ProfileValueUtils.isTestEnabledInThisEnvironment(this.testClass)) {
089                                Annotation ann = AnnotatedElementUtils.findMergedAnnotation(this.testClass, IfProfileValue.class);
090                                throw new AssumptionViolatedException(String.format(
091                                                "Profile configured via [%s] is not enabled in this environment for test class [%s].",
092                                                ann, this.testClass.getName()));
093                        }
094                }
095                else {
096                        if (!ProfileValueUtils.isTestEnabledInThisEnvironment(this.testMethod, this.testClass)) {
097                                throw new AssumptionViolatedException(String.format(
098                                                "Profile configured via @IfProfileValue is not enabled in this environment for test method [%s].",
099                                                this.testMethod));
100                        }
101                }
102
103                this.next.evaluate();
104        }
105
106}