Nest Access Control application tests

- Add flag to force nest desugaring
- Compile Hello/R8 with production R8,
  with R8 compiled with Java 11 (R811),
  with R8 11 shrunk without desugaring,
  with R8 11 shrunk with desugaring
  and ensure all the outputs are identical.

Bug:133608609
Change-Id: I67d101a7c23f6504cb54b0509027db5d5998eaf1
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 5bd0cc2..af1d2e9 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -441,7 +441,8 @@
 
       AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
       appView.setGraphLense(new MemberRebindingAnalysis(appViewWithLiveness).run());
-      if (options.enableNestBasedAccessDesugaring && !options.canUseNestBasedAccess()) {
+      if (options.testing.enableForceNestBasedAccessDesugaringForTest
+          || (options.enableNestBasedAccessDesugaring && !options.canUseNestBasedAccess())) {
         timing.begin("NestBasedAccessDesugaring");
         R8NestBasedAccessDesugaring analyzer = new R8NestBasedAccessDesugaring(appViewWithLiveness);
         boolean changed =
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index cc92f99..e32efa4 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -818,6 +818,9 @@
     // TODO(b/129458850) When fixed, remove this and change all usages to "true".
     public boolean enableStatefulLambdaCreateInstanceMethod = false;
 
+    // Flag to turn on/off JDK11+ nest-access control even when not required (Cf backend)
+    public boolean enableForceNestBasedAccessDesugaringForTest = false;
+
     public boolean desugarLambdasThroughLensCodeRewriter() {
       return enableStatefulLambdaCreateInstanceMethod;
     }
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 9fef6f1..448d698 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -128,6 +128,8 @@
   public static final Path R8_JAR = Paths.get(LIBS_DIR, "r8.jar");
   public static final Path R8_WITH_RELOCATED_DEPS_JAR =
       Paths.get(LIBS_DIR, "r8_with_relocated_deps.jar");
+  public static final Path R8_WITH_RELOCATED_DEPS_JAR_11 =
+      Paths.get(LIBS_DIR, "r8_with_relocated_deps_11.jar");
   public static final Path R8LIB_JAR = Paths.get(LIBS_DIR, "r8lib.jar");
   public static final Path R8LIB_EXCLUDE_DEPS_JAR = Paths.get(LIBS_DIR, "r8lib-exclude-deps.jar");
   public static final Path DEPS_NOT_RELOCATED = Paths.get(LIBS_DIR, "deps-not-relocated.jar");
diff --git a/src/test/java/com/android/tools/r8/cf/BootstrapCurrentEqualityTest.java b/src/test/java/com/android/tools/r8/cf/BootstrapCurrentEqualityTest.java
index 7503774..a30d0bd 100644
--- a/src/test/java/com/android/tools/r8/cf/BootstrapCurrentEqualityTest.java
+++ b/src/test/java/com/android/tools/r8/cf/BootstrapCurrentEqualityTest.java
@@ -27,7 +27,6 @@
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import org.junit.BeforeClass;
@@ -195,7 +194,7 @@
     assertProgramsEqual(result.outputJar(), runR8R8.outputJar());
   }
 
-  private static void assertProgramsEqual(Path expectedJar, Path actualJar) throws Exception {
+  public static void assertProgramsEqual(Path expectedJar, Path actualJar) throws Exception {
     if (filesAreEqual(expectedJar, actualJar)) {
       return;
     }
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11BootstrapTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11BootstrapTest.java
new file mode 100644
index 0000000..8af6abf
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11BootstrapTest.java
@@ -0,0 +1,138 @@
+// 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.nestaccesscontrol;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertTrue;
+
+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.ToolHelper;
+import com.android.tools.r8.cf.BootstrapCurrentEqualityTest;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * This test relies on a freshly built build/libs/r8_with_relocated_deps_11.jar.
+ *
+ * <p>The test compiles Hello/R8 with the same settings using R8 compiled with Java 11 (non shrunk),
+ * and the same but shrunk with/without nest desugaring. All generated jars should be run correctly
+ * and identical.
+ */
+@RunWith(Parameterized.class)
+public class Java11BootstrapTest extends TestBase {
+
+  private static final Path MAIN_KEEP = Paths.get("src/main/keep.txt");
+  private static final String[] HELLO_KEEP = {
+    "-keep class hello.Hello {  public static void main(...);}"
+  };
+
+  private static Path r8Lib11NoDesugar;
+  private static Path r8Lib11Desugar;
+
+  public Java11BootstrapTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withCfRuntime(CfVm.JDK11).build();
+  }
+
+  @BeforeClass
+  public static void beforeAll() throws Exception {
+    r8Lib11NoDesugar = compileR8(false);
+    r8Lib11Desugar = compileR8(true);
+  }
+
+  private static Path compileR8(boolean desugar) throws Exception {
+    // Shrink R8 11 with R8 11
+    return testForExternalR8(TestBase.getStaticTemp(), Backend.CF)
+        .useProvidedR8(ToolHelper.R8_WITH_RELOCATED_DEPS_JAR_11)
+        .addProgramFiles(ToolHelper.R8_WITH_RELOCATED_DEPS_JAR_11)
+        .addKeepRuleFiles(MAIN_KEEP)
+        .addOptionsModification(
+            options -> options.testing.enableForceNestBasedAccessDesugaringForTest = desugar)
+        .compile()
+        .inspect(inspector -> assertNests(inspector, desugar))
+        .outputJar();
+  }
+
+  private static void assertNests(CodeInspector inspector, boolean desugar) {
+    if (desugar) {
+      assertTrue(inspector.allClasses().stream().noneMatch(subj -> subj.getDexClass().isInANest()));
+    } else {
+      assertTrue(inspector.allClasses().stream().anyMatch(subj -> subj.getDexClass().isInANest()));
+    }
+  }
+
+  private Path[] jarsToCompare() {
+    return new Path[] {
+      ToolHelper.R8_WITH_RELOCATED_DEPS_JAR,
+      ToolHelper.R8_WITH_RELOCATED_DEPS_JAR_11,
+      r8Lib11NoDesugar,
+      r8Lib11Desugar
+    };
+  }
+
+  @Test
+  public void testHello() throws Exception {
+    Path prevGeneratedJar = null;
+    String prevRunResult = null;
+    for (Path jar : jarsToCompare()) {
+      Path generatedJar =
+          testForExternalR8(Backend.CF)
+              .useProvidedR8(jar)
+              .addProgramFiles(Paths.get(ToolHelper.EXAMPLES_BUILD_DIR, "hello" + JAR_EXTENSION))
+              .addKeepRules(HELLO_KEEP)
+              .compile()
+              .outputJar();
+      String runResult =
+          ToolHelper.runJava(
+                  parameters.getRuntime().asCf().getVm(),
+                  ImmutableList.of(generatedJar),
+                  "hello.Hello")
+              .toString();
+      if (prevRunResult != null) {
+        assertEquals(prevRunResult, runResult);
+      }
+      prevRunResult = runResult;
+      if (prevGeneratedJar != null) {
+        BootstrapCurrentEqualityTest.assertProgramsEqual(prevGeneratedJar, generatedJar);
+      }
+      prevGeneratedJar = generatedJar;
+    }
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    Path prevGeneratedJar = null;
+    for (Path jar : jarsToCompare()) {
+      Path generatedJar =
+          testForExternalR8(Backend.CF)
+              .useProvidedR8(jar)
+              .addProgramFiles(Paths.get(ToolHelper.EXAMPLES_BUILD_DIR, "hello" + JAR_EXTENSION))
+              .addKeepRules(HELLO_KEEP)
+              .compile()
+              .outputJar();
+      if (prevGeneratedJar != null) {
+        BootstrapCurrentEqualityTest.assertProgramsEqual(prevGeneratedJar, generatedJar);
+      }
+      prevGeneratedJar = generatedJar;
+    }
+  }
+}
diff --git a/tools/test.py b/tools/test.py
index 015e53e..be271f2 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -212,6 +212,7 @@
 
   # Build an R8 with dependencies for bootstrapping tests before adding test sources.
   gradle_args.append('r8WithRelocatedDeps')
+  gradle_args.append('r8WithRelocatedDeps11')
 
   # Add Gradle tasks
   gradle_args.append('cleanTest')