Start to split up backported method test by type
These test both correctness and desugaring on proper API levels.
Test: tools/test.py --dex_vm all --no-internal *desugar.backports.*
Test: tools/test.py --dex_vm all --no-internal *BackportedMethodRewriterTest*
Change-Id: I95659081ea63ff9867882b0b9cd8551a9af8d846
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index 9890298..599cacb 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -28,6 +28,7 @@
import com.android.tools.r8.ir.code.InvokeStatic;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.desugar.BackportedMethodRewriter.RewritableMethods.MethodGenerator;
+import com.android.tools.r8.ir.desugar.backports.BooleanMethods;
import com.android.tools.r8.ir.synthetic.TemplateMethodCode;
import com.android.tools.r8.origin.SynthesizedOrigin;
import com.android.tools.r8.utils.DescriptorUtils;
@@ -317,32 +318,6 @@
}
}
- private static final class BooleanMethods extends TemplateMethodCode {
- BooleanMethods(InternalOptions options, DexMethod method, String methodName) {
- super(options, method, methodName, method.proto.toDescriptorString());
- }
-
- public static int hashCode(boolean b) {
- return Boolean.valueOf(b).hashCode();
- }
-
- public static int compare(boolean a, boolean b) {
- return Boolean.valueOf(a).compareTo(Boolean.valueOf(b));
- }
-
- public static boolean logicalAnd(boolean a, boolean b) {
- return a && b;
- }
-
- public static boolean logicalOr(boolean a, boolean b) {
- return a || b;
- }
-
- public static boolean logicalXor(boolean a, boolean b) {
- return a ^ b;
- }
- }
-
private static final class LongMethods extends TemplateMethodCode {
LongMethods(InternalOptions options, DexMethod method, String methodName) {
super(options, method, methodName, method.proto.toDescriptorString());
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/BooleanMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/BooleanMethods.java
new file mode 100644
index 0000000..514d464
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/BooleanMethods.java
@@ -0,0 +1,35 @@
+// 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.ir.desugar.backports;
+
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.ir.synthetic.TemplateMethodCode;
+import com.android.tools.r8.utils.InternalOptions;
+
+public final class BooleanMethods extends TemplateMethodCode {
+ public BooleanMethods(InternalOptions options, DexMethod method, String methodName) {
+ super(options, method, methodName, method.proto.toDescriptorString());
+ }
+
+ public static int hashCode(boolean b) {
+ return Boolean.valueOf(b).hashCode();
+ }
+
+ public static int compare(boolean a, boolean b) {
+ return Boolean.valueOf(a).compareTo(Boolean.valueOf(b));
+ }
+
+ public static boolean logicalAnd(boolean a, boolean b) {
+ return a && b;
+ }
+
+ public static boolean logicalOr(boolean a, boolean b) {
+ return a || b;
+ }
+
+ public static boolean logicalXor(boolean a, boolean b) {
+ return a ^ b;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/BackportedMethodRewriterTest.java b/src/test/java/com/android/tools/r8/desugar/BackportedMethodRewriterTest.java
index 5eb581d..f840ec9 100644
--- a/src/test/java/com/android/tools/r8/desugar/BackportedMethodRewriterTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/BackportedMethodRewriterTest.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.D8TestCompileResult;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.desugar.backports.BooleanBackportTest;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
@@ -23,6 +24,10 @@
import org.junit.Before;
import org.junit.Test;
+/**
+ * @deprecated New tests should follow the pattern of {@link BooleanBackportTest}.
+ */
+@Deprecated
public class BackportedMethodRewriterTest extends TestBase {
static String expectedOutput = "";
@@ -40,9 +45,9 @@
.run(TestMethods.class)
.assertSuccessWithOutput(expectedOutput);
- assertDesugaring(AndroidApiLevel.O, 70);
- assertDesugaring(AndroidApiLevel.N, 49);
- assertDesugaring(AndroidApiLevel.K, 20);
+ assertDesugaring(AndroidApiLevel.O, 65);
+ assertDesugaring(AndroidApiLevel.N, 44);
+ assertDesugaring(AndroidApiLevel.K, 19);
assertDesugaring(AndroidApiLevel.J_MR2, 0);
}
@@ -215,17 +220,6 @@
}
}
- boolean[] aBooleans = { true, false };
- for (boolean aBoolean : aBooleans) {
- System.out.println(Boolean.hashCode(aBoolean));
- for (boolean bBoolean : aBooleans) {
- System.out.println(Boolean.compare(aBoolean, bBoolean));
- System.out.println(Boolean.logicalAnd(aBoolean, bBoolean));
- System.out.println(Boolean.logicalOr(aBoolean, bBoolean));
- System.out.println(Boolean.logicalXor(aBoolean, bBoolean));
- }
- }
-
long[] aLongs = new long[]{42L, 1L, -1L, Integer.MIN_VALUE, Integer.MAX_VALUE,
Long.MAX_VALUE, Long.MIN_VALUE};
long[] bLongs = new long[]{43L, 2L, -2L, Integer.MIN_VALUE, Integer.MAX_VALUE,
@@ -279,7 +273,9 @@
System.out.println(Objects.compare("b", "a", reverse()));
System.out.println(Objects.compare("a", "a", reverse()));
- Object[] objects = { aBytes, aBooleans, aChars, aDoubles, aFloats, aInts, aLongs, "a", null };
+ Object[] objects = {
+ aBytes, new boolean[] { true, false }, aChars, aDoubles, aFloats, aInts, aLongs, "a", null
+ };
for (Object aObject : objects) {
for (Object bObject : objects) {
System.out.println(Objects.deepEquals(aObject, bObject));
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/AbstractBackportTest.java b/src/test/java/com/android/tools/r8/desugar/backports/AbstractBackportTest.java
new file mode 100644
index 0000000..d139b48
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/AbstractBackportTest.java
@@ -0,0 +1,104 @@
+// 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.backports;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static java.util.stream.Collectors.toList;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.util.List;
+import java.util.NavigableMap;
+import java.util.TreeMap;
+import org.junit.Assert;
+import org.junit.Test;
+
+abstract class AbstractBackportTest extends TestBase {
+ private final TestParameters parameters;
+ private final Class<?> targetClass;
+ private final Class<?> testClass;
+ private final NavigableMap<AndroidApiLevel, Integer> invokeStaticCounts = new TreeMap<>();
+
+ AbstractBackportTest(TestParameters parameters, Class<?> targetClass,
+ Class<?> testClass) {
+ this.parameters = parameters;
+ this.targetClass = targetClass;
+ this.testClass = testClass;
+
+ // Assume all method calls will be rewritten on the lowest API level.
+ invokeStaticCounts.put(AndroidApiLevel.B, 0);
+ }
+
+ void registerTarget(AndroidApiLevel apiLevel, int invokeStaticCount) {
+ invokeStaticCounts.put(apiLevel, invokeStaticCount);
+ }
+
+ @Test
+ public void desugaring() throws Exception {
+ testForD8()
+ .addProgramClasses(testClass, MiniAssert.class)
+ .setMinApi(parameters.getRuntime().asDex().getMinApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), testClass)
+ .assertSuccess()
+ .inspect(this::assertDesugaring);
+ }
+
+ private void assertDesugaring(CodeInspector inspector) {
+ ClassSubject testSubject = inspector.clazz(testClass);
+ assertThat(testSubject, isPresent());
+
+ MethodSubject mainMethod = testSubject.mainMethod();
+ assertThat(mainMethod, isPresent());
+
+ List<InstructionSubject> javaInvokeStatics = mainMethod
+ .streamInstructions()
+ .filter(InstructionSubject::isInvoke)
+ .filter(is -> is.getMethod().holder.toSourceString().equals(targetClass.getName()))
+ .collect(toList());
+
+ AndroidApiLevel apiLevel = parameters.getRuntime().asDex().getMinApiLevel();
+ long expectedTargetInvokes = invokeStaticCounts.ceilingEntry(apiLevel).getValue();
+ long actualTargetInvokes = javaInvokeStatics.size();
+ assertEquals("Expected "
+ + expectedTargetInvokes
+ + " invokes on "
+ + targetClass.getName()
+ + " but found "
+ + actualTargetInvokes
+ + ": "
+ + javaInvokeStatics, expectedTargetInvokes, actualTargetInvokes);
+ }
+
+ /** JUnit {@link Assert} isn't available in the VM runtime. This is a mini mirror of its API. */
+ static abstract class MiniAssert {
+ static void assertTrue(boolean value) {
+ assertEquals(true, value);
+ }
+
+ static void assertFalse(boolean value) {
+ assertEquals(false, value);
+ }
+
+ static void assertEquals(boolean expected, boolean actual) {
+ if (expected != actual) {
+ throw new AssertionError("Expected <" + expected + "> but was <" + actual + '>');
+ }
+ }
+
+ static void assertEquals(int expected, int actual) {
+ if (expected != actual) {
+ throw new AssertionError("Expected <" + expected + "> but was <" + actual + '>');
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/BooleanBackportTest.java b/src/test/java/com/android/tools/r8/desugar/backports/BooleanBackportTest.java
new file mode 100644
index 0000000..874b584
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/BooleanBackportTest.java
@@ -0,0 +1,52 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public final class BooleanBackportTest extends AbstractBackportTest {
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters().withDexRuntimes().build();
+ }
+
+ public BooleanBackportTest(TestParameters parameters) {
+ super(parameters, Boolean.class, Main.class);
+ registerTarget(AndroidApiLevel.N, 18);
+ registerTarget(AndroidApiLevel.K, 4);
+ }
+
+ static final class Main extends MiniAssert {
+ public static void main(String[] args) {
+ assertEquals(1231, Boolean.hashCode(true));
+ assertEquals(1237, Boolean.hashCode(false));
+
+ assertEquals(1, Boolean.compare(true, false));
+ assertEquals(0, Boolean.compare(true, true));
+ assertEquals(0, Boolean.compare(false, false));
+ assertEquals(-1, Boolean.compare(false, true));
+
+ assertTrue(Boolean.logicalAnd(true, true));
+ assertFalse(Boolean.logicalAnd(true, false));
+ assertFalse(Boolean.logicalAnd(false, true));
+ assertFalse(Boolean.logicalAnd(false, false));
+
+ assertTrue(Boolean.logicalOr(true, true));
+ assertTrue(Boolean.logicalOr(true, false));
+ assertTrue(Boolean.logicalOr(false, true));
+ assertFalse(Boolean.logicalOr(false, false));
+
+ assertFalse(Boolean.logicalXor(true, true));
+ assertTrue(Boolean.logicalXor(true, false));
+ assertTrue(Boolean.logicalXor(false, true));
+ assertFalse(Boolean.logicalXor(false, false));
+ }
+ }
+}