001    package org.junit.validator;
002    
003    import static java.util.Collections.singletonList;
004    
005    import java.lang.annotation.Annotation;
006    import java.util.ArrayList;
007    import java.util.Arrays;
008    import java.util.List;
009    
010    import org.junit.runners.model.Annotatable;
011    import org.junit.runners.model.FrameworkField;
012    import org.junit.runners.model.FrameworkMethod;
013    import org.junit.runners.model.TestClass;
014    
015    /**
016     * An {@code AnnotationsValidator} validates all annotations of a test class,
017     * including its annotated fields and methods.
018     * 
019     * @since 4.12
020     */
021    public final class AnnotationsValidator implements TestClassValidator {
022        private static final List<AnnotatableValidator<?>> VALIDATORS = Arrays.<AnnotatableValidator<?>>asList(
023                new ClassValidator(), new MethodValidator(), new FieldValidator());
024    
025        /**
026         * Validate all annotations of the specified test class that are be
027         * annotated with {@link ValidateWith}.
028         * 
029         * @param testClass
030         *            the {@link TestClass} that is validated.
031         * @return the errors found by the validator.
032         */
033        public List<Exception> validateTestClass(TestClass testClass) {
034            List<Exception> validationErrors= new ArrayList<Exception>();
035            for (AnnotatableValidator<?> validator : VALIDATORS) {
036                List<Exception> additionalErrors= validator
037                        .validateTestClass(testClass);
038                validationErrors.addAll(additionalErrors);
039            }
040            return validationErrors;
041        }
042    
043        private static abstract class AnnotatableValidator<T extends Annotatable> {
044            private static final AnnotationValidatorFactory ANNOTATION_VALIDATOR_FACTORY = new AnnotationValidatorFactory();
045    
046            abstract Iterable<T> getAnnotatablesForTestClass(TestClass testClass);
047    
048            abstract List<Exception> validateAnnotatable(
049                    AnnotationValidator validator, T annotatable);
050    
051            public List<Exception> validateTestClass(TestClass testClass) {
052                List<Exception> validationErrors= new ArrayList<Exception>();
053                for (T annotatable : getAnnotatablesForTestClass(testClass)) {
054                    List<Exception> additionalErrors= validateAnnotatable(annotatable);
055                    validationErrors.addAll(additionalErrors);
056                }
057                return validationErrors;
058            }
059    
060            private List<Exception> validateAnnotatable(T annotatable) {
061                List<Exception> validationErrors= new ArrayList<Exception>();
062                for (Annotation annotation : annotatable.getAnnotations()) {
063                    Class<? extends Annotation> annotationType = annotation
064                            .annotationType();
065                    ValidateWith validateWith = annotationType
066                            .getAnnotation(ValidateWith.class);
067                    if (validateWith != null) {
068                        AnnotationValidator annotationValidator = ANNOTATION_VALIDATOR_FACTORY
069                                .createAnnotationValidator(validateWith);
070                        List<Exception> errors= validateAnnotatable(
071                                annotationValidator, annotatable);
072                        validationErrors.addAll(errors);
073                    }
074                }
075                return validationErrors;
076            }
077        }
078    
079        private static class ClassValidator extends AnnotatableValidator<TestClass> {
080            @Override
081            Iterable<TestClass> getAnnotatablesForTestClass(TestClass testClass) {
082                return singletonList(testClass);
083            }
084    
085            @Override
086            List<Exception> validateAnnotatable(
087                    AnnotationValidator validator, TestClass testClass) {
088                return validator.validateAnnotatedClass(testClass);
089            }
090        }
091    
092        private static class MethodValidator extends
093                AnnotatableValidator<FrameworkMethod> {
094            @Override
095            Iterable<FrameworkMethod> getAnnotatablesForTestClass(
096                    TestClass testClass) {
097                return testClass.getAnnotatedMethods();
098            }
099    
100            @Override
101            List<Exception> validateAnnotatable(
102                    AnnotationValidator validator, FrameworkMethod method) {
103                return validator.validateAnnotatedMethod(method);
104            }
105        }
106    
107        private static class FieldValidator extends
108                AnnotatableValidator<FrameworkField> {
109            @Override
110            Iterable<FrameworkField> getAnnotatablesForTestClass(TestClass testClass) {
111                return testClass.getAnnotatedFields();
112            }
113    
114            @Override
115            List<Exception> validateAnnotatable(
116                    AnnotationValidator validator, FrameworkField field) {
117                return validator.validateAnnotatedField(field);
118            }
119        };
120    }