1 /* 2 * Copyright (c) 2020, 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 8257598 27 * @summary check that Record::equals uses the fields and not the accessors for the comparison 28 * @run testng CheckEqualityIsBasedOnFields 29 */ 30 package test.java.lang.reflect.records; 31 32 import java.lang.reflect.Constructor; 33 import java.lang.reflect.Field; 34 import java.lang.reflect.Method; 35 36 import org.testng.annotations.DataProvider; 37 import org.testng.annotations.Test; 38 39 import static org.testng.Assert.*; 40 41 public class CheckEqualityIsBasedOnFields { R01(boolean x)42 public record R01(boolean x) { 43 public boolean x() { 44 return x ? x : !x; 45 } 46 } 47 R02(byte x)48 public record R02(byte x) { 49 public byte x() { 50 return (x >= 50) ? (byte)(x - 50) : x; 51 } 52 } 53 R03(short x)54 public record R03(short x) { 55 public short x() { 56 return (x >= 50) ? (short)(x - 50) : x; 57 } 58 } 59 R04(char x)60 public record R04(char x) { 61 public char x() { 62 return (x >= 50) ? (char)(x - 50) : x; 63 } 64 } 65 R05(int x)66 public record R05(int x) { 67 public int x() { 68 return (x >= 50) ? (x - 50) : x; 69 } 70 } 71 R06(long x)72 public record R06(long x) { 73 public long x() { 74 return (x >= 50) ? (long)(x - 50) : x; 75 } 76 } 77 R07(float x)78 public record R07(float x) { 79 public float x() { 80 return (x >= 50) ? (float)(x - 50) : x; 81 } 82 } R08(double x)83 public record R08(double x) { 84 public double x() { 85 return (x >= 50) ? (double)(x - 50) : x; 86 } 87 } 88 R09(String x)89 public record R09(String x) { 90 public String x() { 91 return (x.length() > 1) ? x.substring(0, 1) : x; 92 } 93 } 94 95 @DataProvider(name = "recordData") recordTypeAndExpectedValue()96 public Object[][] recordTypeAndExpectedValue() { 97 return new Object[][] { 98 new Object[] { R01.class, boolean.class, new Object[]{true, false} }, 99 new Object[] { R02.class, byte.class, new Object[]{(byte)0, (byte)1, (byte)2, (byte)3, (byte)4, (byte)5, 100 (byte)50, (byte)51, (byte)52, (byte)53, (byte)54, (byte)55} }, 101 new Object[] { R03.class, short.class, new Object[]{(short)0, (short)1, (short)2, (short)3, (short)4, (short)5, 102 (short)50, (short)51, (short)52, (short)53, (short)54, (short)55} }, 103 new Object[] { R04.class, char.class, new Object[]{(char)0, (char)1, (char)2, (char)3, (char)4, (char)5, 104 (char)50, (char)51, (char)52, (char)53, (char)54, (char)55} }, 105 new Object[] { R05.class, int.class, new Object[]{0, 1, 2, 3, 4, 5, 50, 51, 52, 53, 54, 55} }, 106 new Object[] { R06.class, long.class, new Object[]{0L, 1L, 2L, 3L, 4L, 5L, 50L, 51L, 52L, 53L, 54L, 55L} }, 107 new Object[] { R07.class, float.class, new Object[]{(float)0, (float)1, (float)2, (float)3, (float)4, (float)5, 108 (float)50, (float)51, (float)52, (float)53, (float)54, (float)55} }, 109 new Object[] { R08.class, double.class, new Object[]{(double)0, (double)1, (double)2, (double)3, (double)4, (double)5, 110 (double)50, (double)51, (double)52, (double)53, (double)54, (double)55} }, 111 new Object[] { R09.class, String.class, new Object[]{"1", "2", "3", "4", "5", 112 "1_", "2_", "3_", "4_", "5_"} }, 113 }; 114 } 115 116 @Test(dataProvider = "recordData") testEqualsDoesntUseAccessors(Class<?> clazz, Class<?> componentClass, Object[] expectedXValues)117 public void testEqualsDoesntUseAccessors(Class<?> clazz, Class<?> componentClass, Object[] expectedXValues) throws Exception { 118 Constructor<?> ctor; 119 Method getter, equalsMethod; 120 ctor = clazz.getConstructor(componentClass); 121 equalsMethod = clazz.getMethod("equals", Object.class); 122 getter = clazz.getMethod("x"); 123 for (int i = 0; i < expectedXValues.length / 2; i++) { 124 Object rec1 = ctor.newInstance(expectedXValues[i]); 125 Object rec2 = ctor.newInstance(expectedXValues[i + expectedXValues.length / 2]); 126 System.out.println(rec1.toString()); 127 System.out.println(rec2.toString()); 128 assertFalse((boolean) equalsMethod.invoke(rec1, rec2)); 129 assertNotEquals(expectedXValues[i], expectedXValues[i + expectedXValues.length / 2]); 130 assertEquals(getter.invoke(rec1), getter.invoke(rec2)); 131 } 132 } 133 } 134