Clément Béra | 83fa01e | 2024-08-02 09:49:58 +0200 | [diff] [blame] | 1 | // Copyright (c) 2024, the R8 project authors. Please see the AUTHORS file |
| 2 | // for details. All rights reserved. Use of this source code is governed by a |
| 3 | // BSD-style license that can be found in the LICENSE file. |
| 4 | |
| 5 | package records; |
| 6 | |
| 7 | import static org.junit.Assume.assumeTrue; |
| 8 | |
| 9 | import com.android.tools.r8.JdkClassFileProvider; |
| 10 | import com.android.tools.r8.NeverInline; |
| 11 | import com.android.tools.r8.R8FullTestBuilder; |
| 12 | import com.android.tools.r8.TestBase; |
| 13 | import com.android.tools.r8.TestParameters; |
| 14 | import com.android.tools.r8.TestParametersCollection; |
| 15 | import com.android.tools.r8.TestRuntime.CfVm; |
| 16 | import com.android.tools.r8.utils.AndroidApiLevel; |
| 17 | import com.android.tools.r8.utils.StringUtils; |
| 18 | import org.junit.Test; |
| 19 | import org.junit.runner.RunWith; |
| 20 | import org.junit.runners.Parameterized; |
| 21 | import org.junit.runners.Parameterized.Parameter; |
| 22 | import org.junit.runners.Parameterized.Parameters; |
| 23 | |
| 24 | @RunWith(Parameterized.class) |
| 25 | public class RecordHashCodeTest extends TestBase { |
| 26 | |
| 27 | private static final String EXPECTED_RESULT = |
| 28 | StringUtils.lines( |
| 29 | "true", "true", "true", "true", "false", "false", "true", "true", "false", "false"); |
| 30 | |
| 31 | @Parameter public TestParameters parameters; |
| 32 | |
| 33 | @Parameters(name = "{0}") |
| 34 | public static TestParametersCollection data() { |
| 35 | return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(); |
| 36 | } |
| 37 | |
| 38 | private boolean isCfRuntimeWithNativeRecordSupport() { |
| 39 | return parameters.isCfRuntime() |
| 40 | && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK14) |
| 41 | && parameters.getApiLevel().equals(AndroidApiLevel.B); |
| 42 | } |
| 43 | |
| 44 | @Test |
| 45 | public void testReference() throws Exception { |
| 46 | assumeTrue(isCfRuntimeWithNativeRecordSupport()); |
| 47 | testForJvm(parameters) |
| 48 | .addInnerClassesAndStrippedOuter(getClass()) |
| 49 | .run(parameters.getRuntime(), TestClass.class) |
| 50 | .assertSuccessWithOutput(EXPECTED_RESULT); |
| 51 | } |
| 52 | |
| 53 | @Test |
| 54 | public void testD8() throws Exception { |
| 55 | testForD8(parameters.getBackend()) |
| 56 | .addInnerClassesAndStrippedOuter(getClass()) |
| 57 | .setMinApi(parameters) |
| 58 | .run(parameters.getRuntime(), TestClass.class) |
| 59 | .applyIf( |
Clément Béra | d8769c2 | 2024-08-15 08:43:58 +0200 | [diff] [blame] | 60 | isRecordsFullyDesugaredForD8(parameters) |
Clément Béra | 83fa01e | 2024-08-02 09:49:58 +0200 | [diff] [blame] | 61 | || runtimeWithRecordsSupport(parameters.getRuntime()), |
| 62 | r -> r.assertSuccessWithOutput(EXPECTED_RESULT), |
| 63 | r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class)); |
| 64 | } |
| 65 | |
| 66 | @Test |
| 67 | public void testR8() throws Exception { |
| 68 | parameters.assumeR8TestParameters(); |
| 69 | assumeTrue(parameters.isDexRuntime() || isCfRuntimeWithNativeRecordSupport()); |
| 70 | R8FullTestBuilder builder = |
| 71 | testForR8(parameters.getBackend()) |
| 72 | .addInnerClassesAndStrippedOuter(getClass()) |
| 73 | .setMinApi(parameters) |
| 74 | .addInliningAnnotations() |
| 75 | .addKeepMainRule(TestClass.class); |
| 76 | if (parameters.isCfRuntime()) { |
| 77 | builder |
| 78 | .addLibraryProvider(JdkClassFileProvider.fromSystemJdk()) |
| 79 | .run(parameters.getRuntime(), TestClass.class) |
| 80 | .assertSuccessWithOutput(EXPECTED_RESULT); |
| 81 | return; |
| 82 | } |
| 83 | builder.run(parameters.getRuntime(), TestClass.class).assertSuccessWithOutput(EXPECTED_RESULT); |
| 84 | } |
| 85 | |
Clément Béra | c36e154 | 2024-08-21 11:16:32 +0200 | [diff] [blame] | 86 | @Test |
| 87 | public void testR8DontShrinkDontObfuscate() throws Exception { |
| 88 | parameters.assumeR8TestParameters(); |
| 89 | assumeTrue(parameters.isDexRuntime() || isCfRuntimeWithNativeRecordSupport()); |
| 90 | R8FullTestBuilder builder = |
| 91 | testForR8(parameters.getBackend()) |
| 92 | .addInnerClassesAndStrippedOuter(getClass()) |
| 93 | .setMinApi(parameters) |
| 94 | .addDontShrink() |
| 95 | .addDontObfuscate() |
| 96 | .addInliningAnnotations() |
| 97 | .addKeepMainRule(TestClass.class); |
| 98 | if (parameters.isCfRuntime()) { |
| 99 | builder |
| 100 | .addLibraryProvider(JdkClassFileProvider.fromSystemJdk()) |
| 101 | .run(parameters.getRuntime(), TestClass.class) |
| 102 | .assertSuccessWithOutput(EXPECTED_RESULT); |
| 103 | return; |
| 104 | } |
| 105 | builder.run(parameters.getRuntime(), TestClass.class).assertSuccessWithOutput(EXPECTED_RESULT); |
| 106 | } |
| 107 | |
Clément Béra | 83fa01e | 2024-08-02 09:49:58 +0200 | [diff] [blame] | 108 | public static class TestClass { |
| 109 | |
| 110 | record Person(String name, int age) {} |
| 111 | |
| 112 | record Food(String name, int sweetness, int saltyness) {} |
| 113 | |
| 114 | public static void main(String[] args) { |
| 115 | Person janeDoe = new Person("Jane Doe", 42); |
| 116 | System.out.println(equals(janeDoe.hashCode(), janeDoe.hashCode())); |
| 117 | System.out.println(equalsHash(janeDoe, janeDoe)); |
| 118 | Person otherJaneDoe = new Person("Jane Doe", 42); |
| 119 | System.out.println(equals(janeDoe.hashCode(), otherJaneDoe.hashCode())); |
| 120 | System.out.println(equalsHash(janeDoe, otherJaneDoe)); |
| 121 | Person johnDoe = new Person("John Doe", 45); |
| 122 | System.out.println(equals(janeDoe.hashCode(), johnDoe.hashCode())); |
| 123 | System.out.println(equalsHash(janeDoe, johnDoe)); |
| 124 | |
| 125 | Food bread = new Food("bread", 1, 100); |
| 126 | System.out.println(equals(bread.hashCode(), bread.hashCode())); |
| 127 | System.out.println(equalsHash(bread, bread)); |
| 128 | Food biscuit = new Food("biscuit", 50, 20); |
| 129 | System.out.println(equals(bread.hashCode(), biscuit.hashCode())); |
| 130 | System.out.println(equalsHash(bread, biscuit)); |
| 131 | } |
| 132 | |
| 133 | @NeverInline |
| 134 | public static boolean equals(int i1, int i2) { |
| 135 | return System.currentTimeMillis() > 0 ? i1 == i2 : false; |
| 136 | } |
| 137 | |
| 138 | @NeverInline |
| 139 | public static boolean equalsHash(Record r1, Record r2) { |
| 140 | return System.currentTimeMillis() > 0 ? equals(r1.hashCode(), r2.hashCode()) : false; |
| 141 | } |
| 142 | } |
| 143 | } |