1package org.junit.internal.runners.rules;
2
3import java.lang.annotation.Annotation;
4import java.util.List;
5
6import org.junit.ClassRule;
7import org.junit.Rule;
8import org.junit.rules.TestRule;
9import org.junit.runners.model.FrameworkField;
10import org.junit.runners.model.TestClass;
11
12/**
13 * A RuleFieldValidator validates the rule fields of a
14 * {@link org.junit.runners.model.TestClass}. All reasons for rejecting the
15 * {@code TestClass} are written to a list of errors.
16 *
17 * There are two slightly different validators. The {@link #CLASS_RULE_VALIDATOR}
18 * validates fields with a {@link ClassRule} annotation and the
19 * {@link #RULE_VALIDATOR} validates fields with a {@link Rule} annotation.
20 */
21public enum RuleFieldValidator {
22	/**
23	 * Validates fields with a {@link ClassRule} annotation.
24	 */
25	CLASS_RULE_VALIDATOR(ClassRule.class, true),
26	/**
27	 * Validates fields with a {@link Rule} annotation.
28	 */
29	RULE_VALIDATOR(Rule.class, false);
30
31	private final Class<? extends Annotation> fAnnotation;
32
33	private final boolean fOnlyStaticFields;
34
35	private RuleFieldValidator(Class<? extends Annotation> annotation,
36			boolean onlyStaticFields) {
37		this.fAnnotation= annotation;
38		this.fOnlyStaticFields= onlyStaticFields;
39	}
40
41	/**
42	 * Validate the {@link org.junit.runners.model.TestClass} and adds reasons
43	 * for rejecting the class to a list of errors.
44	 * @param target the {@code TestClass} to validate.
45	 * @param errors the list of errors.
46	 */
47	public void validate(TestClass target, List<Throwable> errors) {
48		List<FrameworkField> fields= target.getAnnotatedFields(fAnnotation);
49		for (FrameworkField each : fields)
50			validateField(each, errors);
51	}
52
53	private void validateField(FrameworkField field, List<Throwable> errors) {
54		optionallyValidateStatic(field, errors);
55		validatePublic(field, errors);
56		validateTestRuleOrMethodRule(field, errors);
57	}
58
59	private void optionallyValidateStatic(FrameworkField field,
60			List<Throwable> errors) {
61		if (fOnlyStaticFields && !field.isStatic())
62			addError(errors, field, "must be static.");
63	}
64
65	private void validatePublic(FrameworkField field, List<Throwable> errors) {
66		if (!field.isPublic())
67			addError(errors, field, "must be public.");
68	}
69
70	private void validateTestRuleOrMethodRule(FrameworkField field,
71			List<Throwable> errors) {
72		if (!isMethodRule(field) && !isTestRule(field))
73			addError(errors, field, "must implement MethodRule or TestRule.");
74	}
75
76	private boolean isTestRule(FrameworkField target) {
77		return TestRule.class.isAssignableFrom(target.getType());
78	}
79
80	@SuppressWarnings("deprecation")
81	private boolean isMethodRule(FrameworkField target) {
82		return org.junit.rules.MethodRule.class.isAssignableFrom(target
83				.getType());
84	}
85
86	private void addError(List<Throwable> errors, FrameworkField field,
87			String suffix) {
88		String message= "The @" + fAnnotation.getSimpleName() + " '"
89				+ field.getName() + "' " + suffix;
90		errors.add(new Exception(message));
91	}
92}
93