Move remaining record test to java 17 package

Bug: b/363926134
Change-Id: I77aeca7a80d1fce76acdb64bb5afe2e15708812f
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordBlogTest.java b/src/test/examplesJava17/records/RecordBlogTest.java
similarity index 84%
rename from src/test/java/com/android/tools/r8/desugar/records/RecordBlogTest.java
rename to src/test/examplesJava17/records/RecordBlogTest.java
index 10f10f4..1128f07 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordBlogTest.java
+++ b/src/test/examplesJava17/records/RecordBlogTest.java
@@ -2,11 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-package com.android.tools.r8.desugar.records;
+package records;
 
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
+import com.android.tools.r8.JdkClassFileProvider;
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -26,9 +27,6 @@
 @RunWith(Parameterized.class)
 public class RecordBlogTest extends TestBase {
 
-  private static final String RECORD_NAME = "RecordBlog";
-  private static final byte[][] PROGRAM_DATA = RecordTestUtils.getProgramData(RECORD_NAME);
-  private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_NAME);
   private static final String REFERENCE_OUTPUT_FORMAT = "Person[name=%s, age=42]";
   private static final String CLASS = "records.RecordBlog$Person";
   private static final Map<String, String> KEEP_RULE_TO_OUTPUT_FORMAT =
@@ -71,17 +69,17 @@
   public void testReference() throws Exception {
     assumeTrue(isCfRuntimeWithNativeRecordSupport());
     testForJvm(parameters)
-        .addProgramClassFileData(PROGRAM_DATA)
-        .run(parameters.getRuntime(), MAIN_TYPE)
+        .addProgramClassesAndInnerClasses(RecordBlog.class)
+        .run(parameters.getRuntime(), RecordBlog.class)
         .assertSuccessWithOutput(computeOutput(REFERENCE_OUTPUT_FORMAT));
   }
 
   @Test
   public void testD8() throws Exception {
     testForD8(parameters.getBackend())
-        .addProgramClassFileData(PROGRAM_DATA)
+        .addProgramClassesAndInnerClasses(RecordBlog.class)
         .setMinApi(parameters)
-        .run(parameters.getRuntime(), MAIN_TYPE)
+        .run(parameters.getRuntime(), RecordBlog.class)
         .applyIf(
             isRecordsFullyDesugaredForD8(parameters)
                 || runtimeWithRecordsSupport(parameters.getRuntime()),
@@ -99,19 +97,19 @@
           try {
             R8FullTestBuilder builder =
                 testForR8(parameters.getBackend())
-                    .addProgramClassFileData(PROGRAM_DATA)
+                    .addProgramClassesAndInnerClasses(RecordBlog.class)
                     .setMinApi(parameters)
                     .addKeepRules(kr)
-                    .addKeepMainRule(MAIN_TYPE);
+                    .addKeepMainRule(RecordBlog.class);
             String res;
             if (parameters.isCfRuntime()) {
               res =
                   builder
-                      .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
-                      .run(parameters.getRuntime(), MAIN_TYPE)
+                      .addLibraryProvider(JdkClassFileProvider.fromSystemJdk())
+                      .run(parameters.getRuntime(), RecordBlog.class)
                       .getStdOut();
             } else {
-              res = builder.run(parameters.getRuntime(), MAIN_TYPE).getStdOut();
+              res = builder.run(parameters.getRuntime(), RecordBlog.class).getStdOut();
             }
             results.put(kr, res);
           } catch (Exception e) {
diff --git a/src/test/examplesJava17/records/RecordInterface.java b/src/test/examplesJava17/records/RecordInterface.java
deleted file mode 100644
index 8fc1e56..0000000
--- a/src/test/examplesJava17/records/RecordInterface.java
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package records;
-
-public class RecordInterface {
-
-  interface Human {
-    default void printHuman() {
-      System.out.println("Human");
-    }
-  }
-
-  record Person(String name, int age) implements Human {}
-
-  public static void main(String[] args) {
-    Person janeDoe = new Person("Jane Doe", 42);
-    janeDoe.printHuman();
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordInterfaceTest.java b/src/test/examplesJava17/records/RecordInterfaceTest.java
similarity index 75%
rename from src/test/java/com/android/tools/r8/desugar/records/RecordInterfaceTest.java
rename to src/test/examplesJava17/records/RecordInterfaceTest.java
index c537691..d5144b0 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordInterfaceTest.java
+++ b/src/test/examplesJava17/records/RecordInterfaceTest.java
@@ -2,26 +2,31 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-package com.android.tools.r8.desugar.records;
+package records;
 
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assume.assumeTrue;
 
+import com.android.tools.r8.DesugarGraphTestConsumer;
 import com.android.tools.r8.GlobalSyntheticsConsumer;
 import com.android.tools.r8.GlobalSyntheticsTestingConsumer;
+import com.android.tools.r8.JdkClassFileProvider;
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime.CfVm;
-import com.android.tools.r8.desugar.graph.DesugarGraphTestConsumer;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.origin.PathOrigin;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -31,9 +36,6 @@
 @RunWith(Parameterized.class)
 public class RecordInterfaceTest extends TestBase {
 
-  private static final String RECORD_NAME = "RecordInterface";
-  private static final byte[][] PROGRAM_DATA = RecordTestUtils.getProgramData(RECORD_NAME);
-  private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_NAME);
   private static final String EXPECTED_RESULT = StringUtils.lines("Human");
 
   @Parameter(0)
@@ -54,17 +56,17 @@
   public void testReference() throws Exception {
     assumeTrue(isCfRuntimeWithNativeRecordSupport());
     testForJvm(parameters)
-        .addProgramClassFileData(PROGRAM_DATA)
-        .run(parameters.getRuntime(), MAIN_TYPE)
+        .addInnerClassesAndStrippedOuter(getClass())
+        .run(parameters.getRuntime(), RecordInterface.class)
         .assertSuccessWithOutput(EXPECTED_RESULT);
   }
 
   @Test
   public void testD8() throws Exception {
     testForD8(parameters.getBackend())
-        .addProgramClassFileData(PROGRAM_DATA)
+        .addInnerClassesAndStrippedOuter(getClass())
         .setMinApi(parameters)
-        .run(parameters.getRuntime(), MAIN_TYPE)
+        .run(parameters.getRuntime(), RecordInterface.class)
         .applyIf(
             isRecordsFullyDesugaredForD8(parameters)
                 || runtimeWithRecordsSupport(parameters.getRuntime()),
@@ -91,7 +93,7 @@
         .setIncludeClassesChecksum(true)
         .compile()
         .assertNoMessages()
-        .run(parameters.getRuntime(), MAIN_TYPE)
+        .run(parameters.getRuntime(), RecordInterface.class)
         .assertSuccessWithOutput(EXPECTED_RESULT);
     assertNoEdgeToRecord(consumer);
   }
@@ -117,7 +119,7 @@
         .disableDesugaring()
         .compile()
         .assertNoMessages()
-        .run(parameters.getRuntime(), MAIN_TYPE)
+        .run(parameters.getRuntime(), RecordInterface.class)
         .assertSuccessWithOutput(EXPECTED_RESULT);
     assertNoEdgeToRecord(consumer);
   }
@@ -128,12 +130,16 @@
     DesugarGraphTestConsumer consumer = new DesugarGraphTestConsumer();
     Path intermediate =
         testForD8(Backend.DEX)
+            .addStrippedOuter(getClass(), fake)
             .apply(
                 b -> {
-                  // We avoid unknown origin here since they are not allowed when using a Graph
-                  // consumer.
-                  for (byte[] programDatum : PROGRAM_DATA) {
-                    b.getBuilder().addClassProgramData(programDatum, fake);
+                  try {
+                    for (Path file :
+                        ToolHelper.getClassFilesForInnerClasses(ImmutableList.of(getClass()))) {
+                      b.getBuilder().addClassProgramData(Files.readAllBytes(file), fake);
+                    }
+                  } catch (IOException e) {
+                    throw new RuntimeException(e);
                   }
                 })
             .setMinApi(parameters)
@@ -149,7 +155,7 @@
   }
 
   private void assertNoEdgeToRecord(DesugarGraphTestConsumer consumer) {
-    assertEquals(0, consumer.totalEdgeCount());
+    Assert.assertEquals(0, consumer.totalEdgeCount());
   }
 
   @Test
@@ -158,18 +164,37 @@
     assumeTrue(parameters.isDexRuntime() || isCfRuntimeWithNativeRecordSupport());
     R8FullTestBuilder builder =
         testForR8(parameters.getBackend())
-            .addProgramClassFileData(PROGRAM_DATA)
+            .addInnerClassesAndStrippedOuter(getClass())
             .setMinApi(parameters)
-            .addKeepMainRule(MAIN_TYPE);
+            .addKeepMainRule(RecordInterface.class);
     if (parameters.isCfRuntime()) {
       builder
-          .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
+          .addLibraryProvider(JdkClassFileProvider.fromSystemJdk())
           .compile()
           .inspect(RecordTestUtils::assertRecordsAreRecords)
-          .run(parameters.getRuntime(), MAIN_TYPE)
+          .run(parameters.getRuntime(), RecordInterface.class)
           .assertSuccessWithOutput(EXPECTED_RESULT);
       return;
     }
-    builder.run(parameters.getRuntime(), MAIN_TYPE).assertSuccessWithOutput(EXPECTED_RESULT);
+    builder
+        .run(parameters.getRuntime(), RecordInterface.class)
+        .assertSuccessWithOutput(EXPECTED_RESULT);
+  }
+
+  interface Human {
+
+    default void printHuman() {
+      System.out.println("Human");
+    }
+  }
+
+  record Person(String name, int age) implements Human {}
+
+  public class RecordInterface {
+
+    public static void main(String[] args) {
+      Person janeDoe = new Person("Jane Doe", 42);
+      janeDoe.printHuman();
+    }
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomSplitDesugaringTest.java b/src/test/examplesJava17/records/RecordInvokeCustomSplitDesugaringTest.java
similarity index 67%
rename from src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomSplitDesugaringTest.java
rename to src/test/examplesJava17/records/RecordInvokeCustomSplitDesugaringTest.java
index b782568..d797244 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomSplitDesugaringTest.java
+++ b/src/test/examplesJava17/records/RecordInvokeCustomSplitDesugaringTest.java
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-package com.android.tools.r8.desugar.records;
+package records;
 
 import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
 import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
@@ -25,13 +25,12 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import records.RecordInvokeCustom.Empty;
+import records.RecordInvokeCustom.Person;
 
 @RunWith(Parameterized.class)
 public class RecordInvokeCustomSplitDesugaringTest extends TestBase {
 
-  private static final String RECORD_NAME = "RecordInvokeCustom";
-  private static final byte[][] PROGRAM_DATA = RecordTestUtils.getProgramData(RECORD_NAME);
-  private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_NAME);
   private static final String EXPECTED_RESULT =
       StringUtils.lines(
           "%s[]",
@@ -64,7 +63,7 @@
   public void testD8() throws Exception {
     Path desugared =
         testForD8(Backend.CF)
-            .addProgramClassFileData(PROGRAM_DATA)
+            .addInnerClassesAndStrippedOuter(getClass())
             .setMinApi(parameters)
             .compile()
             .writeToZip();
@@ -72,7 +71,7 @@
         .addProgramFiles(desugared)
         .setMinApi(parameters)
         .compile()
-        .run(parameters.getRuntime(), MAIN_TYPE)
+        .run(parameters.getRuntime(), RecordInvokeCustom.class)
         .assertSuccessWithOutput(EXPECTED_RESULT_D8);
   }
 
@@ -81,7 +80,7 @@
     parameters.assumeR8TestParameters();
     Path desugared =
         testForD8(Backend.CF)
-            .addProgramClassFileData(PROGRAM_DATA)
+            .addInnerClassesAndStrippedOuter(getClass())
             .setMinApi(parameters)
             .compile()
             .writeToZip();
@@ -94,7 +93,7 @@
     testForR8(parameters.getBackend())
         .addProgramFiles(desugared)
         .setMinApi(parameters)
-        .addKeepMainRule(MAIN_TYPE)
+        .addKeepMainRule(RecordInvokeCustom.class)
         .allowDiagnosticMessages()
         .compileWithExpectedDiagnostics(
             // Class com.android.tools.r8.RecordTag in desugared input is seen as java.lang.Record
@@ -119,10 +118,12 @@
             })
         .inspect(
             i -> {
-              minifiedNames[0] = extractSimpleFinalName(i, "records.RecordInvokeCustom$Empty");
-              minifiedNames[1] = extractSimpleFinalName(i, "records.RecordInvokeCustom$Person");
+              minifiedNames[0] =
+                  extractSimpleFinalName(i, "records.RecordInvokeCustomSplitDesugaringTest$Empty");
+              minifiedNames[1] =
+                  extractSimpleFinalName(i, "records.RecordInvokeCustomSplitDesugaringTest$Person");
             })
-        .run(parameters.getRuntime(), MAIN_TYPE)
+        .run(parameters.getRuntime(), RecordInvokeCustom.class)
         .assertSuccessWithOutput(
             String.format(EXPECTED_RESULT, minifiedNames[0], minifiedNames[1]));
   }
@@ -131,4 +132,47 @@
     String finalName = i.clazz(name).getFinalName();
     return finalName.split("\\.")[1];
   }
+
+  record Empty() {}
+
+  record Person(String name, int age) {}
+
+  public class RecordInvokeCustom {
+
+    public static void main(String[] args) {
+      emptyTest();
+      equalityTest();
+      toStringTest();
+    }
+
+    private static void emptyTest() {
+      Empty empty1 = new Empty();
+      Empty empty2 = new Empty();
+      System.out.println(empty1.toString());
+      System.out.println(empty1.equals(empty2));
+      System.out.println(empty1.hashCode() == empty2.hashCode());
+      System.out.println(empty1.toString().equals(empty2.toString()));
+    }
+
+    private static void toStringTest() {
+      Person janeDoe = new Person("Jane Doe", 42);
+      System.out.println(janeDoe.toString());
+    }
+
+    private static void equalityTest() {
+      Person jane1 = new Person("Jane Doe", 42);
+      Person jane2 = new Person("Jane Doe", 42);
+      String nonIdenticalString = "Jane " + (System.currentTimeMillis() > 0 ? "Doe" : "Zan");
+      Person jane3 = new Person(nonIdenticalString, 42);
+      Person bob = new Person("Bob", 42);
+      Person youngJane = new Person("Jane Doe", 22);
+      System.out.println(jane1.equals(jane2));
+      System.out.println(jane1.toString().equals(jane2.toString()));
+      System.out.println(nonIdenticalString == "Jane Doe"); // false.
+      System.out.println(nonIdenticalString.equals("Jane Doe")); // true.
+      System.out.println(jane1.equals(jane3));
+      System.out.println(jane1.equals(bob));
+      System.out.println(jane1.equals(youngJane));
+    }
+  }
 }
diff --git a/src/test/examplesJava17/records/RecordInvokeCustomTest.java b/src/test/examplesJava17/records/RecordInvokeCustomTest.java
new file mode 100644
index 0000000..ec3956a
--- /dev/null
+++ b/src/test/examplesJava17/records/RecordInvokeCustomTest.java
@@ -0,0 +1,140 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package records;
+
+import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.desugar.LibraryFilesHelper;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import records.RecordInvokeCustom.Empty;
+import records.RecordInvokeCustom.Person;
+
+@RunWith(Parameterized.class)
+public class RecordInvokeCustomTest extends TestBase {
+
+  private static final String EXPECTED_RESULT =
+      StringUtils.lines(
+          "%s[]",
+          "true",
+          "true",
+          "true",
+          "true",
+          "true",
+          "false",
+          "true",
+          "true",
+          "false",
+          "false",
+          "%s[%s=Jane Doe, %s=42]");
+  private static final String EXPECTED_RESULT_D8 =
+      String.format(EXPECTED_RESULT, "Empty", "Person", "name", "age");
+  private static final String EXPECTED_RESULT_R8 =
+      String.format(EXPECTED_RESULT, "a", "b", "a", "b");
+
+  private final TestParameters parameters;
+
+  public RecordInvokeCustomTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters()
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
+        .withDexRuntimes()
+        .withAllApiLevelsAlsoForCf()
+        .build();
+  }
+
+  @Test
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    testForJvm(parameters)
+        .addInnerClassesAndStrippedOuter(getClass())
+        .run(parameters.getRuntime(), RecordInvokeCustom.class)
+        .assertSuccessWithOutput(EXPECTED_RESULT_D8);
+  }
+
+  @Test
+  public void testD8() throws Exception {
+    testForD8(parameters.getBackend())
+        .addInnerClassesAndStrippedOuter(getClass())
+        .setMinApi(parameters)
+        .compile()
+        .run(parameters.getRuntime(), RecordInvokeCustom.class)
+        .assertSuccessWithOutput(EXPECTED_RESULT_D8);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    parameters.assumeR8TestParameters();
+    R8FullTestBuilder builder =
+        testForR8(parameters.getBackend())
+            .addInnerClassesAndStrippedOuter(getClass())
+            .setMinApi(parameters)
+            .addKeepMainRule(RecordInvokeCustom.class);
+    if (parameters.isCfRuntime()) {
+      builder
+          .addLibraryFiles(LibraryFilesHelper.getJdk15LibraryFiles(temp))
+          .compile()
+          .inspect(RecordTestUtils::assertRecordsAreRecords)
+          .run(parameters.getRuntime(), RecordInvokeCustom.class)
+          .assertSuccessWithOutput(EXPECTED_RESULT_R8);
+      return;
+    }
+    builder
+        .run(parameters.getRuntime(), RecordInvokeCustom.class)
+        .assertSuccessWithOutput(EXPECTED_RESULT_R8);
+  }
+
+  record Empty() {}
+
+  record Person(String name, int age) {}
+
+  public class RecordInvokeCustom {
+
+    public static void main(String[] args) {
+      emptyTest();
+      equalityTest();
+      toStringTest();
+    }
+
+    private static void emptyTest() {
+      Empty empty1 = new Empty();
+      Empty empty2 = new Empty();
+      System.out.println(empty1.toString());
+      System.out.println(empty1.equals(empty2));
+      System.out.println(empty1.hashCode() == empty2.hashCode());
+      System.out.println(empty1.toString().equals(empty2.toString()));
+    }
+
+    private static void toStringTest() {
+      Person janeDoe = new Person("Jane Doe", 42);
+      System.out.println(janeDoe.toString());
+    }
+
+    private static void equalityTest() {
+      Person jane1 = new Person("Jane Doe", 42);
+      Person jane2 = new Person("Jane Doe", 42);
+      String nonIdenticalString = "Jane " + (System.currentTimeMillis() > 0 ? "Doe" : "Zan");
+      Person jane3 = new Person(nonIdenticalString, 42);
+      Person bob = new Person("Bob", 42);
+      Person youngJane = new Person("Jane Doe", 22);
+      System.out.println(jane1.equals(jane2));
+      System.out.println(jane1.toString().equals(jane2.toString()));
+      System.out.println(nonIdenticalString == "Jane Doe"); // false.
+      System.out.println(nonIdenticalString.equals("Jane Doe")); // true.
+      System.out.println(jane1.equals(jane3));
+      System.out.println(jane1.equals(bob));
+      System.out.println(jane1.equals(youngJane));
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordLibMergeTest.java b/src/test/examplesJava17/records/RecordLibMergeTest.java
similarity index 70%
rename from src/test/java/com/android/tools/r8/desugar/records/RecordLibMergeTest.java
rename to src/test/examplesJava17/records/RecordLibMergeTest.java
index ca7a7b5..fd0e655 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordLibMergeTest.java
+++ b/src/test/examplesJava17/records/RecordLibMergeTest.java
@@ -2,8 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-package com.android.tools.r8.desugar.records;
+package records;
 
+import com.android.tools.r8.JdkClassFileProvider;
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -18,11 +19,6 @@
 @RunWith(Parameterized.class)
 public class RecordLibMergeTest extends TestBase {
 
-  private static final String RECORD_LIB = "RecordLib";
-  private static final String RECORD_MAIN = "RecordMain";
-  private static final byte[][] PROGRAM_DATA_LIB = RecordTestUtils.getProgramData(RECORD_LIB);
-  private static final byte[][] PROGRAM_DATA_MAIN = RecordTestUtils.getProgramData(RECORD_MAIN);
-  private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_MAIN);
   private static final String EXPECTED_RESULT = StringUtils.lines("true", "true");
 
   private final TestParameters parameters;
@@ -45,30 +41,30 @@
     parameters.assumeR8TestParameters();
     Path lib =
         testForR8(Backend.CF)
-            .addProgramClassFileData(PROGRAM_DATA_LIB)
+            .addProgramClassesAndInnerClasses(RecordLib.class)
             .addKeepRules(
                 "-keep class records.RecordLib { public static java.lang.Object getRecord(); }")
             .addKeepRules("-keep class records.RecordLib$LibRecord")
-            .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
+            .addLibraryProvider(JdkClassFileProvider.fromSystemJdk())
             .compile()
             .writeToZip();
     R8FullTestBuilder builder =
         testForR8(parameters.getBackend())
             .addProgramFiles(lib)
-            .addProgramClassFileData(PROGRAM_DATA_MAIN)
+            .addProgramClassesAndInnerClasses(RecordMain.class)
             .setMinApi(parameters)
-            .addKeepMainRule(MAIN_TYPE)
+            .addKeepMainRule(RecordMain.class)
             .addKeepRules("-keep class records.RecordLib$LibRecord")
             .addKeepRules("-keep class records.RecordMain$MainRecord");
     if (parameters.isCfRuntime()) {
       builder
-          .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
+          .addLibraryProvider(JdkClassFileProvider.fromSystemJdk())
           .compile()
           .inspect(RecordTestUtils::assertRecordsAreRecords)
-          .run(parameters.getRuntime(), MAIN_TYPE)
+          .run(parameters.getRuntime(), RecordMain.class)
           .assertSuccessWithOutput(EXPECTED_RESULT);
       return;
     }
-    builder.run(parameters.getRuntime(), MAIN_TYPE).assertSuccessWithOutput(EXPECTED_RESULT);
+    builder.run(parameters.getRuntime(), RecordMain.class).assertSuccessWithOutput(EXPECTED_RESULT);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/CompilationDependentSetTest.java b/src/test/java/com/android/tools/r8/desugar/graph/CompilationDependentSetTest.java
index 258805a..c890f40 100644
--- a/src/test/java/com/android/tools/r8/desugar/graph/CompilationDependentSetTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/graph/CompilationDependentSetTest.java
@@ -7,6 +7,7 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.D8TestBuilder;
+import com.android.tools.r8.DesugarGraphTestConsumer;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/InterfaceBridgeDependencyTest.java b/src/test/java/com/android/tools/r8/desugar/graph/InterfaceBridgeDependencyTest.java
index 6c11011..bfd0048 100644
--- a/src/test/java/com/android/tools/r8/desugar/graph/InterfaceBridgeDependencyTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/graph/InterfaceBridgeDependencyTest.java
@@ -8,6 +8,7 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.D8TestBuilder;
+import com.android.tools.r8.DesugarGraphTestConsumer;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/InterfaceToImplementingClassDependencyTest.java b/src/test/java/com/android/tools/r8/desugar/graph/InterfaceToImplementingClassDependencyTest.java
index aab7123..42f49fb 100644
--- a/src/test/java/com/android/tools/r8/desugar/graph/InterfaceToImplementingClassDependencyTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/graph/InterfaceToImplementingClassDependencyTest.java
@@ -7,6 +7,7 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.D8TestBuilder;
+import com.android.tools.r8.DesugarGraphTestConsumer;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/LambdaDependencyTest.java b/src/test/java/com/android/tools/r8/desugar/graph/LambdaDependencyTest.java
index cdb01f6..37674a7 100644
--- a/src/test/java/com/android/tools/r8/desugar/graph/LambdaDependencyTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/graph/LambdaDependencyTest.java
@@ -7,6 +7,7 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.D8TestBuilder;
+import com.android.tools.r8.DesugarGraphTestConsumer;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/NestDependencyTest.java b/src/test/java/com/android/tools/r8/desugar/graph/NestDependencyTest.java
index df53dc1..4f97f34 100644
--- a/src/test/java/com/android/tools/r8/desugar/graph/NestDependencyTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/graph/NestDependencyTest.java
@@ -7,6 +7,7 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.D8TestBuilder;
+import com.android.tools.r8.DesugarGraphTestConsumer;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/Regress167562221Test.java b/src/test/java/com/android/tools/r8/desugar/graph/Regress167562221Test.java
index 650338c..629de48 100644
--- a/src/test/java/com/android/tools/r8/desugar/graph/Regress167562221Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/graph/Regress167562221Test.java
@@ -5,6 +5,7 @@
 
 import static org.junit.Assert.assertEquals;
 
+import com.android.tools.r8.DesugarGraphTestConsumer;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java
deleted file mode 100644
index 8be5a1d..0000000
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.desugar.records;
-
-import com.android.tools.r8.R8FullTestBuilder;
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.TestRuntime.CfVm;
-import com.android.tools.r8.desugar.LibraryFilesHelper;
-import com.android.tools.r8.utils.StringUtils;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-@RunWith(Parameterized.class)
-public class RecordInvokeCustomTest extends TestBase {
-
-  private static final String RECORD_NAME = "RecordInvokeCustom";
-  private static final byte[][] PROGRAM_DATA = RecordTestUtils.getProgramData(RECORD_NAME);
-  private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_NAME);
-  private static final String EXPECTED_RESULT =
-      StringUtils.lines(
-          "%s[]",
-          "true",
-          "true",
-          "true",
-          "true",
-          "true",
-          "false",
-          "true",
-          "true",
-          "false",
-          "false",
-          "%s[%s=Jane Doe, %s=42]");
-  private static final String EXPECTED_RESULT_D8 =
-      String.format(EXPECTED_RESULT, "Empty", "Person", "name", "age");
-  private static final String EXPECTED_RESULT_R8 =
-      String.format(EXPECTED_RESULT, "a", "b", "a", "b");
-
-  private final TestParameters parameters;
-
-  public RecordInvokeCustomTest(TestParameters parameters) {
-    this.parameters = parameters;
-  }
-
-  @Parameterized.Parameters(name = "{0}")
-  public static TestParametersCollection data() {
-    return getTestParameters()
-        .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
-        .withDexRuntimes()
-        .withAllApiLevelsAlsoForCf()
-        .build();
-  }
-
-  @Test
-  public void testJvm() throws Exception {
-    parameters.assumeJvmTestParameters();
-    testForJvm(parameters)
-        .addProgramClassFileData(PROGRAM_DATA)
-        .run(parameters.getRuntime(), MAIN_TYPE)
-        .assertSuccessWithOutput(EXPECTED_RESULT_D8);
-  }
-
-  @Test
-  public void testD8() throws Exception {
-    testForD8(parameters.getBackend())
-        .addProgramClassFileData(PROGRAM_DATA)
-        .setMinApi(parameters)
-        .compile()
-        .run(parameters.getRuntime(), MAIN_TYPE)
-        .assertSuccessWithOutput(EXPECTED_RESULT_D8);
-  }
-
-  @Test
-  public void testR8() throws Exception {
-    parameters.assumeR8TestParameters();
-    R8FullTestBuilder builder =
-        testForR8(parameters.getBackend())
-            .addProgramClassFileData(PROGRAM_DATA)
-            .setMinApi(parameters)
-            .addKeepMainRule(MAIN_TYPE);
-    if (parameters.isCfRuntime()) {
-      builder
-          .addLibraryFiles(LibraryFilesHelper.getJdk15LibraryFiles(temp))
-          .compile()
-          .inspect(RecordTestUtils::assertRecordsAreRecords)
-          .run(parameters.getRuntime(), MAIN_TYPE)
-          .assertSuccessWithOutput(EXPECTED_RESULT_R8);
-      return;
-    }
-    builder.run(parameters.getRuntime(), MAIN_TYPE).assertSuccessWithOutput(EXPECTED_RESULT_R8);
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordTestUtils.java b/src/test/java/com/android/tools/r8/desugar/records/RecordTestUtils.java
deleted file mode 100644
index 1194f76..0000000
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordTestUtils.java
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.desugar.records;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.desugar.LibraryFilesHelper;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.StringUtils;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
-import com.google.common.io.ByteStreams;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import org.junit.rules.TemporaryFolder;
-
-/**
- * Records are compiled using: third_party/openjdk/jdk-15/linux/bin/javac --release 15
- * --enable-preview path/to/file.java
- */
-public class RecordTestUtils {
-
-  private static final String EXAMPLE_FOLDER = "examplesJava17";
-  private static final String RECORD_FOLDER = "records";
-
-  public static Path jar() {
-    return Paths.get(ToolHelper.TESTS_BUILD_DIR, EXAMPLE_FOLDER, RECORD_FOLDER + ".jar");
-  }
-
-  public static Path[] getJdk15LibraryFiles(TemporaryFolder temp) throws Exception {
-    return LibraryFilesHelper.getJdk15LibraryFiles(temp);
-  }
-
-  public static byte[][] getProgramData(String mainClassSimpleName) {
-    byte[][] bytes = classDataFromPrefix(RECORD_FOLDER + "/" + mainClassSimpleName);
-    assert bytes.length > 0 : "Did not find any program data for " + mainClassSimpleName;
-    return bytes;
-  }
-
-  public static String getMainType(String mainClassSimpleName) {
-    return RECORD_FOLDER + "." + mainClassSimpleName;
-  }
-
-  private static byte[][] classDataFromPrefix(String prefix) {
-    Path examplePath = jar();
-    if (!Files.exists(examplePath)) {
-      throw new RuntimeException(
-          "Could not find path "
-              + examplePath
-              + ". Build "
-              + EXAMPLE_FOLDER
-              + " by running tools/gradle.py build"
-              + StringUtils.capitalize(EXAMPLE_FOLDER));
-    }
-    List<byte[]> result = new ArrayList<>();
-    try (ZipFile zipFile = new ZipFile(examplePath.toFile())) {
-      Enumeration<? extends ZipEntry> entries = zipFile.entries();
-      while (entries.hasMoreElements()) {
-        ZipEntry zipEntry = entries.nextElement();
-        if (zipEntry.getName().startsWith(prefix)) {
-          result.add(ByteStreams.toByteArray(zipFile.getInputStream(zipEntry)));
-        }
-      }
-    } catch (IOException e) {
-      throw new RuntimeException("Could not read zip-entry from " + examplePath.toString(), e);
-    }
-    if (result.isEmpty()) {
-      throw new RuntimeException("Did not find any class with prefix " + prefix);
-    }
-    return result.toArray(new byte[0][0]);
-  }
-
-  public static void assertRecordsAreRecords(CodeInspector inspector) {
-    for (FoundClassSubject clazz : inspector.allClasses()) {
-      if (clazz.getDexProgramClass().superType.toString().equals("java.lang.Record")) {
-        assertTrue(clazz.getDexProgramClass().isRecord());
-      }
-    }
-  }
-
-  public static void assertNoJavaLangRecord(CodeInspector inspector, TestParameters parameters) {
-    if (parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.V)) {
-      assertFalse(inspector.clazz("java.lang.RecordTag").isPresent());
-    } else {
-      assertFalse(inspector.clazz("java.lang.Record").isPresent());
-    }
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/desugar/graph/DesugarGraphTestConsumer.java b/src/test/testbase/java/com/android/tools/r8/DesugarGraphTestConsumer.java
similarity index 97%
rename from src/test/java/com/android/tools/r8/desugar/graph/DesugarGraphTestConsumer.java
rename to src/test/testbase/java/com/android/tools/r8/DesugarGraphTestConsumer.java
index 541bfea..29efc40 100644
--- a/src/test/java/com/android/tools/r8/desugar/graph/DesugarGraphTestConsumer.java
+++ b/src/test/testbase/java/com/android/tools/r8/DesugarGraphTestConsumer.java
@@ -1,13 +1,12 @@
 // Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.desugar.graph;
+package com.android.tools.r8;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.DesugarGraphConsumer;
 import com.android.tools.r8.origin.GlobalSyntheticOrigin;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.StringUtils;
diff --git a/src/test/testbase/java/com/android/tools/r8/TestBaseBuilder.java b/src/test/testbase/java/com/android/tools/r8/TestBaseBuilder.java
index 6746b89..98cb209 100644
--- a/src/test/testbase/java/com/android/tools/r8/TestBaseBuilder.java
+++ b/src/test/testbase/java/com/android/tools/r8/TestBaseBuilder.java
@@ -4,12 +4,16 @@
 
 package com.android.tools.r8;
 
+import static com.android.tools.r8.TestBase.descriptor;
+
 import com.android.tools.r8.ProgramResource.Kind;
 import com.android.tools.r8.dump.CompilerDump;
 import com.android.tools.r8.dump.DumpOptions;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.transformers.ClassFileTransformer.FieldPredicate;
+import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.ListUtils;
 import com.google.common.collect.ImmutableMap;
@@ -35,6 +39,19 @@
     this.builder = builder;
   }
 
+  public T addStrippedOuter(Class<?> clazz, Origin origin) throws IOException {
+    builder.addClassProgramData(
+        TestBase.transformer(clazz)
+            .removeFields(FieldPredicate.all())
+            .removeMethods(MethodPredicate.all())
+            .removeAllAnnotations()
+            .setSuper(descriptor(Object.class))
+            .setImplements()
+            .transform(),
+        origin);
+    return self();
+  }
+
   @Override
   public T addProgramClassFileData(Collection<byte[]> classes) {
     for (byte[] clazz : classes) {