1 /*
  2  * Copyright (c) 2024, 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  * @bug 8334334
 27  * @summary reflection test for value classes
 28  * @enablePreview
 29  * @compile ValueClassesReflectionTest.java
 30  * @run testng/othervm ValueClassesReflectionTest
 31  */
 32 
 33 import java.lang.annotation.*;
 34 import java.lang.constant.ClassDesc;
 35 import java.lang.reflect.*;
 36 import java.util.Arrays;
 37 import java.util.List;
 38 import java.util.Set;
 39 import org.testng.annotations.*;
 40 import static org.testng.Assert.*;
 41 
 42 @Test
 43 public class ValueClassesReflectionTest {
 44     final static int numberOfFields = 2;
 45 
 46     value class ValueClass {
 47         private int i = 0;
 48         private String s = "";
 49     }
 50     abstract value class AValueClass {
 51         private int i = 0;
 52         private String s = "";
 53     }
 54     value record ValueRecord(int i, String s) {}
 55 
 56     class Inner {}
 57 
 58     @DataProvider(name = "valueClasses")
 59     public Object[][] valueClassesData() {
 60         return List.of(
 61                 ValueClass.class,
 62                 AValueClass.class,
 63                 ValueRecord.class
 64         ).stream().map(c -> new Object[] {c}).toArray(Object[][]::new);
 65     }
 66 
 67     @Test(dataProvider = "valueClasses")
 68     public void testValueClasses(Class<?> cls) {
 69         assertTrue(cls.isValue());
 70         assertTrue(!cls.isIdentity());
 71         Set<AccessFlag> accessFlagSet = cls.accessFlags();
 72         assertTrue(!accessFlagSet.contains(AccessFlag.IDENTITY));
 73     }
 74 
 75     @DataProvider(name = "notValueClasses")
 76     public Object[][] notSealedClassesData() {
 77         return List.of(
 78                 Inner.class,
 79                 Object.class,
 80                 Void.class, Void[].class,
 81                 byte[].class, Byte[].class,
 82                 short[].class, Short[].class,
 83                 char[].class, Character[].class,
 84                 int[].class, Integer[].class,
 85                 long[].class, Long[].class,
 86                 float[].class, Float[].class,
 87                 double[].class, Double[].class,
 88                 boolean[].class, Boolean[].class,
 89                 String.class, String[].class
 90         ).stream().map(c -> new Object[] {c}).toArray(Object[][]::new);
 91     }
 92 
 93     @Test(dataProvider = "notValueClasses")
 94     public void testNotValueClasses(Class<?> cls) {
 95         assertTrue(!cls.isValue(), " failing for class " + cls);
 96         assertTrue(cls.isIdentity());
 97     }
 98 
 99     @Test(dataProvider = "valueClasses")
100     public void testValueClassReflection(Class<?> valueClass) throws ReflectiveOperationException {
101         assertTrue(valueClass.isValue());
102         Field[] fields = valueClass.getDeclaredFields();
103         assertTrue(fields.length == numberOfFields);
104         for (Field field : fields) {
105             int mod = field.getModifiers();
106             assertTrue((mod & Modifier.STRICT) != 0);
107             assertTrue((mod & Modifier.FINAL) != 0);
108         }
109     }
110 }