1 /*
   2  * Copyright (c) 2019, 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 /**
  27  * RecordMemberTests
  28  *
  29  * @test
  30  * @compile --enable-preview -source ${jdk.version} RecordMemberTests.java
  31  * @run testng/othervm --enable-preview RecordMemberTests
  32  */
  33 
  34 import java.lang.reflect.Constructor;
  35 import java.lang.reflect.Field;
  36 import java.lang.reflect.Method;
  37 import java.lang.reflect.Modifier;
  38 import java.lang.reflect.Parameter;
  39 import java.util.List;
  40 import java.util.function.Supplier;
  41 
  42 import org.testng.annotations.*;
  43 import static org.testng.Assert.*;
  44 
  45 @Test
  46 public class RecordMemberTests {
  47     record R1(int i, int j) {}
  48 
  49     record R2(int i, int j) {
  50         public R2 {}
  51     }
  52 
  53     record R3(int i, int j) {
  54         public R3 {
  55             this.i = i;
  56         }
  57     }
  58 
  59     record R4(int i, int j) {
  60         public R4 {
  61             this.i = i;
  62             this.j = j;
  63         }
  64     }
  65 
  66     record R5(int i, int j) {
  67         public R5 { this.i = this.j = 0; }
  68     }
  69 
  70     R1 r1 = new R1(1, 2);
  71     R2 r2 = new R2(1, 2);
  72     R3 r3 = new R3(1, 2);
  73     R4 r4 = new R4(1, 2);
  74     R5 r5 = new R5(1, 2);
  75 
  76     public void testConstruction() {
  77         for (int i : new int[] { r1.i, r2.i, r3.i, r4.i,
  78                                  r1.i(), r2.i(), r3.i(), r4.i() })
  79             assertEquals(i, 1);
  80 
  81         for (int j : new int[] { r1.j, r2.j, r3.j, r4.j,
  82                                  r1.j(), r2.j(), r3.j(), r4.j() })
  83             assertEquals(j, 2);
  84 
  85         assertEquals(r5.i, 0);
  86         assertEquals(r5.j, 0);
  87     }
  88 
  89     public void testConstructorParameterNames() throws ReflectiveOperationException {
  90         for (Class cl : List.of(R1.class, R2.class, R3.class, R4.class)) {
  91             Constructor c = cl.getConstructor(int.class, int.class);
  92             assertNotNull(c);
  93             Parameter[] parameters = c.getParameters();
  94             assertEquals(parameters.length, 2);
  95             assertEquals(parameters[0].getName(), "i");
  96             assertEquals(parameters[1].getName(), "j");
  97         }
  98     }
  99 
 100     public void testSuperclass() {
 101         assertEquals(R1.class.getSuperclass(), Record.class);
 102         // class is final
 103         assertTrue((R1.class.getModifiers() & Modifier.FINAL) != 0);
 104     }
 105 
 106     public void testMandatedMembersPresent() throws ReflectiveOperationException {
 107         // fields are present, of the right type, final and private
 108         assertEquals(R1.class.getDeclaredFields().length, 2);
 109         for (String s : List.of("i", "j")) {
 110             Field iField = R1.class.getDeclaredField(s);
 111             assertEquals(iField.getType(), int.class);
 112             assertEquals((iField.getModifiers() & Modifier.STATIC), 0);
 113             assertTrue((iField.getModifiers() & Modifier.PRIVATE) != 0);
 114             assertTrue((iField.getModifiers() & Modifier.FINAL) != 0);
 115         }
 116 
 117         // methods are present, of the right descriptor, and public/instance/concrete
 118         for (String s : List.of("i", "j")) {
 119             Method iMethod = R1.class.getDeclaredMethod(s);
 120             assertEquals(iMethod.getReturnType(), int.class);
 121             assertEquals(iMethod.getParameterCount(), 0);
 122             assertEquals((iMethod.getModifiers() & (Modifier.PRIVATE | Modifier.PROTECTED | Modifier.STATIC | Modifier.ABSTRACT)), 0);
 123         }
 124 
 125         Constructor c = R1.class.getConstructor(int.class, int.class);
 126         R1 r1 = (R1) c.newInstance(1, 2);
 127         assertEquals(r1.i(), 1);
 128         assertEquals(r1.j(), 2);
 129     }
 130 
 131     record OrdinaryMembers(int x) {
 132         public static String ss;
 133         public static String ssf () { return ss; }
 134         public String sf () { return "instance"; }
 135     }
 136 
 137     public void testOrdinaryMembers() {
 138         OrdinaryMembers.ss = "foo";
 139         assertEquals(OrdinaryMembers.ssf(), "foo");
 140         OrdinaryMembers o = new OrdinaryMembers(3);
 141         assertEquals(o.sf(), "instance");
 142     }
 143 
 144     class LocalRecordHelper {
 145         Class<?> m(int x) {
 146             record R (int x) { }
 147             assertEquals(new R(x).x(), x);
 148             return R.class;
 149         }
 150     }
 151 
 152     public void testLocalRecordsStatic() {
 153         Class<?> c = new LocalRecordHelper().m(3);
 154         assertTrue(c.isRecord());
 155         assertTrue((c.getModifiers() & Modifier.STATIC) != 0);
 156         assertTrue((c.getModifiers() & Modifier.FINAL) != 0);
 157     }
 158 
 159     static class NestedRecordHelper {
 160         record R1(int x) { }
 161 
 162         static class Nested {
 163             record R2(int x) { }
 164         }
 165 
 166         Class<?> m() {
 167             record R4(int x) { }
 168             return R4.class;
 169         }
 170 
 171         Class<?> m2() {
 172             Supplier<Class<?>> s = () -> {
 173                 record R5(int x) { }
 174                 return R5.class;
 175             };
 176             return s.get();
 177         }
 178 
 179         static Class<?> m3() {
 180             record R6(int x) { }
 181             return R6.class;
 182         }
 183 
 184         static Class<?> m4() {
 185             Supplier<Class<?>> s = () -> {
 186                 record R7(int x) { }
 187                 return R7.class;
 188             };
 189             return s.get();
 190         }
 191     }
 192 
 193     public void testNestedRecordsStatic() {
 194         NestedRecordHelper n = new NestedRecordHelper();
 195         for (Class<?> c : List.of(NestedRecordHelper.R1.class,
 196                                   NestedRecordHelper.Nested.R2.class,
 197                                   n.m(),
 198                                   n.m2(),
 199                                   NestedRecordHelper.m3(),
 200                                   NestedRecordHelper.m4())) {
 201             assertTrue(c.isRecord());
 202             assertTrue((c.getModifiers() & Modifier.STATIC) != 0);
 203             assertTrue((c.getModifiers() & Modifier.FINAL) != 0);
 204         }
 205     }
 206 }