blob: d7db493547f7c5239fabd0091398b13ac576c858 [file] [log] [blame]
/*
* 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);
}
}