Backport List/Map/Set.copyOf factories

Test: tools/test.py --dex_vm all --no-internal -v *Backport*Test*
Test: tools/test.py --no-internal -v *GenerateBackportMethods*
Change-Id: I18521bbdfd8b72eaaa78b4cc09ea5d06a44ec6f3
diff --git a/src/test/examplesJava10/backport/ListBackportJava10Main.java b/src/test/examplesJava10/backport/ListBackportJava10Main.java
new file mode 100644
index 0000000..376f67a
--- /dev/null
+++ b/src/test/examplesJava10/backport/ListBackportJava10Main.java
@@ -0,0 +1,67 @@
+// 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.Arrays;
+import java.util.List;
+
+public class ListBackportJava10Main {
+
+  public static void main(String[] args) {
+    testCopyOf();
+  }
+
+  private static void testCopyOf() {
+    Object anObject0 = new Object();
+    Object anObject1 = new Object();
+    List<Object> original = Arrays.asList(anObject0, anObject1);
+    List<Object> copy = List.copyOf(original);
+    assertEquals(2, copy.size());
+    assertEquals(original, copy);
+    assertSame(anObject0, copy.get(0));
+    assertSame(anObject1, copy.get(1));
+    assertMutationNotAllowed(copy);
+
+    // Mutate the original backing collection and ensure it's not reflected in copy.
+    original.set(0, new Object());
+    assertSame(anObject0, copy.get(0));
+
+    try {
+      List.copyOf(null);
+      throw new AssertionError();
+    } catch (NullPointerException expected) {
+    }
+    try {
+      List.copyOf(Arrays.asList(1, null, 2));
+      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/examplesJava10/backport/MapBackportJava10Main.java b/src/test/examplesJava10/backport/MapBackportJava10Main.java
new file mode 100644
index 0000000..95413e9
--- /dev/null
+++ b/src/test/examplesJava10/backport/MapBackportJava10Main.java
@@ -0,0 +1,82 @@
+// 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.HashMap;
+import java.util.Map;
+
+public class MapBackportJava10Main {
+
+  public static void main(String[] args) {
+    testCopyOf();
+  }
+
+  private static void testCopyOf() {
+    Object key0 = new Object();
+    Object value0 = new Object();
+    Object key1 = new Object();
+    Object value1 = new Object();
+    Map<Object, Object> original = new HashMap<>();
+    original.put(key0, value0);
+    original.put(key1, value1);
+    Map<Object, Object> copy = Map.copyOf(original);
+    assertEquals(2, copy.size());
+    assertEquals(original, copy);
+    assertSame(value0, copy.get(key0));
+    assertSame(value1, copy.get(key1));
+    assertMutationNotAllowed(copy);
+
+    // Mutate the original backing collection and ensure it's not reflected in copy.
+    original.put(key0, new Object());
+    assertSame(value0, copy.get(key0));
+
+    try {
+      Map.copyOf(null);
+      throw new AssertionError();
+    } catch (NullPointerException expected) {
+    }
+    try {
+      Map<Object, Object> map = new HashMap<>();
+      map.put(null, new Object());
+      Map.copyOf(map);
+      throw new AssertionError();
+    } catch (NullPointerException expected) {
+    }
+    try {
+      Map<Object, Object> map = new HashMap<>();
+      map.put(new Object(), null);
+      Map.copyOf(map);
+      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/examplesJava10/backport/SetBackportJava10Main.java b/src/test/examplesJava10/backport/SetBackportJava10Main.java
new file mode 100644
index 0000000..b8fb356
--- /dev/null
+++ b/src/test/examplesJava10/backport/SetBackportJava10Main.java
@@ -0,0 +1,74 @@
+// 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.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class SetBackportJava10Main {
+
+  public static void main(String[] args) {
+    testCopyOf();
+  }
+
+  private static void testCopyOf() {
+    Object anObject0 = new Object();
+    Object anObject1 = new Object();
+    List<Object> original = Arrays.asList(anObject0, anObject1);
+    Set<Object> copy = Set.copyOf(original);
+    assertEquals(2, copy.size());
+    assertEquals(new HashSet<>(original), copy);
+    assertTrue(copy.contains(anObject0));
+    assertTrue(copy.contains(anObject1));
+    assertMutationNotAllowed(copy);
+
+    // Mutate the original backing collection and ensure it's not reflected in copy.
+    Object newObject = new Object();
+    original.set(0, newObject);
+    assertFalse(copy.contains(newObject));
+
+    // Ensure duplicates are allowed and are de-duped.
+    assertEquals(Set.of(1, 2), Set.copyOf(List.of(1, 2, 1, 2)));
+
+    try {
+      Set.copyOf(null);
+      throw new AssertionError();
+    } catch (NullPointerException expected) {
+    }
+    try {
+      Set.copyOf(Arrays.asList(1, null, 2));
+      throw new AssertionError();
+    } catch (NullPointerException expected) {
+    }
+  }
+
+  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/java/com/android/tools/r8/TestRuntime.java b/src/test/java/com/android/tools/r8/TestRuntime.java
index 6347853..99f9a71 100644
--- a/src/test/java/com/android/tools/r8/TestRuntime.java
+++ b/src/test/java/com/android/tools/r8/TestRuntime.java
@@ -25,7 +25,9 @@
   public enum CfVm {
     JDK8("jdk8", 52),
     JDK9("jdk9", 53),
-    JDK11("jdk11", 55);
+    JDK10("jdk10", 54),
+    JDK11("jdk11", 55),
+    ;
 
     private final String name;
     private final int classfileVersion;
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index c0a5ee0..87b2806 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -107,6 +107,7 @@
   public static final String EXAMPLES_ANDROID_O_BUILD_DIR = TESTS_BUILD_DIR + "examplesAndroidO/";
   public static final String EXAMPLES_ANDROID_P_BUILD_DIR = TESTS_BUILD_DIR + "examplesAndroidP/";
   public static final String EXAMPLES_JAVA9_BUILD_DIR = TESTS_BUILD_DIR + "examplesJava9/";
+  public static final String EXAMPLES_JAVA10_BUILD_DIR = TESTS_BUILD_DIR + "examplesJava10/";
   public static final String EXAMPLES_JAVA11_JAR_DIR = TESTS_BUILD_DIR + "examplesJava11/";
   public static final String EXAMPLES_JAVA11_BUILD_DIR = BUILD_DIR + "classes/java/examplesJava11/";
   public static final String EXAMPLES_PROTO_BUILD_DIR = TESTS_BUILD_DIR + "examplesProto/";
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ByteBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ByteBackportJava9Test.java
index 28eefe3..37aa606 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ByteBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ByteBackportJava9Test.java
@@ -31,6 +31,7 @@
 
   public ByteBackportJava9Test(TestParameters parameters) {
     super(parameters, Byte.class, TEST_JAR, "backport.ByteBackportJava9Main");
-    // TODO Once shipped in an actual API level, migrate to ByteBackportTest
+    // 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 ByteBackportTest.
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/CharacterBackportJava11Test.java b/src/test/java/com/android/tools/r8/desugar/backports/CharacterBackportJava11Test.java
index f1d51fc..88be606 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/CharacterBackportJava11Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/CharacterBackportJava11Test.java
@@ -31,6 +31,7 @@
 
   public CharacterBackportJava11Test(TestParameters parameters) {
     super(parameters, Short.class, TEST_JAR, "backport.CharacterBackportJava11Main");
-    // TODO Once shipped in an actual API level, migrate to CharacterBackportTest
+    // 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 CharacterBackportTest.
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava10Test.java
new file mode 100644
index 0000000..309b319
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava10Test.java
@@ -0,0 +1,44 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.desugar.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public class ListBackportJava10Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters()
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK10)
+        .withDexRuntimes()
+        .withAllApiLevels()
+        .build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA10_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public ListBackportJava10Test(TestParameters parameters) {
+    super(parameters, List.class, TEST_JAR, "backport.ListBackportJava10Main");
+    // 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");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java
index a861d1f..03843cc0 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java
@@ -32,7 +32,8 @@
 
   public ListBackportJava9Test(TestParameters parameters) {
     super(parameters, List.class, TEST_JAR, "backport.ListBackportJava9Main");
-    // TODO Once shipped in an actual API level, migrate to ListBackportTest
+    // 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");
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava10Test.java
new file mode 100644
index 0000000..e54d7d8
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava10Test.java
@@ -0,0 +1,44 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.desugar.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Map;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public class MapBackportJava10Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters()
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK10)
+        .withDexRuntimes()
+        .withAllApiLevels()
+        .build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA10_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public MapBackportJava10Test(TestParameters parameters) {
+    super(parameters, Map.class, TEST_JAR, "backport.MapBackportJava10Main");
+    // 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");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava9Test.java
index 06e41f8..fb39b49 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava9Test.java
@@ -32,7 +32,8 @@
 
   public MapBackportJava9Test(TestParameters parameters) {
     super(parameters, Map.class, TEST_JAR, "backport.MapBackportJava9Main");
-    // TODO Once shipped in an actual API level, migrate to MapBackportTest
+    // 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");
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava9Test.java
index 439ef38..387697e 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava9Test.java
@@ -31,6 +31,7 @@
 
   public MathBackportJava9Test(TestParameters parameters) {
     super(parameters, Math.class, TEST_JAR, "backport.MathBackportJava9Main");
-    // TODO Once shipped in an actual API level, migrate to MathBackportTest
+    // 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 MathBackportTest.
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ObjectsBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ObjectsBackportJava9Test.java
index 7544e87..ef8b990 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ObjectsBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ObjectsBackportJava9Test.java
@@ -31,6 +31,7 @@
 
   public ObjectsBackportJava9Test(TestParameters parameters) {
     super(parameters, Short.class, TEST_JAR, "backport.ObjectsBackportJava9Main");
-    // TODO Once shipped in an actual API level, migrate to ObjectsBackportTest
+    // 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 ObjectsBackportTest.
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava9Test.java
index d77052a..0429fe5 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava9Test.java
@@ -33,5 +33,7 @@
 
   public OptionalBackportJava9Test(TestParameters parameters) {
     super(parameters, Short.class, TEST_JAR, "backport.OptionalBackportJava9Main");
+    // 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 OptionalBackportTest.
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava10Test.java
new file mode 100644
index 0000000..5c08b8f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava10Test.java
@@ -0,0 +1,43 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.desugar.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Set;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public class SetBackportJava10Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters()
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK10)
+        .withDexRuntimes()
+        .withAllApiLevels()
+        .build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA10_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public SetBackportJava10Test(TestParameters parameters) {
+    super(parameters, Set.class, TEST_JAR, "backport.SetBackportJava10Main");
+    // 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");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java
index b248e0b..6947ff2 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java
@@ -32,7 +32,8 @@
 
   public SetBackportJava9Test(TestParameters parameters) {
     super(parameters, Set.class, TEST_JAR, "backport.SetBackportJava9Main");
-    // TODO Once shipped in an actual API level, migrate to SetBackportTest
+    // 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");
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ShortBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ShortBackportJava9Test.java
index d56ef5b..beffd8a 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ShortBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ShortBackportJava9Test.java
@@ -31,6 +31,7 @@
 
   public ShortBackportJava9Test(TestParameters parameters) {
     super(parameters, Short.class, TEST_JAR, "backport.ShortBackportJava9Main");
-    // TODO Once shipped in an actual API level, migrate to ShortBackportTest
+    // 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 ShortBackportTest.
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/StreamBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/StreamBackportJava9Test.java
index 0f08ff9..073c179 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/StreamBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/StreamBackportJava9Test.java
@@ -34,6 +34,9 @@
 
   public StreamBackportJava9Test(TestParameters parameters) {
     super(parameters, Stream.class, TEST_JAR, "backport.StreamBackportJava9Main");
+    // 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 StreamBackportTest.
+
     // Available since N as part of library desugaring.
     ignoreInvokes("of");
     ignoreInvokes("empty");
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/StrictMathBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/StrictMathBackportJava9Test.java
index 43cbf48..2f124e7 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/StrictMathBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/StrictMathBackportJava9Test.java
@@ -31,6 +31,7 @@
 
   public StrictMathBackportJava9Test(TestParameters parameters) {
     super(parameters, Math.class, TEST_JAR, "backport.StrictMathBackportJava9Main");
-    // TODO Once shipped in an actual API level, migrate to MathBackportTest
+    // 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.
   }
 }
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/CollectionsMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/CollectionsMethods.java
index dd300da..eac9b74 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/backports/CollectionsMethods.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/CollectionsMethods.java
@@ -4,10 +4,18 @@
 
 package com.android.tools.r8.ir.desugar.backports;
 
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.ListIterator;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
 
 public final class CollectionsMethods {
 
@@ -22,4 +30,30 @@
   public static <T> ListIterator<T> emptyListIterator() {
     return Collections.<T>emptyList().listIterator();
   }
+
+  public static <T> List<T> copyOfList(Collection<? extends T> other) {
+    ArrayList<T> list = new ArrayList<>(other.size());
+    for (T item : other) {
+      list.add(Objects.requireNonNull(item));
+    }
+    return Collections.unmodifiableList(list);
+  }
+
+  public static <T> Set<T> copyOfSet(Collection<? extends T> other) {
+    HashSet<T> set = new HashSet<>(other.size());
+    for (T item : other) {
+      set.add(Objects.requireNonNull(item));
+    }
+    return Collections.unmodifiableSet(set);
+  }
+
+  public static <K, V> Map<K, V> copyOfMap(Map<? extends K, ? extends V> other) {
+    HashMap<K, V> map = new HashMap<>(other.size());
+    for (Map.Entry<? extends K, ? extends V> entry : other.entrySet()) {
+      map.put(
+          Objects.requireNonNull(entry.getKey()),
+          Objects.requireNonNull(entry.getValue()));
+    }
+    return Collections.unmodifiableMap(map);
+  }
 }