Desugared library tests for all API levels

- So far desugared library tests were run
on pre-N devices only, this CL introduce
the ability to run them on all API levels
with different levels of desugaring based
on the API levels.
- A few tests updated to use new
test APIs (Other tests will be updated in
subsequent CLs).
- Introduced 2 desugared library
configuration, pre-N and N-O, so
that Interface emulation is optional

Bug: 134732760
Change-Id: I8bd94fe80f8eafd4d2a210faaac8748c8b5bacfd
diff --git a/src/main/java/com/android/tools/r8/SpecialLibraryConfiguration.java b/src/main/java/com/android/tools/r8/SpecialLibraryConfiguration.java
index 6468d16..9ec6cde 100644
--- a/src/main/java/com/android/tools/r8/SpecialLibraryConfiguration.java
+++ b/src/main/java/com/android/tools/r8/SpecialLibraryConfiguration.java
@@ -4,7 +4,9 @@
 
 package com.android.tools.r8;
 
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.StringDiagnostic;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import java.util.List;
@@ -42,6 +44,16 @@
         .build();
   }
 
+  private static Map<String, String> buildPrefixRewritingForProgramCompilationAndroidNPlus() {
+    // From Android O, emulated interfaces are not supported and are not required.
+    // Prefix rewriting is different to avoid rewriting classes to j$ while they should not,
+    // else Android cannot find the library methods because they use the incorrect types.
+    return ImmutableMap.<String, String>builder()
+        .put("java.time.", "j$.time.")
+        .put("java.util.Desugar", "j$.util.Desugar")
+        .build();
+  }
+
   private static Map<String, String> buildPrefixRewritingForCoreLibCompilation() {
     return ImmutableMap.<String, String>builder()
         // --rewrite_core_library_prefix.
@@ -75,6 +87,18 @@
         .build();
   }
 
+  private static Map<String, String>
+      buildRetargetCoreLibraryMemberForProgramCompilationAndroidNPlus() {
+    // --retarget_core_library_member.
+    return ImmutableMap.<String, String>builder()
+        .put("java.util.Calendar#toInstant", "java.util.DesugarCalendar")
+        .put("java.util.Date#from", "java.util.DesugarDate")
+        .put("java.util.Date#toInstant", "java.util.DesugarDate")
+        .put("java.util.GregorianCalendar#from", "java.util.DesugarGregorianCalendar")
+        .put("java.util.GregorianCalendar#toZonedDateTime", "java.util.DesugarGregorianCalendar")
+        .build();
+  }
+
   private static Map<String, String> buildRetargetCoreLibraryMemberForProgramCompilation() {
     // --retarget_core_library_member.
     return ImmutableMap.<String, String>builder()
@@ -246,19 +270,38 @@
   }
 
   public static void configureLibraryDesugaringForProgramCompilation(InternalOptions options) {
+    // TODO(b/134732760): Make assertions in D8/R8 commands.
+    if (options.minApiLevel >= AndroidApiLevel.P.getLevel()) {
+      options.reporter.warning(
+          new StringDiagnostic(
+              "Desugaring core libraries for Android P and over is possible but not required."));
+    }
     options.coreLibraryCompilation = false;
-    options.retargetCoreLibMember = buildRetargetCoreLibraryMemberForProgramCompilation();
-    options.dontRewriteInvocations = buildDontRewriteInvocations();
-    options.rewritePrefix = buildPrefixRewritingForProgramCompilation();
-    options.emulateLibraryInterface = buildEmulateLibraryInterface();
+    if (options.minApiLevel < AndroidApiLevel.N.getLevel()) {
+      options.rewritePrefix = buildPrefixRewritingForProgramCompilation();
+      options.retargetCoreLibMember = buildRetargetCoreLibraryMemberForProgramCompilation();
+      options.emulateLibraryInterface = buildEmulateLibraryInterface();
+      options.dontRewriteInvocations = buildDontRewriteInvocations();
+    } else {
+      options.rewritePrefix = buildPrefixRewritingForProgramCompilationAndroidNPlus();
+      options.retargetCoreLibMember =
+          buildRetargetCoreLibraryMemberForProgramCompilationAndroidNPlus();
+    }
   }
 
   public static void configureLibraryDesugaringForLibraryCompilation(InternalOptions options) {
+    // TODO(b/134732760): Make assertions in L8 commands.
+    if (options.minApiLevel >= AndroidApiLevel.P.getLevel()) {
+      options.reporter.warning(
+          new StringDiagnostic(
+              "Desugaring core libraries for Android P and over is possible but not required."));
+    }
     options.coreLibraryCompilation = true;
     options.backportCoreLibraryMembers = buildBackportCoreLibraryMembers();
     options.retargetCoreLibMember = buildRetargetCoreLibraryMemberForCoreLibCompilation();
-    options.dontRewriteInvocations = buildDontRewriteInvocations();
     options.rewritePrefix = buildPrefixRewritingForCoreLibCompilation();
+    // The following is ignored starting from Android O.
+    options.dontRewriteInvocations = buildDontRewriteInvocations();
     options.emulateLibraryInterface = buildEmulateLibraryInterface();
   }
 }
diff --git a/src/test/java/com/android/tools/r8/TestCompileResult.java b/src/test/java/com/android/tools/r8/TestCompileResult.java
index dfde83b..8b303ad 100644
--- a/src/test/java/com/android/tools/r8/TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/TestCompileResult.java
@@ -16,6 +16,7 @@
 import com.android.tools.r8.debug.DebugTestConfig;
 import com.android.tools.r8.debug.DexDebugTestConfig;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -31,6 +32,7 @@
 import java.util.List;
 import java.util.concurrent.ExecutionException;
 import java.util.function.Consumer;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 import org.hamcrest.Matcher;
 
@@ -162,6 +164,14 @@
     }
   }
 
+  public CR addDesugaredCoreLibraryRunClassPath(
+      Function<AndroidApiLevel, Path> classPathSupplier, AndroidApiLevel minAPILevel) {
+    if (minAPILevel.getLevel() < AndroidApiLevel.P.getLevel()) {
+      addRunClasspathFiles(classPathSupplier.apply(minAPILevel));
+    }
+    return self();
+  }
+
   public CR enableRuntimeAssertions() {
     assert getBackend() == Backend.CF;
     if (!this.vmArguments.contains("-ea")) {
diff --git a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
index 7b6c7d2..c418f28 100644
--- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -266,8 +266,17 @@
     return self();
   }
 
+  @Deprecated
   public T enableCoreLibraryDesugaring() {
-    builder.addSpecialLibraryConfiguration("default");
+    // TODO(b/134732760): Use the other API instead.
+    return enableCoreLibraryDesugaring(AndroidApiLevel.B);
+  }
+
+  public T enableCoreLibraryDesugaring(AndroidApiLevel minAPILevel) {
+    if (minAPILevel.getLevel() < AndroidApiLevel.P.getLevel()) {
+      builder.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P));
+      builder.addSpecialLibraryConfiguration("default");
+    }
     return self();
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java b/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java
index 4375976..fc2e5df 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java
@@ -20,25 +20,39 @@
 public class CoreLibDesugarTestBase extends TestBase {
 
   protected boolean requiresCoreLibDesugaring(TestParameters parameters) {
+    // TODO(b/134732760): Use the two other APIS instead.
+    return requiresEmulatedInterfaceCoreLibDesugaring(parameters)
+        && requiresRetargetCoreLibMemberDesugaring(parameters);
+  }
+
+  protected boolean requiresEmulatedInterfaceCoreLibDesugaring(TestParameters parameters) {
     return parameters.getApiLevel().getLevel() < AndroidApiLevel.N.getLevel();
   }
 
-  protected Path buildDesugaredLibrary(AndroidApiLevel apiLevel, List<Path> additionalProgramFiles)
-      throws Exception {
-    Path output = temp.newFolder().toPath().resolve("desugar_jdk_libs.zip");
-    L8.run(
-        L8Command.builder()
-            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
-            .addProgramFiles(ToolHelper.getDesugarJDKLibs())
-            .addProgramFiles(additionalProgramFiles)
-            .addSpecialLibraryConfiguration("default")
-            .setMinApiLevel(apiLevel.getLevel())
-            .setOutput(output, OutputMode.DexIndexed)
-            .build());
-    return output;
+  protected boolean requiresRetargetCoreLibMemberDesugaring(TestParameters parameters) {
+    return parameters.getApiLevel().getLevel() < AndroidApiLevel.P.getLevel();
   }
 
-  protected Path buildDesugaredLibrary(AndroidApiLevel apiLevel) throws Exception {
+  protected Path buildDesugaredLibrary(
+      AndroidApiLevel apiLevel, List<Path> additionalProgramFiles) {
+    try {
+      Path output = temp.newFolder().toPath().resolve("desugar_jdk_libs.zip");
+      L8.run(
+          L8Command.builder()
+              .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+              .addProgramFiles(ToolHelper.getDesugarJDKLibs())
+              .addProgramFiles(additionalProgramFiles)
+              .addSpecialLibraryConfiguration("default")
+              .setMinApiLevel(apiLevel.getLevel())
+              .setOutput(output, OutputMode.DexIndexed)
+              .build());
+      return output;
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  protected Path buildDesugaredLibrary(AndroidApiLevel apiLevel) {
     return buildDesugaredLibrary(apiLevel, ImmutableList.of());
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/CustomCollectionTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/CustomCollectionTest.java
index ff96100..445b1dd 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/CustomCollectionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/CustomCollectionTest.java
@@ -10,8 +10,6 @@
 import com.android.tools.r8.D8TestRunResult;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject.JumboStringMode;
@@ -21,7 +19,6 @@
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.junit.Assert;
-import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -45,19 +42,21 @@
 
   @Test
   public void testCustomCollection() throws Exception {
-    Assume.assumeTrue("No desugaring for high API levels", requiresCoreLibDesugaring(parameters));
     D8TestRunResult d8TestRunResult =
         testForD8()
             .addInnerClasses(CustomCollectionTest.class)
-            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring()
+            .enableCoreLibraryDesugaring(parameters.getApiLevel())
             .compile()
             .inspect(this::assertCustomCollectionCallsCorrect)
-            .addRunClasspathFiles(buildDesugaredLibrary(parameters.getApiLevel()))
+            .addDesugaredCoreLibraryRunClassPath(
+                this::buildDesugaredLibrary, parameters.getApiLevel())
             .run(parameters.getRuntime(), EXECUTOR)
             .assertSuccess();
-    assertLines2By2Correct(d8TestRunResult.getStdOut());
+    if (requiresEmulatedInterfaceCoreLibDesugaring(parameters)) {
+      // Expected output is emulated interfaces expected output.
+      assertLines2By2Correct(d8TestRunResult.getStdOut());
+    }
     String[] split = d8TestRunResult.getStdErr().split("Could not find method");
     if (split.length > 2) {
       fail("Could not find multiple methods");
@@ -72,6 +71,11 @@
     Assert.assertFalse(
         direct.streamInstructions().anyMatch(instr -> instr.toString().contains("$-EL")));
     MethodSubject inherited = inspector.clazz(EXECUTOR).uniqueMethodWithName("inheritedTypes");
+    if (!requiresEmulatedInterfaceCoreLibDesugaring(parameters)) {
+      assertTrue(
+          inherited.streamInstructions().noneMatch(instr -> instr.toString().contains("$-EL")));
+      return;
+    }
     assertTrue(
         inherited
             .streamInstructions()
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/JavaUtilFunctionTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/JavaUtilFunctionTest.java
index cb2659e..74a4efa 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/JavaUtilFunctionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/JavaUtilFunctionTest.java
@@ -35,6 +35,9 @@
   }
 
   private void checkRewrittenArguments(CodeInspector inspector) {
+    if (!requiresEmulatedInterfaceCoreLibDesugaring(parameters)) {
+      return;
+    }
     ClassSubject classSubject = inspector.clazz(TestClass.class);
     assertThat(classSubject, isPresent());
     assertEquals(
@@ -50,12 +53,12 @@
   }
 
   @Test
-  public void testJavaUtilOptional() throws Exception {
+  public void testJavaUtilFunction() throws Exception {
     String expectedOutput = StringUtils.lines("Hello, world", "Hello, world");
     testForD8()
         .addInnerClasses(JavaUtilFunctionTest.class)
         .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
-        .setMinApi(parameters.getRuntime())
+        .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring()
         .compile()
         .inspect(this::checkRewrittenArguments)
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/JavaUtilOptionalTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/JavaUtilOptionalTest.java
index 0d838b3..9465aee 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/JavaUtilOptionalTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/JavaUtilOptionalTest.java
@@ -41,6 +41,9 @@
   }
 
   private void checkRewrittenInvokes(CodeInspector inspector) {
+    if (!requiresEmulatedInterfaceCoreLibDesugaring(parameters)) {
+      return;
+    }
     ClassSubject classSubject = inspector.clazz(TestClass.class);
     assertThat(classSubject, isPresent());
     Iterator<InvokeInstructionSubject> iterator =
@@ -76,7 +79,7 @@
     testForD8()
         .addInnerClasses(JavaUtilOptionalTest.class)
         .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
-        .setMinApi(parameters.getRuntime())
+        .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring()
         .compile()
         .inspect(this::checkRewrittenInvokes)
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/corelibjdktests/Jdk11TimeTests.java b/src/test/java/com/android/tools/r8/desugar/corelib/corelibjdktests/Jdk11TimeTests.java
index 1d37013..3aefe01 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/corelibjdktests/Jdk11TimeTests.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/corelibjdktests/Jdk11TimeTests.java
@@ -140,10 +140,11 @@
             .addProgramFiles(Paths.get(JDK_TESTS_BUILD_DIR + "jcommander-1.48.jar"))
             .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring()
+            .enableCoreLibraryDesugaring(parameters.getApiLevel())
             .compile()
             .withArt6Plus64BitsLib()
-            .addRunClasspathFiles(buildDesugaredLibrary(parameters.getApiLevel()));
+            .addDesugaredCoreLibraryRunClassPath(
+                this::buildDesugaredLibrary, parameters.getApiLevel());
     for (String success : successes) {
       D8TestRunResult result =
           compileResult.run(parameters.getRuntime(), "TestNGMainRunner", verbosity, success);