package de.bechte.junit.runners.context.statements.builder;
import de.bechte.junit.runners.context.statements.builder.rules.TestRuleDefinitions;
import de.bechte.junit.runners.model.TestClassPool;
import org.junit.Rule;
import org.junit.internal.runners.statements.Fail;
import org.junit.rules.MethodRule;
import org.junit.rules.RunRules;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;
import org.junit.runners.model.TestClass;
import java.util.ArrayList;
import java.util.List;
import static de.bechte.junit.runners.util.ReflectionUtil.getEnclosingInstance;
/**
* The {@link HierarchicalRunRulesStatementBuilder} creates {@link RunRules} statements for all {@code @Rule} annotated
* fields and methods along the context hierarchy. If no rules exist, the builder returns the provided next
* {@link Statement}.
*/
public class HierarchicalRunRulesStatementBuilder implements MethodStatementBuilder {
public Statement createStatement(final TestClass testClass, final FrameworkMethod method, final Object target,
final Statement next, final Description description, final RunNotifier notifier) {
try {
final TestRuleDefinitions testRules = new TestRuleDefinitions(hierarchyOfTestsFromLowestToHighest(target));
for (Object instance = target; instance != null; instance = getEnclosingInstance(instance)) {
final TestClass instanceTestClass = TestClassPool.forClass(instance.getClass());
testRules.addTestRules(instanceTestClass.getAnnotatedMethodValues(instance, Rule.class, TestRule.class), instance);
testRules.addTestRules(instanceTestClass.getAnnotatedFieldValues(instance, Rule.class, TestRule.class), instance);
testRules.addMethodRules(instanceTestClass.getAnnotatedFieldValues(instance, Rule.class, MethodRule.class), instance);
}
Statement statement = next;
for (Object hierarchyContext = target; hierarchyContext != null; hierarchyContext = getEnclosingInstance(hierarchyContext)) {
for (MethodRule methodRule : testRules.getMethodRulesDefinedForThisHierarchyLevel(hierarchyContext))
if (!testRules.contains(methodRule)) {
statement = methodRule.apply(statement, method, hierarchyContext);
}
if (testRules.testRulesPresent())
statement = new RunRules(statement, testRules.getTestRulesDefinedForThisHierarchyLevel(hierarchyContext), description);
}
return statement;
} catch (final IllegalAccessException e) {
return new Fail(e);
}
}
private List<Object> hierarchyOfTestsFromLowestToHighest(Object target) throws IllegalAccessException {
List<Object> result = new ArrayList<Object>();
for (Object instance = target; instance != null; instance = getEnclosingInstance(instance)) {
result.add(instance);
}
return result;
}
}