Move Java9 backport test to java 9 module

Bug: b/380808556
Change-Id: I37db6d24aad86adbb57f86ef9054f09a4ed721bb
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 + ">");
+      }
+    }
+  }
+}