diff --git a/user/super/com/google/gwt/emul/java/util/List.java b/user/super/com/google/gwt/emul/java/util/List.java index d1d20110b8..6cb9dd1dd3 100644 --- a/user/super/com/google/gwt/emul/java/util/List.java +++ b/user/super/com/google/gwt/emul/java/util/List.java @@ -19,6 +19,7 @@ import java.util.function.UnaryOperator; import javaemul.internal.ArrayHelper; +import java.util.stream.Collectors; import jsinterop.annotations.JsIgnore; import jsinterop.annotations.JsMethod; @@ -164,4 +165,9 @@ default Spliterator spliterator() { } @JsNonNull List subList(int fromIndex, int toIndex); + + static List copyOf(Collection coll) { + // TODO if the given collection is immutable and has no nulls, return it + return coll.stream().collect(Collectors.toUnmodifiableList()); + } } diff --git a/user/super/com/google/gwt/emul/java/util/Map.java b/user/super/com/google/gwt/emul/java/util/Map.java index fd3178b041..8afd7d51bb 100644 --- a/user/super/com/google/gwt/emul/java/util/Map.java +++ b/user/super/com/google/gwt/emul/java/util/Map.java @@ -22,6 +22,7 @@ import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Function; +import java.util.stream.Collectors; import jsinterop.annotations.JsIgnore; import jsinterop.annotations.JsNonNull; @@ -412,4 +413,10 @@ default void replaceAll(BiFunction function) int size(); @JsNonNull Collection values(); + + static Map copyOf(Map map) { + // TODO if the given map is immutable and has no nulls, return it + return map.entrySet().stream().collect(Collectors.toUnmodifiableMap(Entry::getKey, + Entry::getValue)); + } } diff --git a/user/super/com/google/gwt/emul/java/util/Set.java b/user/super/com/google/gwt/emul/java/util/Set.java index eddd4dffe9..498a14af87 100644 --- a/user/super/com/google/gwt/emul/java/util/Set.java +++ b/user/super/com/google/gwt/emul/java/util/Set.java @@ -18,6 +18,8 @@ import static javaemul.internal.InternalPreconditions.checkArgument; import static javaemul.internal.InternalPreconditions.checkNotNull; +import java.util.stream.Collectors; + import jsinterop.annotations.JsIgnore; import jsinterop.annotations.JsType; @@ -98,4 +100,9 @@ static Set of(E... elements) { default Spliterator spliterator() { return Spliterators.spliterator(this, Spliterator.DISTINCT); } + + static Set copyOf(Collection coll) { + // TODO if the given collection is immutable and has no nulls, return it + return coll.stream().collect(Collectors.toUnmodifiableSet()); + } } diff --git a/user/test/com/google/gwt/emultest/EmulJava10Suite.java b/user/test/com/google/gwt/emultest/EmulJava10Suite.java index 2cd6369bb8..5a4f28e052 100644 --- a/user/test/com/google/gwt/emultest/EmulJava10Suite.java +++ b/user/test/com/google/gwt/emultest/EmulJava10Suite.java @@ -19,6 +19,9 @@ import com.google.gwt.emultest.java10.util.OptionalIntTest; import com.google.gwt.emultest.java10.util.OptionalLongTest; import com.google.gwt.emultest.java10.util.OptionalTest; +import com.google.gwt.emultest.java10.util.ListTest; +import com.google.gwt.emultest.java10.util.MapTest; +import com.google.gwt.emultest.java10.util.SetTest; import com.google.gwt.emultest.java10.util.stream.CollectorsTest; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -28,10 +31,13 @@ @RunWith(Suite.class) @SuiteClasses({ CollectorsTest.class, + ListTest.class, + MapTest.class, OptionalDoubleTest.class, OptionalIntTest.class, OptionalLongTest.class, OptionalTest.class, + SetTest.class, }) public class EmulJava10Suite { } diff --git a/user/test/com/google/gwt/emultest/java10/util/ListTest.java b/user/test/com/google/gwt/emultest/java10/util/ListTest.java new file mode 100644 index 0000000000..4fcb3f5ecd --- /dev/null +++ b/user/test/com/google/gwt/emultest/java10/util/ListTest.java @@ -0,0 +1,57 @@ +/* + * Copyright 2023 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.emultest.java10.util; + +import static com.google.gwt.emultest.java9.util.ListTest.assertIsImmutableListOf; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Tests for java.util.List Java 10 API emulation. + */ +public class ListTest extends EmulTestBase { + public void testCopyOf() { + assertIsImmutableListOf(List.copyOf(List.of("a", "b")), "a", "b"); + assertIsImmutableListOf(List.copyOf(Arrays.asList("a", "b")), "a", "b"); + + ArrayList arrayList = new ArrayList<>(); + arrayList.add("a"); + arrayList.add("b"); + List copy = List.copyOf(arrayList); + assertIsImmutableListOf(copy, "a", "b"); + + // verify that mutating the original doesn't affect the copy + arrayList.add("c"); + assertEquals(2, copy.size()); + assertFalse(copy.contains("c")); + + arrayList.remove(0); + assertEquals(2, copy.size()); + assertTrue(copy.contains("a")); + + // ensure that null values in the collection result in a NPE + try { + List.copyOf(Arrays.asList("a", null)); + fail("Expected NullPointerException passing copy a collection with a null value"); + } catch (NullPointerException ignore) { + // expected + } + } +} diff --git a/user/test/com/google/gwt/emultest/java10/util/MapTest.java b/user/test/com/google/gwt/emultest/java10/util/MapTest.java new file mode 100644 index 0000000000..0d09a2d7bc --- /dev/null +++ b/user/test/com/google/gwt/emultest/java10/util/MapTest.java @@ -0,0 +1,64 @@ +/* + * Copyright 2023 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.emultest.java10.util; + +import static com.google.gwt.emultest.java9.util.MapTest.assertIsImmutableMapOf; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.HashMap; +import java.util.Map; + +/** + * Tests for java.util.Map Java 10 API emulation. + */ +public class MapTest extends EmulTestBase { + public void testCopyOf() { + assertIsImmutableMapOf(Map.copyOf(Map.of("a", 1)), "a"); + + HashMap hashMap = new HashMap<>(); + hashMap.put("a", 1); + Map copy = Map.copyOf(hashMap); + assertIsImmutableMapOf(copy, "a"); + + // verify that mutating the original has no effect on the copy + hashMap.put("b", 2); + assertFalse(copy.containsKey("b")); + assertEquals(1, copy.size()); + + hashMap.put("a", 5); + assertEquals(1, (int) copy.get("a")); + + // ensure that null values result in a NPE + HashMap mapWithNullKey = new HashMap<>(); + mapWithNullKey.put(null, 1); + try { + Map.copyOf(mapWithNullKey); + fail("expected NullPointerException from copyOf with a null key"); + } catch (NullPointerException ignored) { + // expected + } + + HashMap mapWithNullValue = new HashMap<>(); + mapWithNullValue.put("key", null); + try { + Map.copyOf(mapWithNullValue); + fail("expected NullPointerException from copyOf with a null value"); + } catch (NullPointerException ignored) { + // expected + } + } +} diff --git a/user/test/com/google/gwt/emultest/java10/util/SetTest.java b/user/test/com/google/gwt/emultest/java10/util/SetTest.java new file mode 100644 index 0000000000..17e37618b1 --- /dev/null +++ b/user/test/com/google/gwt/emultest/java10/util/SetTest.java @@ -0,0 +1,60 @@ +/* + * Copyright 2023 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.emultest.java10.util; + +import static com.google.gwt.emultest.java9.util.SetTest.assertIsImmutableSetOf; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +/** + * Tests for java.util.Set Java 10 API emulation. + */ +public class SetTest extends EmulTestBase { + public void testCopyOf() { + assertIsImmutableSetOf(Set.copyOf(Set.of("a", "b")), "a", "b"); + assertIsImmutableSetOf(Set.copyOf(Arrays.asList("a", "b")), "a", "b"); + + HashSet hashSet = new HashSet<>(); + hashSet.add("a"); + hashSet.add("b"); + Set copy = Set.copyOf(hashSet); + assertIsImmutableSetOf(copy, "a", "b"); + + // verify that mutating the original has no effect on the copy + hashSet.add("c"); + assertEquals(2, copy.size()); + assertFalse(copy.contains("c")); + + hashSet.remove("a"); + assertEquals(2, copy.size()); + assertTrue(copy.contains("a")); + + // ensure that null value result in a NPE + try { + Set.copyOf(Arrays.asList("a", null)); + fail("Expected NullPointerException from null item in collection passed to copyOf"); + } catch (NullPointerException ignored) { + // expected + } + + // ensure that duplicate values result in smaller output + assertIsImmutableSetOf(Set.copyOf(Arrays.asList("a", "a")), "a"); + } +} diff --git a/user/test/com/google/gwt/emultest/java9/util/ListTest.java b/user/test/com/google/gwt/emultest/java9/util/ListTest.java index d1487a477f..da8a156445 100644 --- a/user/test/com/google/gwt/emultest/java9/util/ListTest.java +++ b/user/test/com/google/gwt/emultest/java9/util/ListTest.java @@ -83,7 +83,7 @@ public void testOf() { assertNPE("of", () -> List.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", null)); } - protected static void assertIsImmutableListOf(List list, String... contents) { + public static void assertIsImmutableListOf(List list, String... contents) { assertEquals(contents, list); // quick test that the list impl is sane diff --git a/user/test/com/google/gwt/emultest/java9/util/MapTest.java b/user/test/com/google/gwt/emultest/java9/util/MapTest.java index 9d1356f9ca..d8223376b2 100644 --- a/user/test/com/google/gwt/emultest/java9/util/MapTest.java +++ b/user/test/com/google/gwt/emultest/java9/util/MapTest.java @@ -109,7 +109,7 @@ public void testOf() { "h", 8, "i", 9, "a", 10)); } - protected static void assertIsImmutableMapOf(Map map, String... contents) { + public static void assertIsImmutableMapOf(Map map, String... contents) { assertEquals(contents.length, map.size()); for (int i = 0; i < contents.length; i++) { assertTrue(map.containsKey(contents[i])); diff --git a/user/test/com/google/gwt/emultest/java9/util/SetTest.java b/user/test/com/google/gwt/emultest/java9/util/SetTest.java index 88b1b1bad5..4b41c83a3e 100644 --- a/user/test/com/google/gwt/emultest/java9/util/SetTest.java +++ b/user/test/com/google/gwt/emultest/java9/util/SetTest.java @@ -96,7 +96,7 @@ public void testOf() { assertIAE("Set.of(...)", () -> Set.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "a")); } - protected static void assertIsImmutableSetOf(Set set, String... contents) { + public static void assertIsImmutableSetOf(Set set, String... contents) { assertEquals(contents.length, set.size()); for (int i = 0; i < contents.length; i++) { assertTrue(set.contains(contents[i]));