Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2012 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 
     17 import java.lang.reflect.Array;
     18 import java.lang.reflect.Field;
     19 import java.lang.reflect.Method;
     20 
     21 public class Main {
     22   public static void main(String[] args) throws Exception {
     23     arrayAccess();
     24     arrayStore();
     25     classCast();
     26     classNotFound();
     27     negativeArraySize();
     28     nullPointers();
     29     reflection();
     30     stringIndex();
     31   }
     32 
     33   private static void assertEquals(String expected, String actual) {
     34     if (expected == null && actual == null) {
     35       return;
     36     }
     37     if (expected != null && expected.equals(actual)) {
     38       return;
     39     }
     40     throw new AssertionError("not equal\n" +
     41                                  "expected: " + expected + "\n" +
     42                                  "actual:   " + actual);
     43   }
     44 
     45   private static void fail() {
     46     throw new AssertionError();
     47   }
     48 
     49   private static void arrayAccess() throws Exception {
     50     byte[] bs = new byte[1];
     51     double[] ds = new double[1];
     52     Object[] os = new Object[1];
     53 
     54     // aput
     55     try {
     56       bs[2] = 0;
     57       fail();
     58     } catch (ArrayIndexOutOfBoundsException ex) {
     59       assertEquals("length=1; index=2", ex.getMessage());
     60     }
     61 
     62     // aget
     63     try {
     64       byte b = bs[2];
     65       fail();
     66     } catch (ArrayIndexOutOfBoundsException ex) {
     67       assertEquals("length=1; index=2", ex.getMessage());
     68     }
     69 
     70     // aput-wide
     71     try {
     72       ds[2] = 0.0;
     73       fail();
     74     } catch (ArrayIndexOutOfBoundsException ex) {
     75       assertEquals("length=1; index=2", ex.getMessage());
     76     }
     77 
     78     // aget-wide
     79     try {
     80       double d = ds[2];
     81       fail();
     82     } catch (ArrayIndexOutOfBoundsException ex) {
     83       assertEquals("length=1; index=2", ex.getMessage());
     84     }
     85 
     86     // aput-object
     87     try {
     88       os[2] = null;
     89       fail();
     90     } catch (ArrayIndexOutOfBoundsException ex) {
     91       assertEquals("length=1; index=2", ex.getMessage());
     92     }
     93 
     94     // aget-object
     95     try {
     96       Object o = os[2];
     97       fail();
     98     } catch (ArrayIndexOutOfBoundsException ex) {
     99       assertEquals("length=1; index=2", ex.getMessage());
    100     }
    101   }
    102 
    103   private static void arrayStore() throws Exception {
    104     try {
    105       Object[] array = new String[10];
    106       Object o = new Exception();
    107       array[0] = o;
    108       fail();
    109     } catch (ArrayStoreException ex) {
    110       assertEquals("java.lang.Exception cannot be stored in an array of type java.lang.String[]",
    111                    ex.getMessage());
    112     }
    113 
    114     try {
    115       Object[] array = new C[10][];
    116       Object o = new Integer(5);
    117       array[0] = o;
    118       fail();
    119     } catch (ArrayStoreException ex) {
    120       assertEquals("java.lang.Integer cannot be stored in an array of type Main$C[][]",
    121                    ex.getMessage());
    122     }
    123 
    124     try {
    125       Object[] array = new Float[10][];
    126       Object o = new C[4];
    127       array[0] = o;
    128       fail();
    129     } catch (ArrayStoreException ex) {
    130       assertEquals("Main$C[] cannot be stored in an array of type java.lang.Float[][]",
    131                    ex.getMessage());
    132     }
    133 
    134     try {
    135       String[] src = new String[] { null, null, null, null, "hello", "goodbye" };
    136       Integer[] dst = new Integer[10];
    137       System.arraycopy(src, 1, dst, 0, 5);
    138     } catch (ArrayStoreException ex) {
    139       assertEquals("source[4] of type java.lang.String cannot be stored in destination array of type java.lang.Integer[]",
    140                    ex.getMessage());
    141     }
    142 
    143     try {
    144       String[] src = new String[1];
    145       int[] dst = new int[1];
    146       System.arraycopy(src, 0, dst, 0, 1);
    147     } catch (ArrayStoreException ex) {
    148       assertEquals("Incompatible types: src=java.lang.String[], dst=int[]", ex.getMessage());
    149     }
    150 
    151     try {
    152       float[] src = new float[1];
    153       Runnable[] dst = new Runnable[1];
    154       System.arraycopy(src, 0, dst, 0, 1);
    155     } catch (ArrayStoreException ex) {
    156       assertEquals("Incompatible types: src=float[], dst=java.lang.Runnable[]", ex.getMessage());
    157     }
    158 
    159     try {
    160       boolean[] src = new boolean[1];
    161       double[][] dst = new double[1][];
    162       System.arraycopy(src, 0, dst, 0, 1);
    163     } catch (ArrayStoreException ex) {
    164       assertEquals("Incompatible types: src=boolean[], dst=double[][]", ex.getMessage());
    165     }
    166 
    167     try {
    168       String src = "hello";
    169       Object[] dst = new Object[1];
    170       System.arraycopy(src, 0, dst, 0, 1);
    171     } catch (ArrayStoreException ex) {
    172       assertEquals("source of type java.lang.String is not an array", ex.getMessage());
    173     }
    174 
    175     try {
    176       Object[] src = new Object[1];
    177       Integer dst = new Integer(5);
    178       System.arraycopy(src, 0, dst, 0, 1);
    179     } catch (ArrayStoreException ex) {
    180       assertEquals("destination of type java.lang.Integer is not an array", ex.getMessage());
    181     }
    182 
    183     // This test demonstrates that the exception message complains
    184     // about the source in cases where neither source nor
    185     // destination is an array.
    186     try {
    187       System.arraycopy(new C(), 0, "hello", 0, 1);
    188     } catch (ArrayStoreException ex) {
    189       assertEquals("source of type Main$C is not an array", ex.getMessage());
    190     }
    191   }
    192 
    193   private static void classCast() throws Exception {
    194     // Reference types.
    195     try {
    196       Object o = new Exception();
    197       String s = (String) o;
    198       fail();
    199     } catch (ClassCastException ex) {
    200       assertEquals("java.lang.Exception cannot be cast to java.lang.String", ex.getMessage());
    201     }
    202 
    203     // Arrays of reference types.
    204     try {
    205       Object o = (C) makeArray(String.class);
    206       fail();
    207     } catch (ClassCastException ex) {
    208       assertEquals("java.lang.String[] cannot be cast to Main$C", ex.getMessage());
    209     }
    210 
    211     // Arrays of primitives.
    212     try {
    213       Object o = (C) makeArray(float.class);
    214       fail();
    215     } catch (ClassCastException ex) {
    216       assertEquals("float[] cannot be cast to Main$C", ex.getMessage());
    217     }
    218 
    219     // Multi-dimensional arrays of primitives.
    220     try {
    221       Object o = (C) makeArray(char[].class);
    222       fail();
    223     } catch (ClassCastException ex) {
    224       assertEquals("char[][] cannot be cast to Main$C", ex.getMessage());
    225     }
    226 
    227     // Multi-dimensional arrays of references.
    228     try {
    229       Object o = (Object[][][]) makeInteger();
    230       fail();
    231     } catch (ClassCastException ex) {
    232       assertEquals("java.lang.Integer cannot be cast to java.lang.Object[][][]", ex.getMessage());
    233     }
    234   }
    235 
    236   static class C { }
    237 
    238   /**
    239    * Helper for testCastOperator and testCastOperatorWithArrays. It's important that the
    240    * return type is Object, since otherwise the compiler will just reject the code.
    241    */
    242   private static Object makeInteger() {
    243     return new Integer(5);
    244   }
    245 
    246   /**
    247    * Helper for testCastOperatorWithArrays. It's important that
    248    * the return type is Object.
    249    */
    250   private static Object makeArray(Class c) {
    251     return Array.newInstance(c, 1);
    252   }
    253 
    254   private static void classNotFound() throws Exception {
    255     try {
    256       // There is no such thing as an array of void.
    257       Class.forName("[V");
    258       fail();
    259     } catch (ClassNotFoundException ex) {
    260       assertEquals("Invalid name: [V", ex.getMessage());
    261     }
    262 
    263     try {
    264       // This class name is valid, but doesn't exist.
    265       Class.forName("package.Class");
    266       fail();
    267     } catch (ClassNotFoundException ex) {
    268       assertEquals("package.Class", ex.getMessage());
    269     }
    270 
    271     try {
    272       // This array class name is valid, but the type doesn't exist.
    273       Class.forName("[[Lpackage.Class;");
    274       fail();
    275     } catch (ClassNotFoundException ex) {
    276       assertEquals("[[Lpackage.Class;", ex.getMessage());
    277     }
    278   }
    279 
    280   private static void negativeArraySize() throws Exception {
    281     try {
    282       int[] is = new int[-123];
    283       fail();
    284     } catch (NegativeArraySizeException ex) {
    285       assertEquals("-123", ex.getMessage());
    286     }
    287   }
    288 
    289   // Defeat the fact that null's are untyped for precise detail message creation with quickening.
    290   private static Object returnNullObject() {
    291     return null;
    292   }
    293 
    294   private static A returnNullA() {
    295     return null;
    296   }
    297 
    298   private static void nullPointers() throws Exception {
    299     // Invoke method.
    300     try {
    301       Object o = returnNullObject();
    302       o.hashCode();
    303       fail();
    304     } catch (NullPointerException ex) {
    305       assertEquals("Attempt to invoke virtual method 'int java.lang.Object.hashCode()' on a null object reference", ex.getMessage());
    306     }
    307 
    308     // Read field.
    309     try {
    310       A a = returnNullA();
    311       int i = a.i;
    312       fail();
    313     } catch (NullPointerException ex) {
    314       assertEquals("Attempt to read from field 'int A.i' on a null object reference", ex.getMessage());
    315     }
    316 
    317     // Write field.
    318     try {
    319       A a = returnNullA();
    320       a.i = 1;
    321       fail();
    322     } catch (NullPointerException ex) {
    323       assertEquals("Attempt to write to field 'int A.i' on a null object reference", ex.getMessage());
    324     }
    325 
    326     // Read array.
    327     try {
    328       int[] is = null;
    329       int i = is[0];
    330       fail();
    331     } catch (NullPointerException ex) {
    332       assertEquals("Attempt to read from null array", ex.getMessage());
    333     }
    334 
    335     // Write array.
    336     try {
    337       int[] is = null;
    338       is[0] = 1;
    339       fail();
    340     } catch (NullPointerException ex) {
    341       assertEquals("Attempt to write to null array", ex.getMessage());
    342     }
    343 
    344     // Array length.
    345     try {
    346       int[] is = null;
    347       int i = is.length;
    348       fail();
    349     } catch (NullPointerException ex) {
    350       assertEquals("Attempt to get length of null array", ex.getMessage());
    351     }
    352   }
    353 
    354   private static void reflection() throws Exception {
    355     // Can't assign Integer to a String field.
    356     try {
    357       Field field = A.class.getField("b");
    358       field.set(new A(), 5);
    359       fail();
    360     } catch (IllegalArgumentException expected) {
    361       assertEquals("field A.b has type java.lang.String, got java.lang.Integer",
    362           expected.getMessage());
    363     }
    364 
    365     // Can't unbox null to a primitive.
    366     try {
    367       Field field = A.class.getField("i");
    368       field.set(new A(), null);
    369       fail();
    370     } catch (IllegalArgumentException expected) {
    371       assertEquals("field A.i has type int, got null", expected.getMessage());
    372     }
    373 
    374     // Can't unbox String to a primitive.
    375     try {
    376       Field field = A.class.getField("i");
    377       field.set(new A(), "hello, world!");
    378       fail();
    379     } catch (IllegalArgumentException expected) {
    380       assertEquals("field A.i has type int, got java.lang.String", expected.getMessage());
    381     }
    382 
    383     // Can't pass an Integer as a String.
    384     try {
    385       Method m = A.class.getMethod("m", int.class, String.class);
    386       m.invoke(new A(), 2, 2);
    387       fail();
    388     } catch (IllegalArgumentException expected) {
    389       assertEquals("method A.m argument 2 has type java.lang.String, got java.lang.Integer",
    390           expected.getMessage());
    391     }
    392 
    393     // Can't pass null as an int.
    394     try {
    395       Method m = A.class.getMethod("m", int.class, String.class);
    396       m.invoke(new A(), null, "");
    397       fail();
    398     } catch (IllegalArgumentException expected) {
    399       assertEquals("method A.m argument 1 has type int, got null", expected.getMessage());
    400     }
    401 
    402     try {
    403       Method m = String.class.getMethod("charAt", int.class);
    404       m.invoke("hello"); // Wrong number of arguments.
    405       fail();
    406     } catch (IllegalArgumentException iae) {
    407       assertEquals("Wrong number of arguments; expected 1, got 0", iae.getMessage());
    408     }
    409     try {
    410       Method m = String.class.getMethod("charAt", int.class);
    411       m.invoke("hello", "world"); // Wrong type.
    412       fail();
    413     } catch (IllegalArgumentException iae) {
    414       assertEquals("method java.lang.String.charAt! argument 1 has type int, got java.lang.String",
    415           iae.getMessage());
    416     }
    417     try {
    418       Method m = String.class.getMethod("charAt", int.class);
    419       m.invoke("hello", (Object) null); // Null for a primitive argument.
    420       fail();
    421     } catch (IllegalArgumentException iae) {
    422       assertEquals("method java.lang.String.charAt! argument 1 has type int, got null",
    423           iae.getMessage());
    424     }
    425     try {
    426       Method m = String.class.getMethod("charAt", int.class);
    427       m.invoke(new Integer(5)); // Wrong type for 'this'.
    428       fail();
    429     } catch (IllegalArgumentException iae) {
    430       assertEquals("Expected receiver of type java.lang.String, but got java.lang.Integer",
    431           iae.getMessage());
    432     }
    433     try {
    434       Method m = String.class.getMethod("charAt", int.class);
    435       m.invoke(null); // Null for 'this'.
    436       fail();
    437     } catch (NullPointerException npe) {
    438       assertEquals("null receiver", npe.getMessage());
    439     }
    440   }
    441 
    442   private static void stringIndex() throws Exception {
    443     // charAt too small.
    444     try {
    445       "hello".charAt(-1);
    446       fail();
    447     } catch (StringIndexOutOfBoundsException ex) {
    448       assertEquals("length=5; index=-1", ex.getMessage());
    449     }
    450 
    451     // charAt too big.
    452     try {
    453       "hello".charAt(7);
    454       fail();
    455     } catch (StringIndexOutOfBoundsException ex) {
    456       assertEquals("length=5; index=7", ex.getMessage());
    457     }
    458 
    459     // substring too big.
    460     try {
    461       "hello there".substring(9,14);
    462       fail();
    463     } catch (StringIndexOutOfBoundsException ex) {
    464       assertEquals("length=11; regionStart=9; regionLength=5", ex.getMessage());
    465     }
    466   }
    467 }
    468 
    469 class A {
    470   public String b;
    471   public int i;
    472   public void m(int i, String s) {}
    473 }
    474