Move Java9 backport test to java 9 module

Bug: b/380808556
Change-Id: I37db6d24aad86adbb57f86ef9054f09a4ed721bb
diff --git a/src/test/examplesJava9/backport/ByteBackportJava9Main.java b/src/test/examplesJava9/backport/ByteBackportJava9Main.java
deleted file mode 100644
index 2487a81..0000000
--- a/src/test/examplesJava9/backport/ByteBackportJava9Main.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package backport;
-
-public final class ByteBackportJava9Main {
-  private static final byte MIN_UNSIGNED_VALUE = (byte) 0;
-  private static final byte MAX_UNSIGNED_VALUE = (byte) -1;
-
-  public static void main(String[] args) {
-    testCompareUnsigned();
-  }
-
-  private static void testCompareUnsigned() {
-    assertTrue(Byte.compareUnsigned(MIN_UNSIGNED_VALUE, MIN_UNSIGNED_VALUE) == 0);
-    assertTrue(Byte.compareUnsigned(MIN_UNSIGNED_VALUE, Byte.MAX_VALUE) < 0);
-    assertTrue(Byte.compareUnsigned(MIN_UNSIGNED_VALUE, Byte.MIN_VALUE) < 0);
-    assertTrue(Byte.compareUnsigned(MIN_UNSIGNED_VALUE, MAX_UNSIGNED_VALUE) < 0);
-
-    assertTrue(Byte.compareUnsigned(Byte.MAX_VALUE, MIN_UNSIGNED_VALUE) > 0);
-    assertTrue(Byte.compareUnsigned(Byte.MAX_VALUE, Byte.MAX_VALUE) == 0);
-    assertTrue(Byte.compareUnsigned(Byte.MAX_VALUE, Byte.MIN_VALUE) < 0);
-    assertTrue(Byte.compareUnsigned(Byte.MAX_VALUE, MAX_UNSIGNED_VALUE) < 0);
-
-    assertTrue(Byte.compareUnsigned(Byte.MIN_VALUE, MIN_UNSIGNED_VALUE) > 0);
-    assertTrue(Byte.compareUnsigned(Byte.MIN_VALUE, Byte.MAX_VALUE) > 0);
-    assertTrue(Byte.compareUnsigned(Byte.MIN_VALUE, Byte.MIN_VALUE) == 0);
-    assertTrue(Byte.compareUnsigned(Byte.MIN_VALUE, MAX_UNSIGNED_VALUE) < 0);
-
-    assertTrue(Byte.compareUnsigned(MAX_UNSIGNED_VALUE, MIN_UNSIGNED_VALUE) > 0);
-    assertTrue(Byte.compareUnsigned(MAX_UNSIGNED_VALUE, Byte.MAX_VALUE) > 0);
-    assertTrue(Byte.compareUnsigned(MAX_UNSIGNED_VALUE, Byte.MIN_VALUE) > 0);
-    assertTrue(Byte.compareUnsigned(MAX_UNSIGNED_VALUE, MAX_UNSIGNED_VALUE) == 0);
-  }
-
-  private static void assertTrue(boolean value) {
-    if (!value) {
-      throw new AssertionError("Expected <true> but was <false>");
-    }
-  }
-}
diff --git a/src/test/examplesJava9/backport/ByteBackportJava9Test.java b/src/test/examplesJava9/backport/ByteBackportJava9Test.java
new file mode 100644
index 0000000..9f689fd
--- /dev/null
+++ b/src/test/examplesJava9/backport/ByteBackportJava9Test.java
@@ -0,0 +1,71 @@
+// 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 backport;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.desugar.backports.AbstractBackportTest;
+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 ByteBackportJava9Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return TestBase.getTestParameters()
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
+        .withDexRuntimes()
+        .withAllApiLevelsAlsoForCf()
+        .build();
+  }
+
+  public ByteBackportJava9Test(TestParameters parameters) {
+    super(parameters, Byte.class, ByteBackportJava9Main.class);
+
+    // Byte.compareUnsigned added in API 31.
+    registerTarget(AndroidApiLevel.S, 16);
+  }
+
+  public static class ByteBackportJava9Main {
+
+    private static final byte MIN_UNSIGNED_VALUE = (byte) 0;
+    private static final byte MAX_UNSIGNED_VALUE = (byte) -1;
+
+    public static void main(String[] args) {
+      testCompareUnsigned();
+    }
+
+    private static void testCompareUnsigned() {
+      assertTrue(Byte.compareUnsigned(MIN_UNSIGNED_VALUE, MIN_UNSIGNED_VALUE) == 0);
+      assertTrue(Byte.compareUnsigned(MIN_UNSIGNED_VALUE, Byte.MAX_VALUE) < 0);
+      assertTrue(Byte.compareUnsigned(MIN_UNSIGNED_VALUE, Byte.MIN_VALUE) < 0);
+      assertTrue(Byte.compareUnsigned(MIN_UNSIGNED_VALUE, MAX_UNSIGNED_VALUE) < 0);
+
+      assertTrue(Byte.compareUnsigned(Byte.MAX_VALUE, MIN_UNSIGNED_VALUE) > 0);
+      assertTrue(Byte.compareUnsigned(Byte.MAX_VALUE, Byte.MAX_VALUE) == 0);
+      assertTrue(Byte.compareUnsigned(Byte.MAX_VALUE, Byte.MIN_VALUE) < 0);
+      assertTrue(Byte.compareUnsigned(Byte.MAX_VALUE, MAX_UNSIGNED_VALUE) < 0);
+
+      assertTrue(Byte.compareUnsigned(Byte.MIN_VALUE, MIN_UNSIGNED_VALUE) > 0);
+      assertTrue(Byte.compareUnsigned(Byte.MIN_VALUE, Byte.MAX_VALUE) > 0);
+      assertTrue(Byte.compareUnsigned(Byte.MIN_VALUE, Byte.MIN_VALUE) == 0);
+      assertTrue(Byte.compareUnsigned(Byte.MIN_VALUE, MAX_UNSIGNED_VALUE) < 0);
+
+      assertTrue(Byte.compareUnsigned(MAX_UNSIGNED_VALUE, MIN_UNSIGNED_VALUE) > 0);
+      assertTrue(Byte.compareUnsigned(MAX_UNSIGNED_VALUE, Byte.MAX_VALUE) > 0);
+      assertTrue(Byte.compareUnsigned(MAX_UNSIGNED_VALUE, Byte.MIN_VALUE) > 0);
+      assertTrue(Byte.compareUnsigned(MAX_UNSIGNED_VALUE, MAX_UNSIGNED_VALUE) == 0);
+    }
+
+    private static void assertTrue(boolean value) {
+      if (!value) {
+        throw new AssertionError("Expected <true> but was <false>");
+      }
+    }
+  }
+}
diff --git a/src/test/examplesJava9/backport/IntegerBackportJava9Main.java b/src/test/examplesJava9/backport/IntegerBackportJava9Main.java
deleted file mode 100644
index acf18d2..0000000
--- a/src/test/examplesJava9/backport/IntegerBackportJava9Main.java
+++ /dev/null
@@ -1,166 +0,0 @@
-// Copyright (c) 2021, 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 backport;
-
-public final class IntegerBackportJava9Main {
-  private static final int[] interestingValues = {
-    Integer.MIN_VALUE,
-    Integer.MAX_VALUE,
-    Short.MIN_VALUE,
-    Short.MAX_VALUE,
-    Byte.MIN_VALUE,
-    Byte.MAX_VALUE,
-    0,
-    -1,
-    1,
-    -42,
-    42
-  };
-
-  public static void main(String[] args) {
-    testParseIntegerSubsequenceWithRadix();
-    testParseUnsignedIntegerSubsequenceWithRadix();
-  }
-
-  private static void testParseIntegerSubsequenceWithRadix() {
-    for (int value : interestingValues) {
-      for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
-        for (String prefix : new String[] {"", "x", "xxx"}) {
-          for (String postfix : new String[] {"", "x", "xxx"}) {
-            String valueString = prefix + Long.toString(value, radix) + postfix;
-            int start = prefix.length();
-            int end = valueString.length() - postfix.length();
-            assertEquals(valueString, value, Integer.parseInt(valueString, start, end, radix));
-            if (value > 0) {
-              valueString = prefix + '+' + Long.toString(value, radix) + postfix;
-              end++;
-              assertEquals(valueString, value, Integer.parseInt(valueString, start, end, radix));
-            }
-          }
-        }
-      }
-    }
-
-    try {
-      throw new AssertionError(Integer.parseInt("0", 0, 1, Character.MIN_RADIX - 1));
-    } catch (IllegalArgumentException expected) {
-    }
-    try {
-      throw new AssertionError(Integer.parseInt("0", 0, 1, Character.MAX_RADIX + 1));
-    } catch (IllegalArgumentException expected) {
-    }
-
-    try {
-      throw new AssertionError(Integer.parseInt("", 0, 0, 16));
-    } catch (NumberFormatException expected) {
-    }
-    try {
-      throw new AssertionError(Integer.parseInt("-", 0, 1, 16));
-    } catch (NumberFormatException expected) {
-    }
-    try {
-      throw new AssertionError(Integer.parseInt("+", 0, 1, 16));
-    } catch (NumberFormatException expected) {
-    }
-
-    try {
-      throw new AssertionError(Integer.parseInt("+a", 0, 2, 10));
-    } catch (NumberFormatException expected) {
-    }
-
-    long overflow = 73709551616L;
-    for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
-      for (String prefix : new String[] {"", "x", "xxx"}) {
-        for (String postfix : new String[] {"", "x", "xxx"}) {
-          String overflowString = prefix + Long.toString(overflow, radix) + postfix;
-          int start = prefix.length();
-          int end = overflowString.length() - postfix.length();
-          try {
-            throw new AssertionError(Integer.parseInt(overflowString, start, end, radix));
-          } catch (NumberFormatException expected) {
-          }
-          String underflowString = prefix + '-' + Long.toString(overflow, radix) + postfix;
-          start = prefix.length();
-          end = underflowString.length() - postfix.length();
-          try {
-            throw new AssertionError(Integer.parseInt(underflowString, start, end, radix));
-          } catch (NumberFormatException expected) {
-          }
-        }
-      }
-    }
-  }
-
-  private static void testParseUnsignedIntegerSubsequenceWithRadix() {
-    for (int value : interestingValues) {
-      for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
-        for (String prefix : new String[] {"", "x", "xxx"}) {
-          for (String postfix : new String[] {"", "x", "xxx"}) {
-            String unsignedIntergerString = Long.toString(Integer.toUnsignedLong(value), radix);
-            String valueString = prefix + unsignedIntergerString + postfix;
-            int start = prefix.length();
-            int end = valueString.length() - postfix.length();
-            assertEquals(
-                valueString, value, Integer.parseUnsignedInt(valueString, start, end, radix));
-            if (value > 0) {
-              valueString = prefix + '+' + unsignedIntergerString + postfix;
-              end++;
-              assertEquals(
-                  valueString, value, Integer.parseUnsignedInt(valueString, start, end, radix));
-            }
-          }
-        }
-      }
-    }
-
-    try {
-      throw new AssertionError(Integer.parseUnsignedInt("0", 0, 1, Character.MIN_RADIX - 1));
-    } catch (IllegalArgumentException expected) {
-    }
-    try {
-      throw new AssertionError(Integer.parseUnsignedInt("0", 0, 1, Character.MAX_RADIX + 1));
-    } catch (IllegalArgumentException expected) {
-    }
-
-    try {
-      throw new AssertionError(Integer.parseUnsignedInt("", 0, 0, 16));
-    } catch (NumberFormatException expected) {
-    }
-    try {
-      throw new AssertionError(Integer.parseUnsignedInt("-", 0, 1, 16));
-    } catch (NumberFormatException expected) {
-    }
-    try {
-      throw new AssertionError(Integer.parseUnsignedInt("+", 0, 1, 16));
-    } catch (NumberFormatException expected) {
-    }
-
-    try {
-      throw new AssertionError(Integer.parseUnsignedInt("+a", 0, 2, 10));
-    } catch (NumberFormatException expected) {
-    }
-
-    long overflow = 73709551616L;
-    for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
-      for (String prefix : new String[] {"", "x", "xxx"}) {
-        for (String postfix : new String[] {"", "x", "xxx"}) {
-          String overflowString = prefix + Long.toString(overflow, radix) + postfix;
-          int start = prefix.length();
-          int end = overflowString.length() - postfix.length();
-          try {
-            throw new AssertionError(Integer.parseUnsignedInt(overflowString, start, end, radix));
-          } catch (NumberFormatException expected) {
-          }
-        }
-      }
-    }
-  }
-
-  private static void assertEquals(String m, int expected, int actual) {
-    if (expected != actual) {
-      throw new AssertionError(m + " Expected <" + expected + "> but was <" + actual + '>');
-    }
-  }
-}
diff --git a/src/test/examplesJava9/backport/IntegerBackportJava9Test.java b/src/test/examplesJava9/backport/IntegerBackportJava9Test.java
new file mode 100644
index 0000000..cbafce8
--- /dev/null
+++ b/src/test/examplesJava9/backport/IntegerBackportJava9Test.java
@@ -0,0 +1,196 @@
+// Copyright (c) 2021, 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 backport;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.desugar.backports.AbstractBackportTest;
+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 IntegerBackportJava9Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return TestBase.getTestParameters()
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
+        .withDexRuntimes()
+        .withAllApiLevelsAlsoForCf()
+        .build();
+  }
+
+  public IntegerBackportJava9Test(TestParameters parameters) {
+    super(parameters, Integer.class, IntegerBackportJava9Main.class);
+    // Note: The methods in this test exist in android.jar from Android T. When R8 builds targeting
+    // Java 11 move these tests to IntegerBackportTest (out of examplesJava9).
+
+    registerTarget(AndroidApiLevel.O, 1);
+    registerTarget(AndroidApiLevel.T, 20);
+  }
+
+  public static class IntegerBackportJava9Main {
+    private static final int[] interestingValues = {
+      Integer.MIN_VALUE,
+      Integer.MAX_VALUE,
+      Short.MIN_VALUE,
+      Short.MAX_VALUE,
+      Byte.MIN_VALUE,
+      Byte.MAX_VALUE,
+      0,
+      -1,
+      1,
+      -42,
+      42
+    };
+
+    public static void main(String[] args) {
+      testParseIntegerSubsequenceWithRadix();
+      testParseUnsignedIntegerSubsequenceWithRadix();
+    }
+
+    private static void testParseIntegerSubsequenceWithRadix() {
+      for (int value : interestingValues) {
+        for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
+          for (String prefix : new String[] {"", "x", "xxx"}) {
+            for (String postfix : new String[] {"", "x", "xxx"}) {
+              String valueString = prefix + Long.toString(value, radix) + postfix;
+              int start = prefix.length();
+              int end = valueString.length() - postfix.length();
+              assertEquals(valueString, value, Integer.parseInt(valueString, start, end, radix));
+              if (value > 0) {
+                valueString = prefix + '+' + Long.toString(value, radix) + postfix;
+                end++;
+                assertEquals(valueString, value, Integer.parseInt(valueString, start, end, radix));
+              }
+            }
+          }
+        }
+      }
+
+      try {
+        throw new AssertionError(Integer.parseInt("0", 0, 1, Character.MIN_RADIX - 1));
+      } catch (IllegalArgumentException expected) {
+      }
+      try {
+        throw new AssertionError(Integer.parseInt("0", 0, 1, Character.MAX_RADIX + 1));
+      } catch (IllegalArgumentException expected) {
+      }
+
+      try {
+        throw new AssertionError(Integer.parseInt("", 0, 0, 16));
+      } catch (NumberFormatException expected) {
+      }
+      try {
+        throw new AssertionError(Integer.parseInt("-", 0, 1, 16));
+      } catch (NumberFormatException expected) {
+      }
+      try {
+        throw new AssertionError(Integer.parseInt("+", 0, 1, 16));
+      } catch (NumberFormatException expected) {
+      }
+
+      try {
+        throw new AssertionError(Integer.parseInt("+a", 0, 2, 10));
+      } catch (NumberFormatException expected) {
+      }
+
+      long overflow = 73709551616L;
+      for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
+        for (String prefix : new String[] {"", "x", "xxx"}) {
+          for (String postfix : new String[] {"", "x", "xxx"}) {
+            String overflowString = prefix + Long.toString(overflow, radix) + postfix;
+            int start = prefix.length();
+            int end = overflowString.length() - postfix.length();
+            try {
+              throw new AssertionError(Integer.parseInt(overflowString, start, end, radix));
+            } catch (NumberFormatException expected) {
+            }
+            String underflowString = prefix + '-' + Long.toString(overflow, radix) + postfix;
+            start = prefix.length();
+            end = underflowString.length() - postfix.length();
+            try {
+              throw new AssertionError(Integer.parseInt(underflowString, start, end, radix));
+            } catch (NumberFormatException expected) {
+            }
+          }
+        }
+      }
+    }
+
+    private static void testParseUnsignedIntegerSubsequenceWithRadix() {
+      for (int value : interestingValues) {
+        for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
+          for (String prefix : new String[] {"", "x", "xxx"}) {
+            for (String postfix : new String[] {"", "x", "xxx"}) {
+              String unsignedIntergerString = Long.toString(Integer.toUnsignedLong(value), radix);
+              String valueString = prefix + unsignedIntergerString + postfix;
+              int start = prefix.length();
+              int end = valueString.length() - postfix.length();
+              assertEquals(
+                  valueString, value, Integer.parseUnsignedInt(valueString, start, end, radix));
+              if (value > 0) {
+                valueString = prefix + '+' + unsignedIntergerString + postfix;
+                end++;
+                assertEquals(
+                    valueString, value, Integer.parseUnsignedInt(valueString, start, end, radix));
+              }
+            }
+          }
+        }
+      }
+
+      try {
+        throw new AssertionError(Integer.parseUnsignedInt("0", 0, 1, Character.MIN_RADIX - 1));
+      } catch (IllegalArgumentException expected) {
+      }
+      try {
+        throw new AssertionError(Integer.parseUnsignedInt("0", 0, 1, Character.MAX_RADIX + 1));
+      } catch (IllegalArgumentException expected) {
+      }
+
+      try {
+        throw new AssertionError(Integer.parseUnsignedInt("", 0, 0, 16));
+      } catch (NumberFormatException expected) {
+      }
+      try {
+        throw new AssertionError(Integer.parseUnsignedInt("-", 0, 1, 16));
+      } catch (NumberFormatException expected) {
+      }
+      try {
+        throw new AssertionError(Integer.parseUnsignedInt("+", 0, 1, 16));
+      } catch (NumberFormatException expected) {
+      }
+
+      try {
+        throw new AssertionError(Integer.parseUnsignedInt("+a", 0, 2, 10));
+      } catch (NumberFormatException expected) {
+      }
+
+      long overflow = 73709551616L;
+      for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
+        for (String prefix : new String[] {"", "x", "xxx"}) {
+          for (String postfix : new String[] {"", "x", "xxx"}) {
+            String overflowString = prefix + Long.toString(overflow, radix) + postfix;
+            int start = prefix.length();
+            int end = overflowString.length() - postfix.length();
+            try {
+              throw new AssertionError(Integer.parseUnsignedInt(overflowString, start, end, radix));
+            } catch (NumberFormatException expected) {
+            }
+          }
+        }
+      }
+    }
+
+    private static void assertEquals(String m, int expected, int actual) {
+      if (expected != actual) {
+        throw new AssertionError(m + " Expected <" + expected + "> but was <" + actual + '>');
+      }
+    }
+  }
+}
diff --git a/src/test/examplesJava9/backport/ListBackportJava9Main.java b/src/test/examplesJava9/backport/ListBackportJava9Main.java
deleted file mode 100644
index 4c8ae88..0000000
--- a/src/test/examplesJava9/backport/ListBackportJava9Main.java
+++ /dev/null
@@ -1,170 +0,0 @@
-// 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 backport;
-
-import java.util.List;
-
-public class ListBackportJava9Main {
-
-  public static void main(String[] args) {
-    testOf0();
-    testOf1();
-    testOf2();
-    testOf10();
-    testOfVarargs();
-  }
-
-  private static void testOf0() {
-    List<Object> ofObject = List.of();
-    assertEquals(0, ofObject.size());
-    assertMutationNotAllowed(ofObject);
-
-    List<Integer> ofInteger = List.of();
-    assertEquals(0, ofInteger.size());
-    assertMutationNotAllowed(ofObject);
-  }
-
-  private static void testOf1() {
-    Object anObject = new Object();
-    List<Object> ofObject = List.of(anObject);
-    assertEquals(1, ofObject.size());
-    assertSame(anObject, ofObject.get(0));
-    assertMutationNotAllowed(ofObject);
-
-    List<Integer> ofInteger = List.of(1);
-    assertEquals(1, ofInteger.size());
-    assertEquals(1, ofInteger.get(0));
-
-    try {
-      List.of((Object) null);
-      throw new AssertionError();
-    } catch (NullPointerException expected) {
-    }
-  }
-
-  private static void testOf2() {
-    Object anObject0 = new Object();
-    Object anObject1 = new Object();
-    List<Object> ofObject = List.of(anObject0, anObject1);
-    assertEquals(2, ofObject.size());
-    assertSame(anObject0, ofObject.get(0));
-    assertSame(anObject1, ofObject.get(1));
-    assertMutationNotAllowed(ofObject);
-
-    List<Integer> ofInteger = List.of(1, 2);
-    assertEquals(2, ofInteger.size());
-    assertEquals(1, ofInteger.get(0));
-    assertEquals(2, ofInteger.get(1));
-
-    List<Object> ofMixed = List.of(anObject0, 1);
-    assertEquals(2, ofMixed.size());
-    assertSame(anObject0, ofMixed.get(0));
-    assertEquals(1, ofMixed.get(1));
-    assertMutationNotAllowed(ofMixed);
-
-    try {
-      List.of(1, null);
-      throw new AssertionError();
-    } catch (NullPointerException expected) {
-    }
-  }
-
-  private static void testOf10() {
-    Object anObject0 = new Object();
-    Object anObject6 = new Object();
-    Object anObject9 = new Object();
-    List<Object> ofObject =
-        List.of(anObject0, new Object(), new Object(), new Object(), new Object(), new Object(),
-            anObject6, new Object(), new Object(), anObject9);
-    assertEquals(10, ofObject.size());
-    assertSame(anObject0, ofObject.get(0));
-    assertSame(anObject6, ofObject.get(6));
-    assertSame(anObject9, ofObject.get(9));
-    assertMutationNotAllowed(ofObject);
-
-    List<Integer> ofInteger = List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
-    assertEquals(10, ofInteger.size());
-    assertEquals(0, ofInteger.get(0));
-    assertEquals(6, ofInteger.get(6));
-    assertEquals(9, ofInteger.get(9));
-
-    List<Object> ofMixed = List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, anObject9);
-    assertEquals(10, ofMixed.size());
-    assertEquals(0, ofMixed.get(0));
-    assertEquals(6, ofMixed.get(6));
-    assertSame(anObject9, ofMixed.get(9));
-    assertMutationNotAllowed(ofMixed);
-
-    try {
-      List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, null);
-      throw new AssertionError();
-    } catch (NullPointerException expected) {
-    }
-  }
-
-  private static void testOfVarargs() {
-    Object anObject0 = new Object();
-    Object anObject6 = new Object();
-    Object anObject10 = new Object();
-    List<Object> ofObject =
-        List.of(anObject0, new Object(), new Object(), new Object(), new Object(), new Object(),
-            anObject6, new Object(), new Object(), new Object(), anObject10);
-    assertEquals(11, ofObject.size());
-    assertSame(anObject0, ofObject.get(0));
-    assertSame(anObject6, ofObject.get(6));
-    assertSame(anObject10, ofObject.get(10));
-    assertMutationNotAllowed(ofObject);
-
-    List<Integer> ofInteger = List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
-    assertEquals(11, ofInteger.size());
-    assertEquals(0, ofInteger.get(0));
-    assertEquals(6, ofInteger.get(6));
-    assertEquals(10, ofInteger.get(10));
-
-    List<Object> ofMixed = List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, anObject10);
-    assertEquals(11, ofMixed.size());
-    assertEquals(0, ofMixed.get(0));
-    assertEquals(6, ofMixed.get(6));
-    assertSame(anObject10, ofMixed.get(10));
-    assertMutationNotAllowed(ofMixed);
-
-    // Ensure the supplied mutable array is not used directly since it is mutable.
-    Object[] mutableArray = { anObject0 };
-    List<Object> ofMutableArray = List.of(mutableArray);
-    mutableArray[0] = anObject10;
-    assertSame(anObject0, ofMutableArray.get(0));
-
-    try {
-      List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, null);
-      throw new AssertionError();
-    } catch (NullPointerException expected) {
-    }
-  }
-
-  private static void assertMutationNotAllowed(List<Object> ofObject) {
-    try {
-      ofObject.add(new Object());
-      throw new AssertionError();
-    } catch (UnsupportedOperationException expected) {
-    }
-    try {
-      ofObject.set(0, new Object());
-      throw new AssertionError();
-    } catch (UnsupportedOperationException expected) {
-    }
-  }
-
-  private static void assertSame(Object expected, Object actual) {
-    if (expected != actual) {
-      throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
-    }
-  }
-
-  private static void assertEquals(Object expected, Object actual) {
-    if (expected != actual && !expected.equals(actual)) {
-      throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
-    }
-  }
-}
diff --git a/src/test/examplesJava9/backport/ListBackportJava9Test.java b/src/test/examplesJava9/backport/ListBackportJava9Test.java
new file mode 100644
index 0000000..f7ea015
--- /dev/null
+++ b/src/test/examplesJava9/backport/ListBackportJava9Test.java
@@ -0,0 +1,244 @@
+// 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 backport;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.desugar.backports.AbstractBackportTest;
+import com.android.tools.r8.desugar.backports.IgnoreInvokes;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.util.List;
+import org.hamcrest.CoreMatchers;
+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 ListBackportJava9Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return TestBase.getTestParameters()
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
+        .withDexRuntimes()
+        .withAllApiLevelsAlsoForCf()
+        .build();
+  }
+
+  public ListBackportJava9Test(TestParameters parameters) {
+    super(parameters, List.class, ListBackportJava9Main.class);
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to ListBackportTest.
+
+    // Available since API 1 and used to test created lists.
+    ignoreInvokes("add");
+    ignoreInvokes("get");
+    ignoreInvokes("set");
+    ignoreInvokes("size");
+
+    // List.of added in API 30.
+    registerTarget(AndroidApiLevel.R, 18);
+  }
+
+  @Test
+  public void desugaringApiLevelR() throws Exception {
+    // TODO(b/154759404): This test should start to fail when testing on an Android R VM.
+    // This has now been checked with S, when R testing is added check and remove this.
+    if (parameters.getRuntime().isDex() && parameters.getApiLevel().isEqualTo(AndroidApiLevel.Q)) {
+      testForD8()
+          .setMinApi(AndroidApiLevel.R)
+          .addProgramClasses(MiniAssert.class, IgnoreInvokes.class)
+          .addProgramClasses(ListBackportJava9Main.class)
+          .setIncludeClassesChecksum(true)
+          .compile()
+          .run(parameters.getRuntime(), ListBackportJava9Main.class)
+          .assertFailureWithErrorThatMatches(
+              CoreMatchers.containsString("java.lang.NoSuchMethodError"));
+    }
+  }
+
+  public static class ListBackportJava9Main {
+
+    public static void main(String[] args) {
+      testOf0();
+      testOf1();
+      testOf2();
+      testOf10();
+      testOfVarargs();
+    }
+
+    private static void testOf0() {
+      List<Object> ofObject = List.of();
+      assertEquals(0, ofObject.size());
+      assertMutationNotAllowed(ofObject);
+
+      List<Integer> ofInteger = List.of();
+      assertEquals(0, ofInteger.size());
+      assertMutationNotAllowed(ofObject);
+    }
+
+    private static void testOf1() {
+      Object anObject = new Object();
+      List<Object> ofObject = List.of(anObject);
+      assertEquals(1, ofObject.size());
+      assertSame(anObject, ofObject.get(0));
+      assertMutationNotAllowed(ofObject);
+
+      List<Integer> ofInteger = List.of(1);
+      assertEquals(1, ofInteger.size());
+      assertEquals(1, ofInteger.get(0));
+
+      try {
+        List.of((Object) null);
+        throw new AssertionError();
+      } catch (NullPointerException expected) {
+      }
+    }
+
+    private static void testOf2() {
+      Object anObject0 = new Object();
+      Object anObject1 = new Object();
+      List<Object> ofObject = List.of(anObject0, anObject1);
+      assertEquals(2, ofObject.size());
+      assertSame(anObject0, ofObject.get(0));
+      assertSame(anObject1, ofObject.get(1));
+      assertMutationNotAllowed(ofObject);
+
+      List<Integer> ofInteger = List.of(1, 2);
+      assertEquals(2, ofInteger.size());
+      assertEquals(1, ofInteger.get(0));
+      assertEquals(2, ofInteger.get(1));
+
+      List<Object> ofMixed = List.of(anObject0, 1);
+      assertEquals(2, ofMixed.size());
+      assertSame(anObject0, ofMixed.get(0));
+      assertEquals(1, ofMixed.get(1));
+      assertMutationNotAllowed(ofMixed);
+
+      try {
+        List.of(1, null);
+        throw new AssertionError();
+      } catch (NullPointerException expected) {
+      }
+    }
+
+    private static void testOf10() {
+      Object anObject0 = new Object();
+      Object anObject6 = new Object();
+      Object anObject9 = new Object();
+      List<Object> ofObject =
+          List.of(
+              anObject0,
+              new Object(),
+              new Object(),
+              new Object(),
+              new Object(),
+              new Object(),
+              anObject6,
+              new Object(),
+              new Object(),
+              anObject9);
+      assertEquals(10, ofObject.size());
+      assertSame(anObject0, ofObject.get(0));
+      assertSame(anObject6, ofObject.get(6));
+      assertSame(anObject9, ofObject.get(9));
+      assertMutationNotAllowed(ofObject);
+
+      List<Integer> ofInteger = List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+      assertEquals(10, ofInteger.size());
+      assertEquals(0, ofInteger.get(0));
+      assertEquals(6, ofInteger.get(6));
+      assertEquals(9, ofInteger.get(9));
+
+      List<Object> ofMixed = List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, anObject9);
+      assertEquals(10, ofMixed.size());
+      assertEquals(0, ofMixed.get(0));
+      assertEquals(6, ofMixed.get(6));
+      assertSame(anObject9, ofMixed.get(9));
+      assertMutationNotAllowed(ofMixed);
+
+      try {
+        List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, null);
+        throw new AssertionError();
+      } catch (NullPointerException expected) {
+      }
+    }
+
+    private static void testOfVarargs() {
+      Object anObject0 = new Object();
+      Object anObject6 = new Object();
+      Object anObject10 = new Object();
+      List<Object> ofObject =
+          List.of(
+              anObject0,
+              new Object(),
+              new Object(),
+              new Object(),
+              new Object(),
+              new Object(),
+              anObject6,
+              new Object(),
+              new Object(),
+              new Object(),
+              anObject10);
+      assertEquals(11, ofObject.size());
+      assertSame(anObject0, ofObject.get(0));
+      assertSame(anObject6, ofObject.get(6));
+      assertSame(anObject10, ofObject.get(10));
+      assertMutationNotAllowed(ofObject);
+
+      List<Integer> ofInteger = List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+      assertEquals(11, ofInteger.size());
+      assertEquals(0, ofInteger.get(0));
+      assertEquals(6, ofInteger.get(6));
+      assertEquals(10, ofInteger.get(10));
+
+      List<Object> ofMixed = List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, anObject10);
+      assertEquals(11, ofMixed.size());
+      assertEquals(0, ofMixed.get(0));
+      assertEquals(6, ofMixed.get(6));
+      assertSame(anObject10, ofMixed.get(10));
+      assertMutationNotAllowed(ofMixed);
+
+      // Ensure the supplied mutable array is not used directly since it is mutable.
+      Object[] mutableArray = {anObject0};
+      List<Object> ofMutableArray = List.of(mutableArray);
+      mutableArray[0] = anObject10;
+      assertSame(anObject0, ofMutableArray.get(0));
+
+      try {
+        List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, null);
+        throw new AssertionError();
+      } catch (NullPointerException expected) {
+      }
+    }
+
+    private static void assertMutationNotAllowed(List<Object> ofObject) {
+      try {
+        ofObject.add(new Object());
+        throw new AssertionError();
+      } catch (UnsupportedOperationException expected) {
+      }
+      try {
+        ofObject.set(0, new Object());
+        throw new AssertionError();
+      } catch (UnsupportedOperationException expected) {
+      }
+    }
+
+    private static void assertSame(Object expected, Object actual) {
+      if (expected != actual) {
+        throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+      }
+    }
+
+    private static void assertEquals(Object expected, Object actual) {
+      if (expected != actual && !expected.equals(actual)) {
+        throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+      }
+    }
+  }
+}
diff --git a/src/test/examplesJava9/backport/LongBackportJava9Main.java b/src/test/examplesJava9/backport/LongBackportJava9Main.java
deleted file mode 100644
index f24c337..0000000
--- a/src/test/examplesJava9/backport/LongBackportJava9Main.java
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright (c) 2021, 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 backport;
-
-import java.math.BigInteger;
-
-public final class LongBackportJava9Main {
-  private static final long[] interestingValues = {
-    Long.MIN_VALUE,
-    Long.MAX_VALUE,
-    Integer.MIN_VALUE,
-    Integer.MAX_VALUE,
-    Short.MIN_VALUE,
-    Short.MAX_VALUE,
-    Byte.MIN_VALUE,
-    Byte.MAX_VALUE,
-    0L,
-    -1L,
-    1L,
-    -42L,
-    42L
-  };
-
-  public static void main(String[] args) {
-    testParseLongSubsequenceWithRadix();
-    testParseUnsignedLongSubsequenceWithRadix();
-  }
-
-  private static void testParseLongSubsequenceWithRadix() {
-    for (long value : interestingValues) {
-      for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
-        for (String prefix : new String[] {"", "x", "xxx"}) {
-          for (String postfix : new String[] {"", "x", "xxx"}) {
-            String valueString = prefix + Long.toString(value, radix) + postfix;
-            int start = prefix.length();
-            int end = valueString.length() - postfix.length();
-            assertEquals(valueString, value, Long.parseLong(valueString, start, end, radix));
-            if (value > 0) {
-              valueString = prefix + "+" + Long.toString(value, radix) + postfix;
-              end++;
-              assertEquals(valueString, value, Long.parseLong(valueString, start, end, radix));
-            }
-          }
-        }
-      }
-    }
-
-    try {
-      throw new AssertionError(Long.parseLong("0", 0, 1, Character.MIN_RADIX - 1));
-    } catch (IllegalArgumentException expected) {
-    }
-    try {
-      throw new AssertionError(Long.parseLong("0", 0, 1, Character.MAX_RADIX + 1));
-    } catch (IllegalArgumentException expected) {
-    }
-
-    try {
-      throw new AssertionError(Long.parseLong("", 0, 0, 16));
-    } catch (NumberFormatException expected) {
-    }
-    try {
-      throw new AssertionError(Long.parseLong("-", 0, 1, 16));
-    } catch (NumberFormatException expected) {
-    }
-    try {
-      throw new AssertionError(Long.parseLong("+", 0, 1, 16));
-    } catch (NumberFormatException expected) {
-    }
-
-    try {
-      throw new AssertionError(Long.parseLong("+a", 0, 2, 10));
-    } catch (NumberFormatException expected) {
-    }
-
-    BigInteger overflow = new BigInteger("18446744073709551616");
-    for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
-      for (String prefix : new String[] {"", "x", "xxx"}) {
-        for (String postfix : new String[] {"", "x", "xxx"}) {
-          String overflowString = prefix + overflow.toString(radix) + postfix;
-          int start = prefix.length();
-          int end = overflowString.length() - postfix.length();
-          try {
-            throw new AssertionError(Long.parseLong(overflowString, start, end, radix));
-          } catch (NumberFormatException expected) {
-          }
-        }
-      }
-    }
-  }
-
-  private static void testParseUnsignedLongSubsequenceWithRadix() {
-    for (long value : interestingValues) {
-      for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
-        for (String prefix : new String[] {"", "x", "xxx"}) {
-          for (String postfix : new String[] {"", "x", "xxx"}) {
-            String valueString = prefix + unsignedLongToBigInteger(value).toString(radix) + postfix;
-            int start = prefix.length();
-            int end = valueString.length() - postfix.length();
-            assertEquals(
-                valueString, value, Long.parseUnsignedLong(valueString, start, end, radix));
-            valueString = prefix + "+" + unsignedLongToBigInteger(value).toString(radix) + postfix;
-            end++;
-            assertEquals(
-                valueString, value, Long.parseUnsignedLong(valueString, start, end, radix));
-          }
-        }
-      }
-    }
-
-    try {
-      throw new AssertionError(Long.parseUnsignedLong("0", 0, 1, Character.MIN_RADIX - 1));
-    } catch (IllegalArgumentException expected) {
-    }
-    try {
-      throw new AssertionError(Long.parseUnsignedLong("0", 0, 1, Character.MAX_RADIX + 1));
-    } catch (IllegalArgumentException expected) {
-    }
-
-    try {
-      throw new AssertionError(Long.parseUnsignedLong("", 0, 0, 16));
-    } catch (NumberFormatException expected) {
-    }
-    try {
-      throw new AssertionError(Long.parseUnsignedLong("+", 0, 1, 16));
-    } catch (NumberFormatException expected) {
-    }
-
-    try {
-      throw new AssertionError(Long.parseUnsignedLong("+a", 0, 2, 10));
-    } catch (NumberFormatException expected) {
-    }
-
-    BigInteger overflow = new BigInteger("18446744073709551616");
-    for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
-      for (String prefix : new String[] {"", "x", "xxx", "+", "x+", "xxx+"}) {
-        for (String postfix : new String[] {"", "x", "xxx"}) {
-          String overflowString = prefix + overflow.toString(radix) + postfix;
-          int start = prefix.length();
-          int end = overflowString.length() - postfix.length();
-          try {
-            throw new AssertionError(Long.parseUnsignedLong(overflowString, start, end, radix));
-          } catch (NumberFormatException expected) {
-          }
-        }
-      }
-    }
-  }
-
-  private static BigInteger unsignedLongToBigInteger(long value) {
-    BigInteger bigInt = BigInteger.valueOf(value & 0x7fffffffffffffffL);
-    if (value < 0) {
-      bigInt = bigInt.setBit(Long.SIZE - 1);
-    }
-    return bigInt;
-  }
-
-  private static void assertEquals(String m, long expected, long actual) {
-    if (expected != actual) {
-      throw new AssertionError(m + " Expected <" + expected + "> but was <" + actual + '>');
-    }
-  }
-}
diff --git a/src/test/examplesJava9/backport/LongBackportJava9Test.java b/src/test/examplesJava9/backport/LongBackportJava9Test.java
new file mode 100644
index 0000000..cb64b6d
--- /dev/null
+++ b/src/test/examplesJava9/backport/LongBackportJava9Test.java
@@ -0,0 +1,196 @@
+// Copyright (c) 2021, 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 backport;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.desugar.backports.AbstractBackportTest;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.math.BigInteger;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public final class LongBackportJava9Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return TestBase.getTestParameters()
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
+        .withDexRuntimes()
+        .withAllApiLevelsAlsoForCf()
+        .build();
+  }
+
+  public LongBackportJava9Test(TestParameters parameters) {
+    super(parameters, Long.class, LongBackportJava9Main.class);
+    // Note: The methods in this test exist in android.jar from Android T. When R8 builds targeting
+    // Java 11 move these tests to LongBackportTest (out of examplesJava9).
+
+    ignoreInvokes("toString");
+
+    registerTarget(AndroidApiLevel.T, 17);
+  }
+
+  public static class LongBackportJava9Main {
+    private static final long[] interestingValues = {
+      Long.MIN_VALUE,
+      Long.MAX_VALUE,
+      Integer.MIN_VALUE,
+      Integer.MAX_VALUE,
+      Short.MIN_VALUE,
+      Short.MAX_VALUE,
+      Byte.MIN_VALUE,
+      Byte.MAX_VALUE,
+      0L,
+      -1L,
+      1L,
+      -42L,
+      42L
+    };
+
+    public static void main(String[] args) {
+      testParseLongSubsequenceWithRadix();
+      testParseUnsignedLongSubsequenceWithRadix();
+    }
+
+    private static void testParseLongSubsequenceWithRadix() {
+      for (long value : interestingValues) {
+        for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
+          for (String prefix : new String[] {"", "x", "xxx"}) {
+            for (String postfix : new String[] {"", "x", "xxx"}) {
+              String valueString = prefix + Long.toString(value, radix) + postfix;
+              int start = prefix.length();
+              int end = valueString.length() - postfix.length();
+              assertEquals(valueString, value, Long.parseLong(valueString, start, end, radix));
+              if (value > 0) {
+                valueString = prefix + "+" + Long.toString(value, radix) + postfix;
+                end++;
+                assertEquals(valueString, value, Long.parseLong(valueString, start, end, radix));
+              }
+            }
+          }
+        }
+      }
+
+      try {
+        throw new AssertionError(Long.parseLong("0", 0, 1, Character.MIN_RADIX - 1));
+      } catch (IllegalArgumentException expected) {
+      }
+      try {
+        throw new AssertionError(Long.parseLong("0", 0, 1, Character.MAX_RADIX + 1));
+      } catch (IllegalArgumentException expected) {
+      }
+
+      try {
+        throw new AssertionError(Long.parseLong("", 0, 0, 16));
+      } catch (NumberFormatException expected) {
+      }
+      try {
+        throw new AssertionError(Long.parseLong("-", 0, 1, 16));
+      } catch (NumberFormatException expected) {
+      }
+      try {
+        throw new AssertionError(Long.parseLong("+", 0, 1, 16));
+      } catch (NumberFormatException expected) {
+      }
+
+      try {
+        throw new AssertionError(Long.parseLong("+a", 0, 2, 10));
+      } catch (NumberFormatException expected) {
+      }
+
+      BigInteger overflow = new BigInteger("18446744073709551616");
+      for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
+        for (String prefix : new String[] {"", "x", "xxx"}) {
+          for (String postfix : new String[] {"", "x", "xxx"}) {
+            String overflowString = prefix + overflow.toString(radix) + postfix;
+            int start = prefix.length();
+            int end = overflowString.length() - postfix.length();
+            try {
+              throw new AssertionError(Long.parseLong(overflowString, start, end, radix));
+            } catch (NumberFormatException expected) {
+            }
+          }
+        }
+      }
+    }
+
+    private static void testParseUnsignedLongSubsequenceWithRadix() {
+      for (long value : interestingValues) {
+        for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
+          for (String prefix : new String[] {"", "x", "xxx"}) {
+            for (String postfix : new String[] {"", "x", "xxx"}) {
+              String valueString =
+                  prefix + unsignedLongToBigInteger(value).toString(radix) + postfix;
+              int start = prefix.length();
+              int end = valueString.length() - postfix.length();
+              assertEquals(
+                  valueString, value, Long.parseUnsignedLong(valueString, start, end, radix));
+              valueString =
+                  prefix + "+" + unsignedLongToBigInteger(value).toString(radix) + postfix;
+              end++;
+              assertEquals(
+                  valueString, value, Long.parseUnsignedLong(valueString, start, end, radix));
+            }
+          }
+        }
+      }
+
+      try {
+        throw new AssertionError(Long.parseUnsignedLong("0", 0, 1, Character.MIN_RADIX - 1));
+      } catch (IllegalArgumentException expected) {
+      }
+      try {
+        throw new AssertionError(Long.parseUnsignedLong("0", 0, 1, Character.MAX_RADIX + 1));
+      } catch (IllegalArgumentException expected) {
+      }
+
+      try {
+        throw new AssertionError(Long.parseUnsignedLong("", 0, 0, 16));
+      } catch (NumberFormatException expected) {
+      }
+      try {
+        throw new AssertionError(Long.parseUnsignedLong("+", 0, 1, 16));
+      } catch (NumberFormatException expected) {
+      }
+
+      try {
+        throw new AssertionError(Long.parseUnsignedLong("+a", 0, 2, 10));
+      } catch (NumberFormatException expected) {
+      }
+
+      BigInteger overflow = new BigInteger("18446744073709551616");
+      for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
+        for (String prefix : new String[] {"", "x", "xxx", "+", "x+", "xxx+"}) {
+          for (String postfix : new String[] {"", "x", "xxx"}) {
+            String overflowString = prefix + overflow.toString(radix) + postfix;
+            int start = prefix.length();
+            int end = overflowString.length() - postfix.length();
+            try {
+              throw new AssertionError(Long.parseUnsignedLong(overflowString, start, end, radix));
+            } catch (NumberFormatException expected) {
+            }
+          }
+        }
+      }
+    }
+
+    private static BigInteger unsignedLongToBigInteger(long value) {
+      BigInteger bigInt = BigInteger.valueOf(value & 0x7fffffffffffffffL);
+      if (value < 0) {
+        bigInt = bigInt.setBit(Long.SIZE - 1);
+      }
+      return bigInt;
+    }
+
+    private static void assertEquals(String m, long expected, long actual) {
+      if (expected != actual) {
+        throw new AssertionError(m + " Expected <" + expected + "> but was <" + actual + '>');
+      }
+    }
+  }
+}
diff --git a/src/test/examplesJava9/backport/MapBackportJava9Main.java b/src/test/examplesJava9/backport/MapBackportJava9Main.java
deleted file mode 100644
index 442fd9b..0000000
--- a/src/test/examplesJava9/backport/MapBackportJava9Main.java
+++ /dev/null
@@ -1,273 +0,0 @@
-// 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 backport;
-
-import java.util.AbstractMap;
-import java.util.Map;
-
-public class MapBackportJava9Main {
-
-  public static void main(String[] args) {
-    testOf0();
-    testOf1();
-    testOf2();
-    testOf10();
-    testOfEntries();
-    testEntry();
-  }
-
-  private static void testOf0() {
-    Map<Object, Object> ofObject = Map.of();
-    assertEquals(0, ofObject.size());
-    assertEquals(null, ofObject.get(new Object()));
-    assertMutationNotAllowed(ofObject);
-
-    Map<Integer, Integer> ofInteger = Map.of();
-    assertEquals(0, ofInteger.size());
-    assertEquals(null, ofInteger.get(0));
-  }
-
-  private static void testOf1() {
-    Object objectKey0 = new Object();
-    Object objectValue0 = new Object();
-    Map<Object, Object> ofObject = Map.of(objectKey0, objectValue0);
-    assertEquals(1, ofObject.size());
-    assertSame(objectValue0, ofObject.get(objectKey0));
-    assertEquals(null, ofObject.get(new Object()));
-    assertMutationNotAllowed(ofObject);
-
-    Map<Integer, Integer> ofInteger = Map.of(0, 0);
-    assertEquals(1, ofInteger.size());
-    assertEquals(0, ofInteger.get(0));
-    assertEquals(null, ofInteger.get(1));
-
-    try {
-      Map.of((Object) null, 1);
-      throw new AssertionError();
-    } catch (NullPointerException expected) {
-    }
-    try {
-      Map.of(1, (Object) null);
-      throw new AssertionError();
-    } catch (NullPointerException expected) {
-    }
-  }
-
-  private static void testOf2() {
-    Object objectKey0 = new Object();
-    Object objectValue0 = new Object();
-    Object objectKey1 = new Object();
-    Object objectValue1 = new Object();
-    Map<Object, Object> ofObject = Map.of(objectKey0, objectValue0, objectKey1, objectValue1);
-    assertEquals(2, ofObject.size());
-    assertSame(objectValue0, ofObject.get(objectKey0));
-    assertSame(objectValue1, ofObject.get(objectKey1));
-    assertEquals(null, ofObject.get(new Object()));
-    assertMutationNotAllowed(ofObject);
-
-    Map<Integer, Integer> ofInteger = Map.of(0, 0, 1, 1);
-    assertEquals(2, ofInteger.size());
-    assertEquals(0, ofInteger.get(0));
-    assertEquals(1, ofInteger.get(1));
-    assertEquals(null, ofInteger.get(3));
-
-    Map<Object, Object> ofMixed = Map.of(objectKey0, 0, objectKey1, 1);
-    assertEquals(2, ofMixed.size());
-    assertEquals(0, ofMixed.get(objectKey0));
-    assertEquals(1, ofMixed.get(objectKey1));
-    assertEquals(null, ofMixed.get(new Object()));
-
-    try {
-      Map.of(1, 1, null, 2);
-      throw new AssertionError();
-    } catch (NullPointerException expected) {
-    }
-    try {
-      Map.of(1, 1, 2, null);
-      throw new AssertionError();
-    } catch (NullPointerException expected) {
-    }
-
-    try {
-      Map.of(1, 1, 1, 2);
-      throw new AssertionError();
-    } catch (IllegalArgumentException expected) {
-      assertEquals("duplicate key: 1", expected.getMessage());
-    }
-  }
-
-  private static void testOf10() {
-    Object objectKey0 = new Object();
-    Object objectValue0 = new Object();
-    Object objectKey6 = new Object();
-    Object objectValue6 = new Object();
-    Object objectKey9 = new Object();
-    Object objectValue9 = new Object();
-    Map<Object, Object> ofObject =
-        Map.of(objectKey0, objectValue0, new Object(), new Object(), new Object(), new Object(),
-            new Object(), new Object(), new Object(), new Object(), new Object(), new Object(),
-            objectKey6, objectValue6, new Object(), new Object(), new Object(), new Object(),
-            objectKey9, objectValue9);
-    assertEquals(10, ofObject.size());
-    assertSame(objectValue0, ofObject.get(objectKey0));
-    assertSame(objectValue6, ofObject.get(objectKey6));
-    assertSame(objectValue9, ofObject.get(objectKey9));
-    assertEquals(null, ofObject.get(new Object()));
-    assertMutationNotAllowed(ofObject);
-
-    Map<Integer, Integer> ofInteger =
-        Map.of(0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9);
-    assertEquals(10, ofInteger.size());
-    assertEquals(0, ofInteger.get(0));
-    assertEquals(6, ofInteger.get(6));
-    assertEquals(9, ofInteger.get(9));
-    assertEquals(null, ofInteger.get(10));
-
-    Map<Object, Object> ofMixed =
-        Map.of(0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, objectKey9, objectValue9);
-    assertEquals(10, ofMixed.size());
-    assertEquals(0, ofMixed.get(0));
-    assertEquals(6, ofMixed.get(6));
-    assertSame(objectValue9, ofMixed.get(objectKey9));
-    assertEquals(null, ofMixed.get(9));
-
-    try {
-      Map.of(0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, null, objectValue9);
-      throw new AssertionError();
-    } catch (NullPointerException expected) {
-    }
-    try {
-      Map.of(0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, objectKey9, null);
-      throw new AssertionError();
-    } catch (NullPointerException expected) {
-    }
-
-    try {
-      Map.of(0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 0, 9);
-      throw new AssertionError();
-    } catch (IllegalArgumentException expected) {
-      assertEquals("duplicate key: 0", expected.getMessage());
-    }
-  }
-
-  private static void testOfEntries() {
-    Object objectKey0 = new Object();
-    Object objectValue0 = new Object();
-    Object objectKey1 = new Object();
-    Object objectValue1 = new Object();
-    Map<Object, Object> ofObject = Map.ofEntries(
-        new AbstractMap.SimpleEntry<>(objectKey0, objectValue0),
-        new AbstractMap.SimpleEntry<>(objectKey1, objectValue1));
-    assertEquals(2, ofObject.size());
-    assertSame(objectValue0, ofObject.get(objectKey0));
-    assertSame(objectValue1, ofObject.get(objectKey1));
-    assertEquals(null, ofObject.get(new Object()));
-    assertMutationNotAllowed(ofObject);
-
-    Map<Integer, Integer> ofInteger = Map.ofEntries(
-        new AbstractMap.SimpleEntry<>(0, 0),
-        new AbstractMap.SimpleEntry<>(1, 1));
-    assertEquals(2, ofInteger.size());
-    assertEquals(0, ofInteger.get(0));
-    assertEquals(1, ofInteger.get(1));
-    assertEquals(null, ofInteger.get(2));
-
-    Map<Object, Object> ofMixed = Map.ofEntries(
-        new AbstractMap.SimpleEntry<>(0, objectValue0),
-        new AbstractMap.SimpleEntry<>(objectKey1, 1));
-    assertEquals(2, ofMixed.size());
-    assertSame(objectValue0, ofMixed.get(0));
-    assertEquals(1, ofMixed.get(objectKey1));
-    assertEquals(null, ofMixed.get(1));
-
-    // Ensure the supplied entry objects are not used directly since they are mutable.
-    Map.Entry<Object, Object> mutableEntry =
-        new AbstractMap.SimpleEntry<>(objectKey0, objectValue0);
-    Map<Object, Object> ofMutableEntry = Map.ofEntries(mutableEntry);
-    mutableEntry.setValue(objectValue1);
-    assertSame(objectValue0, ofMutableEntry.get(objectKey0));
-
-    // Ensure the supplied mutable array is not used directly since it is mutable.
-    @SuppressWarnings("unchecked")
-    Map.Entry<Object, Object>[] mutableArray =
-        new Map.Entry[] { new AbstractMap.SimpleEntry<>(objectKey0, objectValue0) };
-    Map<Object, Object> ofArray = Map.ofEntries(mutableArray);
-    mutableArray[0] = new AbstractMap.SimpleEntry<>(objectKey1, objectValue1);
-    assertSame(objectValue0, ofArray.get(objectKey0));
-    assertEquals(null, ofArray.get(objectKey1));
-
-    try {
-      Map.ofEntries(new AbstractMap.SimpleEntry<Object, Integer>(null, 1));
-      throw new AssertionError();
-    } catch (NullPointerException expected) {
-    }
-    try {
-      Map.ofEntries(new AbstractMap.SimpleEntry<Object, Integer>(1, null));
-      throw new AssertionError();
-    } catch (NullPointerException expected) {
-    }
-
-    try {
-      Map.ofEntries(
-          new AbstractMap.SimpleEntry<>(0, objectValue0),
-          new AbstractMap.SimpleEntry<>(0, objectValue1));
-      throw new AssertionError();
-    } catch (IllegalArgumentException expected) {
-      assertEquals("duplicate key: 0", expected.getMessage());
-    }
-  }
-
-  private static void testEntry() {
-    Object key = new Object();
-    Object value = new Object();
-    Map.Entry<Object, Object> entry = Map.entry(key, value);
-    assertSame(key, entry.getKey());
-    assertSame(value, entry.getValue());
-
-    try {
-      entry.setValue(new Object());
-      throw new AssertionError();
-    } catch (UnsupportedOperationException expected) {
-    }
-
-    try {
-      Map.entry(null, value);
-      throw new AssertionError();
-    } catch (NullPointerException expected) {
-    }
-    try {
-      Map.entry(key, null);
-      throw new AssertionError();
-    } catch (NullPointerException expected) {
-    }
-  }
-
-  private static void assertMutationNotAllowed(Map<Object, Object> ofObject) {
-    try {
-      ofObject.put(new Object(), new Object());
-      throw new AssertionError();
-    } catch (UnsupportedOperationException expected) {
-    }
-    for (Map.Entry<Object, Object> entry : ofObject.entrySet()) {
-      try {
-        entry.setValue(new Object());
-        throw new AssertionError();
-      } catch (UnsupportedOperationException expected) {
-      }
-    }
-  }
-
-  private static void assertSame(Object expected, Object actual) {
-    if (expected != actual) {
-      throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
-    }
-  }
-
-  private static void assertEquals(Object expected, Object actual) {
-    if (expected != actual && !expected.equals(actual)) {
-      throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
-    }
-  }
-}
diff --git a/src/test/examplesJava9/backport/MapBackportJava9Test.java b/src/test/examplesJava9/backport/MapBackportJava9Test.java
new file mode 100644
index 0000000..df6af49
--- /dev/null
+++ b/src/test/examplesJava9/backport/MapBackportJava9Test.java
@@ -0,0 +1,346 @@
+// 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 backport;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.desugar.backports.AbstractBackportTest;
+import com.android.tools.r8.desugar.backports.IgnoreInvokes;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.util.AbstractMap;
+import java.util.Map;
+import org.hamcrest.CoreMatchers;
+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 MapBackportJava9Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return TestBase.getTestParameters()
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
+        .withDexRuntimes()
+        .withAllApiLevelsAlsoForCf()
+        .build();
+  }
+
+  public MapBackportJava9Test(TestParameters parameters) {
+    super(parameters, Map.class, MapBackportJava9Main.class);
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to MapBackportTest.
+
+    // Available since API 1 and used to test created maps.
+    ignoreInvokes("entrySet");
+    ignoreInvokes("get");
+    ignoreInvokes("put");
+    ignoreInvokes("size");
+
+    // Map.entry, Map.of and Map.ofEntries added in API 30.
+    registerTarget(AndroidApiLevel.R, 29);
+  }
+
+  @Test
+  public void desugaringApiLevelR() throws Exception {
+    // TODO(b/154759404): This test should start to fail when testing on an Android R VM.
+    // This has now been checked with S, when R testing is added check and remove this.
+    if (parameters.getRuntime().isDex() && parameters.getApiLevel().isEqualTo(AndroidApiLevel.R)) {
+      testForD8()
+          .setMinApi(AndroidApiLevel.R)
+          .addProgramClasses(MiniAssert.class, IgnoreInvokes.class)
+          .addProgramClasses(MapBackportJava9Main.class)
+          .setIncludeClassesChecksum(true)
+          .compile()
+          .run(parameters.getRuntime(), MapBackportJava9Main.class)
+          .assertFailureWithErrorThatMatches(
+              CoreMatchers.containsString("java.lang.NoSuchMethodError"));
+    }
+  }
+
+  public static class MapBackportJava9Main {
+
+    public static void main(String[] args) {
+      testOf0();
+      testOf1();
+      testOf2();
+      testOf10();
+      testOfEntries();
+      testEntry();
+    }
+
+    private static void testOf0() {
+      Map<Object, Object> ofObject = Map.of();
+      assertEquals(0, ofObject.size());
+      assertEquals(null, ofObject.get(new Object()));
+      assertMutationNotAllowed(ofObject);
+
+      Map<Integer, Integer> ofInteger = Map.of();
+      assertEquals(0, ofInteger.size());
+      assertEquals(null, ofInteger.get(0));
+    }
+
+    private static void testOf1() {
+      Object objectKey0 = new Object();
+      Object objectValue0 = new Object();
+      Map<Object, Object> ofObject = Map.of(objectKey0, objectValue0);
+      assertEquals(1, ofObject.size());
+      assertSame(objectValue0, ofObject.get(objectKey0));
+      assertEquals(null, ofObject.get(new Object()));
+      assertMutationNotAllowed(ofObject);
+
+      Map<Integer, Integer> ofInteger = Map.of(0, 0);
+      assertEquals(1, ofInteger.size());
+      assertEquals(0, ofInteger.get(0));
+      assertEquals(null, ofInteger.get(1));
+
+      try {
+        Map.of((Object) null, 1);
+        throw new AssertionError();
+      } catch (NullPointerException expected) {
+      }
+      try {
+        Map.of(1, (Object) null);
+        throw new AssertionError();
+      } catch (NullPointerException expected) {
+      }
+    }
+
+    private static void testOf2() {
+      Object objectKey0 = new Object();
+      Object objectValue0 = new Object();
+      Object objectKey1 = new Object();
+      Object objectValue1 = new Object();
+      Map<Object, Object> ofObject = Map.of(objectKey0, objectValue0, objectKey1, objectValue1);
+      assertEquals(2, ofObject.size());
+      assertSame(objectValue0, ofObject.get(objectKey0));
+      assertSame(objectValue1, ofObject.get(objectKey1));
+      assertEquals(null, ofObject.get(new Object()));
+      assertMutationNotAllowed(ofObject);
+
+      Map<Integer, Integer> ofInteger = Map.of(0, 0, 1, 1);
+      assertEquals(2, ofInteger.size());
+      assertEquals(0, ofInteger.get(0));
+      assertEquals(1, ofInteger.get(1));
+      assertEquals(null, ofInteger.get(3));
+
+      Map<Object, Object> ofMixed = Map.of(objectKey0, 0, objectKey1, 1);
+      assertEquals(2, ofMixed.size());
+      assertEquals(0, ofMixed.get(objectKey0));
+      assertEquals(1, ofMixed.get(objectKey1));
+      assertEquals(null, ofMixed.get(new Object()));
+
+      try {
+        Map.of(1, 1, null, 2);
+        throw new AssertionError();
+      } catch (NullPointerException expected) {
+      }
+      try {
+        Map.of(1, 1, 2, null);
+        throw new AssertionError();
+      } catch (NullPointerException expected) {
+      }
+
+      try {
+        Map.of(1, 1, 1, 2);
+        throw new AssertionError();
+      } catch (IllegalArgumentException expected) {
+        assertEquals("duplicate key: 1", expected.getMessage());
+      }
+    }
+
+    private static void testOf10() {
+      Object objectKey0 = new Object();
+      Object objectValue0 = new Object();
+      Object objectKey6 = new Object();
+      Object objectValue6 = new Object();
+      Object objectKey9 = new Object();
+      Object objectValue9 = new Object();
+      Map<Object, Object> ofObject =
+          Map.of(
+              objectKey0,
+              objectValue0,
+              new Object(),
+              new Object(),
+              new Object(),
+              new Object(),
+              new Object(),
+              new Object(),
+              new Object(),
+              new Object(),
+              new Object(),
+              new Object(),
+              objectKey6,
+              objectValue6,
+              new Object(),
+              new Object(),
+              new Object(),
+              new Object(),
+              objectKey9,
+              objectValue9);
+      assertEquals(10, ofObject.size());
+      assertSame(objectValue0, ofObject.get(objectKey0));
+      assertSame(objectValue6, ofObject.get(objectKey6));
+      assertSame(objectValue9, ofObject.get(objectKey9));
+      assertEquals(null, ofObject.get(new Object()));
+      assertMutationNotAllowed(ofObject);
+
+      Map<Integer, Integer> ofInteger =
+          Map.of(0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9);
+      assertEquals(10, ofInteger.size());
+      assertEquals(0, ofInteger.get(0));
+      assertEquals(6, ofInteger.get(6));
+      assertEquals(9, ofInteger.get(9));
+      assertEquals(null, ofInteger.get(10));
+
+      Map<Object, Object> ofMixed =
+          Map.of(0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, objectKey9, objectValue9);
+      assertEquals(10, ofMixed.size());
+      assertEquals(0, ofMixed.get(0));
+      assertEquals(6, ofMixed.get(6));
+      assertSame(objectValue9, ofMixed.get(objectKey9));
+      assertEquals(null, ofMixed.get(9));
+
+      try {
+        Map.of(0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, null, objectValue9);
+        throw new AssertionError();
+      } catch (NullPointerException expected) {
+      }
+      try {
+        Map.of(0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, objectKey9, null);
+        throw new AssertionError();
+      } catch (NullPointerException expected) {
+      }
+
+      try {
+        Map.of(0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 0, 9);
+        throw new AssertionError();
+      } catch (IllegalArgumentException expected) {
+        assertEquals("duplicate key: 0", expected.getMessage());
+      }
+    }
+
+    private static void testOfEntries() {
+      Object objectKey0 = new Object();
+      Object objectValue0 = new Object();
+      Object objectKey1 = new Object();
+      Object objectValue1 = new Object();
+      Map<Object, Object> ofObject =
+          Map.ofEntries(
+              new AbstractMap.SimpleEntry<>(objectKey0, objectValue0),
+              new AbstractMap.SimpleEntry<>(objectKey1, objectValue1));
+      assertEquals(2, ofObject.size());
+      assertSame(objectValue0, ofObject.get(objectKey0));
+      assertSame(objectValue1, ofObject.get(objectKey1));
+      assertEquals(null, ofObject.get(new Object()));
+      assertMutationNotAllowed(ofObject);
+
+      Map<Integer, Integer> ofInteger =
+          Map.ofEntries(new AbstractMap.SimpleEntry<>(0, 0), new AbstractMap.SimpleEntry<>(1, 1));
+      assertEquals(2, ofInteger.size());
+      assertEquals(0, ofInteger.get(0));
+      assertEquals(1, ofInteger.get(1));
+      assertEquals(null, ofInteger.get(2));
+
+      Map<Object, Object> ofMixed =
+          Map.ofEntries(
+              new AbstractMap.SimpleEntry<>(0, objectValue0),
+              new AbstractMap.SimpleEntry<>(objectKey1, 1));
+      assertEquals(2, ofMixed.size());
+      assertSame(objectValue0, ofMixed.get(0));
+      assertEquals(1, ofMixed.get(objectKey1));
+      assertEquals(null, ofMixed.get(1));
+
+      // Ensure the supplied entry objects are not used directly since they are mutable.
+      Map.Entry<Object, Object> mutableEntry =
+          new AbstractMap.SimpleEntry<>(objectKey0, objectValue0);
+      Map<Object, Object> ofMutableEntry = Map.ofEntries(mutableEntry);
+      mutableEntry.setValue(objectValue1);
+      assertSame(objectValue0, ofMutableEntry.get(objectKey0));
+
+      // Ensure the supplied mutable array is not used directly since it is mutable.
+      @SuppressWarnings("unchecked")
+      Map.Entry<Object, Object>[] mutableArray =
+          new Map.Entry[] {new AbstractMap.SimpleEntry<>(objectKey0, objectValue0)};
+      Map<Object, Object> ofArray = Map.ofEntries(mutableArray);
+      mutableArray[0] = new AbstractMap.SimpleEntry<>(objectKey1, objectValue1);
+      assertSame(objectValue0, ofArray.get(objectKey0));
+      assertEquals(null, ofArray.get(objectKey1));
+
+      try {
+        Map.ofEntries(new AbstractMap.SimpleEntry<Object, Integer>(null, 1));
+        throw new AssertionError();
+      } catch (NullPointerException expected) {
+      }
+      try {
+        Map.ofEntries(new AbstractMap.SimpleEntry<Object, Integer>(1, null));
+        throw new AssertionError();
+      } catch (NullPointerException expected) {
+      }
+
+      try {
+        Map.ofEntries(
+            new AbstractMap.SimpleEntry<>(0, objectValue0),
+            new AbstractMap.SimpleEntry<>(0, objectValue1));
+        throw new AssertionError();
+      } catch (IllegalArgumentException expected) {
+        assertEquals("duplicate key: 0", expected.getMessage());
+      }
+    }
+
+    private static void testEntry() {
+      Object key = new Object();
+      Object value = new Object();
+      Map.Entry<Object, Object> entry = Map.entry(key, value);
+      assertSame(key, entry.getKey());
+      assertSame(value, entry.getValue());
+
+      try {
+        entry.setValue(new Object());
+        throw new AssertionError();
+      } catch (UnsupportedOperationException expected) {
+      }
+
+      try {
+        Map.entry(null, value);
+        throw new AssertionError();
+      } catch (NullPointerException expected) {
+      }
+      try {
+        Map.entry(key, null);
+        throw new AssertionError();
+      } catch (NullPointerException expected) {
+      }
+    }
+
+    private static void assertMutationNotAllowed(Map<Object, Object> ofObject) {
+      try {
+        ofObject.put(new Object(), new Object());
+        throw new AssertionError();
+      } catch (UnsupportedOperationException expected) {
+      }
+      for (Map.Entry<Object, Object> entry : ofObject.entrySet()) {
+        try {
+          entry.setValue(new Object());
+          throw new AssertionError();
+        } catch (UnsupportedOperationException expected) {
+        }
+      }
+    }
+
+    private static void assertSame(Object expected, Object actual) {
+      if (expected != actual) {
+        throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+      }
+    }
+
+    private static void assertEquals(Object expected, Object actual) {
+      if (expected != actual && !expected.equals(actual)) {
+        throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+      }
+    }
+  }
+}
diff --git a/src/test/examplesJava9/backport/MathBackportJava9Main.java b/src/test/examplesJava9/backport/MathBackportJava9Main.java
deleted file mode 100644
index 9030283..0000000
--- a/src/test/examplesJava9/backport/MathBackportJava9Main.java
+++ /dev/null
@@ -1,102 +0,0 @@
-// 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 backport;
-
-import java.math.BigInteger;
-
-public class MathBackportJava9Main {
-
-  public static void main(String[] args) {
-    testMultiplyExactLongInt();
-    testMultiplyFull();
-    testMultiplyHigh();
-    testFloorDivLongInt();
-    testFloorModLongInt();
-  }
-
-  public static void testMultiplyExactLongInt() {
-    assertEquals(8L, Math.multiplyExact(2L, 4));
-    assertEquals(Long.MAX_VALUE, Math.multiplyExact(Long.MAX_VALUE, 1));
-    assertEquals(Long.MIN_VALUE, Math.multiplyExact(Long.MIN_VALUE / 2L, 2));
-    try {
-      throw new AssertionError(Math.multiplyExact(Long.MAX_VALUE, 2));
-    } catch (ArithmeticException expected) {
-    }
-    try {
-      throw new AssertionError(Math.multiplyExact(Long.MIN_VALUE, 2));
-    } catch (ArithmeticException expected) {
-    }
-  }
-
-  public static void testMultiplyFull() {
-    assertEquals(8L, Math.multiplyFull(2, 4));
-    assertEquals(4611686014132420609L,
-        Math.multiplyFull(Integer.MAX_VALUE, Integer.MAX_VALUE));
-    assertEquals(-4611686016279904256L,
-        Math.multiplyFull(Integer.MAX_VALUE, Integer.MIN_VALUE));
-    assertEquals(4611686018427387904L,
-        Math.multiplyFull(Integer.MIN_VALUE, Integer.MIN_VALUE));
-  }
-
-  public static void testMultiplyHigh() {
-    long[] interestingValues = {
-        Long.MIN_VALUE, Long.MAX_VALUE,
-        Integer.MIN_VALUE, Integer.MAX_VALUE,
-        Short.MIN_VALUE, Short.MAX_VALUE,
-        Byte.MIN_VALUE, Byte.MAX_VALUE,
-        0L,
-        -1L, 1L,
-        -42L, 42L
-    };
-    for (long x : interestingValues) {
-      for (long y : interestingValues) {
-        long expected = BigInteger.valueOf(x)
-            .multiply(BigInteger.valueOf(y))
-            .shiftRight(64)
-            .longValue();
-        assertEquals(expected, Math.multiplyHigh(x, y));
-      }
-    }
-  }
-
-  public static void testFloorDivLongInt() {
-    assertEquals(1L, Math.floorDiv(4L, 4));
-    assertEquals(1L, Math.floorDiv(-4L, -4));
-    assertEquals(-1L, Math.floorDiv(-4L, 4));
-    assertEquals(-1L, Math.floorDiv(4L, -4));
-
-    assertEquals(1L, Math.floorDiv(4L, 3));
-    assertEquals(1L, Math.floorDiv(-4L, -3));
-    assertEquals(-2L, Math.floorDiv(-4L, 3));
-    assertEquals(-2L, Math.floorDiv(4L, -3));
-
-    // Spec edge case: result is actually MAX_VALUE+1 which becomes MIN_VALUE.
-    assertEquals(Long.MIN_VALUE, Math.floorDiv(Long.MIN_VALUE, -1));
-  }
-
-  public static void testFloorModLongInt() {
-    assertEquals(0, Math.floorMod(4L, 4));
-    assertEquals(0, Math.floorMod(-4L, -4));
-    assertEquals(0, Math.floorMod(-4L, 4));
-    assertEquals(0, Math.floorMod(4L, -4));
-
-    assertEquals(1, Math.floorMod(4L, 3));
-    assertEquals(-1, Math.floorMod(-4L, -3));
-    assertEquals(2, Math.floorMod(-4L, 3));
-    assertEquals(-2, Math.floorMod(4L, -3));
-  }
-
-  private static void assertEquals(int expected, int actual) {
-    if (expected != actual) {
-      throw new AssertionError("Expected <" + expected + "> but was <" + actual + '>');
-    }
-  }
-
-  private static void assertEquals(long expected, long actual) {
-    if (expected != actual) {
-      throw new AssertionError("Expected <" + expected + "> but was <" + actual + '>');
-    }
-  }
-}
diff --git a/src/test/examplesJava9/backport/MathBackportJava9Test.java b/src/test/examplesJava9/backport/MathBackportJava9Test.java
new file mode 100644
index 0000000..19b600b
--- /dev/null
+++ b/src/test/examplesJava9/backport/MathBackportJava9Test.java
@@ -0,0 +1,131 @@
+// 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 backport;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.desugar.backports.AbstractBackportTest;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.math.BigInteger;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public final class MathBackportJava9Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return TestBase.getTestParameters()
+        .withDexRuntimes()
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
+        .withAllApiLevelsAlsoForCf()
+        .build();
+  }
+
+  public MathBackportJava9Test(TestParameters parameters) {
+    super(parameters, Math.class, MathBackportJava9Main.class);
+
+    // Math.floorDiv, Math.floorMod, Math.multiplyExact, Math.multiplyFull and Math.multiplyHigh
+    // added in API 31.
+    registerTarget(AndroidApiLevel.S, 27);
+  }
+
+  public static class MathBackportJava9Main {
+
+    public static void main(String[] args) {
+      testMultiplyExactLongInt();
+      testMultiplyFull();
+      testMultiplyHigh();
+      testFloorDivLongInt();
+      testFloorModLongInt();
+    }
+
+    public static void testMultiplyExactLongInt() {
+      assertEquals(8L, Math.multiplyExact(2L, 4));
+      assertEquals(Long.MAX_VALUE, Math.multiplyExact(Long.MAX_VALUE, 1));
+      assertEquals(Long.MIN_VALUE, Math.multiplyExact(Long.MIN_VALUE / 2L, 2));
+      try {
+        throw new AssertionError(Math.multiplyExact(Long.MAX_VALUE, 2));
+      } catch (ArithmeticException expected) {
+      }
+      try {
+        throw new AssertionError(Math.multiplyExact(Long.MIN_VALUE, 2));
+      } catch (ArithmeticException expected) {
+      }
+    }
+
+    public static void testMultiplyFull() {
+      assertEquals(8L, Math.multiplyFull(2, 4));
+      assertEquals(4611686014132420609L, Math.multiplyFull(Integer.MAX_VALUE, Integer.MAX_VALUE));
+      assertEquals(-4611686016279904256L, Math.multiplyFull(Integer.MAX_VALUE, Integer.MIN_VALUE));
+      assertEquals(4611686018427387904L, Math.multiplyFull(Integer.MIN_VALUE, Integer.MIN_VALUE));
+    }
+
+    public static void testMultiplyHigh() {
+      long[] interestingValues = {
+        Long.MIN_VALUE,
+        Long.MAX_VALUE,
+        Integer.MIN_VALUE,
+        Integer.MAX_VALUE,
+        Short.MIN_VALUE,
+        Short.MAX_VALUE,
+        Byte.MIN_VALUE,
+        Byte.MAX_VALUE,
+        0L,
+        -1L,
+        1L,
+        -42L,
+        42L
+      };
+      for (long x : interestingValues) {
+        for (long y : interestingValues) {
+          long expected =
+              BigInteger.valueOf(x).multiply(BigInteger.valueOf(y)).shiftRight(64).longValue();
+          assertEquals(expected, Math.multiplyHigh(x, y));
+        }
+      }
+    }
+
+    public static void testFloorDivLongInt() {
+      assertEquals(1L, Math.floorDiv(4L, 4));
+      assertEquals(1L, Math.floorDiv(-4L, -4));
+      assertEquals(-1L, Math.floorDiv(-4L, 4));
+      assertEquals(-1L, Math.floorDiv(4L, -4));
+
+      assertEquals(1L, Math.floorDiv(4L, 3));
+      assertEquals(1L, Math.floorDiv(-4L, -3));
+      assertEquals(-2L, Math.floorDiv(-4L, 3));
+      assertEquals(-2L, Math.floorDiv(4L, -3));
+
+      // Spec edge case: result is actually MAX_VALUE+1 which becomes MIN_VALUE.
+      assertEquals(Long.MIN_VALUE, Math.floorDiv(Long.MIN_VALUE, -1));
+    }
+
+    public static void testFloorModLongInt() {
+      assertEquals(0, Math.floorMod(4L, 4));
+      assertEquals(0, Math.floorMod(-4L, -4));
+      assertEquals(0, Math.floorMod(-4L, 4));
+      assertEquals(0, Math.floorMod(4L, -4));
+
+      assertEquals(1, Math.floorMod(4L, 3));
+      assertEquals(-1, Math.floorMod(-4L, -3));
+      assertEquals(2, Math.floorMod(-4L, 3));
+      assertEquals(-2, Math.floorMod(4L, -3));
+    }
+
+    private static void assertEquals(int expected, int actual) {
+      if (expected != actual) {
+        throw new AssertionError("Expected <" + expected + "> but was <" + actual + '>');
+      }
+    }
+
+    private static void assertEquals(long expected, long actual) {
+      if (expected != actual) {
+        throw new AssertionError("Expected <" + expected + "> but was <" + actual + '>');
+      }
+    }
+  }
+}
diff --git a/src/test/examplesJava9/backport/ObjectsBackportJava9Main.java b/src/test/examplesJava9/backport/ObjectsBackportJava9Main.java
deleted file mode 100644
index 5f0f97f..0000000
--- a/src/test/examplesJava9/backport/ObjectsBackportJava9Main.java
+++ /dev/null
@@ -1,156 +0,0 @@
-package backport;
-
-import java.util.Objects;
-
-public final class ObjectsBackportJava9Main {
-  public static void main(String[] args) {
-    boolean isAndroid = "Dalvik".equals(System.getProperty("java.vm.name"));
-    String majorVersion = System.getProperty("java.vm.version").split("\\.", -1)[0];
-
-    testRequireNonNullElse();
-    if (!isAndroid || Integer.parseInt(majorVersion) >= 7) {
-      // TODO desugaring desugaredlibrary is blocked by
-      // https://issuetracker.google.com/issues/114481425
-      testRequireNonNullElseGet();
-    }
-    testCheckIndex();
-    testCheckFromToIndex();
-    testCheckFromIndexSize();
-  }
-
-  private static void testRequireNonNullElse() {
-    Object one = new Object();
-    Object two = new Object();
-
-    assertSame(one, Objects.requireNonNullElse(one, two));
-    assertSame(two, Objects.requireNonNullElse(null, two));
-
-    try {
-      throw new AssertionError(Objects.requireNonNullElse(null, null));
-    } catch (NullPointerException expected) {
-    }
-  }
-
-  private static void testRequireNonNullElseGet() {
-    Object one = new Object();
-    Object two = new Object();
-
-    assertSame(one, Objects.requireNonNullElseGet(one, () -> two));
-    assertSame(two, Objects.requireNonNullElseGet(null, () -> two));
-
-    try {
-      throw new AssertionError(Objects.requireNonNullElseGet(null, null));
-    } catch (NullPointerException expected) {
-    }
-    try {
-      throw new AssertionError(Objects.requireNonNullElseGet(null, () -> null));
-    } catch (NullPointerException expected) {
-    }
-  }
-
-  private static void testCheckIndex() {
-    for (int i = 0; i < 10; i++) {
-      assertEquals(i, Objects.checkIndex(i, 10));
-    }
-
-    try {
-      throw new AssertionError(Objects.checkIndex(-1, 10));
-    } catch (IndexOutOfBoundsException expected) {
-    }
-    try {
-      throw new AssertionError(Objects.checkIndex(10, 0));
-    } catch (IndexOutOfBoundsException expected) {
-    }
-    try {
-      throw new AssertionError(Objects.checkIndex(0, 0));
-    } catch (IndexOutOfBoundsException expected) {
-    }
-  }
-
-  private static void testCheckFromToIndex() {
-    for (int i = 0; i <= 10; i++) {
-      for (int j = i; j <= 10; j++) {
-        assertEquals(i, Objects.checkFromToIndex(i, j, 10));
-      }
-    }
-    assertEquals(0, Objects.checkFromToIndex(0, 0, 0));
-
-    try {
-      throw new AssertionError(Objects.checkFromToIndex(4, 2, 10));
-    } catch (IndexOutOfBoundsException expected) {
-    }
-    try {
-      throw new AssertionError(Objects.checkFromToIndex(-1, 5, 10));
-    } catch (IndexOutOfBoundsException expected) {
-    }
-    try {
-      throw new AssertionError(Objects.checkFromToIndex(0, -1, 10));
-    } catch (IndexOutOfBoundsException expected) {
-    }
-    try {
-      throw new AssertionError(Objects.checkFromToIndex(11, 11, 10));
-    } catch (IndexOutOfBoundsException expected) {
-    }
-    try {
-      throw new AssertionError(Objects.checkFromToIndex(0, 1, 0));
-    } catch (IndexOutOfBoundsException expected) {
-    }
-    try {
-      throw new AssertionError(Objects.checkFromToIndex(1, 1, 0));
-    } catch (IndexOutOfBoundsException expected) {
-    }
-  }
-
-  private static void testCheckFromIndexSize() {
-    for (int i = 0; i <= 10; i++) {
-      for (int j = 10 - i; j >= 0; j--) {
-        assertEquals(i, Objects.checkFromIndexSize(i, j, 10));
-      }
-    }
-    assertEquals(0, Objects.checkFromIndexSize(0, 0, 0));
-
-    try {
-      throw new AssertionError(Objects.checkFromIndexSize(8, 4, 10));
-    } catch (IndexOutOfBoundsException expected) {
-    }
-    try {
-      throw new AssertionError(Objects.checkFromIndexSize(-1, 5, 10));
-    } catch (IndexOutOfBoundsException expected) {
-    }
-    try {
-      throw new AssertionError(Objects.checkFromIndexSize(11, 0, 10));
-    } catch (IndexOutOfBoundsException expected) {
-    }
-    try {
-      throw new AssertionError(Objects.checkFromIndexSize(0, 1, 0));
-    } catch (IndexOutOfBoundsException expected) {
-    }
-    try {
-      throw new AssertionError(Objects.checkFromIndexSize(1, 1, 0));
-    } catch (IndexOutOfBoundsException expected) {
-    }
-
-    // Check for cases where overflow might occur producing incorrect results.
-    try {
-      throw new AssertionError(Objects.checkFromIndexSize(Integer.MAX_VALUE, 1, Integer.MAX_VALUE));
-    } catch (IndexOutOfBoundsException expected) {
-    }
-    try {
-      throw new AssertionError(Objects.checkFromIndexSize(0, 1, Integer.MIN_VALUE));
-    } catch (IndexOutOfBoundsException expected) {
-    }
-  }
-
-  private static void assertEquals(int expected, int actual) {
-    if (expected != actual) {
-      throw new AssertionError("Expected <" + expected + "> but was <" + actual + '>');
-    }
-  }
-
-  private static void assertSame(Object expected, Object actual) {
-    if (expected != actual) {
-      throw new AssertionError(
-          "Expected <" + expected + "> to be same instance as <" + actual + '>');
-    }
-  }
-}
diff --git a/src/test/examplesJava9/backport/ObjectsBackportJava9Test.java b/src/test/examplesJava9/backport/ObjectsBackportJava9Test.java
new file mode 100644
index 0000000..d41850e
--- /dev/null
+++ b/src/test/examplesJava9/backport/ObjectsBackportJava9Test.java
@@ -0,0 +1,211 @@
+// 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 backport;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.desugar.backports.AbstractBackportTest;
+import com.android.tools.r8.desugar.backports.IgnoreInvokes;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.util.Objects;
+import org.hamcrest.CoreMatchers;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public final class ObjectsBackportJava9Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return TestBase.getTestParameters()
+        .withDexRuntimes()
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
+        .withAllApiLevelsAlsoForCf()
+        .build();
+  }
+
+  public ObjectsBackportJava9Test(TestParameters parameters) {
+    super(parameters, Objects.class, ObjectsBackportJava9Main.class);
+    // Objects.checkFromIndexSize, Objects.checkFromToIndex, Objects.checkIndex,
+    // Objects.requireNonNullElse and Objects.requireNonNullElseGet added in API 30.
+    registerTarget(AndroidApiLevel.R, 28);
+    registerTarget(AndroidApiLevel.N, 0);
+    // Objects.requireNonNullElseGet is not desugared if Supplier is absent.
+    registerTarget(AndroidApiLevel.B, 4);
+  }
+
+  @Test
+  public void desugaringApiLevelR() throws Exception {
+    // TODO(b/154759404): This test should start to fail when testing on an Android R VM.
+    // This has now been checked with S, when R testing is added chck and remove this.
+    if (parameters.getRuntime().isDex() && parameters.getApiLevel().isEqualTo(AndroidApiLevel.R)) {
+      testForD8()
+          .setMinApi(AndroidApiLevel.R)
+          .addProgramClasses(MiniAssert.class, IgnoreInvokes.class)
+          .addProgramClasses(ObjectsBackportJava9Main.class)
+          .setIncludeClassesChecksum(true)
+          .compile()
+          .run(parameters.getRuntime(), ObjectsBackportJava9Main.class)
+          .assertFailureWithErrorThatMatches(
+              CoreMatchers.containsString("java.lang.NoSuchMethodError"));
+    }
+  }
+
+  public static class ObjectsBackportJava9Main {
+    public static void main(String[] args) {
+      boolean isAndroid = "Dalvik".equals(System.getProperty("java.vm.name"));
+      String majorVersion = System.getProperty("java.vm.version").split("\\.", -1)[0];
+
+      testRequireNonNullElse();
+      if (!isAndroid || Integer.parseInt(majorVersion) >= 7) {
+        // TODO desugaring desugaredlibrary is blocked by
+        // https://issuetracker.google.com/issues/114481425
+        testRequireNonNullElseGet();
+      }
+      testCheckIndex();
+      testCheckFromToIndex();
+      testCheckFromIndexSize();
+    }
+
+    private static void testRequireNonNullElse() {
+      Object one = new Object();
+      Object two = new Object();
+
+      assertSame(one, Objects.requireNonNullElse(one, two));
+      assertSame(two, Objects.requireNonNullElse(null, two));
+
+      try {
+        throw new AssertionError(Objects.requireNonNullElse(null, null));
+      } catch (NullPointerException expected) {
+      }
+    }
+
+    private static void testRequireNonNullElseGet() {
+      Object one = new Object();
+      Object two = new Object();
+
+      assertSame(one, Objects.requireNonNullElseGet(one, () -> two));
+      assertSame(two, Objects.requireNonNullElseGet(null, () -> two));
+
+      try {
+        throw new AssertionError(Objects.requireNonNullElseGet(null, null));
+      } catch (NullPointerException expected) {
+      }
+      try {
+        throw new AssertionError(Objects.requireNonNullElseGet(null, () -> null));
+      } catch (NullPointerException expected) {
+      }
+    }
+
+    private static void testCheckIndex() {
+      for (int i = 0; i < 10; i++) {
+        assertEquals(i, Objects.checkIndex(i, 10));
+      }
+
+      try {
+        throw new AssertionError(Objects.checkIndex(-1, 10));
+      } catch (IndexOutOfBoundsException expected) {
+      }
+      try {
+        throw new AssertionError(Objects.checkIndex(10, 0));
+      } catch (IndexOutOfBoundsException expected) {
+      }
+      try {
+        throw new AssertionError(Objects.checkIndex(0, 0));
+      } catch (IndexOutOfBoundsException expected) {
+      }
+    }
+
+    private static void testCheckFromToIndex() {
+      for (int i = 0; i <= 10; i++) {
+        for (int j = i; j <= 10; j++) {
+          assertEquals(i, Objects.checkFromToIndex(i, j, 10));
+        }
+      }
+      assertEquals(0, Objects.checkFromToIndex(0, 0, 0));
+
+      try {
+        throw new AssertionError(Objects.checkFromToIndex(4, 2, 10));
+      } catch (IndexOutOfBoundsException expected) {
+      }
+      try {
+        throw new AssertionError(Objects.checkFromToIndex(-1, 5, 10));
+      } catch (IndexOutOfBoundsException expected) {
+      }
+      try {
+        throw new AssertionError(Objects.checkFromToIndex(0, -1, 10));
+      } catch (IndexOutOfBoundsException expected) {
+      }
+      try {
+        throw new AssertionError(Objects.checkFromToIndex(11, 11, 10));
+      } catch (IndexOutOfBoundsException expected) {
+      }
+      try {
+        throw new AssertionError(Objects.checkFromToIndex(0, 1, 0));
+      } catch (IndexOutOfBoundsException expected) {
+      }
+      try {
+        throw new AssertionError(Objects.checkFromToIndex(1, 1, 0));
+      } catch (IndexOutOfBoundsException expected) {
+      }
+    }
+
+    private static void testCheckFromIndexSize() {
+      for (int i = 0; i <= 10; i++) {
+        for (int j = 10 - i; j >= 0; j--) {
+          assertEquals(i, Objects.checkFromIndexSize(i, j, 10));
+        }
+      }
+      assertEquals(0, Objects.checkFromIndexSize(0, 0, 0));
+
+      try {
+        throw new AssertionError(Objects.checkFromIndexSize(8, 4, 10));
+      } catch (IndexOutOfBoundsException expected) {
+      }
+      try {
+        throw new AssertionError(Objects.checkFromIndexSize(-1, 5, 10));
+      } catch (IndexOutOfBoundsException expected) {
+      }
+      try {
+        throw new AssertionError(Objects.checkFromIndexSize(11, 0, 10));
+      } catch (IndexOutOfBoundsException expected) {
+      }
+      try {
+        throw new AssertionError(Objects.checkFromIndexSize(0, 1, 0));
+      } catch (IndexOutOfBoundsException expected) {
+      }
+      try {
+        throw new AssertionError(Objects.checkFromIndexSize(1, 1, 0));
+      } catch (IndexOutOfBoundsException expected) {
+      }
+
+      // Check for cases where overflow might occur producing incorrect results.
+      try {
+        throw new AssertionError(
+            Objects.checkFromIndexSize(Integer.MAX_VALUE, 1, Integer.MAX_VALUE));
+      } catch (IndexOutOfBoundsException expected) {
+      }
+      try {
+        throw new AssertionError(Objects.checkFromIndexSize(0, 1, Integer.MIN_VALUE));
+      } catch (IndexOutOfBoundsException expected) {
+      }
+    }
+
+    private static void assertEquals(int expected, int actual) {
+      if (expected != actual) {
+        throw new AssertionError("Expected <" + expected + "> but was <" + actual + '>');
+      }
+    }
+
+    private static void assertSame(Object expected, Object actual) {
+      if (expected != actual) {
+        throw new AssertionError(
+            "Expected <" + expected + "> to be same instance as <" + actual + '>');
+      }
+    }
+  }
+}
diff --git a/src/test/examplesJava9/backport/OptionalBackportJava9Main.java b/src/test/examplesJava9/backport/OptionalBackportJava9Main.java
deleted file mode 100644
index c25226f..0000000
--- a/src/test/examplesJava9/backport/OptionalBackportJava9Main.java
+++ /dev/null
@@ -1,82 +0,0 @@
-// 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 backport;
-
-import java.util.Optional;
-
-public final class OptionalBackportJava9Main {
-
-  public static void main(String[] args) {
-    testOr();
-    testOrNull();
-    testIfPresentOrElse();
-    testStream();
-  }
-
-  private static void testOr() {
-    Optional<String> value = Optional.of("value");
-    Optional<String> defaultValue = Optional.of("default");
-    Optional<String> emptyValue = Optional.empty();
-    Optional<String> result;
-
-    result = value.or(() -> defaultValue);
-    assertTrue(value == result);
-    result = emptyValue.or(() -> defaultValue);
-    assertTrue(result == defaultValue);
-  }
-
-  private static void testOrNull() {
-    Optional<String> value = Optional.of("value");
-    Optional<String> emptyValue = Optional.empty();
-
-    try {
-      value.or(null);
-      fail();
-    } catch (NullPointerException e) {
-    }
-
-    try {
-      emptyValue.or(null);
-      fail();
-    } catch (NullPointerException e) {
-    }
-
-    try {
-      value.or(() -> null);
-    } catch (NullPointerException e) {
-      fail();
-    }
-
-    try {
-      emptyValue.or(() -> null);
-      fail();
-    } catch (NullPointerException e) {
-    }
-  }
-
-  private static void testIfPresentOrElse() {
-    Optional<String> value = Optional.of("value");
-    Optional<String> emptyValue = Optional.empty();
-    value.ifPresentOrElse(val -> {}, () -> assertTrue(false));
-    emptyValue.ifPresentOrElse(val -> assertTrue(false), () -> {});
-  }
-
-  private static void testStream() {
-    Optional<String> value = Optional.of("value");
-    Optional<String> emptyValue = Optional.empty();
-    assertTrue(value.stream().count() == 1);
-    assertTrue(emptyValue.stream().count() == 0);
-  }
-
-  private static void assertTrue(boolean value) {
-    if (!value) {
-      throw new AssertionError("Expected <true> but was <false>");
-    }
-  }
-
-  private static void fail() {
-    throw new AssertionError("Failure.");
-  }
-}
diff --git a/src/test/examplesJava9/backport/OptionalBackportJava9Test.java b/src/test/examplesJava9/backport/OptionalBackportJava9Test.java
new file mode 100644
index 0000000..3ecc125
--- /dev/null
+++ b/src/test/examplesJava9/backport/OptionalBackportJava9Test.java
@@ -0,0 +1,116 @@
+// 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 backport;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.desugar.backports.AbstractBackportTest;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.util.Optional;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public final class OptionalBackportJava9Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return TestBase.getTestParameters()
+        .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+        .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
+        .enableApiLevelsForCf()
+        .build();
+  }
+
+  public OptionalBackportJava9Test(TestParameters parameters) {
+    super(parameters, Optional.class, OptionalBackportJava9Main.class);
+    // Note: The methods in this test exist in android.jar from Android T. When R8 builds targeting
+    // Java 11 move these tests to OptionalBackportTest (out of examplesJava9).
+
+    // Available since N.
+    ignoreInvokes("empty");
+    ignoreInvokes("of");
+
+    registerTarget(AndroidApiLevel.T, 10);
+  }
+
+  public static class OptionalBackportJava9Main {
+
+    public static void main(String[] args) {
+      testOr();
+      testOrNull();
+      testIfPresentOrElse();
+      testStream();
+    }
+
+    private static void testOr() {
+      Optional<String> value = Optional.of("value");
+      Optional<String> defaultValue = Optional.of("default");
+      Optional<String> emptyValue = Optional.empty();
+      Optional<String> result;
+
+      result = value.or(() -> defaultValue);
+      assertTrue(value == result);
+      result = emptyValue.or(() -> defaultValue);
+      assertTrue(result == defaultValue);
+    }
+
+    private static void testOrNull() {
+      Optional<String> value = Optional.of("value");
+      Optional<String> emptyValue = Optional.empty();
+
+      try {
+        value.or(null);
+        fail();
+      } catch (NullPointerException e) {
+      }
+
+      try {
+        emptyValue.or(null);
+        fail();
+      } catch (NullPointerException e) {
+      }
+
+      try {
+        value.or(() -> null);
+      } catch (NullPointerException e) {
+        fail();
+      }
+
+      try {
+        emptyValue.or(() -> null);
+        fail();
+      } catch (NullPointerException e) {
+      }
+    }
+
+    private static void testIfPresentOrElse() {
+      Optional<String> value = Optional.of("value");
+      Optional<String> emptyValue = Optional.empty();
+      value.ifPresentOrElse(val -> {}, () -> assertTrue(false));
+      emptyValue.ifPresentOrElse(val -> assertTrue(false), () -> {});
+    }
+
+    private static void testStream() {
+      Optional<String> value = Optional.of("value");
+      Optional<String> emptyValue = Optional.empty();
+      assertTrue(value.stream().count() == 1);
+      assertTrue(emptyValue.stream().count() == 0);
+    }
+
+    private static void assertTrue(boolean value) {
+      if (!value) {
+        throw new AssertionError("Expected <true> but was <false>");
+      }
+    }
+
+    private static void fail() {
+      throw new AssertionError("Failure.");
+    }
+  }
+}
diff --git a/src/test/examplesJava9/backport/OptionalDoubleBackportJava9Main.java b/src/test/examplesJava9/backport/OptionalDoubleBackportJava9Main.java
deleted file mode 100644
index 9b08718..0000000
--- a/src/test/examplesJava9/backport/OptionalDoubleBackportJava9Main.java
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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 backport;
-
-import java.util.OptionalDouble;
-
-public final class OptionalDoubleBackportJava9Main {
-
-  public static void main(String[] args) {
-    testIfPresentOrElseDouble();
-    testStreamDouble();
-  }
-
-  private static void testIfPresentOrElseDouble() {
-    OptionalDouble value = OptionalDouble.of(1.0d);
-    OptionalDouble emptyValue = OptionalDouble.empty();
-    value.ifPresentOrElse(val -> {}, () -> assertTrue(false));
-    emptyValue.ifPresentOrElse(val -> assertTrue(false), () -> {});
-  }
-
-  private static void testStreamDouble() {
-    OptionalDouble value = OptionalDouble.of(2d);
-    OptionalDouble emptyValue = OptionalDouble.empty();
-    assertTrue(value.stream().count() == 1);
-    assertTrue(emptyValue.stream().count() == 0);
-  }
-
-  private static void assertTrue(boolean value) {
-    if (!value) {
-      throw new AssertionError("Expected <true> but was <false>");
-    }
-  }
-}
diff --git a/src/test/examplesJava9/backport/OptionalDoubleBackportJava9Test.java b/src/test/examplesJava9/backport/OptionalDoubleBackportJava9Test.java
new file mode 100644
index 0000000..28ea1e2
--- /dev/null
+++ b/src/test/examplesJava9/backport/OptionalDoubleBackportJava9Test.java
@@ -0,0 +1,69 @@
+// 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 backport;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.desugar.backports.AbstractBackportTest;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.util.OptionalDouble;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public final class OptionalDoubleBackportJava9Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return TestBase.getTestParameters()
+        .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+        .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
+        .enableApiLevelsForCf()
+        .build();
+  }
+
+  public OptionalDoubleBackportJava9Test(TestParameters parameters) {
+    super(parameters, OptionalDouble.class, OptionalDoubleBackportJava9Main.class);
+    // Note: The methods in this test exist in android.jar from Android T. When R8 builds targeting
+    // Java 11 move these tests to OptionalBackportTest (out of examplesJava9).
+
+    // Available since N.
+    ignoreInvokes("empty");
+    ignoreInvokes("of");
+
+    registerTarget(AndroidApiLevel.T, 4);
+  }
+
+  public static class OptionalDoubleBackportJava9Main {
+
+    public static void main(String[] args) {
+      testIfPresentOrElseDouble();
+      testStreamDouble();
+    }
+
+    private static void testIfPresentOrElseDouble() {
+      OptionalDouble value = OptionalDouble.of(1.0d);
+      OptionalDouble emptyValue = OptionalDouble.empty();
+      value.ifPresentOrElse(val -> {}, () -> assertTrue(false));
+      emptyValue.ifPresentOrElse(val -> assertTrue(false), () -> {});
+    }
+
+    private static void testStreamDouble() {
+      OptionalDouble value = OptionalDouble.of(2d);
+      OptionalDouble emptyValue = OptionalDouble.empty();
+      assertTrue(value.stream().count() == 1);
+      assertTrue(emptyValue.stream().count() == 0);
+    }
+
+    private static void assertTrue(boolean value) {
+      if (!value) {
+        throw new AssertionError("Expected <true> but was <false>");
+      }
+    }
+  }
+}
diff --git a/src/test/examplesJava9/backport/OptionalIntBackportJava9Main.java b/src/test/examplesJava9/backport/OptionalIntBackportJava9Main.java
deleted file mode 100644
index fedc472..0000000
--- a/src/test/examplesJava9/backport/OptionalIntBackportJava9Main.java
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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 backport;
-
-import java.util.OptionalInt;
-
-public final class OptionalIntBackportJava9Main {
-
-  public static void main(String[] args) {
-    testIfPresentOrElseInt();
-    testStreamInt();
-  }
-
-  private static void testIfPresentOrElseInt() {
-    OptionalInt value = OptionalInt.of(1);
-    OptionalInt emptyValue = OptionalInt.empty();
-    value.ifPresentOrElse(val -> {}, () -> assertTrue(false));
-    emptyValue.ifPresentOrElse(val -> assertTrue(false), () -> {});
-  }
-
-  private static void testStreamInt() {
-    OptionalInt value = OptionalInt.of(2);
-    OptionalInt emptyValue = OptionalInt.empty();
-    assertTrue(value.stream().count() == 1);
-    assertTrue(emptyValue.stream().count() == 0);
-  }
-
-  private static void assertTrue(boolean value) {
-    if (!value) {
-      throw new AssertionError("Expected <true> but was <false>");
-    }
-  }
-}
diff --git a/src/test/examplesJava9/backport/OptionalIntBackportJava9Test.java b/src/test/examplesJava9/backport/OptionalIntBackportJava9Test.java
new file mode 100644
index 0000000..d0a625d
--- /dev/null
+++ b/src/test/examplesJava9/backport/OptionalIntBackportJava9Test.java
@@ -0,0 +1,69 @@
+// 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 backport;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.desugar.backports.AbstractBackportTest;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.util.OptionalInt;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public final class OptionalIntBackportJava9Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return TestBase.getTestParameters()
+        .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+        .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
+        .enableApiLevelsForCf()
+        .build();
+  }
+
+  public OptionalIntBackportJava9Test(TestParameters parameters) {
+    super(parameters, OptionalInt.class, OptionalIntBackportJava9Main.class);
+    // Note: The methods in this test exist in android.jar from Android T. When R8 builds targeting
+    // Java 11 move these tests to OptionalBackportTest (out of examplesJava9).
+
+    // Available since N.
+    ignoreInvokes("empty");
+    ignoreInvokes("of");
+
+    registerTarget(AndroidApiLevel.T, 4);
+  }
+
+  public static class OptionalIntBackportJava9Main {
+
+    public static void main(String[] args) {
+      testIfPresentOrElseInt();
+      testStreamInt();
+    }
+
+    private static void testIfPresentOrElseInt() {
+      OptionalInt value = OptionalInt.of(1);
+      OptionalInt emptyValue = OptionalInt.empty();
+      value.ifPresentOrElse(val -> {}, () -> assertTrue(false));
+      emptyValue.ifPresentOrElse(val -> assertTrue(false), () -> {});
+    }
+
+    private static void testStreamInt() {
+      OptionalInt value = OptionalInt.of(2);
+      OptionalInt emptyValue = OptionalInt.empty();
+      assertTrue(value.stream().count() == 1);
+      assertTrue(emptyValue.stream().count() == 0);
+    }
+
+    private static void assertTrue(boolean value) {
+      if (!value) {
+        throw new AssertionError("Expected <true> but was <false>");
+      }
+    }
+  }
+}
diff --git a/src/test/examplesJava9/backport/OptionalLongBackportJava9Main.java b/src/test/examplesJava9/backport/OptionalLongBackportJava9Main.java
deleted file mode 100644
index 07438e1..0000000
--- a/src/test/examplesJava9/backport/OptionalLongBackportJava9Main.java
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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 backport;
-
-import java.util.OptionalLong;
-
-public final class OptionalLongBackportJava9Main {
-
-  public static void main(String[] args) {
-    testIfPresentOrElseLong();
-    testStreamLong();
-  }
-
-  private static void testIfPresentOrElseLong() {
-    OptionalLong value = OptionalLong.of(1L);
-    OptionalLong emptyValue = OptionalLong.empty();
-    value.ifPresentOrElse(val -> {}, () -> assertTrue(false));
-    emptyValue.ifPresentOrElse(val -> assertTrue(false), () -> {});
-  }
-
-  private static void testStreamLong() {
-    OptionalLong value = OptionalLong.of(2L);
-    OptionalLong emptyValue = OptionalLong.empty();
-    assertTrue(value.stream().count() == 1);
-    assertTrue(emptyValue.stream().count() == 0);
-  }
-
-  private static void assertTrue(boolean value) {
-    if (!value) {
-      throw new AssertionError("Expected <true> but was <false>");
-    }
-  }
-}
diff --git a/src/test/examplesJava9/backport/OptionalLongBackportJava9Test.java b/src/test/examplesJava9/backport/OptionalLongBackportJava9Test.java
new file mode 100644
index 0000000..019a0f2
--- /dev/null
+++ b/src/test/examplesJava9/backport/OptionalLongBackportJava9Test.java
@@ -0,0 +1,71 @@
+// 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 backport;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.desugar.backports.AbstractBackportTest;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.util.OptionalLong;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public final class OptionalLongBackportJava9Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return TestBase.getTestParameters()
+        .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+        .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
+        .enableApiLevelsForCf()
+        .build();
+  }
+
+  public OptionalLongBackportJava9Test(TestParameters parameters) {
+    super(parameters, OptionalLong.class, OptionalLongBackportJava9Main.class);
+    // Note: The methods in this test exist in android.jar from Android T. When R8 builds targeting
+    // Java 11 move these tests to OptionalBackportTest (out of examplesJava9).
+
+    // Available since N.
+    ignoreInvokes("empty");
+    ignoreInvokes("getAsLong");
+    ignoreInvokes("isPresent");
+    ignoreInvokes("of");
+
+    registerTarget(AndroidApiLevel.T, 4);
+  }
+
+  public static class OptionalLongBackportJava9Main {
+
+    public static void main(String[] args) {
+      testIfPresentOrElseLong();
+      testStreamLong();
+    }
+
+    private static void testIfPresentOrElseLong() {
+      OptionalLong value = OptionalLong.of(1L);
+      OptionalLong emptyValue = OptionalLong.empty();
+      value.ifPresentOrElse(val -> {}, () -> assertTrue(false));
+      emptyValue.ifPresentOrElse(val -> assertTrue(false), () -> {});
+    }
+
+    private static void testStreamLong() {
+      OptionalLong value = OptionalLong.of(2L);
+      OptionalLong emptyValue = OptionalLong.empty();
+      assertTrue(value.stream().count() == 1);
+      assertTrue(emptyValue.stream().count() == 0);
+    }
+
+    private static void assertTrue(boolean value) {
+      if (!value) {
+        throw new AssertionError("Expected <true> but was <false>");
+      }
+    }
+  }
+}
diff --git a/src/test/examplesJava9/backport/SetBackportJava9Main.java b/src/test/examplesJava9/backport/SetBackportJava9Main.java
deleted file mode 100644
index d824bd0..0000000
--- a/src/test/examplesJava9/backport/SetBackportJava9Main.java
+++ /dev/null
@@ -1,207 +0,0 @@
-// 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 backport;
-
-import java.util.Set;
-
-public class SetBackportJava9Main {
-
-  public static void main(String[] args) {
-    testOf0();
-    testOf1();
-    testOf2();
-    testOf10();
-    testOfVarargs();
-  }
-
-  private static void testOf0() {
-    Set<Object> ofObject = Set.of();
-    assertEquals(0, ofObject.size());
-    assertFalse(ofObject.contains(new Object()));
-    assertMutationNotAllowed(ofObject);
-
-    Set<Integer> ofInteger = Set.of();
-    assertEquals(0, ofInteger.size());
-    assertFalse(ofInteger.contains(0));
-  }
-
-  private static void testOf1() {
-    Object anObject = new Object();
-    Set<Object> ofObject = Set.of(anObject);
-    assertEquals(1, ofObject.size());
-    assertTrue(ofObject.contains(anObject));
-    assertFalse(ofObject.contains(new Object()));
-    assertMutationNotAllowed(ofObject);
-
-    Set<Integer> ofInteger = Set.of(1);
-    assertEquals(1, ofInteger.size());
-    assertTrue(ofInteger.contains(1));
-    assertFalse(ofInteger.contains(2));
-
-    try {
-      Set.of((Object) null);
-      throw new AssertionError();
-    } catch (NullPointerException expected) {
-    }
-  }
-
-  private static void testOf2() {
-    Object anObject0 = new Object();
-    Object anObject1 = new Object();
-    Set<Object> ofObject = Set.of(anObject0, anObject1);
-    assertEquals(2, ofObject.size());
-    assertTrue(ofObject.contains(anObject0));
-    assertTrue(ofObject.contains(anObject1));
-    assertFalse(ofObject.contains(new Object()));
-    assertMutationNotAllowed(ofObject);
-
-    Set<Integer> ofInteger = Set.of(1, 2);
-    assertEquals(2, ofInteger.size());
-    assertTrue(ofInteger.contains(1));
-    assertTrue(ofInteger.contains(2));
-    assertFalse(ofInteger.contains(3));
-
-    Set<Object> ofMixed = Set.of(anObject0, 1);
-    assertEquals(2, ofMixed.size());
-    assertTrue(ofMixed.contains(anObject0));
-    assertTrue(ofMixed.contains(1));
-    assertFalse(ofMixed.contains(2));
-    assertFalse(ofMixed.contains(anObject1));
-    assertMutationNotAllowed(ofMixed);
-
-    try {
-      Set.of(1, null);
-      throw new AssertionError();
-    } catch (NullPointerException expected) {
-    }
-
-    try {
-      Set.of(1, 1);
-      throw new AssertionError();
-    } catch (IllegalArgumentException expected) {
-      assertEquals("duplicate element: 1", expected.getMessage());
-    }
-  }
-
-  private static void testOf10() {
-    Object anObject0 = new Object();
-    Object anObject6 = new Object();
-    Object anObject9 = new Object();
-    Set<Object> ofObject =
-        Set.of(anObject0, new Object(), new Object(), new Object(), new Object(), new Object(),
-            anObject6, new Object(), new Object(), anObject9);
-    assertEquals(10, ofObject.size());
-    assertTrue(ofObject.contains(anObject0));
-    assertTrue(ofObject.contains(anObject6));
-    assertTrue(ofObject.contains(anObject9));
-    assertFalse(ofObject.contains(new Object()));
-    assertMutationNotAllowed(ofObject);
-
-    Set<Integer> ofInteger = Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
-    assertEquals(10, ofInteger.size());
-    assertTrue(ofInteger.contains(0));
-    assertTrue(ofInteger.contains(6));
-    assertTrue(ofInteger.contains(9));
-    assertFalse(ofInteger.contains(10));
-
-    Set<Object> ofMixed = Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, anObject9);
-    assertEquals(10, ofMixed.size());
-    assertTrue(ofMixed.contains(0));
-    assertTrue(ofMixed.contains(6));
-    assertTrue(ofMixed.contains(anObject9));
-    assertFalse(ofMixed.contains(anObject0));
-    assertMutationNotAllowed(ofMixed);
-
-    try {
-      Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, null);
-      throw new AssertionError();
-    } catch (NullPointerException expected) {
-    }
-
-    try {
-      Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 0);
-      throw new AssertionError();
-    } catch (IllegalArgumentException expected) {
-      assertEquals("duplicate element: 0", expected.getMessage());
-    }
-  }
-
-  private static void testOfVarargs() {
-    Object anObject0 = new Object();
-    Object anObject6 = new Object();
-    Object anObject10 = new Object();
-    Set<Object> ofObject =
-        Set.of(anObject0, new Object(), new Object(), new Object(), new Object(), new Object(),
-            anObject6, new Object(), new Object(), new Object(), anObject10);
-    assertEquals(11, ofObject.size());
-    assertTrue(ofObject.contains(anObject0));
-    assertTrue(ofObject.contains(anObject6));
-    assertTrue(ofObject.contains(anObject10));
-    assertFalse(ofObject.contains(new Object()));
-    assertMutationNotAllowed(ofObject);
-
-    Set<Integer> ofInteger = Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
-    assertEquals(11, ofInteger.size());
-    assertTrue(ofInteger.contains(0));
-    assertTrue(ofInteger.contains(6));
-    assertTrue(ofInteger.contains(10));
-    assertFalse(ofInteger.contains(11));
-
-    Set<Object> ofMixed = Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, anObject10);
-    assertEquals(11, ofMixed.size());
-    assertTrue(ofMixed.contains(0));
-    assertTrue(ofMixed.contains(6));
-    assertTrue(ofMixed.contains(anObject10));
-    assertFalse(ofMixed.contains(10));
-    assertFalse(ofMixed.contains(anObject0));
-    assertMutationNotAllowed(ofMixed);
-
-    // Ensure the supplied mutable array is not used directly since it is mutable.
-    Object[] mutableArray = { anObject0 };
-    Set<Object> ofMutableArray = Set.of(mutableArray);
-    mutableArray[0] = anObject10;
-    assertTrue(ofMutableArray.contains(anObject0));
-    assertFalse(ofMutableArray.contains(anObject10));
-
-    try {
-      Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, null);
-      throw new AssertionError();
-    } catch (NullPointerException expected) {
-    }
-
-    try {
-      Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
-      throw new AssertionError();
-    } catch (IllegalArgumentException expected) {
-      assertEquals("duplicate element: 0", expected.getMessage());
-    }
-  }
-
-  private static void assertMutationNotAllowed(Set<Object> ofObject) {
-    try {
-      ofObject.add(new Object());
-      throw new AssertionError();
-    } catch (UnsupportedOperationException expected) {
-    }
-  }
-
-  private static void assertTrue(boolean value) {
-    if (!value) {
-      throw new AssertionError("Expected <true> but was <false>");
-    }
-  }
-
-  private static void assertFalse(boolean value) {
-    if (value) {
-      throw new AssertionError("Expected <false> but was <true>");
-    }
-  }
-
-  private static void assertEquals(Object expected, Object actual) {
-    if (expected != actual && !expected.equals(actual)) {
-      throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
-    }
-  }
-}
diff --git a/src/test/examplesJava9/backport/SetBackportJava9Test.java b/src/test/examplesJava9/backport/SetBackportJava9Test.java
new file mode 100644
index 0000000..9682a77
--- /dev/null
+++ b/src/test/examplesJava9/backport/SetBackportJava9Test.java
@@ -0,0 +1,280 @@
+// 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 backport;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.desugar.backports.AbstractBackportTest;
+import com.android.tools.r8.desugar.backports.IgnoreInvokes;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.util.Set;
+import org.hamcrest.CoreMatchers;
+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 SetBackportJava9Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return TestBase.getTestParameters()
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
+        .withDexRuntimes()
+        .withAllApiLevelsAlsoForCf()
+        .build();
+  }
+
+  public SetBackportJava9Test(TestParameters parameters) {
+    super(parameters, Set.class, SetBackportJava9Main.class);
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to SetBackportTest.
+
+    // Available since API 1 and used to test created sets.
+    ignoreInvokes("add");
+    ignoreInvokes("contains");
+    ignoreInvokes("size");
+
+    // Set.of added in API 30.
+    registerTarget(AndroidApiLevel.R, 21);
+  }
+
+  @Test
+  public void desugaringApiLevelR() throws Exception {
+    // TODO(b/154759404): This test should start to fail when testing on an Android R VM.
+    // This has now been checked with S, when R testing is added check and remove this.
+    if (parameters.getRuntime().isDex() && parameters.getApiLevel().isEqualTo(AndroidApiLevel.R)) {
+      testForD8()
+          .setMinApi(AndroidApiLevel.R)
+          .addProgramClasses(MiniAssert.class, IgnoreInvokes.class)
+          .addProgramClasses(SetBackportJava9Main.class)
+          .setIncludeClassesChecksum(true)
+          .compile()
+          .run(parameters.getRuntime(), SetBackportJava9Main.class)
+          .assertFailureWithErrorThatMatches(
+              CoreMatchers.containsString("java.lang.NoSuchMethodError"));
+    }
+  }
+
+  public static class SetBackportJava9Main {
+
+    public static void main(String[] args) {
+      testOf0();
+      testOf1();
+      testOf2();
+      testOf10();
+      testOfVarargs();
+    }
+
+    private static void testOf0() {
+      Set<Object> ofObject = Set.of();
+      assertEquals(0, ofObject.size());
+      assertFalse(ofObject.contains(new Object()));
+      assertMutationNotAllowed(ofObject);
+
+      Set<Integer> ofInteger = Set.of();
+      assertEquals(0, ofInteger.size());
+      assertFalse(ofInteger.contains(0));
+    }
+
+    private static void testOf1() {
+      Object anObject = new Object();
+      Set<Object> ofObject = Set.of(anObject);
+      assertEquals(1, ofObject.size());
+      assertTrue(ofObject.contains(anObject));
+      assertFalse(ofObject.contains(new Object()));
+      assertMutationNotAllowed(ofObject);
+
+      Set<Integer> ofInteger = Set.of(1);
+      assertEquals(1, ofInteger.size());
+      assertTrue(ofInteger.contains(1));
+      assertFalse(ofInteger.contains(2));
+
+      try {
+        Set.of((Object) null);
+        throw new AssertionError();
+      } catch (NullPointerException expected) {
+      }
+    }
+
+    private static void testOf2() {
+      Object anObject0 = new Object();
+      Object anObject1 = new Object();
+      Set<Object> ofObject = Set.of(anObject0, anObject1);
+      assertEquals(2, ofObject.size());
+      assertTrue(ofObject.contains(anObject0));
+      assertTrue(ofObject.contains(anObject1));
+      assertFalse(ofObject.contains(new Object()));
+      assertMutationNotAllowed(ofObject);
+
+      Set<Integer> ofInteger = Set.of(1, 2);
+      assertEquals(2, ofInteger.size());
+      assertTrue(ofInteger.contains(1));
+      assertTrue(ofInteger.contains(2));
+      assertFalse(ofInteger.contains(3));
+
+      Set<Object> ofMixed = Set.of(anObject0, 1);
+      assertEquals(2, ofMixed.size());
+      assertTrue(ofMixed.contains(anObject0));
+      assertTrue(ofMixed.contains(1));
+      assertFalse(ofMixed.contains(2));
+      assertFalse(ofMixed.contains(anObject1));
+      assertMutationNotAllowed(ofMixed);
+
+      try {
+        Set.of(1, null);
+        throw new AssertionError();
+      } catch (NullPointerException expected) {
+      }
+
+      try {
+        Set.of(1, 1);
+        throw new AssertionError();
+      } catch (IllegalArgumentException expected) {
+        assertEquals("duplicate element: 1", expected.getMessage());
+      }
+    }
+
+    private static void testOf10() {
+      Object anObject0 = new Object();
+      Object anObject6 = new Object();
+      Object anObject9 = new Object();
+      Set<Object> ofObject =
+          Set.of(
+              anObject0,
+              new Object(),
+              new Object(),
+              new Object(),
+              new Object(),
+              new Object(),
+              anObject6,
+              new Object(),
+              new Object(),
+              anObject9);
+      assertEquals(10, ofObject.size());
+      assertTrue(ofObject.contains(anObject0));
+      assertTrue(ofObject.contains(anObject6));
+      assertTrue(ofObject.contains(anObject9));
+      assertFalse(ofObject.contains(new Object()));
+      assertMutationNotAllowed(ofObject);
+
+      Set<Integer> ofInteger = Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+      assertEquals(10, ofInteger.size());
+      assertTrue(ofInteger.contains(0));
+      assertTrue(ofInteger.contains(6));
+      assertTrue(ofInteger.contains(9));
+      assertFalse(ofInteger.contains(10));
+
+      Set<Object> ofMixed = Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, anObject9);
+      assertEquals(10, ofMixed.size());
+      assertTrue(ofMixed.contains(0));
+      assertTrue(ofMixed.contains(6));
+      assertTrue(ofMixed.contains(anObject9));
+      assertFalse(ofMixed.contains(anObject0));
+      assertMutationNotAllowed(ofMixed);
+
+      try {
+        Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, null);
+        throw new AssertionError();
+      } catch (NullPointerException expected) {
+      }
+
+      try {
+        Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 0);
+        throw new AssertionError();
+      } catch (IllegalArgumentException expected) {
+        assertEquals("duplicate element: 0", expected.getMessage());
+      }
+    }
+
+    private static void testOfVarargs() {
+      Object anObject0 = new Object();
+      Object anObject6 = new Object();
+      Object anObject10 = new Object();
+      Set<Object> ofObject =
+          Set.of(
+              anObject0,
+              new Object(),
+              new Object(),
+              new Object(),
+              new Object(),
+              new Object(),
+              anObject6,
+              new Object(),
+              new Object(),
+              new Object(),
+              anObject10);
+      assertEquals(11, ofObject.size());
+      assertTrue(ofObject.contains(anObject0));
+      assertTrue(ofObject.contains(anObject6));
+      assertTrue(ofObject.contains(anObject10));
+      assertFalse(ofObject.contains(new Object()));
+      assertMutationNotAllowed(ofObject);
+
+      Set<Integer> ofInteger = Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+      assertEquals(11, ofInteger.size());
+      assertTrue(ofInteger.contains(0));
+      assertTrue(ofInteger.contains(6));
+      assertTrue(ofInteger.contains(10));
+      assertFalse(ofInteger.contains(11));
+
+      Set<Object> ofMixed = Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, anObject10);
+      assertEquals(11, ofMixed.size());
+      assertTrue(ofMixed.contains(0));
+      assertTrue(ofMixed.contains(6));
+      assertTrue(ofMixed.contains(anObject10));
+      assertFalse(ofMixed.contains(10));
+      assertFalse(ofMixed.contains(anObject0));
+      assertMutationNotAllowed(ofMixed);
+
+      // Ensure the supplied mutable array is not used directly since it is mutable.
+      Object[] mutableArray = {anObject0};
+      Set<Object> ofMutableArray = Set.of(mutableArray);
+      mutableArray[0] = anObject10;
+      assertTrue(ofMutableArray.contains(anObject0));
+      assertFalse(ofMutableArray.contains(anObject10));
+
+      try {
+        Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, null);
+        throw new AssertionError();
+      } catch (NullPointerException expected) {
+      }
+
+      try {
+        Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
+        throw new AssertionError();
+      } catch (IllegalArgumentException expected) {
+        assertEquals("duplicate element: 0", expected.getMessage());
+      }
+    }
+
+    private static void assertMutationNotAllowed(Set<Object> ofObject) {
+      try {
+        ofObject.add(new Object());
+        throw new AssertionError();
+      } catch (UnsupportedOperationException expected) {
+      }
+    }
+
+    private static void assertTrue(boolean value) {
+      if (!value) {
+        throw new AssertionError("Expected <true> but was <false>");
+      }
+    }
+
+    private static void assertFalse(boolean value) {
+      if (value) {
+        throw new AssertionError("Expected <false> but was <true>");
+      }
+    }
+
+    private static void assertEquals(Object expected, Object actual) {
+      if (expected != actual && !expected.equals(actual)) {
+        throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+      }
+    }
+  }
+}
diff --git a/src/test/examplesJava9/backport/ShortBackportJava9Main.java b/src/test/examplesJava9/backport/ShortBackportJava9Main.java
deleted file mode 100644
index 63764dd..0000000
--- a/src/test/examplesJava9/backport/ShortBackportJava9Main.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package backport;
-
-public final class ShortBackportJava9Main {
-  private static final byte MIN_UNSIGNED_VALUE = (short) 0;
-  private static final byte MAX_UNSIGNED_VALUE = (short) -1;
-
-  public static void main(String[] args) {
-    testCompareUnsigned();
-  }
-
-  private static void testCompareUnsigned() {
-    assertTrue(Short.compareUnsigned(MIN_UNSIGNED_VALUE, MIN_UNSIGNED_VALUE) == 0);
-    assertTrue(Short.compareUnsigned(MIN_UNSIGNED_VALUE, Short.MAX_VALUE) < 0);
-    assertTrue(Short.compareUnsigned(MIN_UNSIGNED_VALUE, Short.MIN_VALUE) < 0);
-    assertTrue(Short.compareUnsigned(MIN_UNSIGNED_VALUE, MAX_UNSIGNED_VALUE) < 0);
-
-    assertTrue(Short.compareUnsigned(Short.MAX_VALUE, MIN_UNSIGNED_VALUE) > 0);
-    assertTrue(Short.compareUnsigned(Short.MAX_VALUE, Short.MAX_VALUE) == 0);
-    assertTrue(Short.compareUnsigned(Short.MAX_VALUE, Short.MIN_VALUE) < 0);
-    assertTrue(Short.compareUnsigned(Short.MAX_VALUE, MAX_UNSIGNED_VALUE) < 0);
-
-    assertTrue(Short.compareUnsigned(Short.MIN_VALUE, MIN_UNSIGNED_VALUE) > 0);
-    assertTrue(Short.compareUnsigned(Short.MIN_VALUE, Short.MAX_VALUE) > 0);
-    assertTrue(Short.compareUnsigned(Short.MIN_VALUE, Short.MIN_VALUE) == 0);
-    assertTrue(Short.compareUnsigned(Short.MIN_VALUE, MAX_UNSIGNED_VALUE) < 0);
-
-    assertTrue(Short.compareUnsigned(MAX_UNSIGNED_VALUE, MIN_UNSIGNED_VALUE) > 0);
-    assertTrue(Short.compareUnsigned(MAX_UNSIGNED_VALUE, Short.MAX_VALUE) > 0);
-    assertTrue(Short.compareUnsigned(MAX_UNSIGNED_VALUE, Short.MIN_VALUE) > 0);
-    assertTrue(Short.compareUnsigned(MAX_UNSIGNED_VALUE, MAX_UNSIGNED_VALUE) == 0);
-  }
-
-  private static void assertTrue(boolean value) {
-    if (!value) {
-      throw new AssertionError("Expected <true> but was <false>");
-    }
-  }
-}
diff --git a/src/test/examplesJava9/backport/ShortBackportJava9Test.java b/src/test/examplesJava9/backport/ShortBackportJava9Test.java
new file mode 100644
index 0000000..43ccb9f
--- /dev/null
+++ b/src/test/examplesJava9/backport/ShortBackportJava9Test.java
@@ -0,0 +1,69 @@
+// 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 backport;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.desugar.backports.AbstractBackportTest;
+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 ShortBackportJava9Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters()
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
+        .withDexRuntimes()
+        .withAllApiLevelsAlsoForCf()
+        .build();
+  }
+
+  public ShortBackportJava9Test(TestParameters parameters) {
+    super(parameters, Short.class, ShortBackportJava9Main.class);
+
+    // Short.compareUnsigned added in API 31.
+    registerTarget(AndroidApiLevel.S, 16);
+  }
+
+  public static class ShortBackportJava9Main {
+    private static final byte MIN_UNSIGNED_VALUE = (short) 0;
+    private static final byte MAX_UNSIGNED_VALUE = (short) -1;
+
+    public static void main(String[] args) {
+      testCompareUnsigned();
+    }
+
+    private static void testCompareUnsigned() {
+      assertTrue(Short.compareUnsigned(MIN_UNSIGNED_VALUE, MIN_UNSIGNED_VALUE) == 0);
+      assertTrue(Short.compareUnsigned(MIN_UNSIGNED_VALUE, Short.MAX_VALUE) < 0);
+      assertTrue(Short.compareUnsigned(MIN_UNSIGNED_VALUE, Short.MIN_VALUE) < 0);
+      assertTrue(Short.compareUnsigned(MIN_UNSIGNED_VALUE, MAX_UNSIGNED_VALUE) < 0);
+
+      assertTrue(Short.compareUnsigned(Short.MAX_VALUE, MIN_UNSIGNED_VALUE) > 0);
+      assertTrue(Short.compareUnsigned(Short.MAX_VALUE, Short.MAX_VALUE) == 0);
+      assertTrue(Short.compareUnsigned(Short.MAX_VALUE, Short.MIN_VALUE) < 0);
+      assertTrue(Short.compareUnsigned(Short.MAX_VALUE, MAX_UNSIGNED_VALUE) < 0);
+
+      assertTrue(Short.compareUnsigned(Short.MIN_VALUE, MIN_UNSIGNED_VALUE) > 0);
+      assertTrue(Short.compareUnsigned(Short.MIN_VALUE, Short.MAX_VALUE) > 0);
+      assertTrue(Short.compareUnsigned(Short.MIN_VALUE, Short.MIN_VALUE) == 0);
+      assertTrue(Short.compareUnsigned(Short.MIN_VALUE, MAX_UNSIGNED_VALUE) < 0);
+
+      assertTrue(Short.compareUnsigned(MAX_UNSIGNED_VALUE, MIN_UNSIGNED_VALUE) > 0);
+      assertTrue(Short.compareUnsigned(MAX_UNSIGNED_VALUE, Short.MAX_VALUE) > 0);
+      assertTrue(Short.compareUnsigned(MAX_UNSIGNED_VALUE, Short.MIN_VALUE) > 0);
+      assertTrue(Short.compareUnsigned(MAX_UNSIGNED_VALUE, MAX_UNSIGNED_VALUE) == 0);
+    }
+
+    private static void assertTrue(boolean value) {
+      if (!value) {
+        throw new AssertionError("Expected <true> but was <false>");
+      }
+    }
+  }
+}
diff --git a/src/test/examplesJava9/backport/StreamBackportJava9Main.java b/src/test/examplesJava9/backport/StreamBackportJava9Main.java
deleted file mode 100644
index b8c8f28..0000000
--- a/src/test/examplesJava9/backport/StreamBackportJava9Main.java
+++ /dev/null
@@ -1,28 +0,0 @@
-// 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 backport;
-
-import java.util.stream.Stream;
-
-public final class StreamBackportJava9Main {
-
-  public static void main(String[] args) {
-    testOfNullable();
-  }
-
-  public static void testOfNullable() {
-    Object guineaPig = new Object();
-    Stream<Object> streamNonEmpty = Stream.ofNullable(guineaPig);
-    assertTrue(streamNonEmpty.count() == 1);
-    Stream<Object> streamEmpty = Stream.ofNullable(null);
-    assertTrue(streamEmpty.count() == 0);
-  }
-
-  private static void assertTrue(boolean value) {
-    if (!value) {
-      throw new AssertionError("Expected <true> but was <false>");
-    }
-  }
-}
diff --git a/src/test/examplesJava9/backport/StreamBackportJava9Test.java b/src/test/examplesJava9/backport/StreamBackportJava9Test.java
new file mode 100644
index 0000000..c6a7a75
--- /dev/null
+++ b/src/test/examplesJava9/backport/StreamBackportJava9Test.java
@@ -0,0 +1,64 @@
+// 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 backport;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.desugar.backports.AbstractBackportTest;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.util.stream.Stream;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public final class StreamBackportJava9Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return TestBase.getTestParameters()
+        .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+        .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
+        .enableApiLevelsForCf()
+        .build();
+  }
+
+  public StreamBackportJava9Test(TestParameters parameters) {
+    super(parameters, Stream.class, StreamBackportJava9Main.class);
+    // Note: The methods in this test exist from Android U. However, they are only available from
+    // Java 9. When tests build with Java 9 migrate to StreamBackportTest and add insert
+    // StreamBackportJava9Main as an inner class here.
+
+    // Available since N as part of library desugaring.
+    ignoreInvokes("of");
+    ignoreInvokes("empty");
+    ignoreInvokes("count");
+
+    registerTarget(AndroidApiLevel.U, 2);
+  }
+
+  public static class StreamBackportJava9Main {
+
+    public static void main(String[] args) {
+      testOfNullable();
+    }
+
+    public static void testOfNullable() {
+      Object guineaPig = new Object();
+      Stream<Object> streamNonEmpty = Stream.ofNullable(guineaPig);
+      assertTrue(streamNonEmpty.count() == 1);
+      Stream<Object> streamEmpty = Stream.ofNullable(null);
+      assertTrue(streamEmpty.count() == 0);
+    }
+
+    private static void assertTrue(boolean value) {
+      if (!value) {
+        throw new AssertionError("Expected <true> but was <false>");
+      }
+    }
+  }
+}
diff --git a/src/test/examplesJava9/backport/StrictMathBackportJava9Main.java b/src/test/examplesJava9/backport/StrictMathBackportJava9Main.java
deleted file mode 100644
index e9c33ca..0000000
--- a/src/test/examplesJava9/backport/StrictMathBackportJava9Main.java
+++ /dev/null
@@ -1,101 +0,0 @@
-// 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 backport;
-
-import java.math.BigInteger;
-
-public class StrictMathBackportJava9Main {
-
-  public static void main(String[] args) {
-    testMultiplyExactLongInt();
-    testMultiplyFull();
-    testFloorDivLongInt();
-    testFloorModLongInt();
-  }
-
-  public static void testMultiplyExactLongInt() {
-    assertEquals(8L, StrictMath.multiplyExact(2L, 4));
-    assertEquals(Long.MAX_VALUE, StrictMath.multiplyExact(Long.MAX_VALUE, 1));
-    assertEquals(Long.MIN_VALUE, StrictMath.multiplyExact(Long.MIN_VALUE / 2L, 2));
-    try {
-      throw new AssertionError(StrictMath.multiplyExact(Long.MAX_VALUE, 2));
-    } catch (ArithmeticException expected) {
-    }
-    try {
-      throw new AssertionError(StrictMath.multiplyExact(Long.MIN_VALUE, 2));
-    } catch (ArithmeticException expected) {
-    }
-  }
-
-  public static void testMultiplyFull() {
-    assertEquals(8L, StrictMath.multiplyFull(2, 4));
-    assertEquals(4611686014132420609L,
-        StrictMath.multiplyFull(Integer.MAX_VALUE, Integer.MAX_VALUE));
-    assertEquals(-4611686016279904256L,
-        StrictMath.multiplyFull(Integer.MAX_VALUE, Integer.MIN_VALUE));
-    assertEquals(4611686018427387904L,
-        StrictMath.multiplyFull(Integer.MIN_VALUE, Integer.MIN_VALUE));
-  }
-
-  public static void testMultiplyHigh() {
-    long[] interestingValues = {
-        Long.MIN_VALUE, Long.MAX_VALUE,
-        Integer.MIN_VALUE, Integer.MAX_VALUE,
-        Short.MIN_VALUE, Short.MAX_VALUE,
-        Byte.MIN_VALUE, Byte.MAX_VALUE,
-        0L,
-        -1L, 1L,
-        -42L, 42L
-    };
-    for (long x : interestingValues) {
-      for (long y : interestingValues) {
-        long expected = BigInteger.valueOf(x)
-            .multiply(BigInteger.valueOf(y))
-            .shiftRight(64)
-            .longValue();
-        assertEquals(expected, StrictMath.multiplyHigh(x, y));
-      }
-    }
-  }
-
-  public static void testFloorDivLongInt() {
-    assertEquals(1L, StrictMath.floorDiv(4L, 4));
-    assertEquals(1L, StrictMath.floorDiv(-4L, -4));
-    assertEquals(-1L, StrictMath.floorDiv(-4L, 4));
-    assertEquals(-1L, StrictMath.floorDiv(4L, -4));
-
-    assertEquals(1L, StrictMath.floorDiv(4L, 3));
-    assertEquals(1L, StrictMath.floorDiv(-4L, -3));
-    assertEquals(-2L, StrictMath.floorDiv(-4L, 3));
-    assertEquals(-2L, StrictMath.floorDiv(4L, -3));
-
-    // Spec edge case: result is actually MAX_VALUE+1 which becomes MIN_VALUE.
-    assertEquals(Long.MIN_VALUE, StrictMath.floorDiv(Long.MIN_VALUE, -1));
-  }
-
-  public static void testFloorModLongInt() {
-    assertEquals(0, StrictMath.floorMod(4L, 4));
-    assertEquals(0, StrictMath.floorMod(-4L, -4));
-    assertEquals(0, StrictMath.floorMod(-4L, 4));
-    assertEquals(0, StrictMath.floorMod(4L, -4));
-
-    assertEquals(1, StrictMath.floorMod(4L, 3));
-    assertEquals(-1, StrictMath.floorMod(-4L, -3));
-    assertEquals(2, StrictMath.floorMod(-4L, 3));
-    assertEquals(-2, StrictMath.floorMod(4L, -3));
-  }
-
-  private static void assertEquals(int expected, int actual) {
-    if (expected != actual) {
-      throw new AssertionError("Expected <" + expected + "> but was <" + actual + '>');
-    }
-  }
-
-  private static void assertEquals(long expected, long actual) {
-    if (expected != actual) {
-      throw new AssertionError("Expected <" + expected + "> but was <" + actual + '>');
-    }
-  }
-}
diff --git a/src/test/examplesJava9/backport/StrictMathBackportJava9Test.java b/src/test/examplesJava9/backport/StrictMathBackportJava9Test.java
new file mode 100644
index 0000000..b71e4ac
--- /dev/null
+++ b/src/test/examplesJava9/backport/StrictMathBackportJava9Test.java
@@ -0,0 +1,130 @@
+// 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 backport;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.desugar.backports.AbstractBackportTest;
+import java.math.BigInteger;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public final class StrictMathBackportJava9Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return TestBase.getTestParameters()
+        .withDexRuntimes()
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
+        .withAllApiLevelsAlsoForCf()
+        .build();
+  }
+
+  public StrictMathBackportJava9Test(TestParameters parameters) {
+    super(parameters, Math.class, StrictMathBackportJava9Main.class);
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to StrictMathBackportTest.
+  }
+
+  public static class StrictMathBackportJava9Main {
+
+    public static void main(String[] args) {
+      testMultiplyExactLongInt();
+      testMultiplyFull();
+      testFloorDivLongInt();
+      testFloorModLongInt();
+    }
+
+    public static void testMultiplyExactLongInt() {
+      assertEquals(8L, StrictMath.multiplyExact(2L, 4));
+      assertEquals(Long.MAX_VALUE, StrictMath.multiplyExact(Long.MAX_VALUE, 1));
+      assertEquals(Long.MIN_VALUE, StrictMath.multiplyExact(Long.MIN_VALUE / 2L, 2));
+      try {
+        throw new AssertionError(StrictMath.multiplyExact(Long.MAX_VALUE, 2));
+      } catch (ArithmeticException expected) {
+      }
+      try {
+        throw new AssertionError(StrictMath.multiplyExact(Long.MIN_VALUE, 2));
+      } catch (ArithmeticException expected) {
+      }
+    }
+
+    public static void testMultiplyFull() {
+      assertEquals(8L, StrictMath.multiplyFull(2, 4));
+      assertEquals(
+          4611686014132420609L, StrictMath.multiplyFull(Integer.MAX_VALUE, Integer.MAX_VALUE));
+      assertEquals(
+          -4611686016279904256L, StrictMath.multiplyFull(Integer.MAX_VALUE, Integer.MIN_VALUE));
+      assertEquals(
+          4611686018427387904L, StrictMath.multiplyFull(Integer.MIN_VALUE, Integer.MIN_VALUE));
+    }
+
+    public static void testMultiplyHigh() {
+      long[] interestingValues = {
+        Long.MIN_VALUE,
+        Long.MAX_VALUE,
+        Integer.MIN_VALUE,
+        Integer.MAX_VALUE,
+        Short.MIN_VALUE,
+        Short.MAX_VALUE,
+        Byte.MIN_VALUE,
+        Byte.MAX_VALUE,
+        0L,
+        -1L,
+        1L,
+        -42L,
+        42L
+      };
+      for (long x : interestingValues) {
+        for (long y : interestingValues) {
+          long expected =
+              BigInteger.valueOf(x).multiply(BigInteger.valueOf(y)).shiftRight(64).longValue();
+          assertEquals(expected, StrictMath.multiplyHigh(x, y));
+        }
+      }
+    }
+
+    public static void testFloorDivLongInt() {
+      assertEquals(1L, StrictMath.floorDiv(4L, 4));
+      assertEquals(1L, StrictMath.floorDiv(-4L, -4));
+      assertEquals(-1L, StrictMath.floorDiv(-4L, 4));
+      assertEquals(-1L, StrictMath.floorDiv(4L, -4));
+
+      assertEquals(1L, StrictMath.floorDiv(4L, 3));
+      assertEquals(1L, StrictMath.floorDiv(-4L, -3));
+      assertEquals(-2L, StrictMath.floorDiv(-4L, 3));
+      assertEquals(-2L, StrictMath.floorDiv(4L, -3));
+
+      // Spec edge case: result is actually MAX_VALUE+1 which becomes MIN_VALUE.
+      assertEquals(Long.MIN_VALUE, StrictMath.floorDiv(Long.MIN_VALUE, -1));
+    }
+
+    public static void testFloorModLongInt() {
+      assertEquals(0, StrictMath.floorMod(4L, 4));
+      assertEquals(0, StrictMath.floorMod(-4L, -4));
+      assertEquals(0, StrictMath.floorMod(-4L, 4));
+      assertEquals(0, StrictMath.floorMod(4L, -4));
+
+      assertEquals(1, StrictMath.floorMod(4L, 3));
+      assertEquals(-1, StrictMath.floorMod(-4L, -3));
+      assertEquals(2, StrictMath.floorMod(-4L, 3));
+      assertEquals(-2, StrictMath.floorMod(4L, -3));
+    }
+
+    private static void assertEquals(int expected, int actual) {
+      if (expected != actual) {
+        throw new AssertionError("Expected <" + expected + "> but was <" + actual + '>');
+      }
+    }
+
+    private static void assertEquals(long expected, long actual) {
+      if (expected != actual) {
+        throw new AssertionError("Expected <" + expected + "> but was <" + actual + '>');
+      }
+    }
+  }
+}