1 /*
  2  * Copyright (c) 2026, 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 Test jdk.internal.value.ValueClass against preview-only things
 27  * @modules java.base/jdk.internal.value
 28  * @library /test/lib
 29  * @enablePreview
 30  * @compile ${test.file}
 31  * @run driver jdk.test.lib.helpers.StrictProcessor
 32  *             ValueClassPreviewTest$StrictStuff
 33  * @run junit ${test.main.class}
 34  */
 35 
 36 import java.util.Optional;
 37 import java.util.OptionalInt;
 38 
 39 import jdk.internal.value.ValueClass;
 40 import jdk.test.lib.helpers.StrictInit;
 41 import org.junit.jupiter.api.Test;
 42 
 43 import static org.junit.jupiter.api.Assertions.*;
 44 
 45 class ValueClassPreviewTest {
 46     @Test
 47     void testHasBinaryPayload() {
 48         assertTrue(ValueClass.hasBinaryPayload(Integer.class));
 49         assertTrue(ValueClass.hasBinaryPayload(OptionalInt.class));
 50         assertFalse(ValueClass.hasBinaryPayload(Optional.class));
 51 
 52         value record R1(int a, long b, float c) {}
 53         assertTrue(ValueClass.hasBinaryPayload(R1.class));
 54         value record R2(R1 a) {}
 55         assertTrue(ValueClass.hasBinaryPayload(R2.class));
 56         value record R3(String a) {}
 57         assertFalse(ValueClass.hasBinaryPayload(R3.class));
 58         value record R4(R3 a) {}
 59         assertFalse(ValueClass.hasBinaryPayload(R4.class));
 60     }
 61 
 62     @Test
 63     void testSpecialCopy() {
 64         Object[] original = makeArray(4);
 65         assertThrows(NegativeArraySizeException.class, () -> ValueClass.copyOfSpecialArray(original, -1));
 66         assertArrayEquals(original, ValueClass.copyOfSpecialArray(original, 4));
 67         Object[] padded = makeArray(5);
 68         padded[4] = null;
 69         assertArrayEquals(padded, ValueClass.copyOfSpecialArray(original, 5));
 70         Object[] truncated = makeArray(3);
 71         assertArrayEquals(truncated, ValueClass.copyOfSpecialArray(original, 3));
 72     }
 73 
 74     @Test
 75     void testSpecialCopyOfRange() {
 76         Object[] original = makeArray(4);
 77         assertThrows(ArrayIndexOutOfBoundsException.class, () -> ValueClass.copyOfRangeSpecialArray(original, -1, 5));
 78         assertThrows(ArrayIndexOutOfBoundsException.class, () -> ValueClass.copyOfRangeSpecialArray(original, 5, 5));
 79         assertThrows(IllegalArgumentException.class, () -> ValueClass.copyOfRangeSpecialArray(original, 4, 2));
 80         assertArrayEquals(original, ValueClass.copyOfRangeSpecialArray(original, 0, 4));
 81         Object[] padded = makeArray(5);
 82         padded[4] = null;
 83         assertArrayEquals(padded, ValueClass.copyOfRangeSpecialArray(original, 0, 5));
 84         Object[] truncated = makeArray(3);
 85         assertArrayEquals(truncated, ValueClass.copyOfRangeSpecialArray(original, 0, 3));
 86     }
 87 
 88     private static Object[] makeArray(int l) {
 89         Object[] arr = ValueClass.newNullableAtomicArray(Integer.class, l);
 90         for (int i = 0; i < l; i++) {
 91             arr[i] = Integer.valueOf(i);
 92         }
 93         return arr;
 94     }
 95 
 96     abstract static value class AbstractValue {
 97         int a;
 98 
 99         AbstractValue(int a) {
100             this.a = a;
101         }
102     }
103 
104     static value class ChildValue extends AbstractValue {
105         ChildValue(int a) {
106             super(a);
107         }
108     }
109 
110     static class StrictStuff {
111         @StrictInit int i;
112 
113         StrictStuff() {
114             i = 5;
115             super();
116         }
117     }
118 
119     @Test
120     void testHasStrictInstanceField() {
121         assertFalse(ValueClass.hasStrictInstanceField(int.class), "primitive");
122         assertFalse(ValueClass.hasStrictInstanceField(int[].class), "array");
123         assertFalse(ValueClass.hasStrictInstanceField(Runnable.class), "interface");
124         assertTrue(ValueClass.hasStrictInstanceField(Integer.class), "1 prim field");
125         assertTrue(ValueClass.hasStrictInstanceField(Optional.class), "1 ref field");
126         assertFalse(ValueClass.hasStrictInstanceField(Number.class), "no-field AVC");
127         assertTrue(ValueClass.hasStrictInstanceField(AbstractValue.class), "AVC with field");
128         assertFalse(ValueClass.hasStrictInstanceField(ChildValue.class), "no immediately declared field");
129         record EmptyRec() {}
130         value record EmptyValueRec() {}
131         record Rec(String s) {}
132         value record ValueRec(String s) {}
133         assertFalse(ValueClass.hasStrictInstanceField(EmptyRec.class), "empty identity record");
134         assertFalse(ValueClass.hasStrictInstanceField(EmptyValueRec.class), "empty value record");
135         assertTrue(ValueClass.hasStrictInstanceField(Rec.class), "identity record");
136         assertTrue(ValueClass.hasStrictInstanceField(ValueRec.class), "value record");
137     }
138 }