1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package libcore.java.lang.reflect;
18
19import java.lang.annotation.Annotation;
20import java.lang.annotation.Inherited;
21import java.lang.annotation.Retention;
22import java.lang.annotation.RetentionPolicy;
23import java.lang.reflect.AnnotatedElement;
24import java.lang.reflect.Constructor;
25import java.lang.reflect.Field;
26import java.lang.reflect.Method;
27import java.util.Arrays;
28import java.util.HashSet;
29import java.util.Set;
30import junit.framework.TestCase;
31
32public final class AnnotationsTest extends TestCase {
33
34    public void testClassDirectAnnotations() {
35        assertAnnotatedElement(Type.class, AnnotationA.class, AnnotationB.class);
36    }
37
38    public void testClassInheritedAnnotations() {
39        assertAnnotatedElement(ExtendsType.class, AnnotationB.class);
40    }
41
42    public void testConstructorAnnotations() throws Exception {
43        Constructor<Type> constructor = Type.class.getConstructor();
44        assertAnnotatedElement(constructor, AnnotationA.class, AnnotationC.class);
45    }
46
47    public void testFieldAnnotations() throws Exception {
48        Field field = Type.class.getField("field");
49        assertAnnotatedElement(field, AnnotationA.class, AnnotationD.class);
50    }
51
52    public void testMethodAnnotations() throws Exception {
53        Method method = Type.class.getMethod("method", String.class, String.class);
54        assertAnnotatedElement(method, AnnotationB.class, AnnotationC.class);
55    }
56
57    public void testParameterAnnotations() throws Exception {
58        Method method = Type.class.getMethod("method", String.class, String.class);
59        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
60        assertEquals(2, parameterAnnotations.length);
61        assertEquals(set(AnnotationB.class, AnnotationD.class),
62                annotationsToTypes(parameterAnnotations[0]));
63        assertEquals(set(AnnotationC.class, AnnotationD.class),
64                annotationsToTypes(parameterAnnotations[1]));
65    }
66
67    @Retention(RetentionPolicy.RUNTIME)
68    public @interface AnnotationA {}
69
70    @Inherited
71    @Retention(RetentionPolicy.RUNTIME)
72    public @interface AnnotationB {}
73
74    @Retention(RetentionPolicy.RUNTIME)
75    public @interface AnnotationC {}
76
77    @Retention(RetentionPolicy.RUNTIME)
78    public @interface AnnotationD {}
79
80    @AnnotationA @AnnotationB
81    public static class Type {
82        @AnnotationA @AnnotationC public Type() {}
83        @AnnotationA @AnnotationD public String field;
84        @AnnotationB @AnnotationC public void method(@AnnotationB @AnnotationD String parameter1,
85                @AnnotationC @AnnotationD String parameter2) {}
86    }
87
88    public static class ExtendsType extends Type {}
89
90
91    private void assertAnnotatedElement(
92            AnnotatedElement element, Class<? extends Annotation>... expectedAnnotations) {
93        Set<Class<? extends Annotation>> actualTypes = annotationsToTypes(element.getAnnotations());
94        Set<Class<? extends Annotation>> expectedTypes = set(expectedAnnotations);
95        assertEquals(expectedTypes, actualTypes);
96
97        // getAnnotations() should be consistent with isAnnotationPresent() and getAnnotation()
98        assertPresent(expectedTypes.contains(AnnotationA.class), element, AnnotationA.class);
99        assertPresent(expectedTypes.contains(AnnotationB.class), element, AnnotationB.class);
100        assertPresent(expectedTypes.contains(AnnotationC.class), element, AnnotationC.class);
101
102        try {
103            element.isAnnotationPresent(null);
104            fail();
105        } catch (NullPointerException expected) {
106        }
107
108        try {
109            element.getAnnotation(null);
110            fail();
111        } catch (NullPointerException expected) {
112        }
113    }
114
115    private Set<Class<? extends Annotation>> annotationsToTypes(Annotation[] annotations) {
116        Set<Class<? extends Annotation>> result = new HashSet<Class<? extends Annotation>>();
117        for (Annotation annotation : annotations) {
118            result.add(annotation.annotationType());
119        }
120        return result;
121    }
122
123    private void assertPresent(boolean present, AnnotatedElement element,
124            Class<? extends Annotation> annotation) {
125        if (present) {
126            assertNotNull(element.getAnnotation(annotation));
127            assertTrue(element.isAnnotationPresent(annotation));
128        } else {
129            assertNull(element.getAnnotation(annotation));
130            assertFalse(element.isAnnotationPresent(annotation));
131        }
132    }
133
134    private <T> Set<T> set(T... instances) {
135        return new HashSet<T>(Arrays.asList(instances));
136    }
137}
138