diff --git a/README.md b/README.md index 9eb5d06ec3..71354ce75b 100644 --- a/README.md +++ b/README.md @@ -28,10 +28,6 @@ `$ ant clean dist-dev` - or if you don't have `python` and `g++` just run - - `$ ant clean dist-dev` - Then you will get all `.jar` files in the folder `build/lib` and the redistributable file will be: `build/dist/gwt-0.0.0.zip` diff --git a/build_tools/doctool/build.xml b/build_tools/doctool/build.xml index e6524f1496..c4870197b6 100644 --- a/build_tools/doctool/build.xml +++ b/build_tools/doctool/build.xml @@ -4,7 +4,11 @@ - + + diff --git a/common.ant.xml b/common.ant.xml index 7b3604ba60..36a56b4882 100755 --- a/common.ant.xml +++ b/common.ant.xml @@ -62,8 +62,7 @@ - - + @@ -158,8 +157,7 @@ - - + @@ -172,7 +170,7 @@ diff --git a/doc/build.xml b/doc/build.xml index ae20a50add..97c85ef8e4 100644 --- a/doc/build.xml +++ b/doc/build.xml @@ -97,6 +97,7 @@ diff --git a/user/build.xml b/user/build.xml index d488079c87..f7d2545510 100755 --- a/user/build.xml +++ b/user/build.xml @@ -15,10 +15,9 @@ - + value="**/*JreSuite.class,**/OptimizedOnly*" + else="**/*JreSuite.class,**/OptimizedOnly*,**/*Java9Suite.class,**/*Java10Suite.class,**/*Java11Suite.class"> @@ -31,10 +30,9 @@ - + value="**/EmulSuite.class,**/JSONSuite.class,**/RunAsyncSuite.class,**/*CompilerSuite.class,**/*JsInteropSuite.class,**/*JreSuite.class,**/OptimizedOnly*" + else="**/EmulSuite.class,**/JSONSuite.class,**/RunAsyncSuite.class,**/*CompilerSuite.class,**/*JsInteropSuite.class,**/*JreSuite.class,**/OptimizedOnly*,**/*Java9Suite.class,**/*Java10Suite.class,**/*Java11Suite.class"> @@ -298,13 +296,13 @@ Compiles the test code for this project --> + + + + + + + + + + + + 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 f8c3ac7f02..d1d20110b8 100644 --- a/user/super/com/google/gwt/emul/java/util/List.java +++ b/user/super/com/google/gwt/emul/java/util/List.java @@ -18,6 +18,7 @@ import static javaemul.internal.InternalPreconditions.checkNotNull; import java.util.function.UnaryOperator; +import javaemul.internal.ArrayHelper; import jsinterop.annotations.JsIgnore; import jsinterop.annotations.JsMethod; @@ -34,6 +35,85 @@ @JsType public interface List extends Collection { + @JsIgnore + static List of() { + return Collections.unmodifiableList(Collections.emptyList()); + } + + @JsIgnore + static List of(E e1) { + return __ofInternal((E[]) new Object[] {e1}); + } + + @JsIgnore + static List of(E e1, E e2) { + return __ofInternal((E[]) new Object[] {e1, e2}); + } + + @JsIgnore + static List of(E e1, E e2, E e3) { + return __ofInternal((E[]) new Object[] {e1, e2, e3}); + } + + @JsIgnore + static List of(E e1, E e2, E e3, E e4) { + return __ofInternal((E[]) new Object[] {e1, e2, e3, e4}); + } + + @JsIgnore + static List of(E e1, E e2, E e3, E e4, E e5) { + return __ofInternal((E[]) new Object[] {e1, e2, e3, e4, e5}); + } + + @JsIgnore + static List of(E e1, E e2, E e3, E e4, E e5, E e6) { + return __ofInternal((E[]) new Object[] {e1, e2, e3, e4, e5, e6}); + } + + @JsIgnore + static List of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) { + return __ofInternal((E[]) new Object[] {e1, e2, e3, e4, e5, e6, e7}); + } + + @JsIgnore + static List of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) { + return __ofInternal((E[]) new Object[] {e1, e2, e3, e4, e5, e6, e7, e8}); + } + + @JsIgnore + static List of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) { + return __ofInternal((E[]) new Object[] {e1, e2, e3, e4, e5, e6, e7, e8, e9}); + } + + @JsIgnore + static List of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) { + return __ofInternal((E[]) new Object[] {e1, e2, e3, e4, e5, e6, e7, e8, e9, e10}); + } + + // CHECKSTYLE_OFF: Internal only method that cannot collide with future JRE changes + /** + * Internal-only helper to avoid copying the incoming array, and instead just wrap it with an + * immutable List after checking there are no nulls. + */ + @JsIgnore + static List __ofInternal(E[] elements) { + for (int i = 0; i < elements.length; i++) { + checkNotNull(elements[i]); + } + return Collections.unmodifiableList(Arrays.asList(elements)); + } + // CHECKSTYLE_ON + + @JsIgnore + static List of(E... elements) { + for (int i = 0; i < elements.length; i++) { + checkNotNull(elements[i]); + } + return Collections.unmodifiableList( + Arrays.asList((E[]) ArrayHelper.unsafeClone(elements, 0, elements.length)) + ); + } + @JsMethod(name = "addAtIndex") void add(int index, E element); 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 9c134bc6b3..fd3178b041 100644 --- a/user/super/com/google/gwt/emul/java/util/Map.java +++ b/user/super/com/google/gwt/emul/java/util/Map.java @@ -15,6 +15,7 @@ */ package java.util; +import static javaemul.internal.InternalPreconditions.checkArgument; import static javaemul.internal.InternalPreconditions.checkNotNull; import java.io.Serializable; @@ -35,6 +36,211 @@ @JsType public interface Map { + @JsIgnore + static Map of() { + return Collections.unmodifiableMap(Collections.emptyMap()); + } + + @JsIgnore + static Map of(K key, V value) { + return ofEntries( + entry(key, value) + ); + } + + @JsIgnore + static Map of(K k1, V v1, K k2, V v2) { + return ofEntries( + entry(k1, v1), + entry(k2, v2) + ); + } + + @JsIgnore + static Map of( + K k1, V v1, + K k2, V v2, + K k3, V v3 + ) { + return ofEntries( + entry(k1, v1), + entry(k2, v2), + entry(k3, v3) + ); + } + + @JsIgnore + static Map of( + K k1, V v1, + K k2, V v2, + K k3, V v3, + K k4, V v4 + ) { + return ofEntries( + entry(k1, v1), + entry(k2, v2), + entry(k3, v3), + entry(k4, v4) + ); + } + + @JsIgnore + static Map of( + K k1, V v1, + K k2, V v2, + K k3, V v3, + K k4, V v4, + K k5, V v5 + ) { + return ofEntries( + entry(k1, v1), + entry(k2, v2), + entry(k3, v3), + entry(k4, v4), + entry(k5, v5) + ); + } + + @JsIgnore + static Map of( + K k1, V v1, + K k2, V v2, + K k3, V v3, + K k4, V v4, + K k5, V v5, + K k6, V v6 + ) { + return ofEntries( + entry(k1, v1), + entry(k2, v2), + entry(k3, v3), + entry(k4, v4), + entry(k5, v5), + entry(k6, v6) + ); + } + + @JsIgnore + static Map of( + K k1, V v1, + K k2, V v2, + K k3, V v3, + K k4, V v4, + K k5, V v5, + K k6, V v6, + K k7, V v7 + ) { + return ofEntries( + entry(k1, v1), + entry(k2, v2), + entry(k3, v3), + entry(k4, v4), + entry(k5, v5), + entry(k6, v6), + entry(k7, v7) + ); + } + + @JsIgnore + static Map of( + K k1, V v1, + K k2, V v2, + K k3, V v3, + K k4, V v4, + K k5, V v5, + K k6, V v6, + K k7, V v7, + K k8, V v8 + ) { + return ofEntries( + entry(k1, v1), + entry(k2, v2), + entry(k3, v3), + entry(k4, v4), + entry(k5, v5), + entry(k6, v6), + entry(k7, v7), + entry(k8, v8) + ); + } + + @JsIgnore + static Map of( + K k1, V v1, + K k2, V v2, + K k3, V v3, + K k4, V v4, + K k5, V v5, + K k6, V v6, + K k7, V v7, + K k8, V v8, + K k9, V v9 + ) { + return ofEntries( + entry(k1, v1), + entry(k2, v2), + entry(k3, v3), + entry(k4, v4), + entry(k5, v5), + entry(k6, v6), + entry(k7, v7), + entry(k8, v8), + entry(k9, v9) + ); + } + + @JsIgnore + static Map of( + K k1, V v1, + K k2, V v2, + K k3, V v3, + K k4, V v4, + K k5, V v5, + K k6, V v6, + K k7, V v7, + K k8, V v8, + K k9, V v9, + K k10, V v10 + ) { + return ofEntries( + entry(k1, v1), + entry(k2, v2), + entry(k3, v3), + entry(k4, v4), + entry(k5, v5), + entry(k6, v6), + entry(k7, v7), + entry(k8, v8), + entry(k9, v9), + entry(k10, v10) + ); + } + + @JsIgnore + static Entry entry(K key, V value) { + // This isn't quite consistent with the javadoc, since this is serializable, while entry() + // need not be serializable. + return new AbstractMap.SimpleImmutableEntry<>( + checkNotNull(key), + checkNotNull(value) + ); + } + + @JsIgnore + static Map ofEntries(Entry... entries) { + Map map = new HashMap<>(); + + for (int i = 0; i < entries.length; i++) { + // TODO this perhaps can be optimized if we know the entry is an instance of + // AbstractMap.SimpleImmutableEntry, or something more specialized? + Entry entry = checkNotNull(entries[i]); + checkArgument(map.put(checkNotNull(entry.getKey()), checkNotNull(entry.getValue())) == null, + "Can't add multiple entries with the same key"); + } + + return Collections.unmodifiableMap(map); + } + /** * Represents an individual map entry. */ diff --git a/user/super/com/google/gwt/emul/java/util/Optional.java b/user/super/com/google/gwt/emul/java/util/Optional.java index 3258444409..9485ce88fc 100644 --- a/user/super/com/google/gwt/emul/java/util/Optional.java +++ b/user/super/com/google/gwt/emul/java/util/Optional.java @@ -15,14 +15,15 @@ */ package java.util; +import static javaemul.internal.InternalPreconditions.checkCriticalElement; +import static javaemul.internal.InternalPreconditions.checkCriticalNotNull; +import static javaemul.internal.InternalPreconditions.checkNotNull; + import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; - -import static javaemul.internal.InternalPreconditions.checkCriticalElement; -import static javaemul.internal.InternalPreconditions.checkCriticalNotNull; -import static javaemul.internal.InternalPreconditions.checkNotNull; +import java.util.stream.Stream; /** * See @@ -72,6 +73,14 @@ public void ifPresent(Consumer consumer) { } } + public void ifPresentOrElse(Consumer action, Runnable emptyAction) { + if (isPresent()) { + action.accept(ref); + } else { + emptyAction.run(); + } + } + public Optional filter(Predicate predicate) { checkNotNull(predicate); if (!isPresent() || predicate.test(ref)) { @@ -96,6 +105,23 @@ public Optional flatMap(Function> mapper) { return empty(); } + public Optional or(Supplier> supplier) { + checkNotNull(supplier); + if (isPresent()) { + return this; + } else { + return (Optional) checkNotNull(supplier.get()); + } + } + + public Stream stream() { + if (isPresent()) { + return Stream.of(ref); + } else { + return Stream.empty(); + } + } + public T orElse(T other) { return isPresent() ? ref : other; } @@ -104,6 +130,10 @@ public T orElseGet(Supplier other) { return isPresent() ? ref : other.get(); } + public T orElseThrow() { + return get(); + } + public T orElseThrow(Supplier exceptionSupplier) throws X { if (isPresent()) { return ref; diff --git a/user/super/com/google/gwt/emul/java/util/OptionalDouble.java b/user/super/com/google/gwt/emul/java/util/OptionalDouble.java index e6b06af100..fa695b2090 100644 --- a/user/super/com/google/gwt/emul/java/util/OptionalDouble.java +++ b/user/super/com/google/gwt/emul/java/util/OptionalDouble.java @@ -15,11 +15,12 @@ */ package java.util; +import static javaemul.internal.InternalPreconditions.checkCriticalElement; + import java.util.function.DoubleConsumer; import java.util.function.DoubleSupplier; import java.util.function.Supplier; - -import static javaemul.internal.InternalPreconditions.checkCriticalElement; +import java.util.stream.DoubleStream; /** * See @@ -65,6 +66,22 @@ public void ifPresent(DoubleConsumer consumer) { } } + public void ifPresentOrElse(DoubleConsumer action, Runnable emptyAction) { + if (isPresent()) { + action.accept(ref); + } else { + emptyAction.run(); + } + } + + public DoubleStream stream() { + if (isPresent()) { + return DoubleStream.of(ref); + } else { + return DoubleStream.empty(); + } + } + public double orElse(double other) { return present ? ref : other; } @@ -73,6 +90,10 @@ public double orElseGet(DoubleSupplier other) { return present ? ref : other.getAsDouble(); } + public double orElseThrow() { + return getAsDouble(); + } + public double orElseThrow(Supplier exceptionSupplier) throws X { if (present) { return ref; diff --git a/user/super/com/google/gwt/emul/java/util/OptionalInt.java b/user/super/com/google/gwt/emul/java/util/OptionalInt.java index 10b7ce6639..63663b73bc 100644 --- a/user/super/com/google/gwt/emul/java/util/OptionalInt.java +++ b/user/super/com/google/gwt/emul/java/util/OptionalInt.java @@ -15,11 +15,12 @@ */ package java.util; +import static javaemul.internal.InternalPreconditions.checkCriticalElement; + import java.util.function.IntConsumer; import java.util.function.IntSupplier; import java.util.function.Supplier; - -import static javaemul.internal.InternalPreconditions.checkCriticalElement; +import java.util.stream.IntStream; /** * See @@ -65,6 +66,22 @@ public void ifPresent(IntConsumer consumer) { } } + public void ifPresentOrElse(IntConsumer action, Runnable emptyAction) { + if (present) { + action.accept(ref); + } else { + emptyAction.run(); + } + } + + public IntStream stream() { + if (present) { + return IntStream.of(ref); + } else { + return IntStream.empty(); + } + } + public int orElse(int other) { return present ? ref : other; } @@ -73,6 +90,10 @@ public int orElseGet(IntSupplier other) { return present ? ref : other.getAsInt(); } + public int orElseThrow() { + return getAsInt(); + } + public int orElseThrow(Supplier exceptionSupplier) throws X { if (present) { return ref; diff --git a/user/super/com/google/gwt/emul/java/util/OptionalLong.java b/user/super/com/google/gwt/emul/java/util/OptionalLong.java index 8551777860..978bddeb1c 100644 --- a/user/super/com/google/gwt/emul/java/util/OptionalLong.java +++ b/user/super/com/google/gwt/emul/java/util/OptionalLong.java @@ -15,11 +15,12 @@ */ package java.util; +import static javaemul.internal.InternalPreconditions.checkCriticalElement; + import java.util.function.LongConsumer; import java.util.function.LongSupplier; import java.util.function.Supplier; - -import static javaemul.internal.InternalPreconditions.checkCriticalElement; +import java.util.stream.LongStream; /** * See @@ -65,6 +66,22 @@ public void ifPresent(LongConsumer consumer) { } } + public void ifPresentOrElse(LongConsumer action, Runnable emptyAction) { + if (present) { + action.accept(ref); + } else { + emptyAction.run(); + } + } + + public LongStream stream() { + if (present) { + return LongStream.of(ref); + } else { + return LongStream.empty(); + } + } + public long orElse(long other) { return present ? ref : other; } @@ -73,6 +90,10 @@ public long orElseGet(LongSupplier other) { return present ? ref : other.getAsLong(); } + public long orElseThrow() { + return getAsLong(); + } + public long orElseThrow(Supplier exceptionSupplier) throws X { if (present) { return ref; 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 8a5bf8cb38..eddd4dffe9 100644 --- a/user/super/com/google/gwt/emul/java/util/Set.java +++ b/user/super/com/google/gwt/emul/java/util/Set.java @@ -15,6 +15,9 @@ */ package java.util; +import static javaemul.internal.InternalPreconditions.checkArgument; +import static javaemul.internal.InternalPreconditions.checkNotNull; + import jsinterop.annotations.JsIgnore; import jsinterop.annotations.JsType; @@ -26,6 +29,70 @@ */ @JsType public interface Set extends Collection { + @JsIgnore + static Set of() { + return Collections.unmodifiableSet(Collections.emptySet()); + } + + @JsIgnore + static Set of(E e1) { + return of((E[]) new Object[] {e1}); + } + + @JsIgnore + static Set of(E e1, E e2) { + return of((E[]) new Object[] {e1, e2}); + } + + @JsIgnore + static Set of(E e1, E e2, E e3) { + return of((E[]) new Object[] {e1, e2, e3}); + } + + @JsIgnore + static Set of(E e1, E e2, E e3, E e4) { + return of((E[]) new Object[] {e1, e2, e3, e4}); + } + + @JsIgnore + static Set of(E e1, E e2, E e3, E e4, E e5) { + return of((E[]) new Object[] {e1, e2, e3, e4, e5}); + } + + @JsIgnore + static Set of(E e1, E e2, E e3, E e4, E e5, E e6) { + return of((E[]) new Object[] {e1, e2, e3, e4, e5, e6}); + } + + @JsIgnore + static Set of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) { + return of((E[]) new Object[] {e1, e2, e3, e4, e5, e6, e7}); + } + + @JsIgnore + static Set of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) { + return of((E[]) new Object[] {e1, e2, e3, e4, e5, e6, e7, e8}); + } + + @JsIgnore + static Set of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) { + return of((E[]) new Object[] {e1, e2, e3, e4, e5, e6, e7, e8, e9}); + } + + @JsIgnore + static Set of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) { + return of((E[]) new Object[] {e1, e2, e3, e4, e5, e6, e7, e8, e9, e10}); + } + + @JsIgnore + static Set of(E... elements) { + HashSet set = new HashSet<>(); + for (int i = 0; i < elements.length; i++) { + checkArgument(set.add(checkNotNull(elements[i])), "Can't add the same item multiple times"); + } + return Collections.unmodifiableSet(set); + } + @JsIgnore @Override default Spliterator spliterator() { diff --git a/user/test/com/google/gwt/emultest/EmulJava10Suite.java b/user/test/com/google/gwt/emultest/EmulJava10Suite.java new file mode 100644 index 0000000000..e691477626 --- /dev/null +++ b/user/test/com/google/gwt/emultest/EmulJava10Suite.java @@ -0,0 +1,35 @@ +/* + * 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; + +import com.google.gwt.emultest.java10.util.OptionalDoubleTest; +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 org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +/** Test JRE emulations. */ +@RunWith(Suite.class) +@SuiteClasses({ + OptionalDoubleTest.class, + OptionalIntTest.class, + OptionalLongTest.class, + OptionalTest.class, +}) +public class EmulJava10Suite { +} diff --git a/user/test/com/google/gwt/emultest/EmulJava9Suite.java b/user/test/com/google/gwt/emultest/EmulJava9Suite.java new file mode 100644 index 0000000000..6cdf37ed74 --- /dev/null +++ b/user/test/com/google/gwt/emultest/EmulJava9Suite.java @@ -0,0 +1,41 @@ +/* + * 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; + +import com.google.gwt.emultest.java9.util.ListTest; +import com.google.gwt.emultest.java9.util.MapTest; +import com.google.gwt.emultest.java9.util.OptionalDoubleTest; +import com.google.gwt.emultest.java9.util.OptionalIntTest; +import com.google.gwt.emultest.java9.util.OptionalLongTest; +import com.google.gwt.emultest.java9.util.OptionalTest; +import com.google.gwt.emultest.java9.util.SetTest; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +/** Test JRE emulations. */ +@RunWith(Suite.class) +@SuiteClasses({ + ListTest.class, + MapTest.class, + OptionalDoubleTest.class, + OptionalIntTest.class, + OptionalLongTest.class, + OptionalTest.class, + SetTest.class +}) +public class EmulJava9Suite { +} diff --git a/user/test/com/google/gwt/emultest/EmulSuite.gwt.xml b/user/test/com/google/gwt/emultest/EmulSuite.gwt.xml index 550ef4bbf3..85c3a4cf6b 100644 --- a/user/test/com/google/gwt/emultest/EmulSuite.gwt.xml +++ b/user/test/com/google/gwt/emultest/EmulSuite.gwt.xml @@ -17,6 +17,9 @@ + + + diff --git a/user/test/com/google/gwt/emultest/java/util/EmulTestBase.java b/user/test/com/google/gwt/emultest/java/util/EmulTestBase.java index c1fc5de991..93fd94b9e7 100644 --- a/user/test/com/google/gwt/emultest/java/util/EmulTestBase.java +++ b/user/test/com/google/gwt/emultest/java/util/EmulTestBase.java @@ -57,6 +57,24 @@ public static void assertEquals(double[] expected, double[] actual) { Arrays.equals(expected, actual)); } + public static void assertNPE(String methodName, Runnable runnable) { + try { + runnable.run(); + fail("Expected NPE from calling " + methodName); + } catch (NullPointerException ignored) { + // expected + } + } + + public static void assertIAE(String methodName, Runnable runnable) { + try { + runnable.run(); + fail("Expected IAE from calling " + methodName); + } catch (IllegalArgumentException ignored) { + // expected + } + } + @Override public String getModuleName() { return "com.google.gwt.emultest.EmulSuite"; diff --git a/user/test/com/google/gwt/emultest/java10/util/OptionalDoubleTest.java b/user/test/com/google/gwt/emultest/java10/util/OptionalDoubleTest.java new file mode 100644 index 0000000000..ac39290ff1 --- /dev/null +++ b/user/test/com/google/gwt/emultest/java10/util/OptionalDoubleTest.java @@ -0,0 +1,38 @@ +/* + * 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 com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.NoSuchElementException; +import java.util.OptionalDouble; + +/** + * Tests for java.util.OptionalDouble Java 10 API emulation. + */ +public class OptionalDoubleTest extends EmulTestBase { + public void testOrElseThrow() { + try { + OptionalDouble.empty().orElseThrow(); + fail("Expected NoSuchElementException from empty Optional: orElseThrow"); + } catch (NoSuchElementException ignore) { + // expected + } + + double value = OptionalDouble.of(10.0).orElseThrow(); + assertEquals(10.0, value); + } +} diff --git a/user/test/com/google/gwt/emultest/java10/util/OptionalIntTest.java b/user/test/com/google/gwt/emultest/java10/util/OptionalIntTest.java new file mode 100644 index 0000000000..59b3953987 --- /dev/null +++ b/user/test/com/google/gwt/emultest/java10/util/OptionalIntTest.java @@ -0,0 +1,38 @@ +/* + * 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 com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.NoSuchElementException; +import java.util.OptionalInt; + +/** + * Tests for java.util.OptionalInt Java 10 API emulation. + */ +public class OptionalIntTest extends EmulTestBase { + public void testOrElseThrow() { + try { + OptionalInt.empty().orElseThrow(); + fail("Expected NoSuchElementException from empty Optional: orElseThrow"); + } catch (NoSuchElementException ignore) { + // expected + } + + int value = OptionalInt.of(10).orElseThrow(); + assertEquals(10, value); + } +} diff --git a/user/test/com/google/gwt/emultest/java10/util/OptionalLongTest.java b/user/test/com/google/gwt/emultest/java10/util/OptionalLongTest.java new file mode 100644 index 0000000000..1fb35891bd --- /dev/null +++ b/user/test/com/google/gwt/emultest/java10/util/OptionalLongTest.java @@ -0,0 +1,38 @@ +/* + * 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 com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.NoSuchElementException; +import java.util.OptionalLong; + +/** + * Tests for java.util.OptionalLong Java 10 API emulation. + */ +public class OptionalLongTest extends EmulTestBase { + public void testOrElseThrow() { + try { + OptionalLong.empty().orElseThrow(); + fail("Expected NoSuchElementException from empty Optional: orElseThrow"); + } catch (NoSuchElementException ignore) { + // expected + } + + long value = OptionalLong.of(10L).orElseThrow(); + assertEquals(10L, value); + } +} diff --git a/user/test/com/google/gwt/emultest/java10/util/OptionalTest.java b/user/test/com/google/gwt/emultest/java10/util/OptionalTest.java new file mode 100644 index 0000000000..d263599388 --- /dev/null +++ b/user/test/com/google/gwt/emultest/java10/util/OptionalTest.java @@ -0,0 +1,39 @@ +/* + * 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 com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.NoSuchElementException; +import java.util.Optional; + +/** + * Tests for java.util.Optional Java 10 API emulation. + */ +public class OptionalTest extends EmulTestBase { + @SuppressWarnings("OptionalOfRedundantMethod") + public void testOrElseThrow() { + try { + Optional.empty().orElseThrow(); + fail("Expected NoSuchElementException from empty Optional: orElseThrow"); + } catch (NoSuchElementException ignore) { + // expected + } + + String value = Optional.of("value").orElseThrow(); + assertEquals("value", value); + } +} diff --git a/user/test/com/google/gwt/emultest/java9/util/ListTest.java b/user/test/com/google/gwt/emultest/java9/util/ListTest.java new file mode 100644 index 0000000000..d1487a477f --- /dev/null +++ b/user/test/com/google/gwt/emultest/java9/util/ListTest.java @@ -0,0 +1,141 @@ +/* + * 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.java9.util; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.Iterator; +import java.util.List; + +/** + * Tests for java.util.List Java 9 API emulation. + */ +public class ListTest extends EmulTestBase { + + public void testOf() { + assertIsImmutableListOf(List.of()); + assertIsImmutableListOf(List.of("a"), "a"); + assertIsImmutableListOf( + List.of("a", "b"), + "a", "b" + ); + assertIsImmutableListOf( + List.of("a", "b", "c"), + "a", "b", "c" + ); + assertIsImmutableListOf( + List.of("a", "b", "c", "d"), + "a", "b", "c", "d" + ); + assertIsImmutableListOf( + List.of("a", "b", "c", "d", "e"), + "a", "b", "c", "d", "e" + ); + assertIsImmutableListOf( + List.of("a", "b", "c", "d", "e", "f"), + "a", "b", "c", "d", "e", "f" + ); + assertIsImmutableListOf( + List.of("a", "b", "c", "d", "e", "f", "g"), + "a", "b", "c", "d", "e", "f", "g" + ); + assertIsImmutableListOf( + List.of("a", "b", "c", "d", "e", "f", "g", "h"), + "a", "b", "c", "d", "e", "f", "g", "h" + ); + assertIsImmutableListOf( + List.of("a", "b", "c", "d", "e", "f", "g", "h", "i"), + "a", "b", "c", "d", "e", "f", "g", "h", "i" + ); + assertIsImmutableListOf( + List.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "j"), + "a", "b", "c", "d", "e", "f", "g", "h", "i", "j" + ); + assertIsImmutableListOf( + List.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"), + "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k" + ); + + // ensure that NPE is thrown if a value is null + assertNPE("of", () -> List.of((String) null)); + assertNPE("of", () -> List.of("a", null)); + assertNPE("of", () -> List.of("a", "b", null)); + assertNPE("of", () -> List.of("a", "b", "c", null)); + assertNPE("of", () -> List.of("a", "b", "c", "d", null)); + assertNPE("of", () -> List.of("a", "b", "c", "d", "e", null)); + assertNPE("of", () -> List.of("a", "b", "c", "d", "e", "f", null)); + assertNPE("of", () -> List.of("a", "b", "c", "d", "e", "f", "g", null)); + assertNPE("of", () -> List.of("a", "b", "c", "d", "e", "f", "g", "h", null)); + assertNPE("of", () -> List.of("a", "b", "c", "d", "e", "f", "g", "h", "i", null)); + assertNPE("of", () -> List.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", null)); + } + + protected static void assertIsImmutableListOf(List list, String... contents) { + assertEquals(contents, list); + + // quick test that the list impl is sane + if (contents.length == 0) { + assertFalse(list.iterator().hasNext()); + } else { + Iterator itr = list.iterator(); + assertTrue(itr.hasNext()); + assertEquals(contents[0], itr.next()); + assertEquals(contents.length > 1, itr.hasNext()); + } + + // quick check that the list is immutable + try { + list.add("another item"); + fail("List should be unmodifiable: add(T)"); + } catch (UnsupportedOperationException ignored) { + // success + } + + try { + list.remove(0); + fail("List should be unmodifiable: remove(int)"); + } catch (UnsupportedOperationException ignored) { + // success + } + + // if any, remove an item actually in the list + if (contents.length > 0) { + // Without any items, remove(T) defaults to iterating items present, so we only test from + // present items + try { + list.remove(contents[0]); + fail("List should be unmodifiable: remove(T)"); + } catch (UnsupportedOperationException ignored) { + // success + } + } + + // Remove an item that will not be in the list + try { + list.remove("not present"); + fail("List should be unmodifiable: remove(T)"); + } catch (UnsupportedOperationException ignored) { + // success + } + + try { + list.clear(); + fail("List should be unmodifiable: clear()"); + } catch (UnsupportedOperationException ignored) { + // success + } + } +} diff --git a/user/test/com/google/gwt/emultest/java9/util/MapTest.java b/user/test/com/google/gwt/emultest/java9/util/MapTest.java new file mode 100644 index 0000000000..9d1356f9ca --- /dev/null +++ b/user/test/com/google/gwt/emultest/java9/util/MapTest.java @@ -0,0 +1,218 @@ +/* + * 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.java9.util; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.Map; + +/** + * Tests for java.util.Map Java 9 API emulation. + */ +public class MapTest extends EmulTestBase { + + public void testOf() { + assertIsImmutableMapOf(Map.of()); + assertIsImmutableMapOf(Map.of("a", 1), "a"); + assertIsImmutableMapOf( + Map.of("a", 1, "b", 2), + "a", "b" + ); + assertIsImmutableMapOf( + Map.of("a", 1, "b", 2, "c", 3), + "a", "b", "c" + ); + assertIsImmutableMapOf( + Map.of("a", 1, "b", 2, "c", 3, "d", 4), + "a", "b", "c", "d" + ); + assertIsImmutableMapOf( + Map.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5), + "a", "b", "c", "d", "e" + ); + assertIsImmutableMapOf( + Map.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6), + "a", "b", "c", "d", "e", "f" + ); + assertIsImmutableMapOf( + Map.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7), + "a", "b", "c", "d", "e", "f", "g" + ); + assertIsImmutableMapOf( + Map.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, "h", 8), + "a", "b", "c", "d", "e", "f", "g", "h" + ); + assertIsImmutableMapOf( + Map.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, "h", 8, "i", 9), + "a", "b", "c", "d", "e", "f", "g", "h", "i" + ); + assertIsImmutableMapOf( + Map.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, "h", 8, "i", 9, "j", 10), + "a", "b", "c", "d", "e", "f", "g", "h", "i", "j" + ); + + // ensure NullPointerException if either key or value are null for any param + assertNPE("Map.of(1)", () -> Map.of(null, 1)); + assertNPE("Map.of(1)", () -> Map.of("a", null)); + assertNPE("Map.of(2)", () -> Map.of("a", 1, null, 2)); + assertNPE("Map.of(2)", () -> Map.of("a", 1, "b", null)); + assertNPE("Map.of(3)", () -> Map.of("a", 1, "b", 2, null, 3)); + assertNPE("Map.of(3)", () -> Map.of("a", 1, "b", 2, "c", null)); + assertNPE("Map.of(4)", () -> Map.of("a", 1, "b", 2, "c", 3, null, 4)); + assertNPE("Map.of(4)", () -> Map.of("a", 1, "b", 2, "c", 3, "d", null)); + assertNPE("Map.of(5)", () -> Map.of("a", 1, "b", 2, "c", 3, "d", 4, null, 5)); + assertNPE("Map.of(5)", () -> Map.of("a", 1, "b", 2, "c", 3, "d", 4, "e", null)); + assertNPE("Map.of(6)", () -> Map.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5, null, 6)); + assertNPE("Map.of(6)", () -> Map.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", null)); + assertNPE("Map.of(7)", () -> Map.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, + null, 7)); + assertNPE("Map.of(7)", () -> Map.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, + "g", null)); + assertNPE("Map.of(8)", () -> Map.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, + "g", 7, null, 8)); + assertNPE("Map.of(8)", () -> Map.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, + "g", 7, "h", null)); + assertNPE("Map.of(9)", () -> Map.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, + "g", 7, "h", 8, null, 9)); + assertNPE("Map.of(9)", () -> Map.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, + "g", 7, "h", 8, "i", null)); + assertNPE("Map.of(10)", () -> Map.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, + "g", 7, "h", 8, "i", 9, null, 10)); + assertNPE("Map.of(10)", () -> Map.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, + "g", 7, "h", 8, "i", 9, "j", null)); + + // ensure IllegalArgumentException if any key is repeated + assertIAE("Map.of(2)", () -> Map.of("a", 1, "a", 2)); + assertIAE("Map.of(3)", () -> Map.of("a", 1, "b", 2, "a", 3)); + assertIAE("Map.of(4)", () -> Map.of("a", 1, "b", 2, "c", 3, "a", 4)); + assertIAE("Map.of(5)", () -> Map.of("a", 1, "b", 2, "c", 3, "d", 4, "a", 5)); + assertIAE("Map.of(6)", () -> Map.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "a", 6)); + assertIAE("Map.of(7)", () -> Map.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "a", 7)); + assertIAE("Map.of(8)", () -> Map.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, + "a", 8)); + assertIAE("Map.of(9)", () -> Map.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, + "h", 8, "a", 9)); + assertIAE("Map.of(10)", () -> Map.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, + "h", 8, "i", 9, "a", 10)); + } + + protected 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])); + assertFalse(map.containsKey(contents[i] + "nope")); + assertEquals(i + 1, (int) map.get(contents[i])); + } + + // quick check that the map is immutable + try { + map.put("another item", 1); + fail("Set should be unmodifiable: add(T)"); + } catch (UnsupportedOperationException ignored) { + // success + } + + if (contents.length > 1) { + // Without any items, remove(T) defaults to iterating items present, so we only test from + // present items + try { + map.remove(contents[0]); + fail("Map should be unmodifiable: remove(T)"); + } catch (UnsupportedOperationException ignored) { + // success + } + } + + try { + map.remove("not found"); + fail("Map should be unmodifiable: remove(T)"); + } catch (UnsupportedOperationException ignored) { + // success + } + + try { + map.clear(); + fail("Set should be unmodifiable: clear()"); + } catch (UnsupportedOperationException ignored) { + // expected + } + } + + public void testEntry() { + Map.Entry entry = Map.entry("a", "b"); + + assertEquals("a", entry.getKey()); + assertEquals("b", entry.getValue()); + + try { + entry.setValue("z"); + fail("Entry should be immutable: setValue"); + } catch (UnsupportedOperationException ignore) { + // expected + } + + assertNPE("Map.entry", () -> { + Map.entry(null, "value"); + }); + assertNPE("Map.entry", () -> { + Map.entry("key", null); + }); + } + + @SuppressWarnings("DuplicateMapKeys") + public void testOfEntries() { + Map map = Map.ofEntries( + Map.entry("a", 1), + Map.entry("b", 2) + ); + + assertIsImmutableMapOf(map, "a", "b"); + + // ensure NullPointerException if any entry is null, if any key is null, or value is null + assertNPE("Map.ofEntries", () -> { + Map.ofEntries( + Map.entry("a", "b"), + null + ); + }); + assertNPE("Map.ofEntries", () -> { + Map.ofEntries( + Map.entry("a", "b"), + Map.entry("c", null) + ); + }); + assertNPE("Map.ofEntries", () -> { + Map.ofEntries( + Map.entry("a", "b"), + Map.entry(null, "d") + ); + }); + + // ensure IllegalArgumentException if any pair has the same key (same or different value) + assertIAE("Map.ofEntries", () -> { + Map.ofEntries( + Map.entry("a", "b"), + Map.entry("a", "b") + ); + }); + assertIAE("Map.ofEntries", () -> { + Map.ofEntries( + Map.entry("a", "b"), + Map.entry("a", "c") + ); + }); + } +} diff --git a/user/test/com/google/gwt/emultest/java9/util/OptionalDoubleTest.java b/user/test/com/google/gwt/emultest/java9/util/OptionalDoubleTest.java new file mode 100644 index 0000000000..6c1aaf294e --- /dev/null +++ b/user/test/com/google/gwt/emultest/java9/util/OptionalDoubleTest.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.java9.util; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.OptionalDouble; +import java.util.stream.Stream; + +/** + * Tests for java.util.OptionalDouble Java 9 API emulation. + */ +public class OptionalDoubleTest extends EmulTestBase { + public void testIfPresentOrElse() { + int[] called = {0}; + OptionalDouble.of(10.0).ifPresentOrElse(value -> { + assertEquals(10.0, value); + called[0]++; + }, () -> { + fail("should not call empty action"); + }); + assertEquals(1, called[0]); + called[0] = 0; + OptionalDouble.empty().ifPresentOrElse(ignore -> { + fail("Should not call present action"); + }, () -> called[0]++); + assertEquals(1, called[0]); + } + + public void testStream() { + assertEquals(0, OptionalDouble.empty().stream().count()); + assertEquals(1, OptionalDouble.of(10.0).stream().count()); + + assertEquals( + new double[] {10.0, 100.0, 1000.0}, + Stream.of( + OptionalDouble.of(10.0), + OptionalDouble.empty(), + OptionalDouble.of(100.0), + OptionalDouble.of(1000.0) + ).flatMapToDouble(OptionalDouble::stream).toArray() + ); + } +} diff --git a/user/test/com/google/gwt/emultest/java9/util/OptionalIntTest.java b/user/test/com/google/gwt/emultest/java9/util/OptionalIntTest.java new file mode 100644 index 0000000000..b6fa378345 --- /dev/null +++ b/user/test/com/google/gwt/emultest/java9/util/OptionalIntTest.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.java9.util; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.OptionalInt; +import java.util.stream.Stream; + +/** + * Tests for java.util.OptionalInt Java 9 API emulation. + */ +public class OptionalIntTest extends EmulTestBase { + public void testIfPresentOrElse() { + int[] called = {0}; + OptionalInt.of(10).ifPresentOrElse(value -> { + assertEquals(10, value); + called[0]++; + }, () -> { + fail("should not call empty action"); + }); + assertEquals(1, called[0]); + called[0] = 0; + OptionalInt.empty().ifPresentOrElse(ignore -> { + fail("Should not call present action"); + }, () -> called[0]++); + assertEquals(1, called[0]); + } + + public void testStream() { + assertEquals(0, OptionalInt.empty().stream().count()); + assertEquals(1, OptionalInt.of(10).stream().count()); + + assertEquals( + new int[] {10, 100, 1000}, + Stream.of( + OptionalInt.of(10), + OptionalInt.empty(), + OptionalInt.of(100), + OptionalInt.of(1000) + ).flatMapToInt(OptionalInt::stream).toArray() + ); + } +} diff --git a/user/test/com/google/gwt/emultest/java9/util/OptionalLongTest.java b/user/test/com/google/gwt/emultest/java9/util/OptionalLongTest.java new file mode 100644 index 0000000000..5bb4ed670d --- /dev/null +++ b/user/test/com/google/gwt/emultest/java9/util/OptionalLongTest.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.java9.util; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.OptionalLong; +import java.util.stream.Stream; + +/** + * Tests for java.util.OptionalLong Java 9 API emulation. + */ +public class OptionalLongTest extends EmulTestBase { + public void testIfPresentOrElse() { + int[] called = {0}; + OptionalLong.of(10).ifPresentOrElse(value -> { + assertEquals(10, value); + called[0]++; + }, () -> { + fail("should not call empty action"); + }); + assertEquals(1, called[0]); + called[0] = 0; + OptionalLong.empty().ifPresentOrElse(ignore -> { + fail("Should not call present action"); + }, () -> called[0]++); + assertEquals(1, called[0]); + } + + public void testStream() { + assertEquals(0, OptionalLong.empty().stream().count()); + assertEquals(1, OptionalLong.of(10).stream().count()); + + assertEquals( + new long[] {10, 100, 1000}, + Stream.of( + OptionalLong.of(10), + OptionalLong.empty(), + OptionalLong.of(100), + OptionalLong.of(1000) + ).flatMapToLong(OptionalLong::stream).toArray() + ); + } +} diff --git a/user/test/com/google/gwt/emultest/java9/util/OptionalTest.java b/user/test/com/google/gwt/emultest/java9/util/OptionalTest.java new file mode 100644 index 0000000000..e7befa7724 --- /dev/null +++ b/user/test/com/google/gwt/emultest/java9/util/OptionalTest.java @@ -0,0 +1,86 @@ +/* + * 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.java9.util; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.Optional; +import java.util.stream.Stream; + +/** + * Tests for java.util.Optional Java 9 API emulation. + */ +public class OptionalTest extends EmulTestBase { + public void testIfPresentOrElse() { + int[] called = {0}; + Optional.of("value").ifPresentOrElse(value -> { + assertEquals("value", value); + called[0]++; + }, () -> { + fail("should not call empty action"); + }); + assertEquals(1, called[0]); + called[0] = 0; + Optional.empty().ifPresentOrElse(ignore -> { + fail("Should not call present action"); + }, () -> called[0]++); + assertEquals(1, called[0]); + } + + public void testOr() { + Optional or = Optional.of("value").or(() -> Optional.of("replacement")); + assertTrue(or.isPresent()); + assertEquals("value", or.get()); + + or = Optional.empty().or(() -> Optional.of("replacement")); + assertTrue(or.isPresent()); + assertEquals("replacement", or.get()); + + or = Optional.of("value").or(() -> Optional.empty()); + assertTrue(or.isPresent()); + assertEquals("value", or.get()); + + or = Optional.empty().or(() -> Optional.empty()); + assertFalse(or.isPresent()); + + Optional empty = Optional.empty(); + Optional present = Optional.of("asdf"); + assertNPE("empty().or(null)", () -> { + empty.or(null); + }); + assertNPE("present.or(null)", () -> { + present.or(null); + }); + assertNPE("empty.or(() -> null)", () -> { + empty.or(() -> null); + }); + } + + public void testStream() { + assertEquals(0, Optional.empty().stream().count()); + assertEquals(1, Optional.of("foo").stream().count()); + + assertEquals( + new String[] {"a", "b", "c"}, + Stream.of( + Optional.of("a"), + Optional.empty(), + Optional.of("b"), + Optional.of("c") + ).flatMap(Optional::stream).toArray(String[]::new) + ); + } +} diff --git a/user/test/com/google/gwt/emultest/java9/util/SetTest.java b/user/test/com/google/gwt/emultest/java9/util/SetTest.java new file mode 100644 index 0000000000..88b1b1bad5 --- /dev/null +++ b/user/test/com/google/gwt/emultest/java9/util/SetTest.java @@ -0,0 +1,162 @@ +/* + * 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.java9.util; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.Set; + +/** + * Tests for java.util.Set Java 9 API emulation. + */ +public class SetTest extends EmulTestBase { + + public void testOf() { + assertIsImmutableSetOf(Set.of()); + assertIsImmutableSetOf(Set.of("a"), "a"); + assertIsImmutableSetOf( + Set.of("a", "b"), + "a", "b" + ); + assertIsImmutableSetOf( + Set.of("a", "b", "c"), + "a", "b", "c" + ); + assertIsImmutableSetOf( + Set.of("a", "b", "c", "d"), + "a", "b", "c", "d" + ); + assertIsImmutableSetOf( + Set.of("a", "b", "c", "d", "e"), + "a", "b", "c", "d", "e" + ); + assertIsImmutableSetOf( + Set.of("a", "b", "c", "d", "e", "f"), + "a", "b", "c", "d", "e", "f" + ); + assertIsImmutableSetOf( + Set.of("a", "b", "c", "d", "e", "f", "g"), + "a", "b", "c", "d", "e", "f", "g" + ); + assertIsImmutableSetOf( + Set.of("a", "b", "c", "d", "e", "f", "g", "h"), + "a", "b", "c", "d", "e", "f", "g", "h" + ); + assertIsImmutableSetOf( + Set.of("a", "b", "c", "d", "e", "f", "g", "h", "i"), + "a", "b", "c", "d", "e", "f", "g", "h", "i" + ); + assertIsImmutableSetOf( + Set.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "j"), + "a", "b", "c", "d", "e", "f", "g", "h", "i", "j" + ); + assertIsImmutableSetOf( + Set.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"), + "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k" + ); + + // ensure NPE if any element is null + assertNPE("Set.of(1)", () -> Set.of((String) null)); + assertNPE("Set.of(2)", () -> Set.of("a", null)); + assertNPE("Set.of(3)", () -> Set.of("a", "b", null)); + assertNPE("Set.of(4)", () -> Set.of("a", "b", "c", null)); + assertNPE("Set.of(5)", () -> Set.of("a", "b", "c", "d", null)); + assertNPE("Set.of(6)", () -> Set.of("a", "b", "c", "d", "e", null)); + assertNPE("Set.of(7)", () -> Set.of("a", "b", "c", "d", "e", "f", null)); + assertNPE("Set.of(8)", () -> Set.of("a", "b", "c", "d", "e", "f", "g", null)); + assertNPE("Set.of(9)", () -> Set.of("a", "b", "c", "d", "e", "f", "g", "h", null)); + assertNPE("Set.of(10)", () -> Set.of("a", "b", "c", "d", "e", "f", "g", "h", "i", null)); + assertNPE("Set.of(...)", () -> Set.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", null)); + + // ensure IAE if any element is duplicated + assertIAE("Set.of(2)", () -> Set.of("a", "a")); + assertIAE("Set.of(3)", () -> Set.of("a", "b", "a")); + assertIAE("Set.of(4)", () -> Set.of("a", "b", "c", "a")); + assertIAE("Set.of(5)", () -> Set.of("a", "b", "c", "d", "a")); + assertIAE("Set.of(6)", () -> Set.of("a", "b", "c", "d", "e", "a")); + assertIAE("Set.of(7)", () -> Set.of("a", "b", "c", "d", "e", "f", "a")); + assertIAE("Set.of(8)", () -> Set.of("a", "b", "c", "d", "e", "f", "g", "a")); + assertIAE("Set.of(9)", () -> Set.of("a", "b", "c", "d", "e", "f", "g", "h", "a")); + assertIAE("Set.of(10)", () -> Set.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "a")); + assertIAE("Set.of(...)", () -> Set.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "a")); + } + + protected 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])); + assertFalse(set.contains(contents[i] + "nope")); + } + + // quick test that the set impl is sane, aside from the above + if (contents.length == 0) { + assertFalse(set.iterator().hasNext()); + } else { + Iterator itr = set.iterator(); + assertTrue(itr.hasNext()); + + assertContains(contents, itr.next()); + + assertEquals(contents.length > 1, itr.hasNext()); + } + + // quick check that the set is immutable + try { + set.add("another item"); + fail("Set should be unmodifiable: add(T)"); + } catch (UnsupportedOperationException ignored) { + // success + } + + // if any, remove an item actually in the set + if (contents.length > 1) { + // Without any items, remove(T) defaults to iterating items present, so we only test from + // present items + try { + set.remove(contents[0]); + fail("Set should be unmodifiable: remove(T)"); + } catch (UnsupportedOperationException ignored) { + // success + } + } + + // Remove an item that will not be in the set + try { + set.remove("not present"); + fail("Set should be unmodifiable: remove(T)"); + } catch (UnsupportedOperationException ignored) { + // success + } + + try { + set.clear(); + fail("Set should be unmodifiable: clear()"); + } catch (UnsupportedOperationException ignored) { + // success + } + } + + private static void assertContains(String[] contents, String value) { + for (String item : contents) { + if (item.equals(value)) { + return; + } + } + fail("Failed to find '" + value + "' in " + Arrays.toString(contents)); + } +}