Update R8 on DEX compilation test.

Change-Id: I6e76efb1d0c8d4183a6c2e6f8045344f0b00df42
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/r8ondex/R8CompiledThroughDexTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/r8ondex/R8CompiledThroughDexTest.java
index b61e9d8..bb66f2e 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/r8ondex/R8CompiledThroughDexTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/r8ondex/R8CompiledThroughDexTest.java
@@ -7,7 +7,11 @@
 import static junit.framework.TestCase.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.OutputMode;
 import com.android.tools.r8.R8;
+import com.android.tools.r8.R8Command;
+import com.android.tools.r8.R8Command.Builder;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime;
@@ -16,10 +20,15 @@
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.cf.bootstrap.BootstrapCurrentEqualityTest;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
-import java.io.File;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.Pair;
+import com.google.common.collect.ImmutableList;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.ArrayList;
 import java.util.Collections;
+import java.util.List;
+import java.util.function.Consumer;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -29,18 +38,16 @@
 @RunWith(Parameterized.class)
 public class R8CompiledThroughDexTest extends DesugaredLibraryTestBase {
 
-  private static final boolean testExternal = true;
+  private static final boolean minify = false;
 
   private final TestParameters parameters;
 
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    // We do not use withDexRuntimesStartingAtIncluding to exclude dex-default and therefore
-    // avoid this 2 * 8 minutes test running on tools/test.py.
+    // We only run this test with ART 8 and with full desugaring to avoid the large runtime on ART.
     return getTestParameters()
         .withDexRuntime(Version.V8_1_0)
-        .withDexRuntime(Version.V9_0_0)
-        .withAllApiLevels()
+        .withApiLevel(AndroidApiLevel.B)
         .build();
   }
 
@@ -49,13 +56,61 @@
   }
 
   private static String commandLinePathFor(String string) {
+    return commandLinePathFor(Paths.get(string));
+  }
+
+  private static String commandLinePathFor(Path path) {
     // We switch to absolute path due to the art frameworks requiring to run the command in a
     // different folder.
-    return Paths.get(string).toAbsolutePath().toString();
+    return path.toAbsolutePath().toString();
   }
 
   private static final String R8_KEEP = Paths.get("src/main/keep.txt").toAbsolutePath().toString();
 
+  private Pair<List<String>, Consumer<Builder>> buildArguments() {
+    ImmutableList.Builder<String> arguments = ImmutableList.builder();
+    List<Consumer<Builder>> buildup = new ArrayList<>();
+
+    arguments.add(commandLinePathFor(ToolHelper.R8_WITH_RELOCATED_DEPS_JAR));
+    buildup.add(b -> b.addProgramFiles(ToolHelper.R8_WITH_RELOCATED_DEPS_JAR));
+
+    arguments.add("--release");
+    buildup.add(b -> b.setMode(CompilationMode.RELEASE));
+
+    arguments.add("--min-api").add(Integer.toString(parameters.getApiLevel().getLevel()));
+    buildup.add(b -> b.setMinApiLevel(parameters.getApiLevel().getLevel()));
+
+    arguments.add("--lib").add(commandLinePathFor(ToolHelper.JAVA_8_RUNTIME));
+    buildup.add(b -> b.addLibraryFiles(ToolHelper.getJava8RuntimeJar()));
+
+    arguments.add("--pg-conf").add(commandLinePathFor(R8_KEEP));
+    buildup.add(b -> b.addProguardConfigurationFiles(Paths.get(R8_KEEP)));
+
+    if (!minify) {
+      arguments.add("--no-minification");
+      buildup.add(b -> b.setDisableMinification(true));
+    }
+
+    Consumer<Builder> consumer = b -> {};
+    for (Consumer<Builder> step : buildup) {
+      consumer = consumer.andThen(step);
+    }
+
+    return new Pair<>(arguments.build(), consumer);
+  }
+
+  private List<String> getSharedArguments() {
+    return buildArguments().getFirst();
+  }
+
+  private Consumer<Builder> getSharedBuilder() {
+    return buildArguments().getSecond();
+  }
+
+  private void printTime(String title, long start) {
+    System.out.println(title + ": " + ((System.nanoTime() - start) / 1000000000) + "s");
+  }
+
   @Test
   public void testR8CompiledWithR8Dex() throws Exception {
     // Compile once R8_WITH_RELOCATED_DEPS_JAR using normal R8_WITH_RELOCATED_DEPS_JAR to dex,
@@ -66,67 +121,80 @@
     // We use extra VM parameters for memory. The command parameters should look like:
     // -Xmx512m com...R8 --release --min-api 1 --output path/to/folder --lib rt.jar
     // --pg-conf R8KeepRules r8.jar
-    // The 512m memory is required to make it work on ART since default is lower.
+    // The 512m memory is required to run on ART but any higher and the runtime will fail too.
 
-    File ouputFolder = temp.newFolder("output");
+    Path outputFolder = temp.newFolder("output").toPath();
+    Path outputThroughCf = outputFolder.resolve("outThroughCf.zip");
 
-    // Compile R8 to dex on the JVM.
-    Path outputThroughCf = ouputFolder.toPath().resolve("outThroughCf.zip").toAbsolutePath();
-    if (testExternal) {
+    // First run compiles with R8 in process and thus with assertions.
+    {
+      long start = System.nanoTime();
+      // Manually construct the R8 command as the test builder will change defaults compared
+      // to the CLI invocation (eg, compressed and pg-map output).
+      Builder builder = R8Command.builder().setOutput(outputThroughCf, OutputMode.DexIndexed);
+      getSharedBuilder().accept(builder);
+      R8.run(builder.build());
+      printTime("R8/JVM in-process", start);
+    }
+
+    // Second run compiles with R8 externally checking it to be equal with the first compilation.
+    // If this fails, likely due to non-determinism, then that is much faster than waiting for the
+    // Art run compilation to finish if the same error can be found directly.
+    {
+      long start = System.nanoTime();
+      Path outputThroughCfExternal = outputFolder.resolve("outThroughCf_external.zip");
+      Path r8jar = ToolHelper.R8_WITH_RELOCATED_DEPS_JAR;
       ProcessResult javaProcessResult =
           ToolHelper.runJava(
               TestRuntime.getCheckedInJdk9(),
-              Collections.singletonList(ToolHelper.R8_WITH_RELOCATED_DEPS_JAR),
-              "-Xmx512m",
-              R8.class.getTypeName(),
-              "--release",
-              "--min-api",
-              Integer.toString(parameters.getApiLevel().getLevel()),
-              "--output",
-              outputThroughCf.toString(),
-              "--lib",
-              ToolHelper.JAVA_8_RUNTIME,
-              "--pg-conf",
-              R8_KEEP,
-              ToolHelper.R8_WITH_RELOCATED_DEPS_JAR.toAbsolutePath().toString());
+              Collections.singletonList(r8jar),
+              ImmutableList.builder()
+                  .add("-Xmx1g")
+                  .add(R8.class.getTypeName())
+                  .add("--output")
+                  .add(commandLinePathFor(outputThroughCfExternal))
+                  .addAll(getSharedArguments())
+                  .build()
+                  .toArray(new String[0]));
+      printTime("R8/JVM external", start);
       assertEquals(javaProcessResult.toString(), 0, javaProcessResult.exitCode);
-    } else {
-      testForR8(parameters.getBackend())
-          .addProgramFiles(ToolHelper.R8_WITH_RELOCATED_DEPS_JAR)
-          .addLibraryFiles(ToolHelper.getJava8RuntimeJar())
-          .addKeepRuleFiles(Paths.get(R8_KEEP))
-          .setMinApi(parameters.getApiLevel())
-          .compile()
-          .writeToZip(outputThroughCf);
+      assertTrue(
+          "The output of R8/JVM in-process and R8/JVM external differ."
+              + " Make sure you have an up-to-date compilation of "
+              + r8jar
+              + ". If not, that could very likely cause the in-process run (eg, via intellij) to"
+              + " differ from the external run which uses "
+              + r8jar
+              + ". If up-to-date, the likely cause of this error is that R8 is non-deterministic.",
+          BootstrapCurrentEqualityTest.filesAreEqual(outputThroughCf, outputThroughCfExternal));
     }
 
-    // Compile R8 to Dex on Dex, using the previous dex artifact.
+    // Finally compile R8 on the ART runtime using the already compiled DEX version of R8.
     // We need the extra parameter --64 to use 64 bits frameworks.
-    Path ouputThroughDex = ouputFolder.toPath().resolve("outThroughDex.zip").toAbsolutePath();
-    ProcessResult artProcessResult =
-        ToolHelper.runArtRaw(
-            Collections.singletonList(outputThroughCf.toAbsolutePath().toString()),
-            R8.class.getTypeName(),
-            (ToolHelper.ArtCommandBuilder builder) ->
-                builder.appendArtOption("--64").appendArtOption("-Xmx512m"),
-            parameters.getRuntime().asDex().getVm(),
-            true,
-            "--release",
-            "--min-api",
-            Integer.toString(parameters.getApiLevel().getLevel()),
-            "--output",
-            ouputThroughDex.toString(),
-            "--lib",
-            commandLinePathFor(ToolHelper.JAVA_8_RUNTIME),
-            "--pg-conf",
-            commandLinePathFor(R8_KEEP),
-            ToolHelper.R8_WITH_RELOCATED_DEPS_JAR.toAbsolutePath().toString());
-    if (artProcessResult.exitCode != 0) {
-      System.out.println(artProcessResult);
+    {
+      long start = System.nanoTime();
+      Path outputThroughDex = outputFolder.resolve("outThroughDex.zip");
+      ProcessResult artProcessResult =
+          ToolHelper.runArtRaw(
+              Collections.singletonList(commandLinePathFor(outputThroughCf)),
+              R8.class.getTypeName(),
+              builder -> builder.appendArtOption("--64").appendArtOption("-Xmx512m"),
+              parameters.getRuntime().asDex().getVm(),
+              true,
+              ImmutableList.builder()
+                  .add("--output")
+                  .add(commandLinePathFor(outputThroughDex))
+                  .addAll(getSharedArguments())
+                  .build()
+                  .toArray(new String[0]));
+      printTime("R8/ART", start);
+      if (artProcessResult.exitCode != 0) {
+        System.out.println(artProcessResult);
+      }
+      assertEquals(0, artProcessResult.exitCode);
+      assertTrue(
+          "The output of R8/JVM in-process and R8/ART external differ.",
+          BootstrapCurrentEqualityTest.filesAreEqual(outputThroughCf, outputThroughDex));
     }
-    assertEquals(0, artProcessResult.exitCode);
-
-    // Ensure both generated artifacts are equal.
-    assertTrue(BootstrapCurrentEqualityTest.filesAreEqual(outputThroughCf, ouputThroughDex));
   }
 }