Add test for invoke-virtual problems when using applymapping
Additionally, this test also includes a new CompileMemoization
interface that is useful for memoizing compilation results.
Bug: 128868424
Change-Id: I19fd5733c6c1d63a2addc195052af7071698018e
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index bd57729..8839960 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -4,10 +4,10 @@
package com.android.tools.r8;
+import static com.android.tools.r8.utils.InternalOptions.ASM_VERSION;
import static com.google.common.collect.Lists.cartesianProduct;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import static com.android.tools.r8.utils.InternalOptions.ASM_VERSION;
import com.android.tools.r8.DataResourceProvider.Visitor;
import com.android.tools.r8.ToolHelper.ArtCommandBuilder;
@@ -69,6 +69,8 @@
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.rules.TemporaryFolder;
import org.objectweb.asm.ClassReader;
@@ -161,6 +163,23 @@
@Rule
public TestDescriptionWatcher watcher = new TestDescriptionWatcher();
+ private static TemporaryFolder staticTemp = null;
+
+ @BeforeClass
+ public static void testBaseBeforeClassSetup() {
+ assert staticTemp == null;
+ staticTemp = ToolHelper.getTemporaryFolderForTest();
+ }
+
+ @AfterClass
+ public static void testBaseBeforeClassTearDown() {
+ staticTemp = null;
+ }
+
+ public static TemporaryFolder getStaticTemp() {
+ return staticTemp;
+ }
+
public static TestParametersBuilder getTestParameters() {
return TestParametersBuilder.builder();
}
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingVirtualInvokeTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingVirtualInvokeTest.java
new file mode 100644
index 0000000..7989a29
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingVirtualInvokeTest.java
@@ -0,0 +1,151 @@
+// 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.naming.applymapping;
+
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.naming.applymapping.ApplyMappingVirtualInvokeTest.TestClasses.LibraryBase;
+import com.android.tools.r8.naming.applymapping.ApplyMappingVirtualInvokeTest.TestClasses.LibrarySubclass;
+import com.android.tools.r8.naming.applymapping.ApplyMappingVirtualInvokeTest.TestClasses.ProgramClass;
+import com.android.tools.r8.naming.applymapping.ApplyMappingVirtualInvokeTest.TestClasses.ProgramSubclass;
+import com.android.tools.r8.utils.StringUtils;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.concurrent.ExecutionException;
+import java.util.function.Function;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class ApplyMappingVirtualInvokeTest extends TestBase {
+
+ public static final String EXPECTED_PROGRAM = StringUtils.lines("LibraryBase.foo");
+ public static final String EXPECTED_PROGRAM_SUBCLASS =
+ StringUtils.lines("ProgramSubclass.foo", "LibraryBase.foo");
+
+ public static class TestClasses {
+
+ public static class LibraryBase {
+
+ void foo() {
+ System.out.println("LibraryBase.foo");
+ }
+ }
+
+ public static class LibrarySubclass extends LibraryBase {}
+
+ public static class ProgramClass {
+
+ public static void main(String[] args) {
+ new LibrarySubclass().foo();
+ }
+ }
+
+ public static class ProgramSubclass extends LibrarySubclass {
+
+ public static void main(String[] args) {
+ new ProgramSubclass().foo();
+ }
+
+ @Override
+ void foo() {
+ System.out.println("ProgramSubclass.foo");
+ super.foo();
+ }
+ }
+ }
+
+ private static final Class<?>[] LIBRARY_CLASSES = {LibraryBase.class, LibrarySubclass.class};
+ private static final Class<?>[] PROGRAM_CLASSES = {ProgramClass.class, ProgramSubclass.class};
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimes().build();
+ }
+
+ public ApplyMappingVirtualInvokeTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ private static Function<Backend, R8TestCompileResult> compilationResults =
+ memoizeFunction(ApplyMappingVirtualInvokeTest::compile);
+
+ private static R8TestCompileResult compile(Backend backend) throws CompilationFailedException {
+ return testForR8(getStaticTemp(), backend)
+ .addProgramClasses(LIBRARY_CLASSES)
+ .addKeepClassAndMembersRulesWithAllowObfuscation(LIBRARY_CLASSES)
+ .addOptionsModification(
+ options -> {
+ options.enableInlining = false;
+ options.enableVerticalClassMerging = false;
+ options.enableHorizontalClassMerging = false;
+ options.enableClassInlining = false;
+ })
+ .compile();
+ }
+
+ @Test
+ public void runJvmProgramTest()
+ throws ExecutionException, CompilationFailedException, IOException {
+ assumeTrue(parameters.isCfRuntime());
+ testForJvm()
+ .addProgramClasses(LIBRARY_CLASSES)
+ .addProgramClasses(PROGRAM_CLASSES)
+ .run(parameters.getRuntime(), ProgramClass.class)
+ .assertSuccessWithOutput(EXPECTED_PROGRAM);
+ }
+
+ @Test
+ public void runJvmProgramSubclassTest()
+ throws ExecutionException, CompilationFailedException, IOException {
+ assumeTrue(parameters.isCfRuntime());
+ testForJvm()
+ .addProgramClasses(LIBRARY_CLASSES)
+ .addProgramClasses(PROGRAM_CLASSES)
+ .run(parameters.getRuntime(), ProgramSubclass.class)
+ .assertSuccessWithOutput(EXPECTED_PROGRAM_SUBCLASS);
+ }
+
+ @Ignore("b/128868424")
+ @Test
+ public void testProgramClass()
+ throws ExecutionException, CompilationFailedException, IOException {
+ runTest(ProgramClass.class, EXPECTED_PROGRAM);
+ }
+
+ @Ignore("b/128868424")
+ @Test
+ public void testProgramSubClass()
+ throws ExecutionException, IOException, CompilationFailedException {
+ runTest(ProgramSubclass.class, EXPECTED_PROGRAM_SUBCLASS);
+ }
+
+ private void runTest(Class<?> main, String expected)
+ throws ExecutionException, IOException, CompilationFailedException {
+ R8TestCompileResult libraryCompileResult = compilationResults.apply(parameters.getBackend());
+ Path outPath = temp.newFile("out.zip").toPath();
+ libraryCompileResult.writeToZip(outPath);
+ testForR8(parameters.getBackend())
+ .noTreeShaking()
+ .noMinification()
+ .addProgramClasses(PROGRAM_CLASSES)
+ .addApplyMapping(libraryCompileResult.getProguardMap())
+ .addLibraryClasses(LIBRARY_CLASSES)
+ .addLibraryFiles(runtimeJar(parameters.getBackend()))
+ .setMinApi(parameters.getRuntime())
+ .compile()
+ .addRunClasspathFiles(outPath)
+ .run(parameters.getRuntime(), main)
+ .assertSuccessWithOutput(expected);
+ }
+}