
1// Copyright 2017 The Chromium Authors. All rights reserved.2// Use of this source code is governed by a BSD-style license that can be3// found in the LICENSE file.4package org.chromium.base.test.util;5import static org.hamcrest.Matchers.contains;6import static org.junit.Assert.assertEquals;7import static org.junit.Assert.assertNotNull;8import static org.junit.Assert.assertNull;9import static org.junit.Assert.assertThat;10import static org.junit.Assert.fail;11import static org.junit.runner.Description.createTestDescription;12import org.junit.Ignore;13import org.junit.Rule;14import org.junit.Test;15import org.junit.rules.TestRule;16import org.junit.runner.Description;17import org.junit.runner.RunWith;18import org.junit.runners.BlockJUnit4ClassRunner;19import org.junit.runners.model.FrameworkMethod;20import org.junit.runners.model.InitializationError;21import org.junit.runners.model.Statement;22import org.chromium.base.test.util.AnnotationProcessingUtils.AnnotationExtractor;23import java.lang.annotation.Annotation;24import java.lang.annotation.ElementType;25import java.lang.annotation.Retention;26import java.lang.annotation.RetentionPolicy;27import java.lang.annotation.Target;28import java.util.Arrays;29import java.util.Comparator;30import java.util.List;31/** Test for {@link AnnotationProcessingUtils}. */32@RunWith(BlockJUnit4ClassRunner.class)33public class AnnotationProcessingUtilsTest {34    @Test35    public void testGetTargetAnnotation_NotOnClassNorMethod() {36        TargetAnnotation retrievedAnnotation;37        retrievedAnnotation = AnnotationProcessingUtils.getAnnotation(38                createTestDescription(39                        ClassWithoutTargetAnnotation.class, "methodWithoutAnnotation"),40                TargetAnnotation.class);41        assertNull(retrievedAnnotation);42    }43    @Test44    public void testGetTargetAnnotation_NotOnClassButOnMethod() {45        TargetAnnotation retrievedAnnotation;46        retrievedAnnotation = AnnotationProcessingUtils.getAnnotation(47                getTest(ClassWithoutTargetAnnotation.class, "methodWithTargetAnnotation"),48                TargetAnnotation.class);49        assertNotNull(retrievedAnnotation);50    }51    @Test52    public void testGetTargetAnnotation_NotOnClassDifferentOneOnMethod() {53        TargetAnnotation retrievedAnnotation;54        retrievedAnnotation = AnnotationProcessingUtils.getAnnotation(55                getTest(ClassWithoutTargetAnnotation.class, "methodWithAnnotatedAnnotation"),56                TargetAnnotation.class);57        assertNull(retrievedAnnotation);58    }59    @Test60    public void testGetTargetAnnotation_OnClassButNotOnMethod() {61        TargetAnnotation retrievedAnnotation;62        retrievedAnnotation = AnnotationProcessingUtils.getAnnotation(63                getTest(ClassWithAnnotation.class, "methodWithoutAnnotation"),64                TargetAnnotation.class);65        assertNotNull(retrievedAnnotation);66        assertEquals(Location.Class, retrievedAnnotation.value());67    }68    @Test69    public void testGetTargetAnnotation_OnClassAndMethod() {70        TargetAnnotation retrievedAnnotation;71        retrievedAnnotation = AnnotationProcessingUtils.getAnnotation(72                getTest(ClassWithAnnotation.class, "methodWithTargetAnnotation"),73                TargetAnnotation.class);74        assertNotNull(retrievedAnnotation);75        assertEquals(Location.Method, retrievedAnnotation.value());76    }77    @Test78    @Ignore("Rules not supported yet.")79    public void testGetTargetAnnotation_OnRuleButNotOnMethod() {80        TargetAnnotation retrievedAnnotation;81        retrievedAnnotation = AnnotationProcessingUtils.getAnnotation(82                getTest(ClassWithRule.class, "methodWithoutAnnotation"), TargetAnnotation.class);83        assertNotNull(retrievedAnnotation);84        assertEquals(Location.Rule, retrievedAnnotation.value());85    }86    @Test87    @Ignore("Rules not supported yet.")88    public void testGetTargetAnnotation_OnRuleAndMethod() {89        TargetAnnotation retrievedAnnotation;90        retrievedAnnotation = AnnotationProcessingUtils.getAnnotation(91                getTest(ClassWithRule.class, "methodWithTargetAnnotation"), TargetAnnotation.class);92        assertNotNull(retrievedAnnotation);93        assertEquals(Location.Method, retrievedAnnotation.value());94    }95    @Test96    public void testGetMetaAnnotation_Indirectly() {97        MetaAnnotation retrievedAnnotation;98        retrievedAnnotation = AnnotationProcessingUtils.getAnnotation(99                getTest(ClassWithoutTargetAnnotation.class, "methodWithAnnotatedAnnotation"),100                MetaAnnotation.class);101        assertNotNull(retrievedAnnotation);102    }103    @Test104    public void testGetAllTargetAnnotations() {105        List<TargetAnnotation> retrievedAnnotations;106        retrievedAnnotations = AnnotationProcessingUtils.getAnnotations(107                getTest(ClassWithAnnotation.class, "methodWithTargetAnnotation"),108                TargetAnnotation.class);109        assertEquals(2, retrievedAnnotations.size());110        assertEquals(Location.Class, retrievedAnnotations.get(0).value());111        assertEquals(Location.Method, retrievedAnnotations.get(1).value());112    }113    @Test114    public void testGetAllTargetAnnotations_OnParentClass() {115        List<TargetAnnotation> retrievedAnnotations;116        retrievedAnnotations = AnnotationProcessingUtils.getAnnotations(117                getTest(DerivedClassWithoutAnnotation.class, "newMethodWithoutAnnotation"),118                TargetAnnotation.class);119        assertEquals(1, retrievedAnnotations.size());120        assertEquals(Location.Class, retrievedAnnotations.get(0).value());121    }122    @Test123    public void testGetAllTargetAnnotations_OnDerivedMethodAndParentClass() {124        List<TargetAnnotation> retrievedAnnotations;125        retrievedAnnotations = AnnotationProcessingUtils.getAnnotations(126                getTest(DerivedClassWithoutAnnotation.class, "newMethodWithTargetAnnotation"),127                TargetAnnotation.class);128        assertEquals(2, retrievedAnnotations.size());129        assertEquals(Location.Class, retrievedAnnotations.get(0).value());130        assertEquals(Location.DerivedMethod, retrievedAnnotations.get(1).value());131    }132    @Test133    public void testGetAllTargetAnnotations_OnDerivedMethodAndParentClassAndMethod() {134        List<TargetAnnotation> retrievedAnnotations;135        retrievedAnnotations = AnnotationProcessingUtils.getAnnotations(136                getTest(DerivedClassWithoutAnnotation.class, "methodWithTargetAnnotation"),137                TargetAnnotation.class);138        // We should not look at the base implementation of the method. Mostly it should not happen139        // in the context of tests.140        assertEquals(2, retrievedAnnotations.size());141        assertEquals(Location.Class, retrievedAnnotations.get(0).value());142        assertEquals(Location.DerivedMethod, retrievedAnnotations.get(1).value());143    }144    @Test145    public void testGetAllTargetAnnotations_OnDerivedParentAndParentClass() {146        List<TargetAnnotation> retrievedAnnotations;147        retrievedAnnotations = AnnotationProcessingUtils.getAnnotations(148                getTest(DerivedClassWithAnnotation.class, "methodWithoutAnnotation"),149                TargetAnnotation.class);150        assertEquals(2, retrievedAnnotations.size());151        assertEquals(Location.Class, retrievedAnnotations.get(0).value());152        assertEquals(Location.DerivedClass, retrievedAnnotations.get(1).value());153    }154    @Test155    public void testGetAllAnnotations() {156        List<Annotation> annotations;157        AnnotationExtractor annotationExtractor = new AnnotationExtractor(158                TargetAnnotation.class, MetaAnnotation.class, AnnotatedAnnotation.class);159        annotations = annotationExtractor.getMatchingAnnotations(160                getTest(DerivedClassWithAnnotation.class, "methodWithTwoAnnotations"));161        assertEquals(5, annotations.size());162        // Retrieved annotation order:163        // On Parent Class164        assertEquals(TargetAnnotation.class, annotations.get(0).annotationType());165        assertEquals(Location.Class, ((TargetAnnotation) annotations.get(0)).value());166        // On Class167        assertEquals(TargetAnnotation.class, annotations.get(1).annotationType());168        assertEquals(Location.DerivedClass, ((TargetAnnotation) annotations.get(1)).value());169        // Meta-annotations from method170        assertEquals(MetaAnnotation.class, annotations.get(2).annotationType());171        // On Method172        assertEquals(AnnotatedAnnotation.class, annotations.get(3).annotationType());173        assertEquals(TargetAnnotation.class, annotations.get(4).annotationType());174        assertEquals(Location.DerivedMethod, ((TargetAnnotation) annotations.get(4)).value());175    }176    @SuppressWarnings("unchecked")177    @Test178    public void testAnnotationExtractorSortOrder_UnknownAnnotations() {179        AnnotationExtractor annotationExtractor = new AnnotationExtractor(Target.class);180        Comparator<Class<? extends Annotation>> comparator =181                annotationExtractor.getTypeComparator();182        List<Class<? extends Annotation>> testList =183                Arrays.asList(Rule.class, Test.class, Override.class, Target.class, Rule.class);184        testList.sort(comparator);185        assertThat("Unknown annotations should not be reordered and come before the known ones.",186                testList,187                contains(Rule.class, Test.class, Override.class, Rule.class, Target.class));188    }189    @SuppressWarnings("unchecked")190    @Test191    public void testAnnotationExtractorSortOrder_KnownAnnotations() {192        AnnotationExtractor annotationExtractor =193                new AnnotationExtractor(Test.class, Target.class, Rule.class);194        Comparator<Class<? extends Annotation>> comparator =195                annotationExtractor.getTypeComparator();196        List<Class<? extends Annotation>> testList =197                Arrays.asList(Rule.class, Test.class, Override.class, Target.class, Rule.class);198        testList.sort(comparator);199        assertThat(200                "Known annotations should be sorted in the same order as provided to the extractor",201                testList,202                contains(Override.class, Test.class, Target.class, Rule.class, Rule.class));203    }204    private static Description getTest(Class<?> klass, String testName) {205        Description description = null;206        try {207            description = new DummyTestRunner(klass).describe(testName);208        } catch (InitializationError initializationError) {209            initializationError.printStackTrace();210            fail("DummyTestRunner initialization failed:" + initializationError.getMessage());211        }212        if (description == null) {213            fail("Not test named '" + testName + "' in class" + klass.getSimpleName());214        }215        return description;216    }217    // region Test Data: Annotations and dummy test classes218    private enum Location { Unspecified, Class, Method, Rule, DerivedClass, DerivedMethod }219    @Retention(RetentionPolicy.RUNTIME)220    @Target({ElementType.TYPE, ElementType.METHOD})221    private @interface TargetAnnotation {222        Location value() default Location.Unspecified;223    }224    @Retention(RetentionPolicy.RUNTIME)225    @Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.METHOD})226    private @interface MetaAnnotation {}227    @Retention(RetentionPolicy.RUNTIME)228    @Target({ElementType.TYPE, ElementType.METHOD})229    @MetaAnnotation230    private @interface AnnotatedAnnotation {}231    private @interface SimpleAnnotation {}232    @SimpleAnnotation233    private static class ClassWithoutTargetAnnotation {234        @Test235        public void methodWithoutAnnotation() {}236        @Test237        @TargetAnnotation238        public void methodWithTargetAnnotation() {}239        @Test240        @AnnotatedAnnotation241        public void methodWithAnnotatedAnnotation() {}242    }243    @TargetAnnotation(Location.Class)244    private static class ClassWithAnnotation {245        @Test246        public void methodWithoutAnnotation() {}247        @Test248        @TargetAnnotation(Location.Method)249        public void methodWithTargetAnnotation() {}250        @Test251        @MetaAnnotation252        public void methodWithMetaAnnotation() {}253        @Test254        @AnnotatedAnnotation255        public void methodWithAnnotatedAnnotation() {}256    }257    private static class DerivedClassWithoutAnnotation extends ClassWithAnnotation {258        @Test259        public void newMethodWithoutAnnotation() {}260        @Test261        @TargetAnnotation(Location.DerivedMethod)262        public void newMethodWithTargetAnnotation() {}263        @Test264        @Override265        @TargetAnnotation(Location.DerivedMethod)266        public void methodWithTargetAnnotation() {}267    }268    @TargetAnnotation(Location.DerivedClass)269    private static class DerivedClassWithAnnotation extends ClassWithAnnotation {270        @Test271        public void newMethodWithoutAnnotation() {}272        @Test273        @AnnotatedAnnotation274        @TargetAnnotation(Location.DerivedMethod)275        public void methodWithTwoAnnotations() {}276    }277    private static class ClassWithRule {278        @Rule279        Rule1 mRule = new Rule1();280        @Test281        public void methodWithoutAnnotation() {}282        @Test283        @TargetAnnotation284        public void methodWithTargetAnnotation() {}285    }286    @TargetAnnotation(Location.Rule)287    @MetaAnnotation288    private static class Rule1 implements TestRule {289        @Override290        public Statement apply(Statement statement, Description description) {291            return null;292        }293    }294    private static class DummyTestRunner extends BlockJUnit4ClassRunner {295        public DummyTestRunner(Class<?> klass) throws InitializationError {296            super(klass);297        }298        @Override299        protected void collectInitializationErrors(List<Throwable> errors) {300            // Do nothing. BlockJUnit4ClassRunner requires the class to be public, but we don't301            // want/need it.302        }303        public Description describe(String testName) {304            List<FrameworkMethod> tests = getTestClass().getAnnotatedMethods(Test.class);305            for (FrameworkMethod testMethod : tests) {306                if (testMethod.getName().equals(testName)) return describeChild(testMethod);307            }308            return null;309        }310    }311    // endregion312    }...
