Extend callback test to run desugaring twice

Bug: 171867367
Bug: 172433489
Change-Id: I4ea79d9c1a3dfda1f9a603693289288791efdfb2
diff --git a/src/main/java/com/android/tools/r8/utils/ZipUtils.java b/src/main/java/com/android/tools/r8/utils/ZipUtils.java
index f33ed6f..400ef0c 100644
--- a/src/main/java/com/android/tools/r8/utils/ZipUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ZipUtils.java
@@ -23,6 +23,7 @@
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -68,7 +69,11 @@
   }
 
   public static void iter(String zipFileStr, OnEntryHandler handler) throws IOException {
-    try (ZipFile zipFile = new ZipFile(zipFileStr, StandardCharsets.UTF_8)) {
+    iter(Paths.get(zipFileStr), handler);
+  }
+
+  public static void iter(Path zipFilePath, OnEntryHandler handler) throws IOException {
+    try (ZipFile zipFile = new ZipFile(zipFilePath.toFile(), StandardCharsets.UTF_8)) {
       final Enumeration<? extends ZipEntry> entries = zipFile.entries();
       while (entries.hasMoreElements()) {
         ZipEntry entry = entries.nextElement();
@@ -79,6 +84,12 @@
     }
   }
 
+  public static byte[] readSingleEntry(Path zipFilePath, String name) throws IOException {
+    try (ZipFile zipFile = new ZipFile(zipFilePath.toFile(), StandardCharsets.UTF_8)) {
+      return ByteStreams.toByteArray(zipFile.getInputStream(zipFile.getEntry(name)));
+    }
+  }
+
   public static void zip(Path zipFile, Path inputDirectory) throws IOException {
     List<Path> files =
         Files.walk(inputDirectory)
@@ -226,4 +237,8 @@
       return zipFile;
     }
   }
+
+  public static String zipEntryNameForClass(Class<?> clazz) {
+    return DescriptorUtils.getClassBinaryName(clazz) + CLASS_EXTENSION;
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/CallBackConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/CallBackConversionTest.java
index 92d2394..241f4a0 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/CallBackConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/CallBackConversionTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary.conversiontests;
 
+import static com.android.tools.r8.utils.InternalOptions.ASM_VERSION;
 import static junit.framework.TestCase.assertEquals;
 import static junit.framework.TestCase.assertTrue;
 
@@ -11,10 +12,13 @@
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.ZipUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
 import java.nio.file.Path;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.function.Consumer;
 import org.junit.BeforeClass;
@@ -22,6 +26,9 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 import org.junit.runners.Parameterized.Parameters;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
 
 @RunWith(Parameterized.class)
 public class CallBackConversionTest extends DesugaredLibraryTestBase {
@@ -101,10 +108,68 @@
         .assertSuccessWithOutput(EXPECTED_RESULT);
   }
 
+  private static class ClassInfo {
+    private final String classBinaryName;
+    private final List<String> methodNames;
+
+    ClassInfo(String classBinaryNamename, List<String> methodNames) {
+      this.classBinaryName = classBinaryNamename;
+      this.methodNames = methodNames;
+    }
+
+    public String getClassBinaryName() {
+      return classBinaryName;
+    }
+
+    public List<String> getMethodNames() {
+      return methodNames;
+    }
+  }
+
+  private static ClassInfo extractClassInfo(byte[] ccc) {
+    class ClassNameExtractor extends ClassVisitor {
+      private String classBinaryName;
+      private final List<String> methodNames = new ArrayList<>();
+
+      private ClassNameExtractor() {
+        super(ASM_VERSION);
+      }
+
+      @Override
+      public void visit(
+          int version,
+          int access,
+          String name,
+          String signature,
+          String superName,
+          String[] interfaces) {
+        classBinaryName = name;
+        super.visit(version, access, name, signature, superName, interfaces);
+      }
+
+      @Override
+      public MethodVisitor visitMethod(
+          int access, String name, String desc, String signature, String[] exceptions) {
+        methodNames.add(name);
+        return null;
+      }
+
+      ClassInfo getClassInfo() {
+        return new ClassInfo(classBinaryName, methodNames);
+      }
+    }
+
+    ClassReader reader = new ClassReader(ccc);
+    ClassNameExtractor extractor = new ClassNameExtractor();
+    reader.accept(
+        extractor, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
+    return extractor.getClassInfo();
+  }
+
   @Test
   public void testCallBackD8Cf() throws Exception {
     // Use D8 to desugar with Java classfile output.
-    Path jar =
+    Path firstJar =
         testForD8(Backend.CF)
             .setMinApi(parameters.getApiLevel())
             .addProgramClasses(Impl.class)
@@ -114,9 +179,37 @@
             .inspect(CallBackConversionTest::assertDuplicatedAPI)
             .writeToZip();
 
+    ClassInfo info =
+        extractClassInfo(
+            ZipUtils.readSingleEntry(firstJar, ZipUtils.zipEntryNameForClass(Impl.class)));
+    assertEquals(
+        Impl.class.getTypeName(),
+        DescriptorUtils.getJavaTypeFromBinaryName(info.getClassBinaryName()));
+    assertEquals(2, info.methodNames.stream().filter(name -> name.equals("foo")).count());
+
+    // Use D8 to desugar with Java classfile output.
+    Path secondJar =
+        testForD8(Backend.CF)
+            .setMinApi(parameters.getApiLevel())
+            .addProgramFiles(firstJar)
+            .addLibraryClasses(CustomLibClass.class)
+            .enableCoreLibraryDesugaring(parameters.getApiLevel(), new AbsentKeepRuleConsumer())
+            .compile()
+            .inspect(CallBackConversionTest::assertDuplicatedAPI)
+            .writeToZip();
+
+    info =
+        extractClassInfo(
+            ZipUtils.readSingleEntry(secondJar, ZipUtils.zipEntryNameForClass(Impl.class)));
+    assertEquals(
+        Impl.class.getTypeName(),
+        DescriptorUtils.getJavaTypeFromBinaryName(info.getClassBinaryName()));
+    // TODO(b/171867367): This should only be 2.
+    assertEquals(3, info.getMethodNames().stream().filter(name -> name.equals("foo")).count());
+
     // Convert to DEX without desugaring and run.
     testForD8()
-        .addProgramFiles(jar)
+        .addProgramFiles(firstJar)
         .setMinApi(parameters.getApiLevel())
         .disableDesugaring()
         .compile()
@@ -125,7 +218,7 @@
             this::buildDesugaredLibrary,
             parameters.getApiLevel(),
             collectKeepRulesWithTraceReferences(
-                jar, buildDesugaredLibraryClassFile(parameters.getApiLevel())),
+                firstJar, buildDesugaredLibraryClassFile(parameters.getApiLevel())),
             shrinkDesugaredLibrary)
         .addRunClasspathFiles(CUSTOM_LIB)
         .run(parameters.getRuntime(), Impl.class)