1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package org.apache.harmony.tests.java.lang;
19
20import java.io.FileInputStream;
21import java.io.IOException;
22import java.io.InputStream;
23import java.io.Serializable;
24import java.lang.reflect.Constructor;
25import java.lang.reflect.Field;
26import java.lang.reflect.Method;
27import java.lang.reflect.Modifier;
28import java.net.URL;
29import java.security.AccessController;
30import java.security.BasicPermission;
31import java.security.DomainCombiner;
32import java.security.Permission;
33import java.security.ProtectionDomain;
34import java.security.Security;
35import java.util.Arrays;
36import java.util.List;
37import java.util.Vector;
38
39public class ClassTest extends junit.framework.TestCase {
40
41    // Relative resource paths.
42    private static final String SHARP_RESOURCE_RELATIVE_NAME = "test#.properties";
43    private static final String QUERY_RESOURCE_RELATIVE_NAME = "test?.properties";
44    private static final String RESOURCE_RELATIVE_NAME = "test.properties";
45
46    // Absolute resource paths.
47    private static final String ABS_PATH =
48            ClassTest.class.getPackage().getName().replace('.', '/');
49    public static final String SHARP_RESOURCE_ABS_NAME =
50            ABS_PATH + "/" + SHARP_RESOURCE_RELATIVE_NAME;
51    public static final String QUERY_RESOURCE_ABS_NAME =
52            ABS_PATH + "/" + QUERY_RESOURCE_RELATIVE_NAME;
53    public static final String RESOURCE_ABS_NAME = ABS_PATH + "/" + RESOURCE_RELATIVE_NAME;
54
55    public static class TestClass {
56        @SuppressWarnings("unused")
57        private int privField = 1;
58
59        public int pubField = 2;
60
61        private Object cValue = null;
62
63        public Object ack = new Object();
64
65        @SuppressWarnings("unused")
66        private int privMethod() {
67            return 1;
68        }
69
70        public int pubMethod() {
71            return 2;
72        }
73
74        public Object cValue() {
75            return cValue;
76        }
77
78        public TestClass() {
79        }
80
81        @SuppressWarnings("unused")
82        private TestClass(Object o) {
83        }
84    }
85
86    public static class SubTestClass extends TestClass {
87    }
88
89    /**
90     * java.lang.Class#forName(java.lang.String)
91     */
92    public void test_forNameLjava_lang_String() throws Exception {
93        assertSame("Class for name failed for java.lang.Object",
94                Object.class, Class.forName("java.lang.Object"));
95        assertSame("Class for name failed for [[Ljava.lang.Object;",
96                Object[][].class, Class.forName("[[Ljava.lang.Object;"));
97
98        assertSame("Class for name failed for [I",
99                int[].class, Class.forName("[I"));
100
101        try {
102            Class.forName("int");
103            fail();
104        } catch (ClassNotFoundException e) {
105        }
106
107        try {
108            Class.forName("byte");
109            fail();
110        } catch (ClassNotFoundException e) {
111        }
112        try {
113            Class.forName("char");
114            fail();
115        } catch (ClassNotFoundException e) {
116        }
117
118        try {
119            Class.forName("void");
120            fail();
121        } catch (ClassNotFoundException e) {
122        }
123
124        try {
125            Class.forName("short");
126            fail();
127        } catch (ClassNotFoundException e) {
128        }
129        try {
130            Class.forName("long");
131            fail();
132        } catch (ClassNotFoundException e) {
133        }
134
135        try {
136            Class.forName("boolean");
137            fail();
138        } catch (ClassNotFoundException e) {
139        }
140        try {
141            Class.forName("float");
142            fail();
143        } catch (ClassNotFoundException e) {
144        }
145        try {
146            Class.forName("double");
147            fail();
148        } catch (ClassNotFoundException e) {
149        }
150
151        //regression test for JIRA 2162
152        try {
153            Class.forName("%");
154            fail("should throw ClassNotFoundException.");
155        } catch (ClassNotFoundException e) {
156        }
157
158        //Regression Test for HARMONY-3332
159        String securityProviderClassName;
160        int count = 1;
161        while ((securityProviderClassName = Security
162                .getProperty("security.provider." + count++)) != null) {
163            Class.forName(securityProviderClassName);
164        }
165    }
166
167    /**
168     * java.lang.Class#getClasses()
169     */
170    public void test_getClasses() {
171        assertEquals("Incorrect class array returned",
172                2, ClassTest.class.getClasses().length);
173    }
174
175    /**
176     * java.lang.Class#getClasses()
177     */
178    public void test_getClasses_subtest0() {
179        final Permission privCheckPermission = new BasicPermission("Privilege check") {
180            private static final long serialVersionUID = 1L;
181        };
182
183        class MyCombiner implements DomainCombiner {
184            boolean combine;
185
186            public ProtectionDomain[] combine(ProtectionDomain[] executionDomains,
187                    ProtectionDomain[] parentDomains) {
188                combine = true;
189                return new ProtectionDomain[0];
190            }
191
192            private boolean recurring = false;
193
194            public boolean isPriviledged() {
195                if (recurring) {
196                    return true;
197                }
198                try {
199                    recurring = true;
200                    combine = false;
201                    try {
202                        AccessController.checkPermission(privCheckPermission);
203                    } catch (SecurityException e) {
204                    }
205                    return !combine;
206                } finally {
207                    recurring = false;
208                }
209            }
210        }
211    }
212
213    /**
214     * java.lang.Class#getComponentType()
215     */
216    public void test_getComponentType() {
217        assertSame("int array does not have int component type", int.class, int[].class
218                .getComponentType());
219        assertSame("Object array does not have Object component type", Object.class,
220                Object[].class.getComponentType());
221        assertNull("Object has non-null component type", Object.class.getComponentType());
222    }
223
224    /**
225     * java.lang.Class#getConstructor(java.lang.Class[])
226     */
227    public void test_getConstructor$Ljava_lang_Class()
228            throws NoSuchMethodException {
229        TestClass.class.getConstructor(new Class[0]);
230        try {
231            TestClass.class.getConstructor(Object.class);
232            fail("Found private constructor");
233        } catch (NoSuchMethodException e) {
234            // Correct - constructor with obj is private
235        }
236    }
237
238    /**
239     * java.lang.Class#getConstructors()
240     */
241    public void test_getConstructors() throws Exception {
242        Constructor[] c = TestClass.class.getConstructors();
243        assertEquals("Incorrect number of constructors returned", 1, c.length);
244    }
245
246    /**
247     * java.lang.Class#getDeclaredClasses()
248     */
249    public void test_getDeclaredClasses() {
250        assertEquals("Incorrect class array returned", 2, ClassTest.class.getClasses().length);
251    }
252
253    /**
254     * java.lang.Class#getDeclaredConstructor(java.lang.Class[])
255     */
256    public void test_getDeclaredConstructor$Ljava_lang_Class() throws Exception {
257        Constructor<TestClass> c = TestClass.class.getDeclaredConstructor(new Class[0]);
258        assertNull("Incorrect constructor returned", c.newInstance().cValue());
259        c = TestClass.class.getDeclaredConstructor(Object.class);
260    }
261
262    /**
263     * java.lang.Class#getDeclaredConstructors()
264     */
265    public void test_getDeclaredConstructors() throws Exception {
266        Constructor[] c = TestClass.class.getDeclaredConstructors();
267        assertEquals("Incorrect number of constructors returned", 2, c.length);
268    }
269
270    /**
271     * java.lang.Class#getDeclaredField(java.lang.String)
272     */
273    public void test_getDeclaredFieldLjava_lang_String() throws Exception {
274        Field f = TestClass.class.getDeclaredField("pubField");
275        assertEquals("Returned incorrect field", 2, f.getInt(new TestClass()));
276    }
277
278    /**
279     * java.lang.Class#getDeclaredFields()
280     */
281    public void test_getDeclaredFields() throws Exception {
282        Field[] f = TestClass.class.getDeclaredFields();
283        assertEquals("Returned incorrect number of fields", 4, f.length);
284        f = SubTestClass.class.getDeclaredFields();
285        // Declared fields do not include inherited
286        assertEquals("Returned incorrect number of fields", 0, f.length);
287    }
288
289    /**
290     * java.lang.Class#getDeclaredMethod(java.lang.String,
291     *java.lang.Class[])
292     */
293    public void test_getDeclaredMethodLjava_lang_String$Ljava_lang_Class() throws Exception {
294        Method m = TestClass.class.getDeclaredMethod("pubMethod", new Class[0]);
295        assertEquals("Returned incorrect method", 2, ((Integer) (m.invoke(new TestClass())))
296                .intValue());
297        m = TestClass.class.getDeclaredMethod("privMethod", new Class[0]);
298    }
299
300    /**
301     * java.lang.Class#getDeclaredMethods()
302     */
303    public void test_getDeclaredMethods() throws Exception {
304        Method[] m = TestClass.class.getDeclaredMethods();
305        assertEquals("Returned incorrect number of methods", 3, m.length);
306        m = SubTestClass.class.getDeclaredMethods();
307        assertEquals("Returned incorrect number of methods", 0, m.length);
308    }
309
310    /**
311     * java.lang.Class#getDeclaringClass()
312     */
313    public void test_getDeclaringClass() {
314        assertEquals(ClassTest.class, TestClass.class.getDeclaringClass());
315    }
316
317    /**
318     * java.lang.Class#getField(java.lang.String)
319     */
320    public void test_getFieldLjava_lang_String() throws Exception {
321        Field f = TestClass.class.getField("pubField");
322        assertEquals("Returned incorrect field", 2, f.getInt(new TestClass()));
323        try {
324            f = TestClass.class.getField("privField");
325            fail("Private field access failed to throw exception");
326        } catch (NoSuchFieldException e) {
327            // Correct
328        }
329    }
330
331    /**
332     * java.lang.Class#getFields()
333     */
334    public void test_getFields() throws Exception {
335        Field[] f = TestClass.class.getFields();
336        assertEquals("Incorrect number of fields", 2, f.length);
337        f = SubTestClass.class.getFields();
338        // Check inheritance of pub fields
339        assertEquals("Incorrect number of fields", 2, f.length);
340    }
341
342    /**
343     * java.lang.Class#getInterfaces()
344     */
345    public void test_getInterfaces() {
346        Class[] interfaces;
347        List<?> interfaceList;
348        interfaces = Object.class.getInterfaces();
349        assertEquals("Incorrect interface list for Object", 0, interfaces.length);
350        interfaceList = Arrays.asList(Vector.class.getInterfaces());
351        assertTrue("Incorrect interface list for Vector", interfaceList
352                .contains(Cloneable.class)
353                && interfaceList.contains(Serializable.class)
354                && interfaceList.contains(List.class));
355    }
356
357    /**
358     * java.lang.Class#getMethod(java.lang.String, java.lang.Class[])
359     */
360    public void test_getMethodLjava_lang_String$Ljava_lang_Class() throws Exception {
361        Method m = TestClass.class.getMethod("pubMethod", new Class[0]);
362        assertEquals("Returned incorrect method", 2, ((Integer) (m.invoke(new TestClass())))
363                .intValue());
364        try {
365            m = TestClass.class.getMethod("privMethod", new Class[0]);
366            fail("Failed to throw exception accessing private method");
367        } catch (NoSuchMethodException e) {
368            // Correct
369            return;
370        }
371    }
372
373    /**
374     * java.lang.Class#getMethods()
375     */
376    public void test_getMethods() throws Exception {
377        Method[] m = TestClass.class.getMethods();
378        assertEquals("Returned incorrect number of methods",
379                2 + Object.class.getMethods().length, m.length);
380        m = SubTestClass.class.getMethods();
381        assertEquals("Returned incorrect number of sub-class methods",
382                2 + Object.class.getMethods().length, m.length);
383        // Number of inherited methods
384    }
385
386    private static final class PrivateClass {
387    }
388
389    /**
390     * java.lang.Class#getModifiers()
391     */
392    public void test_getModifiers() {
393        int dcm = PrivateClass.class.getModifiers();
394        assertFalse("default class is public", Modifier.isPublic(dcm));
395        assertFalse("default class is protected", Modifier.isProtected(dcm));
396        assertTrue("default class is not private", Modifier.isPrivate(dcm));
397
398        int ocm = Object.class.getModifiers();
399        assertTrue("public class is not public", Modifier.isPublic(ocm));
400        assertFalse("public class is protected", Modifier.isProtected(ocm));
401        assertFalse("public class is private", Modifier.isPrivate(ocm));
402    }
403
404    /**
405     * java.lang.Class#getName()
406     */
407    public void test_getName() throws Exception {
408        String className = Class.forName("java.lang.Object").getName();
409        assertNotNull(className);
410
411        assertEquals("Class getName printed wrong value", "java.lang.Object", className);
412        assertEquals("Class getName printed wrong value", "int", int.class.getName());
413        className = Class.forName("[I").getName();
414        assertNotNull(className);
415        assertEquals("Class getName printed wrong value", "[I", className);
416
417        className = Class.forName("[Ljava.lang.Object;").getName();
418        assertNotNull(className);
419
420        assertEquals("Class getName printed wrong value", "[Ljava.lang.Object;", className);
421    }
422
423    /**
424     * java.lang.Class#getResource(java.lang.String)
425     */
426    public void test_getResourceLjava_lang_String() {
427        final String name = "/resources/test_resource.txt";
428        URL res = getClass().getResource(name);
429        assertNotNull(res);
430    }
431
432    /**
433     * java.lang.Class#getResourceAsStream(java.lang.String)
434     */
435    public void test_getResourceAsStreamLjava_lang_String() throws Exception {
436        final String name = "/resources/test_resource.txt";
437        InputStream str2 = getClass().getResourceAsStream(name);
438        assertNotNull("the file " + name + " can not be found in this directory", str2);
439
440        final String nameBadURI = "org/apache/harmony/luni/tests/test_resource.txt";
441        assertNull("the file " + nameBadURI + " should not be found in this directory",
442                getClass().getResourceAsStream(nameBadURI));
443
444        assertTrue("Cannot read single byte", str2.read() != -1);
445        assertEquals("Cannot read multiple bytes", 5, str2.read(new byte[5]));
446        str2.close();
447    }
448
449    /**
450     * java.lang.Class#getSuperclass()
451     */
452    public void test_getSuperclass() {
453        assertNull("Object has a superclass???", Object.class.getSuperclass());
454        assertSame("Normal class has bogus superclass", InputStream.class,
455                FileInputStream.class.getSuperclass());
456        assertSame("Array class has bogus superclass", Object.class, FileInputStream[].class
457                .getSuperclass());
458        assertNull("Base class has a superclass", int.class.getSuperclass());
459        assertNull("Interface class has a superclass", Cloneable.class.getSuperclass());
460    }
461
462    /**
463     * java.lang.Class#isArray()
464     */
465    public void test_isArray() throws ClassNotFoundException {
466        assertTrue("Non-array type claims to be.", !int.class.isArray());
467        Class<?> clazz = null;
468        clazz = Class.forName("[I");
469        assertTrue("int Array type claims not to be.", clazz.isArray());
470
471        clazz = Class.forName("[Ljava.lang.Object;");
472        assertTrue("Object Array type claims not to be.", clazz.isArray());
473
474        clazz = Class.forName("java.lang.Object");
475        assertTrue("Non-array Object type claims to be.", !clazz.isArray());
476    }
477
478    /**
479     * java.lang.Class#isAssignableFrom(java.lang.Class)
480     */
481    public void test_isAssignableFromLjava_lang_Class() {
482        Class<?> clazz1 = null;
483        Class<?> clazz2 = null;
484
485        clazz1 = Object.class;
486        clazz2 = Class.class;
487        assertTrue("returned false for superclass", clazz1.isAssignableFrom(clazz2));
488
489        clazz1 = TestClass.class;
490        assertTrue("returned false for same class", clazz1.isAssignableFrom(clazz1));
491
492        clazz1 = Runnable.class;
493        clazz2 = Thread.class;
494        assertTrue("returned false for implemented interface", clazz1.isAssignableFrom(clazz2));
495    }
496
497    /**
498     * java.lang.Class#isInterface()
499     */
500    public void test_isInterface() throws ClassNotFoundException {
501        assertTrue("Prim type claims to be interface.", !int.class.isInterface());
502        Class<?> clazz = null;
503        clazz = Class.forName("[I");
504        assertTrue("Prim Array type claims to be interface.", !clazz.isInterface());
505
506        clazz = Class.forName("java.lang.Runnable");
507        assertTrue("Interface type claims not to be interface.", clazz.isInterface());
508        clazz = Class.forName("java.lang.Object");
509        assertTrue("Object type claims to be interface.", !clazz.isInterface());
510
511        clazz = Class.forName("[Ljava.lang.Object;");
512        assertTrue("Array type claims to be interface.", !clazz.isInterface());
513    }
514
515    /**
516     * java.lang.Class#isPrimitive()
517     */
518    public void test_isPrimitive() {
519        assertFalse("Interface type claims to be primitive.", Runnable.class.isPrimitive());
520        assertFalse("Object type claims to be primitive.", Object.class.isPrimitive());
521        assertFalse("Prim Array type claims to be primitive.", int[].class.isPrimitive());
522        assertFalse("Array type claims to be primitive.", Object[].class.isPrimitive());
523        assertTrue("Prim type claims not to be primitive.", int.class.isPrimitive());
524        assertFalse("Object type claims to be primitive.", Object.class.isPrimitive());
525    }
526
527    /**
528     * java.lang.Class#newInstance()
529     */
530    public void test_newInstance() throws Exception {
531        Class<?> clazz = null;
532        clazz = Class.forName("java.lang.Object");
533        assertNotNull("new object instance was null", clazz.newInstance());
534
535        clazz = Class.forName("java.lang.Throwable");
536        assertSame("new Throwable instance was not a throwable",
537                clazz, clazz.newInstance().getClass());
538
539        clazz = Class.forName("java.lang.Integer");
540        try {
541            clazz.newInstance();
542            fail("Exception for instantiating a newInstance with no default constructor is not thrown");
543        } catch (InstantiationException e) {
544            // expected
545        }
546    }
547
548    /**
549     * java.lang.Class#toString()
550     */
551    public void test_toString() throws ClassNotFoundException {
552        assertEquals("Class toString printed wrong value",
553                "int", int.class.toString());
554        Class<?> clazz = null;
555        clazz = Class.forName("[I");
556        assertEquals("Class toString printed wrong value",
557                "class [I", clazz.toString());
558
559        clazz = Class.forName("java.lang.Object");
560        assertEquals("Class toString printed wrong value",
561                "class java.lang.Object", clazz.toString());
562
563        clazz = Class.forName("[Ljava.lang.Object;");
564        assertEquals("Class toString printed wrong value",
565                "class [Ljava.lang.Object;", clazz.toString());
566    }
567
568
569    // Regression Test for JIRA-2047
570    public void test_getResourceAsStream_withSharpChar() throws Exception {
571        // Class.getResourceAsStream() requires a leading "/" for absolute paths.
572        assertNull(getClass().getResourceAsStream(SHARP_RESOURCE_ABS_NAME));
573        assertResourceExists("/" + SHARP_RESOURCE_ABS_NAME);
574        assertResourceExists(SHARP_RESOURCE_RELATIVE_NAME);
575
576        InputStream in =
577                this.getClass().getClassLoader().getResourceAsStream(SHARP_RESOURCE_ABS_NAME);
578        assertNotNull(in);
579        in.close();
580    }
581
582    public void test_getResource_withSharpChar() throws Exception {
583        // Class.getResourceAsStream() requires a leading "/" for absolute paths.
584        assertNull(getClass().getResource(SHARP_RESOURCE_ABS_NAME));
585        URL absoluteURL = getClass().getResource("/" + SHARP_RESOURCE_ABS_NAME);
586
587        // Make sure the name has been encoded.
588        assertEquals(ABS_PATH + "/test%23.properties",
589                absoluteURL.getFile().replaceAll("^.*!/", ""));
590
591        // Make sure accessing it via an absolute and relative path produces the same result.
592        URL relativeURL = getClass().getResource(SHARP_RESOURCE_RELATIVE_NAME);
593        assertEquals(absoluteURL, relativeURL);
594    }
595
596    public void test_getResourceAsStream_withQueryChar() throws Exception {
597        // Class.getResourceAsStream() requires a leading "/" for absolute paths.
598        assertNull(getClass().getResourceAsStream(QUERY_RESOURCE_ABS_NAME));
599        assertResourceExists("/" + QUERY_RESOURCE_ABS_NAME);
600        assertResourceExists(QUERY_RESOURCE_RELATIVE_NAME);
601
602        InputStream in =
603                this.getClass().getClassLoader().getResourceAsStream(QUERY_RESOURCE_ABS_NAME);
604        assertNotNull(in);
605        in.close();
606    }
607
608    public void test_getResource_withQueryChar() throws Exception {
609        // Class.getResourceAsStream() requires a leading "/" for absolute paths.
610        assertNull(getClass().getResource(QUERY_RESOURCE_ABS_NAME));
611        URL absoluteURL = getClass().getResource("/" + QUERY_RESOURCE_ABS_NAME);
612
613        // Make sure the name has been encoded.
614        assertEquals(ABS_PATH + "/test%3f.properties",
615                absoluteURL.getFile().replaceAll("^.*!/", ""));
616
617        // Make sure accessing it via an absolute and relative path produces the same result.
618        URL relativeURL = getClass().getResource(QUERY_RESOURCE_RELATIVE_NAME);
619        assertEquals(absoluteURL, relativeURL);
620    }
621
622    public void test_getResourceAsStream() throws Exception {
623        // Class.getResourceAsStream() requires a leading "/" for absolute paths.
624        assertNull(getClass().getResourceAsStream(RESOURCE_ABS_NAME));
625        assertResourceExists("/" + RESOURCE_ABS_NAME);
626        assertResourceExists(RESOURCE_RELATIVE_NAME);
627
628        InputStream in = this.getClass().getClassLoader().getResourceAsStream(RESOURCE_ABS_NAME);
629        assertNotNull(in);
630        in.close();
631    }
632
633    private void assertResourceExists(String resourceName) throws IOException {
634        InputStream in = getClass().getResourceAsStream(resourceName);
635        assertNotNull(in);
636        in.close();
637    }
638
639    /*
640    * Regression test for HARMONY-2644:
641    * Load system and non-system array classes via Class.forName()
642    */
643    public void test_forName_arrays() throws Exception {
644        Class c1 = getClass();
645        String s = c1.getName();
646        Class a1 = Class.forName("[L" + s + ";");
647        Class a2 = Class.forName("[[L" + s + ";");
648        assertSame(c1, a1.getComponentType());
649        assertSame(a1, a2.getComponentType());
650        Class l4 = Class.forName("[[[[[J");
651        assertSame(long[][][][][].class, l4);
652
653        try {
654            System.out.println(Class.forName("[;"));
655            fail("1");
656        } catch (ClassNotFoundException ok) {
657        }
658        try {
659            System.out.println(Class.forName("[["));
660            fail("2");
661        } catch (ClassNotFoundException ok) {
662        }
663        try {
664            System.out.println(Class.forName("[L"));
665            fail("3");
666        } catch (ClassNotFoundException ok) {
667        }
668        try {
669            System.out.println(Class.forName("[L;"));
670            fail("4");
671        } catch (ClassNotFoundException ok) {
672        }
673        try {
674            System.out.println(Class.forName(";"));
675            fail("5");
676        } catch (ClassNotFoundException ok) {
677        }
678        try {
679            System.out.println(Class.forName(""));
680            fail("6");
681        } catch (ClassNotFoundException ok) {
682        }
683    }
684}
685