Rewrite DefaultMethodsTest to new test infrastructure
Change-Id: Ib6ad7fdf3eb92b855ca540b44e1e96d23569c37e
diff --git a/src/test/java/com/android/tools/r8/shaking/defaultmethods/DefaultMethodsTest.java b/src/test/java/com/android/tools/r8/shaking/defaultmethods/DefaultMethodsTest.java
index eebb7d5..690052b 100644
--- a/src/test/java/com/android/tools/r8/shaking/defaultmethods/DefaultMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/defaultmethods/DefaultMethodsTest.java
@@ -4,17 +4,15 @@
package com.android.tools.r8.shaking.defaultmethods;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbstract;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.ClassFileConsumer;
-import com.android.tools.r8.DexIndexedConsumer;
-import com.android.tools.r8.R8Command;
import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
@@ -24,47 +22,33 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class DefaultMethodsTest extends TestBase {
- private Backend backend;
+ private final TestParameters parameters;
- @Parameterized.Parameters(name = "Backend: {0}")
- public static Backend[] data() {
- return ToolHelper.getBackends();
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
}
- public DefaultMethodsTest(Backend backend) {
- this.backend = backend;
+ public DefaultMethodsTest(TestParameters parameters) {
+ this.parameters = parameters;
}
private void runTest(List<String> additionalKeepRules, Consumer<CodeInspector> inspection)
throws Exception {
- R8Command.Builder builder = R8Command.builder();
- builder.addProgramFiles(ToolHelper.getClassFileForTestClass(InterfaceWithDefaultMethods.class));
- builder.addProgramFiles(ToolHelper.getClassFileForTestClass(ClassImplementingInterface.class));
- builder.addProgramFiles(ToolHelper.getClassFileForTestClass(TestClass.class));
- if (backend == Backend.DEX) {
- builder.setProgramConsumer(DexIndexedConsumer.emptyConsumer());
- int apiLevel = AndroidApiLevel.O.getLevel();
- builder.setMinApiLevel(apiLevel);
- builder.addLibraryFiles(ToolHelper.getAndroidJar(apiLevel));
- } else {
- assert backend == Backend.CF;
- builder.setProgramConsumer(ClassFileConsumer.emptyConsumer());
- builder.addLibraryFiles(ToolHelper.getJava8RuntimeJar());
- }
- // Always keep main in the test class, so the output never becomes empty.
- builder.addProguardConfiguration(ImmutableList.of(
- "-keep class " + TestClass.class.getCanonicalName() + "{",
- " public static void main(java.lang.String[]);",
- "}",
- "-dontobfuscate"),
- Origin.unknown());
- builder.addProguardConfiguration(additionalKeepRules, Origin.unknown());
- AndroidApp app = ToolHelper.runR8(builder.build(), o -> o.enableClassInlining = false);
- inspection.accept(new CodeInspector(app));
+ testForR8(parameters.getBackend())
+ .addProgramClasses(
+ InterfaceWithDefaultMethods.class, ClassImplementingInterface.class, TestClass.class)
+ .setMinApi(parameters.getApiLevel())
+ .addKeepMainRule(TestClass.class)
+ .addKeepRules(additionalKeepRules)
+ .noMinification()
+ .compile()
+ .inspect(inspection);
}
private void interfaceNotKept(CodeInspector inspector) {
@@ -73,53 +57,98 @@
private void defaultMethodNotKept(CodeInspector inspector) {
ClassSubject clazz = inspector.clazz(InterfaceWithDefaultMethods.class);
- assertTrue(clazz.isPresent());
- assertFalse(clazz.method("int", "method", ImmutableList.of()).isPresent());
+ assertThat(clazz, isPresent());
+ assertThat(clazz.method("int", "method", ImmutableList.of()), not(isPresent()));
}
private void defaultMethodKept(CodeInspector inspector) {
ClassSubject clazz = inspector.clazz(InterfaceWithDefaultMethods.class);
- assertTrue(clazz.isPresent());
+ assertThat(clazz, isPresent());
MethodSubject method = clazz.method("int", "method", ImmutableList.of());
- assertTrue(method.isPresent());
- assertFalse(method.isAbstract());
+ assertThat(method, isPresent());
+ ClassSubject companionClass = clazz.toCompanionClass();
+ if (parameters.canUseDefaultAndStaticInterfaceMethods()) {
+ assertThat(method, not(isAbstract()));
+ assertThat(companionClass, not(isPresent()));
+ } else {
+ assertThat(method, isAbstract());
+ assertThat(companionClass, isPresent());
+ MethodSubject defaultMethod = method.toMethodOnCompanionClass();
+ assertThat(defaultMethod, isPresent());
+ }
+ }
+
+ private void defaultMethodKeptWithoutCompanionClass(CodeInspector inspector) {
+ ClassSubject clazz = inspector.clazz(InterfaceWithDefaultMethods.class);
+ assertThat(clazz, isPresent());
+ MethodSubject method = clazz.method("int", "method", ImmutableList.of());
+ assertThat(method, isPresent());
+ ClassSubject companionClass = clazz.toCompanionClass();
+ if (parameters.canUseDefaultAndStaticInterfaceMethods()) {
+ assertThat(method, not(isAbstract()));
+ } else {
+ assertThat(method, isAbstract());
+ }
+ assertThat(companionClass, not(isPresent()));
}
@Test
- public void test() throws Exception {
+ public void testInterfaceNotKept() throws Exception {
runTest(ImmutableList.of(), this::interfaceNotKept);
- runTest(ImmutableList.of(
- "-keep interface " + InterfaceWithDefaultMethods.class.getCanonicalName() + "{",
- "}"
- ), this::defaultMethodNotKept);
- runTest(ImmutableList.of(
- "-keep interface " + InterfaceWithDefaultMethods.class.getCanonicalName() + "{",
- " <methods>;",
- "}"
- ), this::defaultMethodKept);
- runTest(ImmutableList.of(
- "-keep interface " + InterfaceWithDefaultMethods.class.getCanonicalName() + "{",
- " public int method();",
- "}"
- ), this::defaultMethodKept);
+ }
+
+ @Test
+ public void testDefaultMethodNotKept() throws Exception {
runTest(
ImmutableList.of(
- "-keep class " + ClassImplementingInterface.class.getCanonicalName() + "{",
+ "-keep interface " + InterfaceWithDefaultMethods.class.getTypeName() + "{", "}"),
+ this::defaultMethodNotKept);
+ }
+
+ @Test
+ public void testDefaultMethodKeptWithMethods() throws Exception {
+ runTest(
+ ImmutableList.of(
+ "-keep interface " + InterfaceWithDefaultMethods.class.getTypeName() + "{",
+ " <methods>;",
+ "}"),
+ this::defaultMethodKept);
+ }
+
+ @Test
+ public void testDefaultMethodsKeptExplicitly() throws Exception {
+ runTest(
+ ImmutableList.of(
+ "-keep interface " + InterfaceWithDefaultMethods.class.getTypeName() + "{",
+ " public int method();",
+ "}"),
+ this::defaultMethodKept);
+ }
+
+ @Test
+ public void testDefaultMethodNotKeptIndirectly() throws Exception {
+ runTest(
+ ImmutableList.of(
+ "-keep class " + ClassImplementingInterface.class.getTypeName() + "{",
" <methods>;",
"}",
// Prevent InterfaceWithDefaultMethods from being merged into ClassImplementingInterface
- "-keep class " + InterfaceWithDefaultMethods.class.getCanonicalName()),
+ "-keep class " + InterfaceWithDefaultMethods.class.getTypeName()),
this::defaultMethodNotKept);
+ }
+
+ @Test
+ public void testDefaultMethodKeptIndirectly() throws Exception {
runTest(
ImmutableList.of(
- "-keep class " + ClassImplementingInterface.class.getCanonicalName() + "{",
+ "-keep class " + ClassImplementingInterface.class.getTypeName() + "{",
" <methods>;",
"}",
"-keep class " + TestClass.class.getCanonicalName() + "{",
" public void useInterfaceMethod();",
"}",
// Prevent InterfaceWithDefaultMethods from being merged into ClassImplementingInterface
- "-keep class " + InterfaceWithDefaultMethods.class.getCanonicalName()),
- this::defaultMethodKept);
+ "-keep class " + InterfaceWithDefaultMethods.class.getTypeName()),
+ this::defaultMethodKeptWithoutCompanionClass);
}
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
index 81b988e..f872a70 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
@@ -7,12 +7,17 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.references.ClassReference;
import java.util.List;
import java.util.function.Consumer;
import kotlinx.metadata.jvm.KotlinClassMetadata;
public class AbsentClassSubject extends ClassSubject {
+ public AbsentClassSubject(CodeInspector codeInspector, ClassReference reference) {
+ super(codeInspector, reference);
+ }
+
@Override
public boolean isPresent() {
return false;
@@ -172,4 +177,9 @@
public KotlinClassMetadata getKotlinClassMetadata() {
return null;
}
+
+ @Override
+ public ClassSubject toCompanionClass() {
+ throw new Unreachable("Cannot determine EnclosingMethod attribute of an absent class");
+ }
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
index 38dc236..c62f945 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
@@ -142,4 +142,9 @@
public String getJvmMethodSignatureAsString() {
return null;
}
+
+ @Override
+ public MethodSubject toMethodOnCompanionClass() {
+ throw new Unreachable("Cannot determine companion class method");
+ }
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
index 97a3b29..84d76a1 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
@@ -4,10 +4,14 @@
package com.android.tools.r8.utils.codeinspector;
+import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
+
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
+import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.references.Reference;
import com.android.tools.r8.references.TypeReference;
import com.android.tools.r8.smali.SmaliBuilder;
import com.android.tools.r8.utils.ListUtils;
@@ -23,6 +27,14 @@
public abstract class ClassSubject extends Subject {
+ protected final ClassReference reference;
+ protected final CodeInspector codeInspector;
+
+ public ClassSubject(CodeInspector codeInspector, ClassReference reference) {
+ this.codeInspector = codeInspector;
+ this.reference = reference;
+ }
+
public abstract void forAllMethods(Consumer<FoundMethodSubject> inspection);
public final List<FoundMethodSubject> allMethods() {
@@ -192,4 +204,11 @@
public abstract KmPackageSubject getKmPackage();
public abstract KotlinClassMetadata getKotlinClassMetadata();
+
+ public ClassSubject toCompanionClass() {
+ String descriptor = reference.getDescriptor();
+ return codeInspector.clazz(
+ Reference.classFromDescriptor(
+ descriptor.substring(0, descriptor.length() - 1) + COMPANION_CLASS_NAME_SUFFIX + ";"));
+ }
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
index 76ed0e2..ac30cb7 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
@@ -280,9 +280,9 @@
}
DexClass clazz = application.definitionFor(toDexTypeIgnorePrimitives(name));
if (clazz == null) {
- return new AbsentClassSubject();
+ return new AbsentClassSubject(this, reference);
}
- return new FoundClassSubject(this, clazz, naming);
+ return new FoundClassSubject(this, clazz, naming, reference);
}
public ClassSubject companionClassFor(Class<?> clazz) {
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
index 2ce3024..bd65812 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
@@ -24,6 +24,7 @@
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.naming.MemberNaming.Signature;
import com.android.tools.r8.naming.signature.GenericSignatureParser;
+import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.StringUtils;
import java.util.List;
@@ -32,13 +33,15 @@
public class FoundClassSubject extends ClassSubject {
- private final CodeInspector codeInspector;
private final DexClass dexClass;
final ClassNamingForNameMapper naming;
FoundClassSubject(
- CodeInspector codeInspector, DexClass dexClass, ClassNamingForNameMapper naming) {
- this.codeInspector = codeInspector;
+ CodeInspector codeInspector,
+ DexClass dexClass,
+ ClassNamingForNameMapper naming,
+ ClassReference reference) {
+ super(codeInspector, reference);
this.dexClass = dexClass;
this.naming = naming;
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmDeclarationContainerSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmDeclarationContainerSubject.java
index 6363747..a74c3d8 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmDeclarationContainerSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmDeclarationContainerSubject.java
@@ -129,7 +129,7 @@
default ClassSubject getClassSubjectFromKmType(KmType kmType) {
String descriptor = getDescriptorFromKmType(kmType);
if (descriptor == null) {
- return new AbsentClassSubject();
+ return new AbsentClassSubject(codeInspector(), Reference.classFromDescriptor("Lnot_found;"));
}
return getClassSubjectFromDescriptor(descriptor);
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
index 1f1fe84..d4f8b5b 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.utils.codeinspector;
+import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.DEFAULT_METHOD_PREFIX;
+
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfPosition;
import com.android.tools.r8.code.Instruction;
@@ -31,6 +33,7 @@
import com.android.tools.r8.naming.signature.GenericSignatureParser;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.references.TypeReference;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.LocalVariableTable.LocalVariableTableEntry;
import com.google.common.base.Predicates;
@@ -39,6 +42,7 @@
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import java.util.Arrays;
import java.util.Iterator;
+import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -372,4 +376,19 @@
+ ")"
+ dexMethod.method.proto.returnType.toDescriptorString();
}
+
+ @Override
+ public MethodSubject toMethodOnCompanionClass() {
+ ClassSubject companionClass = clazz.toCompanionClass();
+ MethodReference reference = asMethodReference();
+ List<String> p =
+ ImmutableList.<String>builder()
+ .add(clazz.getFinalName())
+ .addAll(reference.getFormalTypes().stream().map(TypeReference::getTypeName).iterator())
+ .build();
+ return companionClass.method(
+ reference.getReturnType().getTypeName(),
+ DEFAULT_METHOD_PREFIX + reference.getMethodName(),
+ p);
+ }
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
index 8fc439f..690838d 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
@@ -102,4 +102,6 @@
}
public abstract String getJvmMethodSignatureAsString();
+
+ public abstract MethodSubject toMethodOnCompanionClass();
}