| /* |
| * Copyright (c) 2014 CEA and others. |
| * |
| * 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: |
| * Christian W. Damus (CEA) - Initial API and implementation |
| * |
| */ |
| package org.eclipse.papyrus.junit.framework.classification.rules; |
| |
| import static org.junit.Assert.fail; |
| |
| import java.lang.reflect.Field; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Member; |
| import java.lang.reflect.Method; |
| |
| import org.eclipse.papyrus.junit.framework.classification.ClassificationRunner; |
| import org.junit.Assume; |
| import org.junit.Rule; |
| import org.junit.rules.MethodRule; |
| import org.junit.runners.model.FrameworkMethod; |
| import org.junit.runners.model.Statement; |
| |
| |
| /** |
| * <p> |
| * A JUnit {@linkplain Rule rule} that skips tests annotated as {@linkplain Conditional @Conditional} when their {@linkplain Condition conditions} are |
| * not satisfied. This model is compatible with the JUnit execution and reporting in the Papyrus Hudson build, which does not understand |
| * {@linkplain Assume#assumeThat(Object, org.hamcrest.Matcher) assumption failures} and reports them as test failures. |
| * </p> |
| * <p> |
| * <b>Note</b> that this is not ideal, as tests will be reported in the JDT's JUnit view as passes, when in fact they should be reported as skipped. |
| * It is better to use the {@link ClassificationRunner} if possible (such as when not using some other test runner). |
| * </p> |
| * |
| * @see Conditional |
| * @see Condition |
| * @see Rule |
| * @see ClassificationRunner |
| */ |
| public class ConditionRule implements MethodRule { |
| |
| public ConditionRule() { |
| super(); |
| } |
| |
| public Statement apply(final Statement base, final FrameworkMethod method, final Object target) { |
| return new Statement() { |
| |
| @Override |
| public void evaluate() throws Throwable { |
| if(testCondition(method.getMethod().getDeclaringClass(), method.getAnnotation(Conditional.class), target)) { |
| base.evaluate(); |
| } |
| } |
| }; |
| } |
| |
| public static boolean testCondition(Class<?> testClass, Conditional conditional, Object test) { |
| boolean result = true; |
| |
| if(conditional != null) { |
| Method conditionMethod = findConditionMethod(testClass, conditional); |
| if(conditionMethod != null) { |
| result = evaluateCondition(conditionMethod, test); |
| } else { |
| Field conditionField = findConditionField(testClass, conditional); |
| if(conditionField != null) { |
| result = evaluateCondition(conditionField, test); |
| } else { |
| fail("Condition not found: " + conditional.key()); |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| static Method findConditionMethod(Class<?> testClass, Conditional conditional) { |
| Method result = null; |
| |
| for(Method next : testClass.getDeclaredMethods()) { |
| Condition condition = next.getAnnotation(Condition.class); |
| if((condition != null) && match(conditional.key(), condition, next)) { |
| result = next; |
| break; |
| } |
| } |
| |
| return result; |
| } |
| |
| static Field findConditionField(Class<?> testClass, Conditional conditional) { |
| Field result = null; |
| |
| for(Field next : testClass.getDeclaredFields()) { |
| Condition condition = next.getAnnotation(Condition.class); |
| if((condition != null) && match(conditional.key(), condition, next)) { |
| result = next; |
| break; |
| } |
| } |
| |
| return result; |
| } |
| |
| static boolean evaluateCondition(Method conditionMethod, Object test) { |
| boolean result = true; |
| |
| try { |
| result = (Boolean)conditionMethod.invoke(test); |
| } catch (InvocationTargetException e) { |
| e.getTargetException().printStackTrace(); |
| fail("Condition method evaluation failed: " + e.getTargetException().getLocalizedMessage()); |
| } catch (Exception e) { |
| fail(String.format("Condition method must be public, accept no arguments, and return a boolean result: %s::%s()", conditionMethod.getDeclaringClass().getSimpleName(), conditionMethod.getName())); |
| } |
| |
| return result; |
| } |
| |
| static boolean evaluateCondition(Field conditionField, Object test) { |
| boolean result = true; |
| |
| try { |
| result = (Boolean)conditionField.get(test); |
| } catch (Exception e) { |
| fail(String.format("Condition field must be public and boolean-valued: %s::%s", conditionField.getDeclaringClass().getSimpleName(), conditionField.getName())); |
| } |
| |
| return result; |
| } |
| |
| static boolean match(String conditionKey, Condition condition, Member conditionMember) { |
| String match = condition.key(); |
| if((match == null) || match.equals("")) { |
| match = conditionMember.getName(); |
| } |
| |
| return match.equals(conditionKey); |
| } |
| } |