Merge "Add a smoke test that runs r8.jar in a forked process so that the built jar is loaded separately and tested."
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 5200a09..7b4f199 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -56,6 +56,8 @@
// Actually running Proguard should only be during development.
private static final boolean RUN_PROGUARD = System.getProperty("run_proguard") != null;
+ // Actually running r8.jar in a forked process.
+ private static final boolean RUN_R8_JAR = System.getProperty("run_r8_jar") != null;
@Rule
public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
@@ -71,6 +73,13 @@
}
/**
+ * Check if tests should run R8 in a forked process when applicable.
+ */
+ protected boolean isRunR8Jar() {
+ return RUN_R8_JAR;
+ }
+
+ /**
* Write lines of text to a temporary file.
*/
protected Path writeTextToTempFile(String... lines) throws IOException {
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 10f62a1..200a1e7 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -70,6 +70,7 @@
public class ToolHelper {
public static final String BUILD_DIR = "build/";
+ public static final String LIBS_DIR = BUILD_DIR + "libs/";
public static final String TESTS_DIR = "src/test/";
public static final String EXAMPLES_DIR = TESTS_DIR + "examples/";
public static final String EXAMPLES_ANDROID_O_DIR = TESTS_DIR + "examplesAndroidO/";
@@ -78,6 +79,8 @@
public static final String TESTS_BUILD_DIR = BUILD_DIR + "test/";
public static final String EXAMPLES_BUILD_DIR = TESTS_BUILD_DIR + "examples/";
public static final String EXAMPLES_KOTLIN_BUILD_DIR = TESTS_BUILD_DIR + "examplesKotlin/";
+ public static final String EXAMPLES_KOTLIN_RESOURCE_DIR =
+ TESTS_BUILD_DIR + "kotlinR8TestResources/";
public static final String EXAMPLES_ANDROID_N_BUILD_DIR = TESTS_BUILD_DIR + "examplesAndroidN/";
public static final String EXAMPLES_ANDROID_O_BUILD_DIR = TESTS_BUILD_DIR + "examplesAndroidO/";
public static final String EXAMPLES_ANDROID_P_BUILD_DIR = TESTS_BUILD_DIR + "examplesAndroidP/";
@@ -979,6 +982,12 @@
return forkJava(dir, R8.class, args);
}
+ public static ProcessResult forkR8Jar(Path dir, String... args)
+ throws IOException, InterruptedException {
+ String r8Jar = Paths.get(LIBS_DIR, "r8.jar").toAbsolutePath().toString();
+ return forkJavaWithJar(dir, r8Jar, Arrays.asList(args));
+ }
+
public static ProcessResult forkGenerateMainDexList(Path dir, List<String> args1, String... args2)
throws IOException, InterruptedException {
List<String> args = new ArrayList<>();
@@ -997,8 +1006,18 @@
return forkJava(dir, clazz, Arrays.asList(args));
}
+ private static ProcessResult forkJavaWithJar(Path dir, String jarPath, List<String> args)
+ throws IOException {
+ List<String> command = new ImmutableList.Builder<String>()
+ .add(getJavaExecutable())
+ .add("-jar").add(jarPath)
+ .addAll(args)
+ .build();
+ return runProcess(new ProcessBuilder(command).directory(dir.toFile()));
+ }
+
private static ProcessResult forkJava(Path dir, Class clazz, List<String> args)
- throws IOException, InterruptedException {
+ throws IOException {
List<String> command = new ImmutableList.Builder<String>()
.add(getJavaExecutable())
.add("-cp").add(System.getProperty("java.class.path"))
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinLambdaMergingTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinLambdaMergingTest.java
index e1431a6..062095c 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinLambdaMergingTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinLambdaMergingTest.java
@@ -43,7 +43,7 @@
abstract boolean match(DexClass clazz);
}
- private static class Group extends LambdaOrGroup {
+ static class Group extends LambdaOrGroup {
final String pkg;
final String capture;
final int arity;
@@ -83,31 +83,32 @@
}
}
- private Group kstyleImpl(String pkg, String capture, int arity, int singletons) {
+ private static Group kstyleImpl(String pkg, String capture, int arity, int singletons) {
assertEquals(capture.isEmpty(), singletons != 0);
return new Group(pkg, capture, arity, KOTLIN_FUNCTION_IFACE_STR + arity, singletons);
}
- private Group kstyle(String pkg, int arity, int singletons) {
+ static Group kstyle(String pkg, int arity, int singletons) {
assertTrue(singletons != 0);
return kstyleImpl(pkg, "", arity, singletons);
}
- private Group kstyle(String pkg, String capture, int arity) {
+ private static Group kstyle(String pkg, String capture, int arity) {
assertFalse(capture.isEmpty());
return kstyleImpl(pkg, capture, arity, 0);
}
- private Group jstyleImpl(String pkg, String capture, int arity, String sam, int singletons) {
+ private static Group jstyleImpl(
+ String pkg, String capture, int arity, String sam, int singletons) {
assertTrue(capture.isEmpty() || singletons == 0);
return new Group(pkg, capture, arity, sam, singletons);
}
- private Group jstyle(String pkg, String capture, int arity, String sam) {
+ private static Group jstyle(String pkg, String capture, int arity, String sam) {
return jstyleImpl(pkg, capture, arity, sam, 0);
}
- private Group jstyle(String pkg, int arity, String sam, int singletons) {
+ private static Group jstyle(String pkg, int arity, String sam, int singletons) {
return jstyleImpl(pkg, "", arity, sam, singletons);
}
@@ -116,7 +117,7 @@
final String name;
final int arity;
- private Lambda(String pkg, String name, int arity) {
+ Lambda(String pkg, String name, int arity) {
this.pkg = pkg;
this.name = name;
this.arity = arity;
@@ -143,7 +144,15 @@
final List<DexClass> groups = new ArrayList<>();
Verifier(AndroidApp app) throws IOException, ExecutionException {
- this.dexInspector = new DexInspector(app);
+ this(new DexInspector(app));
+ }
+
+ Verifier(DexInspector dexInspector) {
+ this.dexInspector = dexInspector;
+ initGroupsAndLambdas();
+ }
+
+ private void initGroupsAndLambdas() {
dexInspector.forAllClasses(clazz -> {
DexClass dexClass = clazz.getDexClass();
if (isLambdaOrGroup(dexClass)) {
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinxMetadataExtensionsServiceTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinxMetadataExtensionsServiceTest.java
new file mode 100644
index 0000000..2beb777
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinxMetadataExtensionsServiceTest.java
@@ -0,0 +1,108 @@
+// Copyright (c) 2018, 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;
+
+import static com.android.tools.r8.ToolHelper.EXAMPLES_KOTLIN_RESOURCE_DIR;
+import static com.android.tools.r8.kotlin.KotlinLambdaMergingTest.kstyle;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.kotlin.KotlinLambdaMergingTest.Group;
+import com.android.tools.r8.kotlin.KotlinLambdaMergingTest.Lambda;
+import com.android.tools.r8.kotlin.KotlinLambdaMergingTest.Verifier;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.DexInspector;
+import com.android.tools.r8.utils.FileUtils;
+import com.google.common.collect.ImmutableList;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import org.junit.Test;
+
+public class KotlinxMetadataExtensionsServiceTest extends TestBase {
+
+ private void forkR8_kstyle_trivial(boolean allowAccessModification) throws Exception {
+ if (!isRunR8Jar()) {
+ return;
+ }
+ Path working = temp.getRoot().toPath();
+ Path kotlinJar =
+ Paths.get(EXAMPLES_KOTLIN_RESOURCE_DIR, "JAVA_8", "lambdas_kstyle_trivial.jar")
+ .toAbsolutePath();
+ Path output = working.resolve("classes.dex");
+ assertFalse(Files.exists(output));
+ Path proguardConfiguration = temp.newFile("test.conf").toPath();
+ List<String> lines = ImmutableList.of(
+ "-keepattributes Signature,InnerClasses,EnclosingMethod",
+ "-keep class **MainKt {",
+ " public static void main(...);",
+ "}",
+ "-printmapping",
+ "-dontobfuscate",
+ allowAccessModification ? "-allowaccessmodification" : ""
+ );
+ FileUtils.writeTextFile(proguardConfiguration, lines);
+ ProcessResult result = ToolHelper.forkR8Jar(working,
+ "--pg-conf", proguardConfiguration.toString(),
+ "--lib", ToolHelper.getAndroidJar(AndroidApiLevel.O).toAbsolutePath().toString(),
+ kotlinJar.toString());
+ assertEquals(0, result.exitCode);
+ assertThat(result.stderr, not(containsString(
+ "No MetadataExtensions instances found in the classpath")));
+ assertTrue(Files.exists(output));
+
+ DexInspector inspector = new DexInspector(output);
+ Verifier verifier = new Verifier(inspector);
+ String pkg = "lambdas_kstyle_trivial";
+ verifier.assertLambdaGroups(
+ allowAccessModification ?
+ new Group[]{
+ kstyle("", 0, 4),
+ kstyle("", 1, 8),
+ kstyle("", 2, 2), // -\
+ kstyle("", 2, 5), // - 3 groups different by main method
+ kstyle("", 2, 4), // -/
+ kstyle("", 3, 2),
+ kstyle("", 22, 2)} :
+ new Group[]{
+ kstyle(pkg, 0, 2),
+ kstyle(pkg, 1, 4),
+ kstyle(pkg, 2, 5), // - 2 groups different by main method
+ kstyle(pkg, 2, 4), // -/
+ kstyle(pkg, 3, 2),
+ kstyle(pkg, 22, 2),
+ kstyle(pkg + "/inner", 0, 2),
+ kstyle(pkg + "/inner", 1, 4)}
+ );
+
+ verifier.assertLambdas(
+ allowAccessModification ?
+ new Lambda[]{
+ new Lambda(pkg, "MainKt$testStateless$6", 1) /* Banned for limited inlining */} :
+ new Lambda[]{
+ new Lambda(pkg, "MainKt$testStateless$6", 1), /* Banned for limited inlining */
+ new Lambda(pkg, "MainKt$testStateless$8", 2),
+ new Lambda(pkg + "/inner", "InnerKt$testInnerStateless$7", 2)}
+ );
+ }
+
+ @Test
+ public void testTrivialKs_allowAccessModification() throws Exception {
+ forkR8_kstyle_trivial(true);
+ }
+
+ @Test
+ public void testTrivialKs_notAllowAccessModification() throws Exception {
+ forkR8_kstyle_trivial(false);
+ }
+
+}