/** * Copyright (c) Codice Foundation * <p> * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, either version 3 of the * License, or any later version. * <p> * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. A copy of the GNU Lesser General Public License * is distributed along with this program and can be found at * <http://www.gnu.org/licenses/lgpl.html>. */ /******************************************************************************* * Copyright (c) 2013,2014 RĂ¼diger Herrmann * 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 * * Contributors: * RĂ¼diger Herrmann - initial API and implementation * Matt Morrissette - allow to use non-static inner IgnoreConditions ******************************************************************************/ package org.codice.ddf.itests.common.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Modifier; import org.junit.Assume; import org.junit.rules.MethodRule; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.Statement; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ConditionalIgnoreRule implements MethodRule { private static final Logger LOGGER = LoggerFactory.getLogger(ConditionalIgnoreRule.class); public interface IgnoreCondition { boolean isSatisfied(); } @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface ConditionalIgnore { Class<? extends IgnoreCondition> condition(); } @Override public Statement apply(Statement base, FrameworkMethod method, Object target) { Statement result = base; if (hasConditionalIgnoreAnnotation(method)) { IgnoreCondition condition = getIgnoreContition(target, method); if (condition.isSatisfied()) { LOGGER.warn("IgnoreCondition {} applies, ignoring test {}", condition.getClass() .getSimpleName(), method.getName()); result = new IgnoreStatement(condition); } } return result; } private static boolean hasConditionalIgnoreAnnotation(FrameworkMethod method) { return method.getAnnotation(ConditionalIgnore.class) != null; } private static IgnoreCondition getIgnoreContition(Object target, FrameworkMethod method) { ConditionalIgnore annotation = method.getAnnotation(ConditionalIgnore.class); return new IgnoreConditionCreator(target, annotation).create(); } private static class IgnoreConditionCreator { private final Object target; private final Class<? extends IgnoreCondition> conditionType; IgnoreConditionCreator(Object target, ConditionalIgnore annotation) { this.target = target; this.conditionType = annotation.condition(); } IgnoreCondition create() { checkConditionType(); try { return createCondition(); } catch (RuntimeException re) { throw re; } catch (Exception e) { throw new RuntimeException(e); } } private IgnoreCondition createCondition() throws Exception { IgnoreCondition result; if (isConditionTypeStandalone()) { result = conditionType.newInstance(); } else { result = conditionType.getDeclaredConstructor(target.getClass()) .newInstance(target); } return result; } private void checkConditionType() { if (!isConditionTypeStandalone() && !isConditionTypeDeclaredInTarget()) { String msg = "Conditional class '%s' is a member class " + "but was not declared inside the test case using it.\n" + "Either make this class a static class, " + "standalone class (by declaring it in it's own file) " + "or move it inside the test case using it"; throw new IllegalArgumentException(String.format(msg, conditionType.getName())); } } private boolean isConditionTypeStandalone() { return !conditionType.isMemberClass() || Modifier.isStatic(conditionType.getModifiers()); } private boolean isConditionTypeDeclaredInTarget() { return target.getClass() .isAssignableFrom(conditionType.getDeclaringClass()); } } private static class IgnoreStatement extends Statement { private final IgnoreCondition condition; IgnoreStatement(IgnoreCondition condition) { this.condition = condition; } @Override public void evaluate() { Assume.assumeTrue("Ignored by " + condition.getClass() .getSimpleName(), false); } } }