Add test for allow access modification with kotlin metadata

Bug: 154348683
Change-Id: I93b945e6a8c0c41cf6066018c5b3c2dca0405c85
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java
new file mode 100644
index 0000000..549f834
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java
@@ -0,0 +1,156 @@
+// Copyright (c) 2020, 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.kotlin.metadata;
+
+import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static junit.framework.TestCase.assertEquals;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.StringContains.containsString;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.StringUtils;
+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 java.nio.file.Path;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MetadataRewriteAllowAccessModificationTest extends KotlinMetadataTestBase {
+
+  private static final String PKG_LIB = PKG + ".allow_access_modification_lib";
+  private static final String PKG_APP = PKG + ".allow_access_modification_app";
+  private final String EXPECTED =
+      StringUtils.lines(
+          "4",
+          "2",
+          "42",
+          "3",
+          "1",
+          "42",
+          "5",
+          "6",
+          "7",
+          "funPrivate",
+          "funInternal",
+          "funProtected",
+          "extensionPrivate",
+          "extensionInternal",
+          "companionPrivate",
+          "companionInternal",
+          "staticPrivate",
+          "staticInternal");
+
+  @Parameterized.Parameters(name = "{0} target: {1}")
+  public static Collection<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+  }
+
+  public MetadataRewriteAllowAccessModificationTest(
+      TestParameters parameters, KotlinTargetVersion targetVersion) {
+    super(targetVersion);
+    this.parameters = parameters;
+  }
+
+  private static Map<KotlinTargetVersion, Path> libJars = new HashMap<>();
+  private static Map<KotlinTargetVersion, Path> libReferenceJars = new HashMap<>();
+  private final TestParameters parameters;
+
+  @BeforeClass
+  public static void createLibJar() throws Exception {
+    for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
+      libJars.put(
+          targetVersion,
+          kotlinc(KOTLINC, targetVersion)
+              .addSourceFiles(
+                  getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"))
+              .compile());
+      libReferenceJars.put(
+          targetVersion,
+          kotlinc(KOTLINC, targetVersion)
+              .addSourceFiles(
+                  getKotlinFileInTest(
+                      DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib_reference"))
+              .compile());
+    }
+  }
+
+  @Test
+  public void smokeTest() throws Exception {
+    Path libJar = libReferenceJars.get(targetVersion);
+    Path output =
+        kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+            .addClasspathFiles(libJar)
+            .addSourceFiles(
+                getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
+            .setOutputPath(temp.newFolder().toPath())
+            .compile();
+    testForJvm()
+        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+        .addClasspath(output)
+        .run(parameters.getRuntime(), PKG_APP + ".MainKt")
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  @Test
+  public void testMetadataForLib() throws Exception {
+    // We compile libjar with -allowaccesmodification such that all visibility modifiers are updated
+    // to be public. We also compile it with a mapping file to rename Lib to LibReference. After
+    // running with R8, the output should be binary compatible with libReference.
+    Path libJar =
+        testForR8(parameters.getBackend())
+            .addProgramFiles(libJars.get(targetVersion))
+            .addKeepRules("-keepclassmembers,allowaccessmodification class **.Lib { *; }")
+            .addKeepRules("-keep,allowaccessmodification,allowobfuscation class **.Lib { *; }")
+            .addKeepRules("-keepclassmembers,allowaccessmodification class **.Lib$Comp { *; }")
+            .addKeepRules("-keep,allowaccessmodification,allowobfuscation class **.Lib$Comp { *; }")
+            .addKeepRules("-keep,allowaccessmodification,allowobfuscation class **.LibKt { *; }")
+            .addKeepRules("-allowaccessmodification")
+            .addApplyMapping(
+                StringUtils.lines(
+                    PKG_LIB + ".Lib -> " + PKG_LIB + ".LibReference:",
+                    PKG_LIB + ".Lib$Comp -> " + PKG_LIB + ".LibReference$Comp:",
+                    PKG_LIB + ".LibKt -> " + PKG_LIB + ".LibReferenceKt:",
+                    "  void extensionPrivate(" + PKG_LIB + ".Lib) -> extensionPrivate",
+                    "  void extensionInternal(" + PKG_LIB + ".Lib) -> extensionInternal",
+                    "  void staticPrivate() -> staticPrivateReference",
+                    "  void staticInternal() -> staticInternalReference"))
+            .addKeepRuntimeVisibleAnnotations()
+            .compile()
+            .inspect(this::inspect)
+            .writeToZip();
+    ProcessResult mainResult =
+        kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+            .addClasspathFiles(libJar)
+            .addSourceFiles(
+                getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
+            .setOutputPath(temp.newFolder().toPath())
+            .compileRaw();
+    assertEquals(1, mainResult.exitCode);
+    assertThat(mainResult.stderr, containsString("cannot access 'LibReference'"));
+  }
+
+  private void inspect(CodeInspector inspector) throws Exception {
+    // TODO(b/154348683): Assert equality between LibReference and Lib.
+    // assertEqualMetadata(new CodeInspector(libReferenceJars.get(targetVersion)), inspector);
+    ClassSubject lib = inspector.clazz(PKG_LIB + ".Lib");
+    MethodSubject funInline = lib.uniqueMethodWithName("funInline$main");
+    assertThat(funInline, isPresent());
+    // TODO(b/154348683): Keep the inline method package private.
+    // assertTrue(funInline.isPackagePrivate());
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/allow_access_modification_app/main.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/allow_access_modification_app/main.kt
new file mode 100644
index 0000000..fc2e518
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/allow_access_modification_app/main.kt
@@ -0,0 +1,40 @@
+// Copyright (c) 2020, 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.kotlin.metadata.allow_access_modification_app
+
+import com.android.tools.r8.kotlin.metadata.allow_access_modification_lib.LibReference
+import com.android.tools.r8.kotlin.metadata.allow_access_modification_lib.extensionInternal
+import com.android.tools.r8.kotlin.metadata.allow_access_modification_lib.extensionPrivate
+import com.android.tools.r8.kotlin.metadata.allow_access_modification_lib.staticInternalReference
+import com.android.tools.r8.kotlin.metadata.allow_access_modification_lib.staticPrivateReference
+
+fun main() {
+  val libReference = LibReference(1, 2, 3, 4)
+  println(libReference.propPrimaryPrivate)
+  println(libReference.propPrimaryInternal)
+  println(libReference.propPrivate)
+  libReference.propPrimaryPrivate = 5
+  libReference.propPrimaryInternal = 6
+  libReference.propPrivate = 7
+  println(libReference.readOnlyPropPrimaryPrivate)
+  println(libReference.readOnlyPropPrimaryInternal)
+  println(libReference.readOnlyPropInternal)
+  println(libReference.propPrimaryPrivate)
+  println(libReference.propPrimaryInternal)
+  println(libReference.propPrivate)
+
+  libReference.funPrivate()
+  libReference.funInternal()
+  libReference.funProtected()
+
+  libReference.extensionPrivate()
+  libReference.extensionInternal()
+
+  LibReference.companionPrivate()
+  LibReference.companionInternal()
+
+  staticPrivateReference()
+  staticInternalReference()
+}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/allow_access_modification_lib/lib.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/allow_access_modification_lib/lib.kt
new file mode 100644
index 0000000..f77d4f8
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/allow_access_modification_lib/lib.kt
@@ -0,0 +1,59 @@
+// Copyright (c) 2020, 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.kotlin.metadata.allow_access_modification_lib
+
+internal class Lib internal constructor(
+  internal val readOnlyPropPrimaryInternal: Int,
+  internal var propPrimaryInternal : Int,
+  private val readOnlyPropPrimaryPrivate: Int,
+  internal var propPrimaryPrivate : Int) {
+
+  internal val propInternal: Int = 42
+  private var propPrivate: Int = 0
+
+  private fun funPrivate() {
+    println("funPrivate")
+  }
+
+  internal fun funInternal() {
+    println("funInternal")
+  }
+
+  protected fun funProtected() {
+    println("funProtected")
+  }
+
+  // Keep this internal to ensure we do not modify inline functions.
+  internal inline fun funInline() {
+    println("funInline")
+  }
+
+  internal companion object Comp {
+
+    private fun companionPrivate() {
+      println("companionPrivate")
+    }
+
+    internal fun companionInternal() {
+      println("companionInternal")
+    }
+  }
+}
+
+private fun Lib.extensionPrivate() {
+  println("extensionPrivate")
+}
+
+internal fun Lib.extensionInternal() {
+  println("extensionInternal")
+}
+
+private fun staticPrivate() {
+  println("staticPrivate")
+}
+
+internal fun staticInternal() {
+  println("staticInternal")
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/allow_access_modification_lib/lib_reference.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/allow_access_modification_lib/lib_reference.kt
new file mode 100644
index 0000000..a26d8d2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/allow_access_modification_lib/lib_reference.kt
@@ -0,0 +1,59 @@
+// Copyright (c) 2020, 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.kotlin.metadata.allow_access_modification_lib
+
+class LibReference(
+  val readOnlyPropPrimaryInternal: Int,
+  var propPrimaryInternal : Int,
+  val readOnlyPropPrimaryPrivate: Int,
+  var propPrimaryPrivate : Int) {
+
+  val readOnlyPropInternal: Int = 42
+  var propPrivate: Int = 42
+
+  fun funPrivate() {
+    println("funPrivate")
+  }
+
+  fun funInternal() {
+    println("funInternal")
+  }
+
+  fun funProtected() {
+    println("funProtected")
+  }
+
+  // Keep this internal to ensure we do not modify inline functions.
+  internal inline fun funInline() {
+    println("funInline")
+  }
+
+  companion object Factory {
+
+    fun companionPrivate() {
+      println("companionPrivate")
+    }
+
+    fun companionInternal() {
+      println("companionInternal")
+    }
+  }
+}
+
+fun LibReference.extensionPrivate() {
+  println("extensionPrivate")
+}
+
+fun LibReference.extensionInternal() {
+  println("extensionInternal")
+}
+
+fun staticPrivateReference() {
+  println("staticPrivate")
+}
+
+fun staticInternalReference() {
+  println("staticInternal")
+}