Improve List.of backport implementations to match spec

Also update tests to cover behavior mandated by the spec.

Test: tools/test.py --no-internal -v *BackportJava9Test*
Change-Id: I656dc60177aff5f7e66190f5139a3e7fa98976c0
diff --git a/src/test/examplesJava9/backport/ListBackportJava9Main.java b/src/test/examplesJava9/backport/ListBackportJava9Main.java
index 9ad147f..88d20ab 100644
--- a/src/test/examplesJava9/backport/ListBackportJava9Main.java
+++ b/src/test/examplesJava9/backport/ListBackportJava9Main.java
@@ -8,7 +8,7 @@
 
 public class ListBackportJava9Main {
 
-  public static void main(String[] args) throws Exception {
+  public static void main(String[] args) {
     testOf0();
     testOf1();
     testOf2();
@@ -17,50 +17,114 @@
 
   private static void testOf0() {
     List<Object> ofObject = List.of();
+    assertEquals(0, ofObject.size());
+    assertMutationNotAllowed(ofObject);
+
     List<Integer> ofInteger = List.of();
-    assertTrue(ofObject instanceof List);
-    assertTrue(ofObject.size() == 0);
-    assertTrue(ofInteger instanceof List);
-    assertTrue(ofInteger.size() == 0);
+    assertEquals(0, ofInteger.size());
+    assertMutationNotAllowed(ofObject);
   }
 
   private static void testOf1() {
-    List<Object> ofObject = List.of(new Object());
+    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);
-    assertTrue(ofObject instanceof List);
-    assertTrue(ofObject.size() == 1);
-    assertTrue(ofInteger instanceof List);
-    assertTrue(ofInteger.size() == 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() {
-    List<Object> ofObject = List.of(new Object(), new Object());
+    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);
-    List<Object> ofMixed = List.of(new Object(), 1);
-    assertTrue(ofObject instanceof List);
-    assertTrue(ofObject.size() == 2);
-    assertTrue(ofInteger instanceof List);
-    assertTrue(ofInteger.size() == 2);
-    assertTrue(ofMixed instanceof List);
-    assertTrue(ofMixed.size() == 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 e = new Object();
-    List<Object> ofObject = List.of(e, e, e, e, e, e, e, e, e, e);
+    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);
-    List<Object> ofMixed = List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, e);
-    assertTrue(ofObject instanceof List);
-    assertTrue(ofObject.size() == 10);
-    assertTrue(ofInteger instanceof List);
-    assertTrue(ofInteger.size() == 10);
-    assertTrue(ofMixed instanceof List);
-    assertTrue(ofMixed.size() == 10);
+    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 assertTrue(boolean value) {
-    if (!value) {
-      throw new AssertionError("Expected <true> but was <false>");
+  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 + ">");
     }
   }
 }