1/*
2 * Copyright (C) 2008 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.reflect.Constructor;
20import java.lang.reflect.Field;
21import java.lang.reflect.Method;
22import java.lang.reflect.Modifier;
23import java.util.ArrayList;
24import java.util.HashSet;
25import java.util.Set;
26import junit.framework.TestCase;
27
28public final class OldAndroidClassTest extends TestCase {
29    private static final String packageName = "libcore.java.lang.reflect";
30
31    public void testNewInstance() throws Exception {
32        Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
33        Object instance = helloClass.newInstance();
34        assertNotNull(instance);
35    }
36
37    public void testForName() throws Exception {
38        try {
39            Class.forName("this.class.DoesNotExist");
40            fail();
41        } catch (ClassNotFoundException expected) {
42        }
43    }
44
45    public void testNewInstancePrivateConstructor() throws Exception {
46        try {
47            Class.forName(packageName + ".ClassWithPrivateConstructor").newInstance();
48            fail();
49        } catch (IllegalAccessException expected) {
50        }
51    }
52
53    public void testGetDeclaredMethod() throws Exception {
54        Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
55        Method method = helloClass.getDeclaredMethod("method", (Class[]) null);
56        method.invoke(new OldAndroidClassTest(), (Object[]) null);
57    }
58
59    public void testGetDeclaredMethodWithArgs() throws Exception {
60        Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
61        Method method = helloClass.getDeclaredMethod("methodWithArgs", Object.class);
62
63        Object invokeArgs[] = new Object[1];
64        invokeArgs[0] = "Hello";
65        Object ret = method.invoke(new OldAndroidClassTest(), invokeArgs);
66        assertEquals(ret, invokeArgs[0]);
67    }
68
69    public void testGetDeclaredMethodPrivate() throws Exception {
70        Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
71        Method method = helloClass.getDeclaredMethod("privateMethod", (Class[]) null);
72        method.invoke(new OldAndroidClassTest(), (Object[]) null);
73    }
74
75    public void testGetSuperclass() throws Exception {
76        Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
77        Class objectClass = Class.forName("java.lang.Object");
78        assertEquals(helloClass.getSuperclass().getSuperclass().getSuperclass(), objectClass);
79    }
80
81    public void testIsAssignableFrom() throws Exception {
82        Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
83        Class objectClass = Class.forName("java.lang.Object");
84        assertTrue(objectClass.isAssignableFrom(helloClass));
85        assertFalse(helloClass.isAssignableFrom(objectClass));
86    }
87
88    public void testGetConstructor() throws Exception {
89        Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
90        Constructor constructor = helloClass.getConstructor((Class[]) null);
91        assertNotNull(constructor);
92    }
93
94    public void testGetModifiers() throws Exception {
95        Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
96        assertTrue(Modifier.isPublic(helloClass.getModifiers()));
97    }
98
99    public void testGetMethod() throws Exception {
100        Class helloClass = Class.forName(OldAndroidClassTest.class.getName());
101        helloClass.getMethod("method", (Class[]) null);
102        try {
103            Class[] argTypes = new Class[1];
104            argTypes[0] = helloClass;
105            helloClass.getMethod("method", argTypes);
106            fail();
107        } catch (NoSuchMethodException expected) {
108        }
109    }
110
111    // http://code.google.com/p/android/issues/detail?id=14
112    public void testFieldSet() throws Exception {
113        OldAndroidClassTest.SimpleClass obj = new OldAndroidClassTest.SimpleClass();
114        Field field = obj.getClass().getDeclaredField("str");
115        field.set(obj, null);
116    }
117
118    public class SimpleClass {
119        public String str;
120    }
121
122    public Object methodWithArgs(Object o) {
123        return o;
124    }
125
126    boolean methodInvoked;
127
128    public void method() {
129        methodInvoked = true;
130    }
131
132    boolean privateMethodInvoked;
133
134    public void privateMethod() {
135        privateMethodInvoked = true;
136    }
137
138    // Regression for 1018067: Class.getMethods() returns the same method over
139    // and over again from all base classes
140    public void testClassGetMethodsNoDupes() {
141        Method[] methods = ArrayList.class.getMethods();
142        Set<String> set = new HashSet<String>();
143
144        for (Method method : methods) {
145            String signature = method.toString();
146
147            int par = signature.indexOf('(');
148            int dot = signature.lastIndexOf('.', par);
149
150            signature = signature.substring(dot + 1);
151
152            assertFalse("Duplicate " + signature, set.contains(signature));
153            set.add(signature);
154        }
155    }
156
157    interface MyInterface {
158        void foo();
159    }
160
161    interface MyOtherInterface extends MyInterface {
162        void bar();
163    }
164
165    abstract class MyClass implements MyOtherInterface {
166        public void gabba() {
167        }
168
169        public void hey() {
170        }
171    }
172
173    // Check if we also reflect methods from interfaces
174    public void testGetMethodsInterfaces() {
175        Method[] methods = MyInterface.class.getMethods();
176        assertTrue(hasMethod(methods, ".foo("));
177
178        methods = MyOtherInterface.class.getMethods();
179        assertTrue(hasMethod(methods, ".foo("));
180        assertTrue(hasMethod(methods, ".bar("));
181
182        methods = MyClass.class.getMethods();
183        assertTrue(hasMethod(methods, ".foo("));
184        assertTrue(hasMethod(methods, ".bar("));
185
186        assertTrue(hasMethod(methods, ".gabba("));
187        assertTrue(hasMethod(methods, ".hey("));
188
189        assertTrue(hasMethod(methods, ".toString("));
190    }
191
192    private boolean hasMethod(Method[] methods, String signature) {
193        for (Method method : methods) {
194            if (method.toString().contains(signature)) {
195                return true;
196            }
197        }
198        return false;
199    }
200
201    // Test for Class.getPackage();
202    public void testClassGetPackage() {
203        assertNotNull(getClass().getPackage());
204        assertEquals(packageName, getClass().getPackage().getName());
205        assertEquals("Unknown", getClass().getPackage().getSpecificationTitle());
206
207        Package p = Object.class.getPackage();
208        assertNotNull(p);
209        assertEquals("java.lang", p.getName());
210        assertSame(p, Object.class.getPackage());
211    }
212
213    // Regression test for #1123708: Problem with getCanonicalName(),
214    // getSimpleName(), and getPackage().
215    //
216    // A couple of interesting cases need to be checked: Top-level classes,
217    // member classes, local classes, and anonymous classes. Also, boundary
218    // cases with '$' in the class names are checked, since the '$' is used
219    // as the separator between outer and inner class, so this might lead
220    // to problems (it did in the previous implementation).
221    //
222    // Caution: Adding local or anonymous classes elsewhere in this
223    // file might affect the test.
224    private class MemberClass {
225    }
226
227    private class Mi$o$oup {
228    }
229
230    public void testVariousClassNames() {
231        Class<?> clazz = this.getClass();
232        String pkg = (clazz.getPackage() == null ? "" : clazz.getPackage().getName() + ".");
233
234        // Simple, top-level class
235
236        assertEquals(pkg + "OldAndroidClassTest", clazz.getName());
237        assertEquals("OldAndroidClassTest", clazz.getSimpleName());
238        assertEquals(pkg + "OldAndroidClassTest", clazz.getCanonicalName());
239
240        clazz = MemberClass.class;
241
242        assertEquals(pkg + "OldAndroidClassTest$MemberClass", clazz.getName());
243        assertEquals("MemberClass", clazz.getSimpleName());
244        assertEquals(pkg + "OldAndroidClassTest.MemberClass", clazz.getCanonicalName());
245
246        class LocalClass {
247            // This space intentionally left blank.
248        }
249
250        clazz = LocalClass.class;
251
252        assertEquals(pkg + "OldAndroidClassTest$1LocalClass", clazz.getName());
253        assertEquals("LocalClass", clazz.getSimpleName());
254        assertNull(clazz.getCanonicalName());
255
256        clazz = new Object() { }.getClass();
257
258        assertEquals(pkg + "OldAndroidClassTest$1", clazz.getName());
259        assertEquals("", clazz.getSimpleName());
260        assertNull(clazz.getCanonicalName());
261
262        // Weird special cases with dollar in name.
263
264        clazz = Mou$$aka.class;
265
266        assertEquals(pkg + "Mou$$aka", clazz.getName());
267        assertEquals("Mou$$aka", clazz.getSimpleName());
268        assertEquals(pkg + "Mou$$aka", clazz.getCanonicalName());
269
270        clazz = Mi$o$oup.class;
271
272        assertEquals(pkg + "OldAndroidClassTest$Mi$o$oup", clazz.getName());
273        assertEquals("Mi$o$oup", clazz.getSimpleName());
274        assertEquals(pkg + "OldAndroidClassTest.Mi$o$oup", clazz.getCanonicalName());
275
276        class Ma$hedPotatoe$ {
277        }
278
279        clazz = Ma$hedPotatoe$.class;
280
281        assertEquals(pkg + "OldAndroidClassTest$1Ma$hedPotatoe$", clazz.getName());
282        assertEquals("Ma$hedPotatoe$", clazz.getSimpleName());
283        assertNull(clazz.getCanonicalName());
284    }
285
286    public void testLocalMemberClass() {
287        Class<?> clazz = this.getClass();
288
289        assertFalse(clazz.isMemberClass());
290        assertFalse(clazz.isLocalClass());
291
292        clazz = MemberClass.class;
293
294        assertTrue(clazz.isMemberClass());
295        assertFalse(clazz.isLocalClass());
296
297        class OtherLocalClass {
298        }
299
300        clazz = OtherLocalClass.class;
301
302        assertFalse(clazz.isMemberClass());
303        assertTrue(clazz.isLocalClass());
304
305        clazz = new Object() { }.getClass();
306
307        assertFalse(clazz.isMemberClass());
308        assertFalse(clazz.isLocalClass());
309    }
310}
311
312class ClassWithPrivateConstructor {
313    private ClassWithPrivateConstructor() {
314    }
315}
316
317class Mou$$aka {
318}
319