1 /*
   2  * Copyright (c) 2018, 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 import java.lang.invoke.MethodHandles;
  25 import java.lang.constant.ClassDesc;
  26 import java.lang.constant.ConstantDescs;
  27 import java.lang.reflect.Array;
  28 import java.lang.reflect.Field;
  29 import java.lang.reflect.Modifier;
  30 import java.util.Arrays;
  31 import java.util.List;
  32 import java.util.Map;
  33 
  34 import org.testng.annotations.Test;
  35 
  36 import static org.testng.Assert.assertEquals;
  37 import static org.testng.Assert.assertFalse;
  38 import static org.testng.Assert.assertNotEquals;
  39 import static org.testng.Assert.assertNull;
  40 import static org.testng.Assert.assertTrue;
  41 import static org.testng.Assert.fail;
  42 
  43 /**
  44  * @test
  45  * @compile ClassDescTest.java
  46  * @run testng ClassDescTest
  47  * @summary unit tests for java.lang.constant.ClassDesc
  48  */
  49 @Test
  50 public class ClassDescTest extends SymbolicDescTest {
  51 
  52     private void testClassDesc(ClassDesc r) throws ReflectiveOperationException {
  53         testSymbolicDesc(r);
  54 
  55         // Test descriptor accessor, factory, equals
  56         assertEquals(r, ClassDesc.ofDescriptor(r.descriptorString()));
  57 
  58         if (!r.descriptorString().equals("V")) {
  59             assertEquals(r, r.arrayType().componentType());
  60             // Commutativity: array -> resolve -> componentType -> toSymbolic
  61             assertEquals(r, ((Class<?>) r.arrayType().resolveConstantDesc(LOOKUP)).getComponentType().describeConstable().orElseThrow());
  62             // Commutativity: resolve -> array -> toSymbolic -> component type
  63             assertEquals(r, Array.newInstance(((Class<?>) r.resolveConstantDesc(LOOKUP)), 0).getClass().describeConstable().orElseThrow().componentType());
  64         }
  65 
  66         if (r.isArray()) {
  67             assertEquals(r, r.componentType().arrayType());
  68             assertEquals(r, ((Class<?>) r.resolveConstantDesc(LOOKUP)).getComponentType().describeConstable().orElseThrow().arrayType());
  69             assertEquals(r, Array.newInstance(((Class<?>) r.componentType().resolveConstantDesc(LOOKUP)), 0).getClass().describeConstable().orElseThrow());
  70         }
  71     }
  72 
  73     private void testClassDesc(ClassDesc r, Class<?> c) throws ReflectiveOperationException {
  74         testClassDesc(r);
  75 
  76         assertEquals(r.resolveConstantDesc(LOOKUP), c);
  77         assertEquals(c.describeConstable().orElseThrow(), r);
  78         assertEquals(ClassDesc.ofDescriptor(c.descriptorString()), r);
  79     }
  80 
  81     public void testSymbolicDescsConstants() throws ReflectiveOperationException {
  82         int tested = 0;
  83         Field[] fields = ConstantDescs.class.getDeclaredFields();
  84         for (Field f : fields) {
  85             try {
  86                 if (f.getType().equals(ClassDesc.class)
  87                     && ((f.getModifiers() & Modifier.STATIC) != 0)
  88                     && ((f.getModifiers() & Modifier.PUBLIC) != 0)) {
  89                     ClassDesc cr = (ClassDesc) f.get(null);
  90                     Class c = (Class)cr.resolveConstantDesc(MethodHandles.lookup());
  91                     testClassDesc(cr, c);
  92                     ++tested;
  93                 }
  94             }
  95             catch (Throwable e) {
  96                 System.out.println(e.getMessage());
  97                 fail("Error testing field " + f.getName(), e);
  98             }
  99         }
 100 
 101         assertTrue(tested > 0);
 102     }
 103 
 104     public void testPrimitiveClassDesc() throws ReflectiveOperationException {
 105         for (Primitives p : Primitives.values()) {
 106             List<ClassDesc> descs = List.of(ClassDesc.ofDescriptor(p.descriptor),
 107                                            p.classDesc,
 108                                            (ClassDesc) p.clazz.describeConstable().orElseThrow());
 109             for (ClassDesc c : descs) {
 110                 testClassDesc(c, p.clazz);
 111                 assertTrue(c.isPrimitive());
 112                 assertEquals(p.descriptor, c.descriptorString());
 113                 assertEquals(p.name, c.displayName());
 114                 descs.forEach(cc -> assertEquals(c, cc));
 115                 if (p != Primitives.VOID) {
 116                     testClassDesc(c.arrayType(), p.arrayClass);
 117                     assertEquals(c, ((ClassDesc) p.arrayClass.describeConstable().orElseThrow()).componentType());
 118                     assertEquals(c, p.classDesc.arrayType().componentType());
 119                 }
 120             }
 121 
 122             for (Primitives other : Primitives.values()) {
 123                 ClassDesc otherDescr = ClassDesc.ofDescriptor(other.descriptor);
 124                 if (p != other)
 125                     descs.forEach(c -> assertNotEquals(c, otherDescr));
 126                 else
 127                     descs.forEach(c -> assertEquals(c, otherDescr));
 128             }
 129         }
 130     }
 131 
 132     public void testSimpleClassDesc() throws ReflectiveOperationException {
 133 
 134         List<ClassDesc> stringClassDescs = Arrays.asList(ClassDesc.ofDescriptor("Ljava/lang/String;"),
 135                                                         ClassDesc.of("java.lang", "String"),
 136                                                         ClassDesc.of("java.lang.String"),
 137                                                         ClassDesc.of("java.lang.String").arrayType().componentType(),
 138                                                         String.class.describeConstable().orElseThrow());
 139         for (ClassDesc r : stringClassDescs) {
 140             testClassDesc(r, String.class);
 141             assertFalse(r.isPrimitive());
 142             assertEquals("Ljava/lang/String;", r.descriptorString());
 143             assertEquals("String", r.displayName());
 144             assertEquals(r.arrayType().resolveConstantDesc(LOOKUP), String[].class);
 145             stringClassDescs.forEach(rr -> assertEquals(r, rr));
 146         }
 147 
 148         testClassDesc(ClassDesc.of("java.lang.String").arrayType(), String[].class);
 149         testClassDesc(ClassDesc.of("java.util.Map").inner("Entry"), Map.Entry.class);
 150 
 151         ClassDesc thisClassDesc = ClassDesc.ofDescriptor("LClassDescTest;");
 152         assertEquals(thisClassDesc, ClassDesc.of("", "ClassDescTest"));
 153         assertEquals(thisClassDesc, ClassDesc.of("ClassDescTest"));
 154         assertEquals(thisClassDesc.displayName(), "ClassDescTest");
 155         testClassDesc(thisClassDesc, ClassDescTest.class);
 156     }
 157 
 158     public void testPackageName() {
 159         assertEquals("com.foo", ClassDesc.of("com.foo.Bar").packageName());
 160         assertEquals("com.foo", ClassDesc.of("com.foo.Bar").inner("Baz").packageName());
 161         assertEquals("", ClassDesc.of("Bar").packageName());
 162         assertEquals("", ClassDesc.of("Bar").inner("Baz").packageName());
 163 
 164         assertEquals("", ConstantDescs.CD_int.packageName());
 165         assertEquals("", ConstantDescs.CD_int.arrayType().packageName());
 166         assertEquals("", ConstantDescs.CD_String.arrayType().packageName());
 167         assertEquals("", ClassDesc.of("Bar").arrayType().packageName());
 168     }
 169 
 170     private void testBadArrayRank(ClassDesc cr) {
 171         try {
 172             cr.arrayType(-1);
 173             fail("");
 174         } catch (IllegalArgumentException e) {
 175             // good
 176         }
 177     }
 178 
 179     public void testArrayClassDesc() throws ReflectiveOperationException {
 180         for (String d : basicDescs) {
 181             ClassDesc a0 = ClassDesc.ofDescriptor(d);
 182             ClassDesc a1 = a0.arrayType();
 183             ClassDesc a2 = a1.arrayType();
 184 
 185             testClassDesc(a0);
 186             testClassDesc(a1);
 187             testClassDesc(a2);
 188             assertFalse(a0.isArray());
 189             assertTrue(a1.isArray());
 190             assertTrue(a2.isArray());
 191             assertFalse(a1.isPrimitive());
 192             assertFalse(a2.isPrimitive());
 193             assertEquals(a0.descriptorString(), d);
 194             assertEquals(a1.descriptorString(), "[" + a0.descriptorString());
 195             assertEquals(a2.descriptorString(), "[[" + a0.descriptorString());
 196 
 197             assertNull(a0.componentType());
 198             assertEquals(a0, a1.componentType());
 199             assertEquals(a1, a2.componentType());
 200 
 201             assertNotEquals(a0, a1);
 202             assertNotEquals(a1, a2);
 203 
 204             assertEquals(a1, ClassDesc.ofDescriptor("[" + d));
 205             assertEquals(a2, ClassDesc.ofDescriptor("[[" + d));
 206             assertEquals(classToDescriptor((Class<?>) a0.resolveConstantDesc(LOOKUP)), a0.descriptorString());
 207             assertEquals(classToDescriptor((Class<?>) a1.resolveConstantDesc(LOOKUP)), a1.descriptorString());
 208             assertEquals(classToDescriptor((Class<?>) a2.resolveConstantDesc(LOOKUP)), a2.descriptorString());
 209 
 210             testBadArrayRank(ConstantDescs.CD_int);
 211             testBadArrayRank(ConstantDescs.CD_String);
 212             testBadArrayRank(ClassDesc.of("Bar"));
 213         }
 214     }
 215 
 216     public void testBadClassDescs() {
 217         List<String> badDescriptors = List.of("II", "I;", "Q", "L",
 218                                               "java.lang.String", "[]", "Ljava/lang/String",
 219                                               "Ljava.lang.String;", "java/lang/String");
 220 
 221         for (String d : badDescriptors) {
 222             try {
 223                 ClassDesc constant = ClassDesc.ofDescriptor(d);
 224                 fail(d);
 225             }
 226             catch (IllegalArgumentException e) {
 227                 // good
 228             }
 229         }
 230 
 231         List<String> badBinaryNames = List.of("I;", "[]", "Ljava/lang/String",
 232                 "Ljava.lang.String;", "java/lang/String");
 233         for (String d : badBinaryNames) {
 234             try {
 235                 ClassDesc constant = ClassDesc.of(d);
 236                 fail(d);
 237             } catch (IllegalArgumentException e) {
 238                 // good
 239             }
 240         }
 241 
 242         for (Primitives p : Primitives.values()) {
 243             testBadInnerClasses(ClassDesc.ofDescriptor(p.descriptor), "any");
 244             testBadInnerClasses(ClassDesc.ofDescriptor(p.descriptor), "any", "other");
 245         }
 246     }
 247 
 248     private void testBadInnerClasses(ClassDesc cr, String firstInnerName, String... moreInnerNames) {
 249         try {
 250             cr.inner(firstInnerName, moreInnerNames);
 251             fail("");
 252         } catch (IllegalStateException e) {
 253             // good
 254         }
 255     }
 256 }