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 }...