Test for adding twr synthetics to baseline profile

Bug: b/265729283
Change-Id: I9136fd23acdf5d06ba905a37f3ad028ba2d83b3c
diff --git a/src/test/java/com/android/tools/r8/desugar/twr/TwrCloseResourceDuplicationTest.java b/src/test/java/com/android/tools/r8/desugar/twr/TwrCloseResourceDuplicationTest.java
index fae6781..156f775 100644
--- a/src/test/java/com/android/tools/r8/desugar/twr/TwrCloseResourceDuplicationTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/twr/TwrCloseResourceDuplicationTest.java
@@ -28,22 +28,24 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class TwrCloseResourceDuplicationTest extends TestBase {
 
   private static final String PKG = "twrcloseresourceduplication";
   private static final String EXAMPLE = "examplesJava9/" + PKG;
-  private final JavaExampleClassProxy MAIN =
+  protected static final JavaExampleClassProxy MAIN =
       new JavaExampleClassProxy(EXAMPLE, PKG + "/TwrCloseResourceDuplication");
-  private final JavaExampleClassProxy FOO =
+  protected static final JavaExampleClassProxy FOO =
       new JavaExampleClassProxy(EXAMPLE, PKG + "/TwrCloseResourceDuplication$Foo");
-  private final JavaExampleClassProxy BAR =
+  protected static final JavaExampleClassProxy BAR =
       new JavaExampleClassProxy(EXAMPLE, PKG + "/TwrCloseResourceDuplication$Bar");
 
   static final int INPUT_CLASSES = 3;
 
-  static final String EXPECTED =
+  protected static final String EXPECTED =
       StringUtils.lines(
           "foo opened 1",
           "foo post close 1",
@@ -56,9 +58,10 @@
           "bar caught from 2: RuntimeException",
           "bar post close 2");
 
-  private final TestParameters parameters;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameterized.Parameters(name = "{0}")
+  @Parameters(name = "{0}")
   public static TestParametersCollection data() {
     return getTestParameters()
         .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
@@ -67,11 +70,7 @@
         .build();
   }
 
-  public TwrCloseResourceDuplicationTest(TestParameters parameters) {
-    this.parameters = parameters;
-  }
-
-  private String getZipFile() throws IOException {
+  protected String getZipFile() throws IOException {
     return ZipUtils.ZipBuilder.builder(temp.newFile("file.zip").toPath())
         // DEX VMs from 4.4 up-to 9.0 including, will fail if no entry is added.
         .addBytes("entry", new byte[1])
@@ -79,7 +78,7 @@
         .toString();
   }
 
-  private List<Path> getProgramInputs() throws Exception {
+  protected static List<Path> getProgramInputs() {
     return ImmutableList.of(JavaExampleClassProxy.examplesJar(EXAMPLE));
   }
 
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/TwrCloseResourceDuplicationProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/completeness/TwrCloseResourceDuplicationProfileRewritingTest.java
new file mode 100644
index 0000000..80a799c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/profile/art/completeness/TwrCloseResourceDuplicationProfileRewritingTest.java
@@ -0,0 +1,161 @@
+// 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 com.android.tools.r8.profile.art.completeness;
+
+import static com.android.tools.r8.Jdk11TestUtils.getJdk11LibraryFiles;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.notIf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.desugar.twr.TwrCloseResourceDuplicationTest;
+import com.android.tools.r8.profile.art.model.ExternalArtProfile;
+import com.android.tools.r8.profile.art.utils.ArtProfileInspector;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.references.TypeReference;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.InternalOptions.InlinerOptions;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class TwrCloseResourceDuplicationProfileRewritingTest
+    extends TwrCloseResourceDuplicationTest {
+
+  @Test
+  public void testR8ProfileRewriting() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramFiles(TwrCloseResourceDuplicationTest.getProgramInputs())
+        .addKeepMainRule(MAIN.typeName())
+        .addKeepClassAndMembersRules(FOO.typeName(), BAR.typeName())
+        .addArtProfileForRewriting(getArtProfile())
+        .addOptionsModification(InlinerOptions::disableInlining)
+        .applyIf(
+            parameters.isCfRuntime(),
+            testBuilder ->
+                testBuilder
+                    .addLibraryFiles(getJdk11LibraryFiles(temp))
+                    .addDefaultRuntimeLibrary(parameters)
+                    .addOptionsModification(
+                        options ->
+                            options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces()),
+            testBuilder ->
+                testBuilder.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.LATEST)))
+        .noHorizontalClassMergingOfSynthetics()
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .inspectResidualArtProfile(this::inspect)
+        .run(parameters.getRuntime(), MAIN.typeName(), getZipFile())
+        .assertSuccessWithOutput(TwrCloseResourceDuplicationTest.EXPECTED);
+  }
+
+  private ExternalArtProfile getArtProfile() {
+    List<TypeReference> closeResourceFormalParameters =
+        ImmutableList.of(
+            Reference.classFromClass(Throwable.class),
+            Reference.classFromClass(AutoCloseable.class));
+    return ExternalArtProfile.builder()
+        .addMethodRule(
+            Reference.method(
+                FOO.getClassReference(),
+                "foo",
+                ImmutableList.of(Reference.classFromClass(String.class)),
+                null))
+        .addMethodRule(
+            Reference.method(
+                FOO.getClassReference(), "$closeResource", closeResourceFormalParameters, null))
+        .addMethodRule(
+            Reference.method(
+                BAR.getClassReference(),
+                "bar",
+                ImmutableList.of(Reference.classFromClass(String.class)),
+                null))
+        .addMethodRule(
+            Reference.method(
+                BAR.getClassReference(), "$closeResource", closeResourceFormalParameters, null))
+        .build();
+  }
+
+  private void inspect(ArtProfileInspector profileInspector, CodeInspector inspector) {
+    boolean hasTwrCloseResourceSupport =
+        parameters.isCfRuntime()
+            || parameters
+                .getApiLevel()
+                .isGreaterThanOrEqualTo(apiLevelWithTwrCloseResourceSupport());
+
+    assertEquals(hasTwrCloseResourceSupport ? 3 : 7, inspector.allClasses().size());
+    assertThat(inspector.clazz(MAIN.typeName()), isPresent());
+
+    // Class Foo has two methods foo() and $closeResource().
+    ClassSubject fooClassSubject = inspector.clazz(FOO.typeName());
+    assertThat(fooClassSubject, isPresent());
+
+    MethodSubject fooMethodSubject = fooClassSubject.uniqueMethodWithOriginalName("foo");
+    assertThat(fooMethodSubject, isPresent());
+
+    MethodSubject fooCloseResourceMethodSubject =
+        fooClassSubject.uniqueMethodWithOriginalName("$closeResource");
+    assertThat(fooCloseResourceMethodSubject, isPresent());
+
+    // Class Bar has two methods bar() and $closeResource().
+    ClassSubject barClassSubject = inspector.clazz(BAR.typeName());
+    assertThat(barClassSubject, isPresent());
+
+    MethodSubject barMethodSubject = barClassSubject.uniqueMethodWithOriginalName("bar");
+    assertThat(barMethodSubject, isPresent());
+
+    MethodSubject barCloseResourceMethodSubject =
+        barClassSubject.uniqueMethodWithOriginalName("$closeResource");
+    assertThat(barCloseResourceMethodSubject, isPresent());
+
+    // There is a synthetic API outline, a backport and two twr classes.
+    ClassSubject syntheticApiOutlineClassSubject =
+        inspector.clazz(
+            SyntheticItemsTestUtils.syntheticApiOutlineClass(BAR.getClassReference(), 0));
+    assertThat(syntheticApiOutlineClassSubject, notIf(isPresent(), hasTwrCloseResourceSupport));
+
+    ClassSubject syntheticBackportClassSubject =
+        inspector.clazz(SyntheticItemsTestUtils.syntheticBackportClass(BAR.getClassReference(), 1));
+    assertThat(syntheticBackportClassSubject, notIf(isPresent(), hasTwrCloseResourceSupport));
+
+    ClassSubject syntheticTwrCloseResourceClassSubject =
+        inspector.clazz(
+            SyntheticItemsTestUtils.syntheticTwrCloseResourceClass(BAR.getClassReference(), 2));
+    assertThat(
+        syntheticTwrCloseResourceClassSubject, notIf(isPresent(), hasTwrCloseResourceSupport));
+
+    ClassSubject otherSyntheticTwrCloseResourceClassSubject =
+        inspector.clazz(
+            SyntheticItemsTestUtils.syntheticTwrCloseResourceClass(BAR.getClassReference(), 3));
+    assertThat(
+        otherSyntheticTwrCloseResourceClassSubject, notIf(isPresent(), hasTwrCloseResourceSupport));
+
+    // Verify that the residual profile contains all of the above.
+    // TODO(b/265729283): Profile should include the twr syntehtic methods.
+    profileInspector
+        .assertContainsMethodRules(
+            fooMethodSubject,
+            fooCloseResourceMethodSubject,
+            barMethodSubject,
+            barCloseResourceMethodSubject)
+        .applyIf(
+            !hasTwrCloseResourceSupport,
+            i ->
+                i.assertContainsClassRules(
+                        syntheticApiOutlineClassSubject, syntheticBackportClassSubject)
+                    .assertContainsMethodRules(
+                        syntheticApiOutlineClassSubject.uniqueMethod(),
+                        syntheticBackportClassSubject.uniqueMethod()))
+        .assertContainsNoOtherRules();
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/profile/art/utils/ArtProfileInspector.java b/src/test/java/com/android/tools/r8/profile/art/utils/ArtProfileInspector.java
index d498e18..3b75886 100644
--- a/src/test/java/com/android/tools/r8/profile/art/utils/ArtProfileInspector.java
+++ b/src/test/java/com/android/tools/r8/profile/art/utils/ArtProfileInspector.java
@@ -53,13 +53,20 @@
     return this;
   }
 
+  public ArtProfileInspector assertContainsClassRules(ClassReference... classReferences) {
+    for (ClassReference classReference : classReferences) {
+      assertContainsClassRule(classReference);
+    }
+    return this;
+  }
+
   public ArtProfileInspector assertContainsClassRule(ClassSubject classSubject) {
     return assertContainsClassRule(classSubject.getFinalReference());
   }
 
-  public ArtProfileInspector assertContainsClassRules(ClassReference... classReferences) {
-    for (ClassReference classReference : classReferences) {
-      assertContainsClassRule(classReference);
+  public ArtProfileInspector assertContainsClassRules(ClassSubject... classSubjects) {
+    for (ClassSubject classSubject : classSubjects) {
+      assertContainsClassRule(classSubject);
     }
     return this;
   }