1 /*
  2  * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 /*
 25  * @test
 26  * @summary Basic test for Array::get, Array::set, Arrays::setAll on primitive class array
 27  * @compile -XDenablePrimitiveClasses ValueArray.java
 28  * @run testng/othervm -XX:+EnableValhalla -XX:+EnablePrimitiveClasses -XX:FlatArrayElementMaxSize=-1 ValueArray
 29  * @compile -XDenablePrimitiveClasses ValueArray.java
 30  * @run testng/othervm -XX:+EnableValhalla -XX:+EnablePrimitiveClasses -XX:FlatArrayElementMaxSize=0  ValueArray
 31  */
 32 
 33 import java.lang.reflect.Array;
 34 import java.util.Arrays;
 35 
 36 import org.testng.annotations.DataProvider;
 37 import org.testng.annotations.Test;
 38 import static org.testng.Assert.*;
 39 
 40 import jdk.internal.value.PrimitiveClass;
 41 
 42 public class ValueArray {
 43     @DataProvider(name="elementTypes")
 44     static Object[][] elementTypes() {
 45         return new Object[][]{
 46             new Object[] { PrimitiveClass.asValueType(Point.class), Point.default },
 47             new Object[] { Point.ref.class, null },
 48             new Object[] { ValueOptional.class, null },
 49         };
 50     }
 51 
 52     /*
 53      * Test an array created from the given element type via Array::newInstance
 54      */
 55     @Test(dataProvider="elementTypes")
 56     public void testElementType(Class<?> elementType, Object defaultValue) {
 57         assertTrue(elementType.isValue());
 58         assertTrue(PrimitiveClass.isPrimaryType(elementType) || defaultValue != null);
 59 
 60         Object[] array = (Object[])Array.newInstance(elementType, 1);
 61         Class<?> arrayType = array.getClass();
 62         assertTrue(arrayType.componentType() == elementType);
 63         // Array is a reference type
 64         assertTrue(arrayType.isArray());
 65         assertTrue(PrimitiveClass.isPrimaryType(arrayType));
 66         assertEquals(PrimitiveClass.asPrimaryType(arrayType), arrayType);
 67         assertTrue(array[0] == defaultValue);
 68 
 69         // check the element type of multi-dimensional array
 70         Object[][] multiArray = (Object[][])Array.newInstance(elementType, 1, 2, 3);
 71         Class<?> c = multiArray.getClass();
 72         while (c.getComponentType() != null) {
 73             c = c.getComponentType();
 74         }
 75         assertTrue(c == elementType);
 76     }
 77 
 78     @DataProvider(name="arrayTypes")
 79     static Object[][] arrayTypes() {
 80         return new Object[][] {
 81             new Object[] { Object[].class,
 82                            new Object[] { new Object(), new Object()}},
 83             new Object[] { Point[].class,
 84                            new Point[] { Point.makePoint(1, 2),
 85                                          Point.makePoint(10, 20),
 86                                          Point.makePoint(100, 200)}},
 87             new Object[] { Point[][].class,
 88                            new Point[][] { new Point[] { Point.makePoint(1, 2),
 89                                                          Point.makePoint(10, 20)}}},
 90             new Object[] { Point.ref[].class,
 91                            new Point.ref[] { Point.makePoint(11, 22),
 92                                              Point.makePoint(110, 220),
 93                                              null }},
 94             new Object[] { NonFlattenValue[].class,
 95                            new NonFlattenValue[] { NonFlattenValue.make(1, 2),
 96                                                    NonFlattenValue.make(10, 20),
 97                                                    NonFlattenValue.make(100, 200)}},
 98             new Object[] { Point[].class,  new Point[0] },
 99             new Object[] { Point.ref[].class,  new Point.ref[0] },
100             new Object[] { ValueOptional[].class,  new ValueOptional[0] },
101         };
102     }
103 
104     /*
105      * Test the following properties of an array of value class:
106      * - class name
107      * - array element can be null or not
108      * - array covariance if the element type is a primitive value type
109      */
110     @Test(dataProvider="arrayTypes")
111     public void testArrays(Class<?> arrayClass, Object[] array) {
112         testClassName(arrayClass);
113         testArrayElements(arrayClass, array);
114         Class<?> componentType = arrayClass.componentType();
115         if (PrimitiveClass.isPrimitiveClass(componentType)) {
116             Object[] qArray = (Object[]) Array.newInstance(PrimitiveClass.asValueType(componentType), 0);
117             Object[] lArray = (Object[]) Array.newInstance(PrimitiveClass.asPrimaryType(componentType), 0);
118             testArrayCovariance(componentType, qArray, lArray);
119         }
120     }
121 
122     /**
123      * Verify the array class's name of the form "[QPoint;" or "[LPoint;"
124      */
125     static void testClassName(Class<?> arrayClass) {
126         // test class names
127         String arrayClassName = arrayClass.getName();
128         StringBuilder sb = new StringBuilder();
129         Class<?> c = arrayClass;
130         while (c.isArray()) {
131             sb.append("[");
132             c = c.getComponentType();
133         }
134         sb.append(PrimitiveClass.isPrimitiveValueType(c) ? "Q" : "L").append(c.getName()).append(";");
135         assertEquals(sb.toString(), arrayClassName);
136     }
137 
138     /**
139      * Setting the elements of an array.
140      * NPE will be thrown if null is set on an element in an array of primitive value type
141      */
142     static void testArrayElements(Class<?> arrayClass, Object[] array) {
143         Class<?> componentType = arrayClass.getComponentType();
144         assertTrue(arrayClass.isArray());
145         assertTrue(array.getClass() == arrayClass);
146         Object[] newArray = (Object[]) Array.newInstance(componentType, array.length);
147         assertTrue(newArray.getClass() == arrayClass);
148         assertTrue(newArray.getClass().getComponentType() == componentType);
149 
150         // set elements
151         for (int i = 0; i < array.length; i++) {
152             Array.set(newArray, i, array[i]);
153         }
154         for (int i = 0; i < array.length; i++) {
155             Object o = Array.get(newArray, i);
156             assertEquals(o, array[i]);
157         }
158         Arrays.setAll(newArray, i -> array[i]);
159 
160         // test nullable
161         if (!PrimitiveClass.isPrimitiveValueType(componentType)) {
162             for (int i = 0; i < newArray.length; i++) {
163                 Array.set(newArray, i, null);
164             }
165         } else {
166             for (int i = 0; i < newArray.length; i++) {
167                 try {
168                     Array.set(newArray, i, null);
169                     fail("expect NPE but not thrown");
170                 } catch (NullPointerException e) {
171                 }
172             }
173         }
174     }
175 
176     /**
177      * Point[] is a subtype of Point.ref[], which is a subtype of Object[].
178      */
179     static void testArrayCovariance(Class<?> componentType, Object[] qArray, Object[] lArray) {
180         assertTrue(PrimitiveClass.isPrimitiveClass(componentType));
181 
182         // Class.instanceOf (self)
183         assertTrue(qArray.getClass().isInstance(qArray));
184         assertTrue(lArray.getClass().isInstance(lArray));
185 
186         // Class.isAssignableFrom (self)
187         assertTrue(qArray.getClass().isAssignableFrom(qArray.getClass()));
188         assertTrue(lArray.getClass().isAssignableFrom(lArray.getClass()));
189 
190         // V.val[] is a subtype of V.ref[]
191         assertFalse(qArray.getClass().isInstance(lArray));
192         assertTrue(lArray.getClass().isInstance(qArray));
193 
194         // V.val[] is a subtype of V.ref[]
195         assertTrue(lArray.getClass().isAssignableFrom(qArray.getClass()));
196         assertFalse(qArray.getClass().isAssignableFrom(lArray.getClass()));
197 
198         // Class.cast (self)
199         qArray.getClass().cast(qArray);
200         lArray.getClass().cast(lArray);
201 
202         // Class.cast
203         lArray.getClass().cast(qArray);
204         try {
205             qArray.getClass().cast(lArray);
206             fail("cast of Point.ref[] to Point[] should not succeed");
207         } catch (ClassCastException cce) {
208         }
209     }
210 
211     @Test
212     public static void testIntArray() {
213         int[] array = new int[] { 1, 2, 3};
214         for (int i=0; i < array.length; i++) {
215             Array.set(array, i, Integer.valueOf(i*10));
216         }
217 
218         for (int i=0; i < array.length; i++) {
219             Integer o = (Integer) Array.get(array, i);
220             assertTrue(o.intValue() == i*10);
221         }
222         Arrays.setAll(array, i -> array[i]);
223     }
224 
225     @Test
226     public static void testNonArrayObject() {
227         Object o = new Object();
228         try {
229             Array.get(o, 0);
230             fail("IAE not thrown");
231         } catch (IllegalArgumentException e) {}
232 
233         try {
234             Array.set(o, 0, o);
235             fail("IAE not thrown");
236         } catch (IllegalArgumentException e) {}
237 
238     }
239 
240     @Test
241     static void testInstanceOf() {
242         Point[] qArray = new Point[0];
243         Point.ref[] lArray = new Point.ref[0];
244         ValueOptional[] vArray = new ValueOptional[0];
245 
246         // language instanceof
247         assertTrue(qArray instanceof Point[]);
248         assertTrue(lArray instanceof Point.ref[]);
249         assertTrue(vArray instanceof ValueOptional[]);
250     }
251 }