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         assertEquals("", ClassDesc.of("Bar").inner("Baz", "Foo").packageName());
 164 
 165         assertEquals("", ConstantDescs.CD_int.packageName());
 166         assertEquals("", ConstantDescs.CD_int.arrayType().packageName());
 167         assertEquals("", ConstantDescs.CD_String.arrayType().packageName());
 168         assertEquals("", ClassDesc.of("Bar").arrayType().packageName());
 169     }
 170 
 171     private void testBadArrayRank(ClassDesc cr) {
 172         try {
 173             cr.arrayType(-1);
 174             fail("");
 175         } catch (IllegalArgumentException e) {
 176             // good
 177         }
 178     }
 179 
 180     public void testArrayClassDesc() throws ReflectiveOperationException {
 181         for (String d : basicDescs) {
 182             ClassDesc a0 = ClassDesc.ofDescriptor(d);
 183             ClassDesc a1 = a0.arrayType();
 184             ClassDesc a2 = a1.arrayType();
 185 
 186             testClassDesc(a0);
 187             testClassDesc(a1);
 188             testClassDesc(a2);
 189             assertFalse(a0.isArray());
 190             assertTrue(a1.isArray());
 191             assertTrue(a2.isArray());
 192             assertFalse(a1.isPrimitive());
 193             assertFalse(a2.isPrimitive());
 194             assertEquals(a0.descriptorString(), d);
 195             assertEquals(a1.descriptorString(), "[" + a0.descriptorString());
 196             assertEquals(a2.descriptorString(), "[[" + a0.descriptorString());
 197 
 198             assertNull(a0.componentType());
 199             assertEquals(a0, a1.componentType());
 200             assertEquals(a1, a2.componentType());
 201 
 202             assertNotEquals(a0, a1);
 203             assertNotEquals(a1, a2);
 204 
 205             assertEquals(a1, ClassDesc.ofDescriptor("[" + d));
 206             assertEquals(a2, ClassDesc.ofDescriptor("[[" + d));
 207             assertEquals(classToDescriptor((Class<?>) a0.resolveConstantDesc(LOOKUP)), a0.descriptorString());
 208             assertEquals(classToDescriptor((Class<?>) a1.resolveConstantDesc(LOOKUP)), a1.descriptorString());
 209             assertEquals(classToDescriptor((Class<?>) a2.resolveConstantDesc(LOOKUP)), a2.descriptorString());
 210 
 211             testBadArrayRank(ConstantDescs.CD_int);
 212             testBadArrayRank(ConstantDescs.CD_String);
 213             testBadArrayRank(ClassDesc.of("Bar"));
 214         }
 215     }
 216 
 217     public void testBadClassDescs() {
 218         List<String> badDescriptors = List.of("II", "I;", "Q", "L",
 219                                               "java.lang.String", "[]", "Ljava/lang/String",
 220                                               "Ljava.lang.String;", "java/lang/String");
 221 
 222         for (String d : badDescriptors) {
 223             try {
 224                 ClassDesc constant = ClassDesc.ofDescriptor(d);
 225                 fail(d);
 226             }
 227             catch (IllegalArgumentException e) {
 228                 // good
 229             }
 230         }
 231 
 232         List<String> badBinaryNames = List.of("I;", "[]", "Ljava/lang/String",
 233                 "Ljava.lang.String;", "java/lang/String");
 234         for (String d : badBinaryNames) {
 235             try {
 236                 ClassDesc constant = ClassDesc.of(d);
 237                 fail(d);
 238             } catch (IllegalArgumentException e) {
 239                 // good
 240             }
 241         }
 242 
 243         for (Primitives p : Primitives.values()) {
 244             testBadInnerClasses(ClassDesc.ofDescriptor(p.descriptor), "any");
 245             testBadInnerClasses(ClassDesc.ofDescriptor(p.descriptor), "any", "other");
 246         }
 247     }
 248 
 249     private void testBadInnerClasses(ClassDesc cr, String firstInnerName, String... moreInnerNames) {
 250         try {
 251             cr.inner(firstInnerName, moreInnerNames);
 252             fail("");
 253         } catch (IllegalStateException e) {
 254             // good
 255         }
 256     }
 257 
 258     public void testLangClasses() {
 259         Double d = 1.0;
 260         assertEquals(d.resolveConstantDesc(LOOKUP), d);
 261         assertEquals(d.describeConstable().get(), d);
 262 
 263         Integer i = 1;
 264         assertEquals(i.resolveConstantDesc(LOOKUP), i);
 265         assertEquals(i.describeConstable().get(), i);
 266 
 267         Float f = 1.0f;
 268         assertEquals(f.resolveConstantDesc(LOOKUP), f);
 269         assertEquals(f.describeConstable().get(), f);
 270 
 271         Long l = 1L;
 272         assertEquals(l.resolveConstantDesc(LOOKUP), l);
 273         assertEquals(l.describeConstable().get(), l);
 274 
 275         String s = "";
 276         assertEquals(s.resolveConstantDesc(LOOKUP), s);
 277         assertEquals(s.describeConstable().get(), s);
 278     }
 279 }