diff options
author | Neil Fuller <nfuller@google.com> | 2016-08-12 10:00:23 +0100 |
---|---|---|
committer | Neil Fuller <nfuller@google.com> | 2016-08-17 14:16:27 +0100 |
commit | ee3e080dc11ef39567381faadf149c88e7860ce3 (patch) | |
tree | 98e162cc0b65f9f7c6e11d05522729c9aa57cfaf | |
parent | c8e286ecfdc24e1880820ac14aadcf8234ba7bb9 (diff) |
Improved tests for repeated annotations
Existing annotation tests have been moved into
libcore.java.lang.reflect.annotations. Existing coverage has
been extended to handle repeated annotation behavior to avoid
regressions.
There were previously some repeated annotation tests for classes
in libcore.java.lang.reflect.AnnotationsTest and these have been
replaced.
Existing tests for non-repeated annotations have been
retained but moved to new Class/Field/Constructor test classes.
Shared utility code and annotation definitions has been moved
to AnnotedElementTestSupport.
AnnotationsTests and Annotations57649Test has been moved into
the new package.
AnnotationTests retains tests associated with the
runtime-generated Annotation object (e.g. default values).
AnnotationTest contained some tests that appear to have nothing
to do with annotations. They have been moved to ReflectionTest
with minimal de-duping for the isAnonymousClass() test.
Note: AnnotationsTest.testRetentionPolicy() fails
before and after the change. See bug 29500035.
Bug: 27466777
Bug: 28666126
Test: cts run --class <All of the tests modified/added>
Change-Id: I55416b68cf0cf5eb104015b3907e78f0b39c8ad5
20 files changed, 1851 insertions, 6 deletions
diff --git a/luni/src/test/java/libcore/java/lang/reflect/ReflectionTest.java b/luni/src/test/java/libcore/java/lang/reflect/ReflectionTest.java index 1950bf34d5..f690295635 100644 --- a/luni/src/test/java/libcore/java/lang/reflect/ReflectionTest.java +++ b/luni/src/test/java/libcore/java/lang/reflect/ReflectionTest.java @@ -16,22 +16,28 @@ package libcore.java.lang.reflect; +import java.io.IOException; import java.io.Serializable; import java.lang.reflect.Constructor; import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Member; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Proxy; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.util.AbstractCollection; import java.util.AbstractList; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.RandomAccess; import java.util.Set; -import junit.framework.Assert; import junit.framework.TestCase; public final class ReflectionTest extends TestCase { @@ -430,4 +436,215 @@ public final class ReflectionTest extends TestCase { void foobar() {} } } + + public void testGetEnclosingClass() { + assertNull(ReflectionTest.class.getEnclosingClass()); + assertEquals(ReflectionTest.class, Foo.class.getEnclosingClass()); + assertEquals(ReflectionTest.class, HasMemberClassesInterface.class.getEnclosingClass()); + assertEquals(HasMemberClassesInterface.class, + HasMemberClassesInterface.D.class.getEnclosingClass()); + assertEquals(ReflectionTest.class, Foo.class.getEnclosingClass()); + } + + public void testGetDeclaringClass() { + assertNull(ReflectionTest.class.getDeclaringClass()); + assertEquals(ReflectionTest.class, Foo.class.getDeclaringClass()); + assertEquals(ReflectionTest.class, HasMemberClassesInterface.class.getDeclaringClass()); + assertEquals(HasMemberClassesInterface.class, + HasMemberClassesInterface.D.class.getDeclaringClass()); + } + + public void testGetEnclosingClassIsTransitiveForClassesDefinedInAMethod() { + class C {} + assertEquals(ReflectionTest.class, C.class.getEnclosingClass()); + } + + public void testGetDeclaringClassIsNotTransitiveForClassesDefinedInAMethod() { + class C {} + assertEquals(null, C.class.getDeclaringClass()); + } + + public void testGetEnclosingMethodIsNotTransitive() { + class C { + class D {} + } + assertEquals(null, C.D.class.getEnclosingMethod()); + } + + private static final Object staticAnonymous = new Object() {}; + + public void testStaticFieldAnonymousClass() { + // The class declared in the <clinit> is enclosed by the <clinit>'s class. + // http://b/11245138 + assertEquals(ReflectionTest.class, staticAnonymous.getClass().getEnclosingClass()); + // However, because it is anonymous, it has no declaring class. + // https://code.google.com/p/android/issues/detail?id=61003 + assertNull(staticAnonymous.getClass().getDeclaringClass()); + // Because the class is declared in <clinit> which is not exposed through reflection, + // it has no enclosing method or constructor. + assertNull(staticAnonymous.getClass().getEnclosingMethod()); + assertNull(staticAnonymous.getClass().getEnclosingConstructor()); + } + + public void testGetEnclosingMethodOfTopLevelClass() { + assertNull(ReflectionTest.class.getEnclosingMethod()); + } + + public void testGetEnclosingConstructorOfTopLevelClass() { + assertNull(ReflectionTest.class.getEnclosingConstructor()); + } + + public void testClassEnclosedByConstructor() throws Exception { + Foo foo = new Foo("string"); + assertEquals(Foo.class, foo.c.getEnclosingClass()); + assertEquals(Foo.class.getDeclaredConstructor(String.class), + foo.c.getEnclosingConstructor()); + assertNull(foo.c.getEnclosingMethod()); + assertNull(foo.c.getDeclaringClass()); + } + + public void testClassEnclosedByMethod() throws Exception { + Foo foo = new Foo(); + foo.foo("string"); + assertEquals(Foo.class, foo.c.getEnclosingClass()); + assertNull(foo.c.getEnclosingConstructor()); + assertEquals(Foo.class.getDeclaredMethod("foo", String.class), + foo.c.getEnclosingMethod()); + assertNull(foo.c.getDeclaringClass()); + } + + public void testGetClasses() throws Exception { + // getClasses() doesn't include classes inherited from interfaces! + assertSetEquals(HasMemberClasses.class.getClasses(), + HasMemberClassesSuperclass.B.class, HasMemberClasses.H.class); + } + + public void testGetDeclaredClasses() throws Exception { + assertSetEquals(HasMemberClasses.class.getDeclaredClasses(), + HasMemberClasses.G.class, HasMemberClasses.H.class, HasMemberClasses.I.class, + HasMemberClasses.J.class, HasMemberClasses.K.class, HasMemberClasses.L.class); + } + + public void testConstructorGetExceptions() throws Exception { + assertSetEquals(HasThrows.class.getConstructor().getExceptionTypes(), + IOException.class, InvocationTargetException.class, IllegalStateException.class); + assertSetEquals(HasThrows.class.getConstructor(Void.class).getExceptionTypes()); + } + + public void testClassMethodGetExceptions() throws Exception { + assertSetEquals(HasThrows.class.getMethod("foo").getExceptionTypes(), + IOException.class, InvocationTargetException.class, IllegalStateException.class); + assertSetEquals(HasThrows.class.getMethod("foo", Void.class).getExceptionTypes()); + } + + public void testProxyMethodGetExceptions() throws Exception { + InvocationHandler emptyInvocationHandler = new InvocationHandler() { + @Override public Object invoke(Object proxy, Method method, Object[] args) { + return null; + } + }; + + Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), + new Class[] { ThrowsInterface.class }, emptyInvocationHandler); + assertSetEquals(proxy.getClass().getMethod("foo").getExceptionTypes(), + IOException.class, InvocationTargetException.class, IllegalStateException.class); + assertSetEquals(proxy.getClass().getMethod("foo", Void.class).getExceptionTypes()); + } + + public void testClassModifiers() { + int modifiers = ReflectionTest.class.getModifiers(); + assertTrue(Modifier.isPublic(modifiers)); + assertFalse(Modifier.isProtected(modifiers)); + assertFalse(Modifier.isPrivate(modifiers)); + assertFalse(Modifier.isAbstract(modifiers)); + assertFalse(Modifier.isStatic(modifiers)); + assertTrue(Modifier.isFinal(modifiers)); + assertFalse(Modifier.isStrict(modifiers)); + } + + public void testInnerClassModifiers() { + int modifiers = Foo.class.getModifiers(); + assertFalse(Modifier.isPublic(modifiers)); + assertFalse(Modifier.isProtected(modifiers)); + assertTrue(Modifier.isPrivate(modifiers)); + assertFalse(Modifier.isAbstract(modifiers)); + assertTrue(Modifier.isStatic(modifiers)); + assertFalse(Modifier.isFinal(modifiers)); + assertFalse(Modifier.isStrict(modifiers)); + } + + public void testAnonymousClassModifiers() { + int modifiers = staticAnonymous.getClass().getModifiers(); + assertFalse(Modifier.isPublic(modifiers)); + assertFalse(Modifier.isProtected(modifiers)); + assertFalse(Modifier.isPrivate(modifiers)); + assertFalse(Modifier.isAbstract(modifiers)); + assertTrue(Modifier.isStatic(modifiers)); + assertFalse(Modifier.isFinal(modifiers)); + assertFalse(Modifier.isStrict(modifiers)); + } + + public void testInnerClassName() { + assertEquals("ReflectionTest", ReflectionTest.class.getSimpleName()); + assertEquals("Foo", Foo.class.getSimpleName()); + assertEquals("", staticAnonymous.getClass().getSimpleName()); + } + + private static class Foo { + Class<?> c; + private Foo() { + } + private Foo(String s) { + c = new Object() {}.getClass(); + } + private Foo(int i) { + c = new Object() {}.getClass(); + } + private void foo(String s) { + c = new Object() {}.getClass(); + } + private void foo(int i) { + c = new Object() {}.getClass(); + } + } + + static class HasMemberClassesSuperclass { + class A {} + public class B {} + static class C {} + } + + public interface HasMemberClassesInterface { + class D {} + public class E {} + static class F {} + } + + public static class HasMemberClasses extends HasMemberClassesSuperclass + implements HasMemberClassesInterface { + class G {} + public class H {} + static class I {} + enum J {} + interface K {} + @interface L {} + } + + public static class HasThrows { + public HasThrows() throws IOException, InvocationTargetException, IllegalStateException {} + public HasThrows(Void v) {} + public void foo() throws IOException, InvocationTargetException, IllegalStateException {} + public void foo(Void v) {} + } + + public static interface ThrowsInterface { + void foo() throws IOException, InvocationTargetException, IllegalStateException; + void foo(Void v); + } + + private void assertSetEquals(Object[] actual, Object... expected) { + Set<Object> actualSet = new HashSet<Object>(Arrays.asList(actual)); + Set<Object> expectedSet = new HashSet<Object>(Arrays.asList(expected)); + assertEquals(expectedSet, actualSet); + } } diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotatedElementTestSupport.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotatedElementTestSupport.java new file mode 100644 index 0000000000..ec574699b6 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotatedElementTestSupport.java @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package libcore.java.lang.reflect.annotations; + +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.AnnotatedElement; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.StringJoiner; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertNull; +import static junit.framework.Assert.assertTrue; +import static junit.framework.Assert.fail; + +/** + * Utility methods and annotation definitions for use when testing implementations of + * AnnotatedElement. + * + * <p>For compactness, the repeated annotation methods that take strings use a format based on Java + * syntax rather than the toString() of annotations. For example, "@Repeated(1)" rather than + * "@libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated(value=1)". Use + * {@link #EXPECT_EMPTY} to indicate "no annotationed expected". + */ +public class AnnotatedElementTestSupport { + + @Retention(RetentionPolicy.RUNTIME) + public @interface AnnotationA {} + + @Inherited + @Retention(RetentionPolicy.RUNTIME) + public @interface AnnotationB {} + + @Retention(RetentionPolicy.RUNTIME) + public @interface AnnotationC {} + + @Retention(RetentionPolicy.RUNTIME) + public @interface AnnotationD {} + + @Retention(RetentionPolicy.RUNTIME) + @Inherited + @Target({ ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, + ElementType.PARAMETER, ElementType.PACKAGE }) + public @interface Container { + Repeated[] value(); + } + + @Repeatable(Container.class) + @Retention(RetentionPolicy.RUNTIME) + @Inherited + @Target({ ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, + ElementType.PARAMETER, ElementType.PACKAGE }) + public @interface Repeated { + int value(); + } + + /** + * A named constant that can be used with assert methods below that take + * "String[] expectedAnnotationStrings" as their final argument to indicate "none". + */ + public static final String[] EXPECT_EMPTY = new String[0]; + + private AnnotatedElementTestSupport() { + } + + /** + * Test the {@link AnnotatedElement} methods associated with "presence". i.e. methods that + * deal with annotations being "present" (i.e. "direct" or "inherited" annotations, not + * "indirect"). + * + * <p>Asserts that calling {@link AnnotatedElement#getAnnotations()} on the supplied element + * returns annotations of the supplied expected classes. + * + * <p>Where the expected classes contains some subset from + * {@link AnnotationA}, {@link AnnotationB} and {@link AnnotationC}, this method also asserts + * that {@link AnnotatedElement#isAnnotationPresent(Class)} and + * {@link AnnotatedElement#getAnnotation(Class)} works as expected. + * + * <p>This method also confirms that {@link AnnotatedElement#isAnnotationPresent(Class)} and + * {@link AnnotatedElement#getAnnotation(Class)} work correctly with a {@code null} argument. + */ + static void checkAnnotatedElementPresentMethods( + AnnotatedElement element, Class<? extends Annotation>... expectedAnnotations) { + Set<Class<? extends Annotation>> actualTypes = annotationsToTypes(element.getAnnotations()); + Set<Class<? extends Annotation>> expectedTypes = set(expectedAnnotations); + assertEquals(expectedTypes, actualTypes); + + // getAnnotations() should be consistent with isAnnotationPresent() and getAnnotation() + assertPresent(expectedTypes.contains(AnnotationA.class), element, AnnotationA.class); + assertPresent(expectedTypes.contains(AnnotationB.class), element, AnnotationB.class); + assertPresent(expectedTypes.contains(AnnotationC.class), element, AnnotationC.class); + + try { + element.isAnnotationPresent(null); + fail(); + } catch (NullPointerException expected) { + } + + try { + element.getAnnotation(null); + fail(); + } catch (NullPointerException expected) { + } + } + + /** + * Test the {@link AnnotatedElement} methods associated with "direct" annotations. + * + * <p>Asserts that calling {@link AnnotatedElement#getDeclaredAnnotations()} on the supplied + * element returns annotations of the supplied expected classes. + * + * <p>Where the expected classes contains some subset from + * {@link AnnotationA}, {@link AnnotationB} and {@link AnnotationC}, this method also asserts + * that {@link AnnotatedElement#getDeclaredAnnotation(Class)} works as expected. + * + * <p>This method also confirms that {@link AnnotatedElement#isAnnotationPresent(Class)} and + * {@link AnnotatedElement#getAnnotation(Class)} work correctly with a {@code null} argument. + */ + static void checkAnnotatedElementDirectMethods( + AnnotatedElement element, + Class<? extends Annotation>... expectedDeclaredAnnotations) { + Set<Class<? extends Annotation>> actualTypes = annotationsToTypes(element.getDeclaredAnnotations()); + Set<Class<? extends Annotation>> expectedTypes = set(expectedDeclaredAnnotations); + assertEquals(expectedTypes, actualTypes); + + assertDeclared(expectedTypes.contains(AnnotationA.class), element, AnnotationA.class); + assertDeclared(expectedTypes.contains(AnnotationB.class), element, AnnotationB.class); + assertDeclared(expectedTypes.contains(AnnotationC.class), element, AnnotationC.class); + + try { + element.getDeclaredAnnotation(null); + fail(); + } catch (NullPointerException expected) { + } + } + + /** + * Extracts the annotation types ({@link Annotation#annotationType()} from the supplied + * annotations. + */ + static Set<Class<? extends Annotation>> annotationsToTypes(Annotation[] annotations) { + Set<Class<? extends Annotation>> result = new HashSet<Class<? extends Annotation>>(); + for (Annotation annotation : annotations) { + result.add(annotation.annotationType()); + } + return result; + } + + private static void assertPresent(boolean present, AnnotatedElement element, + Class<? extends Annotation> annotation) { + if (present) { + assertNotNull(element.getAnnotation(annotation)); + assertTrue(element.isAnnotationPresent(annotation)); + } else { + assertNull(element.getAnnotation(annotation)); + assertFalse(element.isAnnotationPresent(annotation)); + } + } + + private static void assertDeclared(boolean present, AnnotatedElement element, + Class<? extends Annotation> annotation) { + if (present) { + assertNotNull(element.getDeclaredAnnotation(annotation)); + } else { + assertNull(element.getDeclaredAnnotation(annotation)); + } + } + + @SafeVarargs + static <T> Set<T> set(T... instances) { + return new HashSet<>(Arrays.asList(instances)); + } + + /** + * Asserts that {@link AnnotatedElement#isAnnotationPresent(Class)} returns the expected result. + */ + static void assertIsAnnotationPresent( + AnnotatedElement element, Class<? extends Annotation> annotationType, + boolean expected) { + assertEquals("element.isAnnotationPresent() for " + element + " and " + annotationType, + expected, element.isAnnotationPresent(annotationType)); + } + + /** + * Asserts that {@link AnnotatedElement#getDeclaredAnnotation(Class)} returns the expected + * result. The result is specified using a String. See {@link AnnotatedElementTestSupport} for + * the string syntax. + */ + static void assertGetDeclaredAnnotation(AnnotatedElement annotatedElement, + Class<? extends Annotation> annotationType, String expectedAnnotationString) { + Annotation annotation = annotatedElement.getDeclaredAnnotation(annotationType); + assertAnnotationMatches(annotation, expectedAnnotationString); + } + + /** + * Asserts that {@link AnnotatedElement#getDeclaredAnnotationsByType(Class)} returns the + * expected result. The result is specified using a String. See + * {@link AnnotatedElementTestSupport} for the string syntax. + */ + static void assertGetDeclaredAnnotationsByType( + AnnotatedElement annotatedElement, Class<? extends Annotation> annotationType, + String[] expectedAnnotationStrings) { + Annotation[] annotations = annotatedElement.getDeclaredAnnotationsByType(annotationType); + assertAnnotationsMatch(annotations, expectedAnnotationStrings); + } + + /** + * Asserts that {@link AnnotatedElement#getAnnotationsByType(Class)} returns the + * expected result. The result is specified using a String. See + * {@link AnnotatedElementTestSupport} for the string syntax. + */ + static void assertGetAnnotationsByType(AnnotatedElement annotatedElement, + Class<? extends Annotation> annotationType, String[] expectedAnnotationStrings) + throws Exception { + Annotation[] annotations = annotatedElement.getAnnotationsByType(annotationType); + assertAnnotationsMatch(annotations, expectedAnnotationStrings); + } + + private static void assertAnnotationMatches( + Annotation annotation, String expectedAnnotationString) { + if (expectedAnnotationString == null) { + assertNull(annotation); + } else { + assertNotNull(annotation); + assertEquals(expectedAnnotationString, createAnnotationTestString(annotation)); + } + } + + /** + * Asserts that the supplied annotations match the expectation Strings. See + * {@link AnnotatedElementTestSupport} for the string syntax. + */ + static void assertAnnotationsMatch(Annotation[] annotations, + String[] expectedAnnotationStrings) { + + // Due to Android's dex format insisting that Annotations are sorted by name the ordering of + // annotations is determined by the (simple?) name of the Annotation, not just the order + // that they are defined in the source. Tests have to be sensitive to that when handling + // mixed usage of "Container" and "Repeated" - the "Container" annotations will be + // discovered before "Repeated" due to their sort ordering. + // + // This code assumes that repeated annotations with the same name will be specified in the + // source their natural sort order when attributes are considered, just to make the testing + // simpler. + // e.g. @Repeated(1) @Repeated(2), never @Repeated(2) @Repeated(1) + + // Sorting the expected and actual strings _should_ work providing the assumptions above + // hold. It may mask random ordering issues but it's harder to deal with that while the + // source ordering is no observed. Providing no developers are ascribing meaning to the + // relative order of annotations things should be ok. + Arrays.sort(expectedAnnotationStrings); + + String[] actualAnnotationStrings = createAnnotationTestStrings(annotations); + Arrays.sort(actualAnnotationStrings); + + assertEquals( + Arrays.asList(expectedAnnotationStrings), + Arrays.asList(actualAnnotationStrings)); + } + + private static String[] createAnnotationTestStrings(Annotation[] annotations) { + String[] annotationStrings = new String[annotations.length]; + for (int i = 0; i < annotations.length; i++) { + annotationStrings[i] = createAnnotationTestString(annotations[i]); + } + return annotationStrings; + } + + private static String createAnnotationTestString(Annotation annotation) { + return "@" + annotation.annotationType().getSimpleName() + createArgumentsTestString( + annotation); + } + + private static String createArgumentsTestString(Annotation annotation) { + if (annotation instanceof Repeated) { + Repeated repeated = (Repeated) annotation; + return "(" + repeated.value() + ")"; + } else if (annotation instanceof Container) { + Container container = (Container) annotation; + String[] repeatedValues = createAnnotationTestStrings(container.value()); + StringJoiner joiner = new StringJoiner(", ", "{", "}"); + for (String repeatedValue : repeatedValues) { + joiner.add(repeatedValue); + } + String repeatedValuesString = joiner.toString(); + return "(" + repeatedValuesString + ")"; + } + throw new AssertionError("Unknown annotation: " + annotation); + } +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/Annotations57649Test.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/Annotations57649Test.java index 60e294bd6c..94c265eae9 100644 --- a/luni/src/test/java/libcore/java/lang/reflect/Annotations57649Test.java +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/Annotations57649Test.java @@ -1,4 +1,4 @@ -package libcore.java.lang.reflect; +package libcore.java.lang.reflect.annotations; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotationsTest.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotationsTest.java new file mode 100644 index 0000000000..a694981c70 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotationsTest.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package libcore.java.lang.reflect.annotations; + +import junit.framework.TestCase; + +import java.lang.annotation.Annotation; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationA; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationB; + +import dalvik.system.VMRuntime; + +/** + * Tests for the behavior of Annotation instances at runtime. + */ +public class AnnotationsTest extends TestCase { + + enum Breakfast { WAFFLES, PANCAKES } + + @Retention(RetentionPolicy.RUNTIME) + public @interface HasDefaultsAnnotation { + byte a() default 5; + short b() default 6; + int c() default 7; + long d() default 8; + float e() default 9.0f; + double f() default 10.0; + char g() default 'k'; + boolean h() default true; + Breakfast i() default Breakfast.WAFFLES; + AnnotationA j() default @AnnotationA(); + String k() default "maple"; + Class l() default AnnotationB.class; + int[] m() default { 1, 2, 3 }; + Breakfast[] n() default { Breakfast.WAFFLES, Breakfast.PANCAKES }; + Breakfast o(); + int p(); + } + + public void testAnnotationDefaults() throws Exception { + assertEquals((byte) 5, defaultValue("a")); + assertEquals((short) 6, defaultValue("b")); + assertEquals(7, defaultValue("c")); + assertEquals(8L, defaultValue("d")); + assertEquals(9.0f, defaultValue("e")); + assertEquals(10.0, defaultValue("f")); + assertEquals('k', defaultValue("g")); + assertEquals(true, defaultValue("h")); + assertEquals(Breakfast.WAFFLES, defaultValue("i")); + assertEquals("@" + AnnotationA.class.getName() + "()", defaultValue("j").toString()); + assertEquals("maple", defaultValue("k")); + assertEquals(AnnotationB.class, defaultValue("l")); + assertEquals("[1, 2, 3]", Arrays.toString((int[]) defaultValue("m"))); + assertEquals("[WAFFLES, PANCAKES]", Arrays.toString((Breakfast[]) defaultValue("n"))); + assertEquals(null, defaultValue("o")); + assertEquals(null, defaultValue("p")); + } + + private static Object defaultValue(String name) throws NoSuchMethodException { + return HasDefaultsAnnotation.class.getMethod(name).getDefaultValue(); + } + + @Retention(RetentionPolicy.CLASS) + public @interface ClassRetentionAnnotation {} + + @Retention(RetentionPolicy.RUNTIME) + public @interface RuntimeRetentionAnnotation {} + + @Retention(RetentionPolicy.SOURCE) + public @interface SourceRetentionAnnotation {} + + @ClassRetentionAnnotation @RuntimeRetentionAnnotation @SourceRetentionAnnotation + public static class RetentionAnnotations {} + + public void testRetentionPolicy() { + // b/29500035 + int savedTargetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion(); + try { + // Test N and later behavior + VMRuntime.getRuntime().setTargetSdkVersion(24); + Annotation classRetentionAnnotation = + RetentionAnnotations.class.getAnnotation(ClassRetentionAnnotation.class); + assertNull(classRetentionAnnotation); + + // Test pre-N behavior + VMRuntime.getRuntime().setTargetSdkVersion(23); + classRetentionAnnotation = + RetentionAnnotations.class.getAnnotation(ClassRetentionAnnotation.class); + assertNotNull(classRetentionAnnotation); + } finally { + VMRuntime.getRuntime().setTargetSdkVersion(savedTargetSdkVersion); + } + assertNotNull(RetentionAnnotations.class.getAnnotation(RuntimeRetentionAnnotation.class)); + assertNull(RetentionAnnotations.class.getAnnotation(SourceRetentionAnnotation.class)); + } +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/ClassTest.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/ClassTest.java new file mode 100644 index 0000000000..5488ed19d0 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/ClassTest.java @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package libcore.java.lang.reflect.annotations; + +import junit.framework.TestCase; + +import java.lang.annotation.Inherited; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationA; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationB; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Container; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated; + +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.EXPECT_EMPTY; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.checkAnnotatedElementPresentMethods; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.checkAnnotatedElementDirectMethods; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertGetDeclaredAnnotation; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertIsAnnotationPresent; + +public class ClassTest extends TestCase { + + public void setUp() throws Exception { + super.setUp(); + // Required by all the tests. + Repeated.class.isAnnotationPresent(Inherited.class); + } + + @AnnotationA + @AnnotationB + private static class Type { + } + + public static class ExtendsType extends Type {} + + public void testClassDirectAnnotations() { + checkAnnotatedElementPresentMethods(Type.class, AnnotationA.class, AnnotationB.class); + checkAnnotatedElementDirectMethods(Type.class, AnnotationA.class, AnnotationB.class); + } + + public void testClassInheritedAnnotations() { + checkAnnotatedElementPresentMethods(ExtendsType.class, AnnotationB.class); + checkAnnotatedElementDirectMethods(ExtendsType.class); + } + + @Repeated(1) + private static class SingleAnnotation {} + + @Repeated(1) + @Repeated(2) + private static class MultipleAnnotation {} + + @Container({@Repeated(1)}) + private static class MultipleAnnotationExplicitSingle {} + + @Repeated(1) + @Container({@Repeated(2), @Repeated(3)}) + private static class MultipleAnnotationOddity {} + + private static class NoAnnotation {} + + private static class InheritedNoNewAnnotation extends SingleAnnotation {} + + @Repeated(2) + private static class InheritedSingleWithNewSingleAnnotation extends SingleAnnotation {} + + @Repeated(2) + @Repeated(3) + private static class InheritedSingleWithNewMultipleAnnotations extends SingleAnnotation {} + + @Repeated(2) + private static class InheritedMultipleWithNewSingleAnnotation extends MultipleAnnotation {} + + @Repeated(2) + @Repeated(3) + private static class InheritedMultipleWithNewMultipleAnnotations extends MultipleAnnotation {} + + public void testIsAnnotationPresent() throws Exception { + Class<Repeated> repeated = Repeated.class; + assertIsAnnotationPresent(NoAnnotation.class, repeated, false); + assertIsAnnotationPresent(SingleAnnotation.class, repeated, true); + assertIsAnnotationPresent(MultipleAnnotation.class, repeated, false); + assertIsAnnotationPresent(MultipleAnnotationExplicitSingle.class, repeated, false); + assertIsAnnotationPresent(MultipleAnnotationOddity.class, repeated, true); + assertIsAnnotationPresent(InheritedNoNewAnnotation.class, repeated, true); + assertIsAnnotationPresent(InheritedSingleWithNewSingleAnnotation.class, repeated, true); + assertIsAnnotationPresent(InheritedSingleWithNewMultipleAnnotations.class, repeated, true); + assertIsAnnotationPresent(InheritedMultipleWithNewSingleAnnotation.class, repeated, true); + assertIsAnnotationPresent(InheritedMultipleWithNewMultipleAnnotations.class, repeated, + false); + + Class<Container> container = Container.class; + assertIsAnnotationPresent(NoAnnotation.class, repeated, false); + assertIsAnnotationPresent(SingleAnnotation.class, container, false); + assertIsAnnotationPresent(MultipleAnnotation.class, container, true); + assertIsAnnotationPresent(MultipleAnnotationExplicitSingle.class, container, true); + assertIsAnnotationPresent(MultipleAnnotationOddity.class, container, true); + assertIsAnnotationPresent(InheritedNoNewAnnotation.class, container, false); + assertIsAnnotationPresent(InheritedSingleWithNewSingleAnnotation.class, container, false); + assertIsAnnotationPresent(InheritedSingleWithNewMultipleAnnotations.class, container, true); + assertIsAnnotationPresent(InheritedMultipleWithNewSingleAnnotation.class, container, true); + assertIsAnnotationPresent(InheritedMultipleWithNewMultipleAnnotations.class, container, + true); + } + + public void testGetDeclaredAnnotation() throws Exception { + Class<Repeated> repeated = Repeated.class; + assertGetDeclaredAnnotation(NoAnnotation.class, repeated, null); + assertGetDeclaredAnnotation(SingleAnnotation.class, repeated, "@Repeated(1)"); + assertGetDeclaredAnnotation(MultipleAnnotation.class, repeated, null); + assertGetDeclaredAnnotation(MultipleAnnotationExplicitSingle.class, repeated, null); + assertGetDeclaredAnnotation(MultipleAnnotationOddity.class, repeated, "@Repeated(1)"); + assertGetDeclaredAnnotation(InheritedNoNewAnnotation.class, repeated, null); + assertGetDeclaredAnnotation(InheritedSingleWithNewSingleAnnotation.class, repeated, + "@Repeated(2)"); + assertGetDeclaredAnnotation(InheritedSingleWithNewMultipleAnnotations.class, repeated, + null); + assertGetDeclaredAnnotation(InheritedMultipleWithNewSingleAnnotation.class, repeated, + "@Repeated(2)"); + assertGetDeclaredAnnotation(InheritedMultipleWithNewMultipleAnnotations.class, repeated, + null); + + Class<Container> container = Container.class; + assertGetDeclaredAnnotation(NoAnnotation.class, container, null); + assertGetDeclaredAnnotation(SingleAnnotation.class, container, null); + assertGetDeclaredAnnotation(MultipleAnnotation.class, container, + "@Container({@Repeated(1), @Repeated(2)})"); + assertGetDeclaredAnnotation(MultipleAnnotationExplicitSingle.class, container, + "@Container({@Repeated(1)})"); + assertGetDeclaredAnnotation(MultipleAnnotationOddity.class, container, + "@Container({@Repeated(2), @Repeated(3)})"); + assertGetDeclaredAnnotation(InheritedNoNewAnnotation.class, container, null); + assertGetDeclaredAnnotation(InheritedSingleWithNewSingleAnnotation.class, container, null); + assertGetDeclaredAnnotation(InheritedSingleWithNewMultipleAnnotations.class, container, + "@Container({@Repeated(2), @Repeated(3)})"); + assertGetDeclaredAnnotation(InheritedMultipleWithNewSingleAnnotation.class, container, + null); + assertGetDeclaredAnnotation(InheritedMultipleWithNewMultipleAnnotations.class, container, + "@Container({@Repeated(2), @Repeated(3)})"); + } + + public void testGetDeclaredAnnotationsByType() throws Exception { + Class<Repeated> repeated = Repeated.class; + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + NoAnnotation.class, repeated, EXPECT_EMPTY); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + SingleAnnotation.class, repeated, new String[] { "@Repeated(1)" }); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + MultipleAnnotation.class, repeated, new String[] { "@Repeated(1)", "@Repeated(2)" }); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + MultipleAnnotationExplicitSingle.class, repeated, new String[] { "@Repeated(1)" }); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + MultipleAnnotationOddity.class, repeated, + new String[] { "@Repeated(1)", "@Repeated(2)", "@Repeated(3)" }); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + InheritedNoNewAnnotation.class, repeated, EXPECT_EMPTY); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + InheritedSingleWithNewSingleAnnotation.class, repeated, + new String[] { "@Repeated(2)" }); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + InheritedSingleWithNewMultipleAnnotations.class, repeated, + new String[] { "@Repeated(2)", "@Repeated(3)" }); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + InheritedMultipleWithNewSingleAnnotation.class, repeated, + new String[] { "@Repeated(2)" }); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + InheritedMultipleWithNewMultipleAnnotations.class, repeated, + new String[] { "@Repeated(2)", "@Repeated(3)" }); + + Class<Container> container = Container.class; + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + NoAnnotation.class, container, EXPECT_EMPTY); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + SingleAnnotation.class, container, EXPECT_EMPTY); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + MultipleAnnotation.class, container, + new String[] { "@Container({@Repeated(1), @Repeated(2)})" }); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + MultipleAnnotationExplicitSingle.class, container, + new String[] { "@Container({@Repeated(1)})" }); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + MultipleAnnotationOddity.class, container, + new String[] { "@Container({@Repeated(2), @Repeated(3)})" }); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + InheritedNoNewAnnotation.class, container, EXPECT_EMPTY); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + InheritedSingleWithNewSingleAnnotation.class, container, EXPECT_EMPTY); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + InheritedSingleWithNewMultipleAnnotations.class, container, + new String[] { "@Container({@Repeated(2), @Repeated(3)})" }); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + InheritedMultipleWithNewSingleAnnotation.class, container, EXPECT_EMPTY); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + InheritedMultipleWithNewMultipleAnnotations.class, container, + new String[] { "@Container({@Repeated(2), @Repeated(3)})" }); + } + + public void testGetAnnotationsByType() throws Exception { + Class<Repeated> repeated = Repeated.class; + AnnotatedElementTestSupport.assertGetAnnotationsByType( + NoAnnotation.class, repeated, EXPECT_EMPTY); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + SingleAnnotation.class, repeated, new String[] { "@Repeated(1)" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + MultipleAnnotation.class, repeated, new String[] { "@Repeated(1)", "@Repeated(2)" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + MultipleAnnotationExplicitSingle.class, repeated, new String[] { "@Repeated(1)" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + MultipleAnnotationOddity.class, repeated, + new String[] { "@Repeated(1)", "@Repeated(2)", "@Repeated(3)" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + InheritedNoNewAnnotation.class, repeated, new String[] { "@Repeated(1)" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + InheritedSingleWithNewSingleAnnotation.class, repeated, + new String[] { "@Repeated(2)" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + InheritedSingleWithNewMultipleAnnotations.class, repeated, + new String[] { "@Repeated(2)", "@Repeated(3)" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + InheritedMultipleWithNewSingleAnnotation.class, repeated, + new String[] { "@Repeated(2)" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + InheritedMultipleWithNewMultipleAnnotations.class, repeated, + new String[] { "@Repeated(2)", "@Repeated(3)" }); + + Class<Container> container = Container.class; + AnnotatedElementTestSupport.assertGetAnnotationsByType( + NoAnnotation.class, container, EXPECT_EMPTY); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + SingleAnnotation.class, container, EXPECT_EMPTY); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + MultipleAnnotation.class, container, + new String[] { "@Container({@Repeated(1), @Repeated(2)})" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + MultipleAnnotationExplicitSingle.class, container, + new String[] { "@Container({@Repeated(1)})" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + MultipleAnnotationOddity.class, container, + new String[] { "@Container({@Repeated(2), @Repeated(3)})" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + InheritedNoNewAnnotation.class, container, EXPECT_EMPTY); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + InheritedSingleWithNewSingleAnnotation.class, container, EXPECT_EMPTY); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + InheritedSingleWithNewMultipleAnnotations.class, container, + new String[] { "@Container({@Repeated(2), @Repeated(3)})" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + InheritedMultipleWithNewSingleAnnotation.class, container, + new String[] { "@Container({@Repeated(1), @Repeated(2)})" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + InheritedMultipleWithNewMultipleAnnotations.class, container, + new String[] { "@Container({@Repeated(2), @Repeated(3)})" }); + } +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/ConstructorTest.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/ConstructorTest.java new file mode 100644 index 0000000000..828b6016f2 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/ConstructorTest.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package libcore.java.lang.reflect.annotations; + +import junit.framework.TestCase; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationA; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationC; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Container; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated; + +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.EXPECT_EMPTY; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.checkAnnotatedElementPresentMethods; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertGetDeclaredAnnotation; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertIsAnnotationPresent; + +public class ConstructorTest extends TestCase { + + private static class Type { + @AnnotationA + @AnnotationC + public Type() {} + } + + public void testConstructorAnnotations() throws Exception { + Constructor<Type> constructor = Type.class.getConstructor(); + checkAnnotatedElementPresentMethods(constructor, AnnotationA.class, AnnotationC.class); + } + + // A class with multiple constructors that differ by their argument count. + private static class AnnotatedClass { + @Repeated(1) + public AnnotatedClass() {} + + @Repeated(1) + @Repeated(2) + public AnnotatedClass(int a) {} + + @Container({@Repeated(1)}) + public AnnotatedClass(int a, int b) {} + + @Repeated(1) + @Container({@Repeated(2), @Repeated(3)}) + public AnnotatedClass(int a, int b, int c) {} + + public AnnotatedClass(int a, int b, int c, int d) {} + } + + // Tests for isAnnotationPresent and getDeclaredAnnotation. + public void testDeclaredAnnotation() throws Exception { + Class<?> c = AnnotatedClass.class; + + Class<? extends Annotation> repeated = Repeated.class; + checkDeclaredAnnotation(c, 4, repeated, null); + checkDeclaredAnnotation(c, 3, repeated, "@Repeated(1)"); + checkDeclaredAnnotation(c, 2, repeated, null); + checkDeclaredAnnotation(c, 1, repeated, null); + checkDeclaredAnnotation(c, 0, repeated, "@Repeated(1)"); + + Class<? extends Annotation> container = Container.class; + checkDeclaredAnnotation(c, 4, container, null); + checkDeclaredAnnotation(c, 3, container, "@Container({@Repeated(2), @Repeated(3)})"); + checkDeclaredAnnotation(c, 2, container, "@Container({@Repeated(1)})"); + checkDeclaredAnnotation(c, 1, container, "@Container({@Repeated(1), @Repeated(2)})"); + checkDeclaredAnnotation(c, 0, container, null); + } + + private static void checkDeclaredAnnotation(Class<?> c, int constructorArgCount, + Class<? extends Annotation> annotationType, + String expectedAnnotationString) throws Exception { + Constructor constructor = getConstructor(c, constructorArgCount); + + // isAnnotationPresent + assertIsAnnotationPresent(constructor, annotationType, + expectedAnnotationString != null); + + // getDeclaredAnnotation + assertGetDeclaredAnnotation(constructor, annotationType, expectedAnnotationString); + } + + public void testGetDeclaredAnnotationsByType() throws Exception { + Class<?> c = AnnotatedClass.class; + + Class<? extends Annotation> repeated = Repeated.class; + assertGetDeclaredAnnotationsByType(c, 4, repeated, EXPECT_EMPTY); + assertGetDeclaredAnnotationsByType(c, 3, repeated, + "@Repeated(1)", "@Repeated(2)", "@Repeated(3)"); + assertGetDeclaredAnnotationsByType(c, 2, repeated, "@Repeated(1)"); + assertGetDeclaredAnnotationsByType(c, 1, repeated, "@Repeated(1)", "@Repeated(2)"); + assertGetDeclaredAnnotationsByType(c, 0, repeated, "@Repeated(1)"); + + Class<? extends Annotation> container = Container.class; + assertGetDeclaredAnnotationsByType(c, 4, container, EXPECT_EMPTY); + assertGetDeclaredAnnotationsByType(c, 3, container, + "@Container({@Repeated(2), @Repeated(3)})"); + assertGetDeclaredAnnotationsByType(c, 2, container, "@Container({@Repeated(1)})"); + assertGetDeclaredAnnotationsByType(c, 1, container, + "@Container({@Repeated(1), @Repeated(2)})"); + assertGetDeclaredAnnotationsByType(c, 0, container, EXPECT_EMPTY); + } + + private static void assertGetDeclaredAnnotationsByType(Class<?> c, int constructorArgCount, + Class<? extends Annotation> annotationType, + String... expectedAnnotationStrings) throws Exception { + Constructor<?> constructor = getConstructor(c, constructorArgCount); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + constructor, annotationType, expectedAnnotationStrings); + } + + public void testGetAnnotationsByType() throws Exception { + Class<?> c = AnnotatedClass.class; + + Class<? extends Annotation> repeated = Repeated.class; + assertGetAnnotationsByType(c, 4, repeated, EXPECT_EMPTY); + assertGetAnnotationsByType(c, 3, repeated, "@Repeated(1)", "@Repeated(2)", "@Repeated(3)"); + assertGetAnnotationsByType(c, 2, repeated, "@Repeated(1)"); + assertGetAnnotationsByType(c, 1, repeated, "@Repeated(1)", "@Repeated(2)"); + assertGetAnnotationsByType(c, 0, repeated, "@Repeated(1)"); + + Class<? extends Annotation> container = Container.class; + assertGetAnnotationsByType(c, 4, container, EXPECT_EMPTY); + assertGetAnnotationsByType(c, 3, container, "@Container({@Repeated(2), @Repeated(3)})"); + assertGetAnnotationsByType(c, 2, container, "@Container({@Repeated(1)})"); + assertGetAnnotationsByType(c, 1, container, "@Container({@Repeated(1), @Repeated(2)})"); + assertGetAnnotationsByType(c, 0, container, EXPECT_EMPTY); + } + + private static void assertGetAnnotationsByType(Class<?> c, int constructorArgCount, + Class<? extends Annotation> annotationType, + String... expectedAnnotationStrings) throws Exception { + Constructor<?> constructor = getConstructor(c, constructorArgCount); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + constructor, annotationType, expectedAnnotationStrings); + } + + private static Constructor<?> getConstructor(Class<?> c, int constructorArgCount) + throws NoSuchMethodException { + + Class<?>[] args = new Class[constructorArgCount]; + for (int i = 0; i < constructorArgCount; i++) { + args[i] = Integer.TYPE; + } + return c.getDeclaredConstructor(args); + } +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/FieldTest.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/FieldTest.java new file mode 100644 index 0000000000..8ab7d8ea05 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/FieldTest.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package libcore.java.lang.reflect.annotations; + +import junit.framework.TestCase; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationA; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationD; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Container; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated; + +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.EXPECT_EMPTY; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.checkAnnotatedElementPresentMethods; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertGetDeclaredAnnotation; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertIsAnnotationPresent; + +public class FieldTest extends TestCase { + + private static class Type { + @AnnotationA + @AnnotationD + public String field; + } + + public void testFieldAnnotations() throws Exception { + Field field = Type.class.getField("field"); + checkAnnotatedElementPresentMethods(field, AnnotationA.class, AnnotationD.class); + } + + private static class AnnotatedClass { + @Repeated(1) + private Object singleAnnotation; + + @Repeated(1) + @Repeated(2) + private Object multipleAnnotation; + + @Container({@Repeated(1)}) + private Object multipleAnnotationExplicitSingle; + + @Repeated(1) + @Container({@Repeated(2), @Repeated(3)}) + private Object multipleAnnotationOddity; + + private Object noAnnotation; + } + + // Tests for isAnnotationPresent and getDeclaredAnnotation. + public void testDeclaredAnnotation() throws Exception { + Class<?> c = AnnotatedClass.class; + + Class<? extends Annotation> repeated = Repeated.class; + checkDeclaredAnnotation(c, "noAnnotation", repeated, null); + checkDeclaredAnnotation(c, "multipleAnnotationOddity", repeated, "@Repeated(1)"); + checkDeclaredAnnotation(c, "multipleAnnotationExplicitSingle", repeated, null); + checkDeclaredAnnotation(c, "multipleAnnotation", repeated, null); + checkDeclaredAnnotation(c, "singleAnnotation", repeated, "@Repeated(1)"); + + Class<? extends Annotation> container = Container.class; + checkDeclaredAnnotation(c, "noAnnotation", container, null); + checkDeclaredAnnotation(c, "multipleAnnotationOddity", container, + "@Container({@Repeated(2), @Repeated(3)})"); + checkDeclaredAnnotation(c, "multipleAnnotationExplicitSingle", container, + "@Container({@Repeated(1)})"); + checkDeclaredAnnotation(c, "multipleAnnotation", container, + "@Container({@Repeated(1), @Repeated(2)})"); + checkDeclaredAnnotation(c, "singleAnnotation", container, null); + } + + private static void checkDeclaredAnnotation( + Class<?> c, String fieldName, Class<? extends Annotation> annotationType, + String expectedAnnotationString) throws Exception { + Field field = c.getDeclaredField(fieldName); + + // isAnnotationPresent + assertIsAnnotationPresent(field, annotationType, expectedAnnotationString != null); + + // getDeclaredAnnotation + assertGetDeclaredAnnotation(field, annotationType, expectedAnnotationString); + } + + public void testGetDeclaredAnnotationsByType() throws Exception { + Class<?> c = AnnotatedClass.class; + + Class<? extends Annotation> repeated = Repeated.class; + assertGetDeclaredAnnotationsByType(c, repeated, "noAnnotation", EXPECT_EMPTY); + assertGetDeclaredAnnotationsByType(c, repeated, "multipleAnnotationOddity", + "@Repeated(1)", "@Repeated(2)", "@Repeated(3)"); + assertGetDeclaredAnnotationsByType(c, repeated, "multipleAnnotationExplicitSingle", + "@Repeated(1)"); + assertGetDeclaredAnnotationsByType(c, repeated, "multipleAnnotation", + "@Repeated(1)", "@Repeated(2)"); + assertGetDeclaredAnnotationsByType(c, repeated, "singleAnnotation", "@Repeated(1)"); + + Class<? extends Annotation> container = Container.class; + assertGetDeclaredAnnotationsByType(c, container, "noAnnotation", EXPECT_EMPTY); + assertGetDeclaredAnnotationsByType(c, container, "multipleAnnotationOddity", + "@Container({@Repeated(2), @Repeated(3)})"); + assertGetDeclaredAnnotationsByType(c, container, "multipleAnnotationExplicitSingle", + "@Container({@Repeated(1)})"); + assertGetDeclaredAnnotationsByType(c, container, "multipleAnnotation", + "@Container({@Repeated(1), @Repeated(2)})"); + assertGetDeclaredAnnotationsByType(c, container, "singleAnnotation", EXPECT_EMPTY); + } + + private static void assertGetDeclaredAnnotationsByType( + Class<?> c, Class<? extends Annotation> annotationType, String fieldName, + String... expectedAnnotationStrings) throws Exception { + Field field = c.getDeclaredField(fieldName); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + field, annotationType, expectedAnnotationStrings); + } + + public void testGetAnnotationsByType() throws Exception { + Class<?> c = AnnotatedClass.class; + + Class<? extends Annotation> repeated = Repeated.class; + assertGetAnnotationsByType(c, repeated, "noAnnotation", EXPECT_EMPTY); + assertGetAnnotationsByType(c, repeated, "multipleAnnotationOddity", + "@Repeated(1)", "@Repeated(2)", "@Repeated(3)"); + assertGetAnnotationsByType(c, repeated, "multipleAnnotationExplicitSingle", + "@Repeated(1)"); + assertGetAnnotationsByType(c, repeated, "multipleAnnotation", + "@Repeated(1)", "@Repeated(2)"); + assertGetAnnotationsByType(c, repeated, "singleAnnotation", "@Repeated(1)"); + + Class<? extends Annotation> container = Container.class; + assertGetAnnotationsByType(c, container, "noAnnotation", EXPECT_EMPTY); + assertGetAnnotationsByType(c, container, "multipleAnnotationOddity", + "@Container({@Repeated(2), @Repeated(3)})"); + assertGetAnnotationsByType(c, container, "multipleAnnotationExplicitSingle", + "@Container({@Repeated(1)})"); + assertGetAnnotationsByType(c, container, "multipleAnnotation", + "@Container({@Repeated(1), @Repeated(2)})"); + assertGetAnnotationsByType(c, container, "singleAnnotation", EXPECT_EMPTY); + } + + private static void assertGetAnnotationsByType( + Class<?> c, Class<? extends Annotation> annotationType, + String fieldName, String... expectedAnnotationStrings) throws Exception { + Field field = c.getDeclaredField(fieldName); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + field, annotationType, expectedAnnotationStrings); + } +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/MethodTest.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/MethodTest.java new file mode 100644 index 0000000000..c732a9d531 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/MethodTest.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package libcore.java.lang.reflect.annotations; + +import junit.framework.TestCase; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationB; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationC; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Container; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated; + +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.EXPECT_EMPTY; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.checkAnnotatedElementPresentMethods; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertGetDeclaredAnnotation; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertIsAnnotationPresent; + +public class MethodTest extends TestCase { + + private static class Type { + @AnnotationB + @AnnotationC + public void method(String parameter1, String parameter2) {} + } + + public void testMethodAnnotations() throws Exception { + Method method = Type.class.getMethod("method", String.class, String.class); + checkAnnotatedElementPresentMethods(method, AnnotationB.class, AnnotationC.class); + } + + private static class AnnotatedClass { + @Repeated(1) + public void singleAnnotation() {} + + @Repeated(1) + @Repeated(2) + public void multipleAnnotation() {} + + @Container({@Repeated(1)}) + public void multipleAnnotationExplicitSingle() {} + + @Repeated(1) + @Container({@Repeated(2), @Repeated(3)}) + public void multipleAnnotationOddity() {} + + public void noAnnotation() {} + } + + // Tests for isAnnotationPresent and getDeclaredAnnotation. + public void testDeclaredAnnotation() throws Exception { + Class<?> c = AnnotatedClass.class; + + Class<? extends Annotation> repeated = Repeated.class; + checkDeclaredAnnotation(c, "noAnnotation", repeated, null); + checkDeclaredAnnotation(c, "multipleAnnotationOddity", repeated, "@Repeated(1)"); + checkDeclaredAnnotation(c, "multipleAnnotationExplicitSingle", repeated, null); + checkDeclaredAnnotation(c, "multipleAnnotation", repeated, null); + checkDeclaredAnnotation(c, "singleAnnotation", repeated, "@Repeated(1)"); + + Class<? extends Annotation> container = Container.class; + checkDeclaredAnnotation(c, "noAnnotation", container, null); + checkDeclaredAnnotation(c, "multipleAnnotationOddity", container, + "@Container({@Repeated(2), @Repeated(3)})"); + checkDeclaredAnnotation(c, "multipleAnnotationExplicitSingle", container, + "@Container({@Repeated(1)})"); + checkDeclaredAnnotation(c, "multipleAnnotation", container, + "@Container({@Repeated(1), @Repeated(2)})"); + checkDeclaredAnnotation(c, "singleAnnotation", container, null); + } + + private static void checkDeclaredAnnotation( + Class<?> c, String methodName, Class<? extends Annotation> annotationType, + String expectedAnnotationString) throws Exception { + Method method = c.getDeclaredMethod(methodName); + + // isAnnotationPresent + assertIsAnnotationPresent(method, annotationType, expectedAnnotationString != null); + + // getDeclaredAnnotation + assertGetDeclaredAnnotation(method, annotationType, expectedAnnotationString); + } + + public void testGetDeclaredAnnotationsByType() throws Exception { + Class<?> c = AnnotatedClass.class; + + Class<? extends Annotation> repeated = Repeated.class; + assertGetDeclaredAnnotationsByType(c, repeated, "noAnnotation", EXPECT_EMPTY); + assertGetDeclaredAnnotationsByType(c, repeated, "multipleAnnotationOddity", + "@Repeated(1)", "@Repeated(2)", "@Repeated(3)"); + assertGetDeclaredAnnotationsByType(c, repeated, "multipleAnnotationExplicitSingle", + "@Repeated(1)"); + assertGetDeclaredAnnotationsByType(c, repeated, "multipleAnnotation", + "@Repeated(1)", "@Repeated(2)"); + assertGetDeclaredAnnotationsByType(c, repeated, "singleAnnotation", "@Repeated(1)"); + + Class<? extends Annotation> container = Container.class; + assertGetDeclaredAnnotationsByType(c, container, "noAnnotation", EXPECT_EMPTY); + assertGetDeclaredAnnotationsByType(c, container, "multipleAnnotationOddity", + "@Container({@Repeated(2), @Repeated(3)})"); + assertGetDeclaredAnnotationsByType(c, container, "multipleAnnotationExplicitSingle", + "@Container({@Repeated(1)})"); + assertGetDeclaredAnnotationsByType(c, container, "multipleAnnotation", + "@Container({@Repeated(1), @Repeated(2)})"); + assertGetDeclaredAnnotationsByType(c, container, "singleAnnotation", EXPECT_EMPTY); + } + + private static void assertGetDeclaredAnnotationsByType( + Class<?> c, Class<? extends Annotation> annotationType, String methodName, + String... expectedAnnotationStrings) throws Exception { + Method method = c.getDeclaredMethod(methodName); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + method, annotationType, expectedAnnotationStrings); + } + + public void testGetAnnotationsByType() throws Exception { + Class<?> c = AnnotatedClass.class; + + Class<? extends Annotation> repeated = Repeated.class; + assertGetAnnotationsByType(c, repeated, "noAnnotation", EXPECT_EMPTY); + assertGetAnnotationsByType(c, repeated, "multipleAnnotationOddity", + "@Repeated(1)", "@Repeated(2)", "@Repeated(3)"); + assertGetAnnotationsByType(c, repeated, "multipleAnnotationExplicitSingle", + "@Repeated(1)"); + assertGetAnnotationsByType(c, repeated, "multipleAnnotation", + "@Repeated(1)", "@Repeated(2)"); + assertGetAnnotationsByType(c, repeated, "singleAnnotation", "@Repeated(1)"); + + Class<? extends Annotation> container = Container.class; + assertGetAnnotationsByType(c, container, "noAnnotation", EXPECT_EMPTY); + assertGetAnnotationsByType(c, container, "multipleAnnotationOddity", + "@Container({@Repeated(2), @Repeated(3)})"); + assertGetAnnotationsByType(c, container, "multipleAnnotationExplicitSingle", + "@Container({@Repeated(1)})"); + assertGetAnnotationsByType(c, container, "multipleAnnotation", + "@Container({@Repeated(1), @Repeated(2)})"); + assertGetAnnotationsByType(c, container, "singleAnnotation", EXPECT_EMPTY); + } + + private static void assertGetAnnotationsByType( + Class<?> c, Class<? extends Annotation> annotationType, + String methodName, String... expectedAnnotationStrings) throws Exception { + Method method = c.getDeclaredMethod(methodName); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + method, annotationType, expectedAnnotationStrings); + } +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/PackageTest.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/PackageTest.java new file mode 100644 index 0000000000..f54a64e437 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/PackageTest.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package libcore.java.lang.reflect.annotations; + +import junit.framework.TestCase; + +import java.lang.annotation.Annotation; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Container; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated; +import libcore.java.lang.reflect.annotations.multipleannotation.MultipleAnnotation; +import libcore.java.lang.reflect.annotations.multipleannotationexplicitsingle.MultipleAnnotationExplicitSingle; +import libcore.java.lang.reflect.annotations.multipleannotationoddity.MultipleAnnotationOddity; +import libcore.java.lang.reflect.annotations.noannotation.NoAnnotation; +import libcore.java.lang.reflect.annotations.singleannotation.SingleAnnotation; + +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.EXPECT_EMPTY; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertGetDeclaredAnnotation; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertIsAnnotationPresent; + +public class PackageTest extends TestCase { + + // Tests for isAnnotationPresent and getDeclaredAnnotation. + public void testDeclaredAnnotation() throws Exception { + Class<Repeated> repeated = Repeated.class; + checkDeclaredAnnotation(NoAnnotation.class, repeated, null); + checkDeclaredAnnotation(SingleAnnotation.class, repeated, "@Repeated(1)"); + checkDeclaredAnnotation(MultipleAnnotation.class, repeated, null); + checkDeclaredAnnotation(MultipleAnnotationExplicitSingle.class, repeated, null); + checkDeclaredAnnotation(MultipleAnnotationOddity.class, repeated, "@Repeated(1)"); + + Class<Container> container = Container.class; + checkDeclaredAnnotation(NoAnnotation.class, container, null); + checkDeclaredAnnotation(SingleAnnotation.class, container, null); + checkDeclaredAnnotation(MultipleAnnotation.class, container, + "@Container({@Repeated(1), @Repeated(2)})"); + checkDeclaredAnnotation(MultipleAnnotationExplicitSingle.class, container, + "@Container({@Repeated(1)})"); + checkDeclaredAnnotation(MultipleAnnotationOddity.class, container, + "@Container({@Repeated(2), @Repeated(3)})"); + } + + private static void checkDeclaredAnnotation( + Class<?> classInPackage, Class<? extends Annotation> annotationType, + String expectedAnnotationString) throws Exception { + + Package aPackage = classInPackage.getPackage(); + // isAnnotationPresent + assertIsAnnotationPresent(aPackage, annotationType, expectedAnnotationString != null); + + // getDeclaredAnnotation + assertGetDeclaredAnnotation(aPackage, annotationType, expectedAnnotationString); + } + + public void testGetDeclaredAnnotationsByType() throws Exception { + Class<Repeated> repeated = Repeated.class; + + assertGetDeclaredAnnotationsByType(NoAnnotation.class, repeated, EXPECT_EMPTY); + assertGetDeclaredAnnotationsByType(SingleAnnotation.class, repeated, + "@Repeated(1)"); + assertGetDeclaredAnnotationsByType(MultipleAnnotation.class, repeated, + "@Repeated(1)", "@Repeated(2)"); + assertGetDeclaredAnnotationsByType(MultipleAnnotationExplicitSingle.class, repeated, + "@Repeated(1)"); + assertGetDeclaredAnnotationsByType(MultipleAnnotationOddity.class, repeated, + "@Repeated(1)", "@Repeated(2)", "@Repeated(3)"); + + Class<Container> container = Container.class; + assertGetDeclaredAnnotationsByType(NoAnnotation.class, container, EXPECT_EMPTY); + assertGetDeclaredAnnotationsByType(SingleAnnotation.class, container, EXPECT_EMPTY); + assertGetDeclaredAnnotationsByType(MultipleAnnotation.class, container, + "@Container({@Repeated(1), @Repeated(2)})"); + assertGetDeclaredAnnotationsByType(MultipleAnnotationExplicitSingle.class, container, + "@Container({@Repeated(1)})"); + assertGetDeclaredAnnotationsByType(MultipleAnnotationOddity.class, container, + "@Container({@Repeated(2), @Repeated(3)})"); + } + + private static void assertGetDeclaredAnnotationsByType( + Class<?> classInPackage, Class<? extends Annotation> annotationType, + String... expectedAnnotationStrings) throws Exception { + Package aPackage = classInPackage.getPackage(); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + aPackage, annotationType, expectedAnnotationStrings); + } + + public void testGetAnnotationsByType() throws Exception { + Class<Repeated> repeated = Repeated.class; + assertGetAnnotationsByType(NoAnnotation.class, repeated, EXPECT_EMPTY); + assertGetAnnotationsByType(SingleAnnotation.class, repeated, "@Repeated(1)"); + assertGetAnnotationsByType(MultipleAnnotation.class, repeated, + "@Repeated(1)", "@Repeated(2)"); + assertGetAnnotationsByType(MultipleAnnotationExplicitSingle.class, repeated, + "@Repeated(1)"); + assertGetAnnotationsByType(MultipleAnnotationOddity.class, repeated, + "@Repeated(1)", "@Repeated(2)", "@Repeated(3)"); + + Class<Container> container = Container.class; + assertGetAnnotationsByType(NoAnnotation.class, container, EXPECT_EMPTY); + assertGetAnnotationsByType(SingleAnnotation.class, container, EXPECT_EMPTY); + assertGetAnnotationsByType(MultipleAnnotation.class, container, + "@Container({@Repeated(1), @Repeated(2)})"); + assertGetAnnotationsByType(MultipleAnnotationExplicitSingle.class, container, + "@Container({@Repeated(1)})"); + assertGetAnnotationsByType(MultipleAnnotationOddity.class, container, + "@Container({@Repeated(2), @Repeated(3)})"); + } + + private static void assertGetAnnotationsByType(Class<?> classInPackage, + Class<? extends Annotation> annotationType, + String... expectedAnnotationStrings) throws Exception { + Package aPackage = classInPackage.getPackage(); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + aPackage, annotationType, expectedAnnotationStrings); + } +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/ParameterTest.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/ParameterTest.java new file mode 100644 index 0000000000..f40ac9f15e --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/ParameterTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package libcore.java.lang.reflect.annotations; + +import junit.framework.TestCase; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationB; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationC; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationD; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Container; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated; + +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.EXPECT_EMPTY; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.annotationsToTypes; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertAnnotationsMatch; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.set; + +public class ParameterTest extends TestCase { + private static class Type { + @AnnotationB + @AnnotationC + public void method(String parameter1, String parameter2) {} + + @AnnotationB + @AnnotationC + public void parameters(@AnnotationB @AnnotationD String parameter1, + @AnnotationC @AnnotationD String parameter2) {} + } + + public void testParameterAnnotations() throws Exception { + Method method = Type.class.getMethod("method", String.class, String.class); + Annotation[][] noParameterAnnotations = method.getParameterAnnotations(); + assertEquals(2, noParameterAnnotations.length); + assertEquals(set(), annotationsToTypes(noParameterAnnotations[0])); + assertEquals(set(), annotationsToTypes(noParameterAnnotations[1])); + + Method parameters = Type.class.getMethod("parameters", String.class, String.class); + Annotation[][] parameterAnnotations = parameters.getParameterAnnotations(); + assertEquals(2, parameterAnnotations.length); + assertEquals(set(AnnotationB.class, AnnotationD.class), + annotationsToTypes(parameterAnnotations[0])); + assertEquals(set(AnnotationC.class, AnnotationD.class), + annotationsToTypes(parameterAnnotations[1])); + } + + private static class AnnotatedClass { + public void singleAnnotation(@Repeated(1) String p0) {} + + public void multipleAnnotation(@Repeated(1) @Repeated(2) String p0) {} + + public void multipleAnnotationExplicitSingle(@Container({@Repeated(1)}) String p0) {} + + public void multipleAnnotationOddity( + @Repeated(1) @Container({@Repeated(2), @Repeated(3)}) String p0) {} + + public void noAnnotation(String p0) {} + } + + public void testGetParameterAnnotations() throws Exception { + Class<?> c = AnnotatedClass.class; + + assertParameter0Annotations(c, "noAnnotation", EXPECT_EMPTY); + assertParameter0Annotations(c, "multipleAnnotationOddity", + "@Repeated(1)", "@Container({@Repeated(2), @Repeated(3)})"); + assertParameter0Annotations(c, "multipleAnnotationExplicitSingle", + "@Container({@Repeated(1)})"); + assertParameter0Annotations(c, "multipleAnnotation", + "@Container({@Repeated(1), @Repeated(2)})"); + assertParameter0Annotations(c, "singleAnnotation", + "@Repeated(1)"); + } + + private static void assertParameter0Annotations( + Class<?> c, String methodName, String... expectedAnnotationStrings) throws Exception { + Annotation[][] allAnnotations = + c.getDeclaredMethod(methodName, String.class).getParameterAnnotations(); + final int expectedParameterCount = 1; + assertEquals(expectedParameterCount, allAnnotations.length); + + Annotation[] p0Annotations = allAnnotations[0]; + assertAnnotationsMatch(p0Annotations, expectedAnnotationStrings); + } +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotation/MultipleAnnotation.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotation/MultipleAnnotation.java new file mode 100644 index 0000000000..d3e77ae479 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotation/MultipleAnnotation.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package libcore.java.lang.reflect.annotations.multipleannotation; + +import libcore.java.lang.reflect.annotations.PackageTest; + +/** + * This class exists so that (after it is loaded) the ClassLoader will be aware of the associated + * package and return a {@link Package} object. See {@link PackageTest}. + */ +public class MultipleAnnotation { +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotation/package-info.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotation/package-info.java new file mode 100644 index 0000000000..1ab457ecf7 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotation/package-info.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * See {@link libcore.java.lang.reflect.annotations.PackageTest}. + */ +@Repeated(1) +@Repeated(2) +package libcore.java.lang.reflect.annotations.multipleannotation; + +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated; diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotationexplicitsingle/MultipleAnnotationExplicitSingle.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotationexplicitsingle/MultipleAnnotationExplicitSingle.java new file mode 100644 index 0000000000..d14ff198b2 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotationexplicitsingle/MultipleAnnotationExplicitSingle.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package libcore.java.lang.reflect.annotations.multipleannotationexplicitsingle; + +import libcore.java.lang.reflect.annotations.PackageTest; + +/** + * This class exists so that (after it is loaded) the ClassLoader will be aware of the associated + * package and return a {@link Package} object. See {@link PackageTest}. + */ +public class MultipleAnnotationExplicitSingle { +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotationexplicitsingle/package-info.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotationexplicitsingle/package-info.java new file mode 100644 index 0000000000..cf41d87bbb --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotationexplicitsingle/package-info.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * See {@link libcore.java.lang.reflect.annotations.PackageTest}. + */ +@Container({@Repeated(1)}) +package libcore.java.lang.reflect.annotations.multipleannotationexplicitsingle; + +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Container; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated;
\ No newline at end of file diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotationoddity/MultipleAnnotationOddity.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotationoddity/MultipleAnnotationOddity.java new file mode 100644 index 0000000000..b85f50ff8a --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotationoddity/MultipleAnnotationOddity.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package libcore.java.lang.reflect.annotations.multipleannotationoddity; + +import libcore.java.lang.reflect.annotations.PackageTest; + +/** + * This class exists so that (after it is loaded) the ClassLoader will be aware of the associated + * package and return a {@link Package} object. See {@link PackageTest}. + */ +public class MultipleAnnotationOddity { +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotationoddity/package-info.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotationoddity/package-info.java new file mode 100644 index 0000000000..afbd99eda8 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotationoddity/package-info.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * See {@link libcore.java.lang.reflect.annotations.PackageTest}. + */ +@Repeated(1) +@Container({@Repeated(2), @Repeated(3)}) +package libcore.java.lang.reflect.annotations.multipleannotationoddity; + +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Container; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated;
\ No newline at end of file diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/noannotation/NoAnnotation.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/noannotation/NoAnnotation.java new file mode 100644 index 0000000000..e7fd957565 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/noannotation/NoAnnotation.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package libcore.java.lang.reflect.annotations.noannotation; + +import libcore.java.lang.reflect.annotations.PackageTest; + +/** + * This class exists so that (after it is loaded) the ClassLoader will be aware of the associated + * package and return a {@link Package} object. See {@link PackageTest}. + */ +public class NoAnnotation { +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/package-info.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/noannotation/package-info.java index 1a84c2ef91..2942f1a740 100644 --- a/luni/src/test/java/libcore/java/lang/reflect/package-info.java +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/noannotation/package-info.java @@ -14,7 +14,7 @@ * limitations under the License. */ -//Used by AnnotationsTest. -@AnnotationsTest.RepeatableAnnotation -@AnnotationsTest.RepeatableAnnotation -package libcore.java.lang.reflect;
\ No newline at end of file +/** + * See {@link libcore.java.lang.reflect.annotations.PackageTest}. + */ +package libcore.java.lang.reflect.annotations.noannotation;
\ No newline at end of file diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/singleannotation/SingleAnnotation.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/singleannotation/SingleAnnotation.java new file mode 100644 index 0000000000..453b2996e5 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/singleannotation/SingleAnnotation.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package libcore.java.lang.reflect.annotations.singleannotation; + +import libcore.java.lang.reflect.annotations.PackageTest; + +/** + * This class exists so that (after it is loaded) the ClassLoader will be aware of the associated + * package and return a {@link Package} object. See {@link PackageTest}. + */ +public class SingleAnnotation { +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/singleannotation/package-info.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/singleannotation/package-info.java new file mode 100644 index 0000000000..3686f80799 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/singleannotation/package-info.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * See {@link libcore.java.lang.reflect.annotations.PackageTest}. + */ +@Repeated(1) +package libcore.java.lang.reflect.annotations.singleannotation; + +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated; + |