From abceee4cb811e2638921c48385ab9d177a319bbd Mon Sep 17 00:00:00 2001 From: Zbynek Konecny Date: Fri, 20 Oct 2023 16:03:48 +0200 Subject: [PATCH 1/4] Do not set crossOrigin for file protocol (#9854) This allows using GWT compiled code with `installCode=false` also with `file://` protocol. See https://github.com/gwtproject/gwt/issues/9734#issuecomment-1729695795 for the relevant Chrome error message. --- .../google/gwt/core/ext/linker/impl/installScriptDirect.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/installScriptDirect.js b/dev/core/src/com/google/gwt/core/ext/linker/impl/installScriptDirect.js index 725505e0bf..2df43d2615 100644 --- a/dev/core/src/com/google/gwt/core/ext/linker/impl/installScriptDirect.js +++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/installScriptDirect.js @@ -9,7 +9,9 @@ function installScript(filename) { var docbody = doc.body; var script = doc.createElement('script'); script.language='javascript'; - script.crossOrigin=''; + if (location.host) { + script.crossOrigin=''; + } script.src = code; if (__MODULE_FUNC__.__errFn) { script.onerror = function() { From d73d095eabcf18d565ee9eebacdaa2895ae77c52 Mon Sep 17 00:00:00 2001 From: Colin Alworth Date: Tue, 7 Nov 2023 13:30:41 -0600 Subject: [PATCH 2/4] Add Java 11 Optional.isEmpty() (#9853) Partial #9547 Co-authored-by: Alexey Abashev --- .../gwt/emul/java/util/OptionalDouble.java | 4 +++ .../gwt/emul/java/util/OptionalInt.java | 4 +++ .../gwt/emul/java/util/OptionalLong.java | 4 +++ .../google/gwt/emultest/EmulJava11Suite.java | 34 +++++++++++++++++++ .../java11/util/OptionalDoubleTest.java | 30 ++++++++++++++++ .../emultest/java11/util/OptionalIntTest.java | 30 ++++++++++++++++ .../java11/util/OptionalLongTest.java | 30 ++++++++++++++++ .../emultest/java11/util/OptionalTest.java | 30 ++++++++++++++++ 8 files changed, 166 insertions(+) create mode 100644 user/test/com/google/gwt/emultest/EmulJava11Suite.java create mode 100644 user/test/com/google/gwt/emultest/java11/util/OptionalDoubleTest.java create mode 100644 user/test/com/google/gwt/emultest/java11/util/OptionalIntTest.java create mode 100644 user/test/com/google/gwt/emultest/java11/util/OptionalLongTest.java create mode 100644 user/test/com/google/gwt/emultest/java11/util/OptionalTest.java 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 fa695b2090..b7a5151e83 100644 --- a/user/super/com/google/gwt/emul/java/util/OptionalDouble.java +++ b/user/super/com/google/gwt/emul/java/util/OptionalDouble.java @@ -55,6 +55,10 @@ public boolean isPresent() { return present; } + public boolean isEmpty() { + return !present; + } + public double getAsDouble() { checkCriticalElement(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 63663b73bc..cd4ab8fb3e 100644 --- a/user/super/com/google/gwt/emul/java/util/OptionalInt.java +++ b/user/super/com/google/gwt/emul/java/util/OptionalInt.java @@ -55,6 +55,10 @@ public boolean isPresent() { return present; } + public boolean isEmpty() { + return !present; + } + public int getAsInt() { checkCriticalElement(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 978bddeb1c..11394bb4c7 100644 --- a/user/super/com/google/gwt/emul/java/util/OptionalLong.java +++ b/user/super/com/google/gwt/emul/java/util/OptionalLong.java @@ -55,6 +55,10 @@ public boolean isPresent() { return present; } + public boolean isEmpty() { + return !present; + } + public long getAsLong() { checkCriticalElement(present); return ref; diff --git a/user/test/com/google/gwt/emultest/EmulJava11Suite.java b/user/test/com/google/gwt/emultest/EmulJava11Suite.java new file mode 100644 index 0000000000..18260e0714 --- /dev/null +++ b/user/test/com/google/gwt/emultest/EmulJava11Suite.java @@ -0,0 +1,34 @@ +/* + * 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.java11.util.OptionalDoubleTest; +import com.google.gwt.emultest.java11.util.OptionalIntTest; +import com.google.gwt.emultest.java11.util.OptionalLongTest; +import com.google.gwt.emultest.java11.util.OptionalTest; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +/** Test JRE emulations. */ +@RunWith(Suite.class) +@Suite.SuiteClasses({ + OptionalDoubleTest.class, + OptionalIntTest.class, + OptionalLongTest.class, + OptionalTest.class, +}) +public class EmulJava11Suite { +} diff --git a/user/test/com/google/gwt/emultest/java11/util/OptionalDoubleTest.java b/user/test/com/google/gwt/emultest/java11/util/OptionalDoubleTest.java new file mode 100644 index 0000000000..5a2779bb21 --- /dev/null +++ b/user/test/com/google/gwt/emultest/java11/util/OptionalDoubleTest.java @@ -0,0 +1,30 @@ +/* + * 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.java11.util; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.OptionalDouble; + +/** + * Tests for java.util.OptionalDouble Java 11 API emulation. + */ +public class OptionalDoubleTest extends EmulTestBase { + public void testIsEmpty() { + assertTrue(OptionalDouble.empty().isEmpty()); + assertFalse(OptionalDouble.of(78.9).isEmpty()); + } +} diff --git a/user/test/com/google/gwt/emultest/java11/util/OptionalIntTest.java b/user/test/com/google/gwt/emultest/java11/util/OptionalIntTest.java new file mode 100644 index 0000000000..2c909b8e96 --- /dev/null +++ b/user/test/com/google/gwt/emultest/java11/util/OptionalIntTest.java @@ -0,0 +1,30 @@ +/* + * 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.java11.util; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.OptionalInt; + +/** + * Tests for java.util.OptionalInt Java 11 API emulation. + */ +public class OptionalIntTest extends EmulTestBase { + public void testIsEmpty() { + assertTrue(OptionalInt.empty().isEmpty()); + assertFalse(OptionalInt.of(456).isEmpty()); + } +} diff --git a/user/test/com/google/gwt/emultest/java11/util/OptionalLongTest.java b/user/test/com/google/gwt/emultest/java11/util/OptionalLongTest.java new file mode 100644 index 0000000000..54c6117651 --- /dev/null +++ b/user/test/com/google/gwt/emultest/java11/util/OptionalLongTest.java @@ -0,0 +1,30 @@ +/* + * 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.java11.util; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.OptionalLong; + +/** + * Tests for java.util.OptionalLong Java 11 API emulation. + */ +public class OptionalLongTest extends EmulTestBase { + public void testIsEmpty() { + assertTrue(OptionalLong.empty().isEmpty()); + assertFalse(OptionalLong.of(123L).isEmpty()); + } +} diff --git a/user/test/com/google/gwt/emultest/java11/util/OptionalTest.java b/user/test/com/google/gwt/emultest/java11/util/OptionalTest.java new file mode 100644 index 0000000000..80586871cd --- /dev/null +++ b/user/test/com/google/gwt/emultest/java11/util/OptionalTest.java @@ -0,0 +1,30 @@ +/* + * 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.java11.util; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.Optional; + +/** + * Tests for java.util.Optional Java 11 API emulation. + */ +public class OptionalTest extends EmulTestBase { + public void testIsEmpty() { + assertTrue(Optional.empty().isEmpty()); + assertFalse(Optional.of(this).isEmpty()); + } +} From 1ca97c479868dd40219d4fe64a25823592f820af Mon Sep 17 00:00:00 2001 From: Colin Alworth Date: Thu, 9 Nov 2023 19:34:02 -0600 Subject: [PATCH 3/4] Add Java 9 Stream APIs (#9837) Partial #9547 --- .../gwt/emul/java/util/stream/Collectors.java | 32 +++++ .../emul/java/util/stream/DoubleStream.java | 82 ++++++++++++- .../gwt/emul/java/util/stream/IntStream.java | 83 ++++++++++++- .../gwt/emul/java/util/stream/LongStream.java | 83 ++++++++++++- .../gwt/emul/java/util/stream/Stream.java | 89 +++++++++++++- .../google/gwt/emultest/EmulJava9Suite.java | 10 ++ .../java8/util/stream/CollectorsTest.java | 4 +- .../java8/util/stream/DoubleStreamTest.java | 22 ++++ .../java8/util/stream/IntStreamTest.java | 22 ++++ .../java8/util/stream/LongStreamTest.java | 22 ++++ .../java8/util/stream/StreamTest.java | 16 +++ .../java9/util/stream/CollectorsTest.java | 60 ++++++++++ .../java9/util/stream/DoubleStreamTest.java | 104 ++++++++++++++++ .../java9/util/stream/IntStreamTest.java | 103 ++++++++++++++++ .../java9/util/stream/LongStreamTest.java | 103 ++++++++++++++++ .../java9/util/stream/StreamTest.java | 111 ++++++++++++++++++ 16 files changed, 936 insertions(+), 10 deletions(-) create mode 100644 user/test/com/google/gwt/emultest/java9/util/stream/CollectorsTest.java create mode 100644 user/test/com/google/gwt/emultest/java9/util/stream/DoubleStreamTest.java create mode 100644 user/test/com/google/gwt/emultest/java9/util/stream/IntStreamTest.java create mode 100644 user/test/com/google/gwt/emultest/java9/util/stream/LongStreamTest.java create mode 100644 user/test/com/google/gwt/emultest/java9/util/stream/StreamTest.java diff --git a/user/super/com/google/gwt/emul/java/util/stream/Collectors.java b/user/super/com/google/gwt/emul/java/util/stream/Collectors.java index d19f64cae2..60d908edb9 100644 --- a/user/super/com/google/gwt/emul/java/util/stream/Collectors.java +++ b/user/super/com/google/gwt/emul/java/util/stream/Collectors.java @@ -170,6 +170,38 @@ public static Collector joining(CharSequence delimiter) { downstream.finisher()); } + public static Collector flatMapping(Function> mapper, Collector downstream) { + return new CollectorImpl<>( + downstream.supplier(), + (A a, T t) -> { + Stream stream = mapper.apply(t); + if (stream == null) { + return; + } + stream.forEach(u -> { + downstream.accumulator().accept(a, u); + }); + }, + downstream.combiner(), + downstream.finisher() + ); + } + + public static Collector filtering(Predicate predicate, + Collector downstream) { + return new CollectorImpl<>( + downstream.supplier(), + (a, t) -> { + if (predicate.test(t)) { + downstream.accumulator().accept(a, t); + } + }, + downstream.combiner(), + downstream.finisher() + ); + } + public static Collector> maxBy(Comparator comparator) { return reducing(BinaryOperator.maxBy(comparator)); } diff --git a/user/super/com/google/gwt/emul/java/util/stream/DoubleStream.java b/user/super/com/google/gwt/emul/java/util/stream/DoubleStream.java index 012bd0982f..c0d81589a4 100644 --- a/user/super/com/google/gwt/emul/java/util/stream/DoubleStream.java +++ b/user/super/com/google/gwt/emul/java/util/stream/DoubleStream.java @@ -146,19 +146,35 @@ public boolean tryAdvance(DoubleConsumer action) { } static DoubleStream iterate(double seed, DoubleUnaryOperator f) { + return iterate(seed, ignore -> true, f); + } + + static DoubleStream iterate(double seed, DoublePredicate hasNext, DoubleUnaryOperator f) { Spliterator.OfDouble spliterator = new Spliterators.AbstractDoubleSpliterator( Long.MAX_VALUE, Spliterator.IMMUTABLE | Spliterator.ORDERED) { + private boolean first = true; private double next = seed; + private boolean terminated = false; @Override public boolean tryAdvance(DoubleConsumer action) { + if (terminated) { + return false; + } + if (!first) { + next = f.applyAsDouble(next); + } + first = false; + + if (!hasNext.test(next)) { + terminated = true; + return false; + } action.accept(next); - next = f.applyAsDouble(next); return true; } }; - return StreamSupport.doubleStream(spliterator, false); } @@ -185,6 +201,39 @@ static DoubleStream of(double t) { DoubleStream distinct(); + default DoubleStream dropWhile(DoublePredicate predicate) { + Spliterator.OfDouble prev = spliterator(); + Spliterator.OfDouble spliterator = + new Spliterators.AbstractDoubleSpliterator(prev.estimateSize(), + prev.characteristics() & ~(Spliterator.SIZED | Spliterator.SUBSIZED)) { + private boolean drop = true; + private boolean found; + + @Override + public boolean tryAdvance(DoubleConsumer action) { + found = false; + if (drop) { + // drop items until we find one that matches + while (drop && prev.tryAdvance((double item) -> { + if (!predicate.test(item)) { + drop = false; + found = true; + action.accept(item); + } + })) { + // do nothing, work is done in tryAdvance + } + // only return true if we accepted at least one item + return found; + } else { + // accept one item, return result + return prev.tryAdvance(action); + } + } + }; + return StreamSupport.doubleStream(spliterator, false); + } + DoubleStream filter(DoublePredicate predicate); OptionalDouble findAny(); @@ -239,5 +288,34 @@ static DoubleStream of(double t) { DoubleSummaryStatistics summaryStatistics(); + default DoubleStream takeWhile(DoublePredicate predicate) { + Spliterator.OfDouble original = spliterator(); + Spliterator.OfDouble spliterator = + new Spliterators.AbstractDoubleSpliterator(original.estimateSize(), + original.characteristics() & ~(Spliterator.SIZED | Spliterator.SUBSIZED)) { + private boolean take = true; + private boolean found; + + @Override + public boolean tryAdvance(DoubleConsumer action) { + found = false; + if (!take) { + // already failed the check + return false; + } + original.tryAdvance((double item) -> { + if (predicate.test(item)) { + found = true; + action.accept(item); + } else { + take = false; + } + }); + return found; + } + }; + return StreamSupport.doubleStream(spliterator, false); + } + double[] toArray(); } diff --git a/user/super/com/google/gwt/emul/java/util/stream/IntStream.java b/user/super/com/google/gwt/emul/java/util/stream/IntStream.java index e661b5ca99..bac1b49844 100644 --- a/user/super/com/google/gwt/emul/java/util/stream/IntStream.java +++ b/user/super/com/google/gwt/emul/java/util/stream/IntStream.java @@ -149,20 +149,35 @@ public boolean tryAdvance(IntConsumer action) { } static IntStream iterate(int seed, IntUnaryOperator f) { + return iterate(seed, ignore -> true, f); + } - AbstractIntSpliterator spliterator = + static IntStream iterate(int seed, IntPredicate hasNext, IntUnaryOperator f) { + Spliterator.OfInt spliterator = new Spliterators.AbstractIntSpliterator( Long.MAX_VALUE, Spliterator.IMMUTABLE | Spliterator.ORDERED) { + private boolean first = true; private int next = seed; + private boolean terminated = false; @Override public boolean tryAdvance(IntConsumer action) { + if (terminated) { + return false; + } + if (!first) { + next = f.applyAsInt(next); + } + first = false; + + if (!hasNext.test(next)) { + terminated = true; + return false; + } action.accept(next); - next = f.applyAsInt(next); return true; } }; - return StreamSupport.intStream(spliterator, false); } @@ -235,6 +250,39 @@ public boolean tryAdvance(IntConsumer action) { IntStream distinct(); + default IntStream dropWhile(IntPredicate predicate) { + Spliterator.OfInt prev = spliterator(); + Spliterator.OfInt spliterator = + new Spliterators.AbstractIntSpliterator(prev.estimateSize(), + prev.characteristics() & ~(Spliterator.SIZED | Spliterator.SUBSIZED)) { + private boolean drop = true; + private boolean found; + + @Override + public boolean tryAdvance(IntConsumer action) { + found = false; + if (drop) { + // drop items until we find one that matches + while (drop && prev.tryAdvance((int item) -> { + if (!predicate.test(item)) { + drop = false; + found = true; + action.accept(item); + } + })) { + // do nothing, work is done in tryAdvance + } + // only return true if we accepted at least one item + return found; + } else { + // accept one item, return result + return prev.tryAdvance(action); + } + } + }; + return StreamSupport.intStream(spliterator, false); + } + IntStream filter(IntPredicate predicate); OptionalInt findAny(); @@ -289,5 +337,34 @@ public boolean tryAdvance(IntConsumer action) { IntSummaryStatistics summaryStatistics(); + default IntStream takeWhile(IntPredicate predicate) { + Spliterator.OfInt original = spliterator(); + Spliterator.OfInt spliterator = + new Spliterators.AbstractIntSpliterator(original.estimateSize(), + original.characteristics() & ~(Spliterator.SIZED | Spliterator.SUBSIZED)) { + private boolean take = true; + private boolean found; + + @Override + public boolean tryAdvance(IntConsumer action) { + found = false; + if (!take) { + // already failed the check + return false; + } + original.tryAdvance((int item) -> { + if (predicate.test(item)) { + found = true; + action.accept(item); + } else { + take = false; + } + }); + return found; + } + }; + return StreamSupport.intStream(spliterator, false); + } + int[] toArray(); } diff --git a/user/super/com/google/gwt/emul/java/util/stream/LongStream.java b/user/super/com/google/gwt/emul/java/util/stream/LongStream.java index 63861467c9..821c2f7f40 100644 --- a/user/super/com/google/gwt/emul/java/util/stream/LongStream.java +++ b/user/super/com/google/gwt/emul/java/util/stream/LongStream.java @@ -149,15 +149,32 @@ public boolean tryAdvance(LongConsumer action) { } static LongStream iterate(long seed, LongUnaryOperator f) { - AbstractLongSpliterator spliterator = + return iterate(seed, ignore -> true, f); + } + + static LongStream iterate(long seed, LongPredicate hasNext, LongUnaryOperator f) { + Spliterator.OfLong spliterator = new Spliterators.AbstractLongSpliterator( Long.MAX_VALUE, Spliterator.IMMUTABLE | Spliterator.ORDERED) { + private boolean first = true; private long next = seed; + private boolean terminated = false; @Override public boolean tryAdvance(LongConsumer action) { + if (terminated) { + return false; + } + if (!first) { + next = f.applyAsLong(next); + } + first = false; + + if (!hasNext.test(next)) { + terminated = true; + return false; + } action.accept(next); - next = f.applyAsLong(next); return true; } }; @@ -231,6 +248,39 @@ public boolean tryAdvance(LongConsumer action) { LongStream distinct(); + default LongStream dropWhile(LongPredicate predicate) { + Spliterator.OfLong prev = spliterator(); + Spliterator.OfLong spliterator = + new Spliterators.AbstractLongSpliterator(prev.estimateSize(), + prev.characteristics() & ~(Spliterator.SIZED | Spliterator.SUBSIZED)) { + private boolean drop = true; + private boolean found; + + @Override + public boolean tryAdvance(LongConsumer action) { + found = false; + if (drop) { + // drop items until we find one that matches + while (drop && prev.tryAdvance((long item) -> { + if (!predicate.test(item)) { + drop = false; + found = true; + action.accept(item); + } + })) { + // do nothing, work is done in tryAdvance + } + // only return true if we accepted at least one item + return found; + } else { + // accept one item, return result + return prev.tryAdvance(action); + } + } + }; + return StreamSupport.longStream(spliterator, false); + } + LongStream filter(LongPredicate predicate); OptionalLong findAny(); @@ -285,5 +335,34 @@ public boolean tryAdvance(LongConsumer action) { LongSummaryStatistics summaryStatistics(); + default LongStream takeWhile(LongPredicate predicate) { + Spliterator.OfLong original = spliterator(); + Spliterator.OfLong spliterator = + new Spliterators.AbstractLongSpliterator(original.estimateSize(), + original.characteristics() & ~(Spliterator.SIZED | Spliterator.SUBSIZED)) { + private boolean take = true; + private boolean found; + + @Override + public boolean tryAdvance(LongConsumer action) { + found = false; + if (!take) { + // already failed the check + return false; + } + original.tryAdvance((long item) -> { + if (predicate.test(item)) { + found = true; + action.accept(item); + } else { + take = false; + } + }); + return found; + } + }; + return StreamSupport.longStream(spliterator, false); + } + long[] toArray(); } diff --git a/user/super/com/google/gwt/emul/java/util/stream/Stream.java b/user/super/com/google/gwt/emul/java/util/stream/Stream.java index 70a9dd9c82..386d329391 100644 --- a/user/super/com/google/gwt/emul/java/util/stream/Stream.java +++ b/user/super/com/google/gwt/emul/java/util/stream/Stream.java @@ -150,15 +150,32 @@ public boolean tryAdvance(Consumer action) { } static Stream iterate(T seed, UnaryOperator f) { + return iterate(seed, ignore -> true, f); + } + + static Stream iterate(T seed, Predicate hasNext, UnaryOperator f) { AbstractSpliterator spliterator = new Spliterators.AbstractSpliterator( Long.MAX_VALUE, Spliterator.IMMUTABLE | Spliterator.ORDERED) { + private boolean first = true; private T next = seed; + private boolean terminated = false; @Override public boolean tryAdvance(Consumer action) { + if (terminated) { + return false; + } + if (!first) { + next = f.apply(next); + } + first = false; + + if (!hasNext.test(next)) { + terminated = true; + return false; + } action.accept(next); - next = f.apply(next); return true; } }; @@ -175,6 +192,14 @@ static Stream of(T... values) { return Arrays.stream(values); } + static Stream ofNullable(T t) { + if (t == null) { + return empty(); + } else { + return of(t); + } + } + boolean allMatch(Predicate predicate); boolean anyMatch(Predicate predicate); @@ -188,6 +213,39 @@ R collect( Stream distinct(); + default Stream dropWhile(Predicate predicate) { + Spliterator prev = spliterator(); + Spliterator spliterator = + new Spliterators.AbstractSpliterator(prev.estimateSize(), + prev.characteristics() & ~(Spliterator.SIZED | Spliterator.SUBSIZED)) { + private boolean drop = true; + private boolean found; + + @Override + public boolean tryAdvance(Consumer action) { + found = false; + if (drop) { + // drop items until we find one that matches + while (drop && prev.tryAdvance(item -> { + if (!predicate.test(item)) { + drop = false; + found = true; + action.accept(item); + } + })) { + // do nothing, work is done in tryAdvance + } + // only return true if we accepted at least one item + return found; + } else { + // accept one item, return result + return prev.tryAdvance(action); + } + } + }; + return StreamSupport.stream(spliterator, false); + } + Stream filter(Predicate predicate); Optional findAny(); @@ -236,6 +294,35 @@ R collect( Stream sorted(Comparator comparator); + default Stream takeWhile(Predicate predicate) { + Spliterator original = spliterator(); + Spliterator spliterator = + new Spliterators.AbstractSpliterator(original.estimateSize(), + original.characteristics() & ~(Spliterator.SIZED | Spliterator.SUBSIZED)) { + private boolean take = true; + private boolean found; + + @Override + public boolean tryAdvance(Consumer action) { + found = false; + if (!take) { + // already failed the check + return false; + } + original.tryAdvance(item -> { + if (predicate.test(item)) { + found = true; + action.accept(item); + } else { + take = false; + } + }); + return found; + } + }; + return StreamSupport.stream(spliterator, false); + } + Object[] toArray(); A[] toArray(IntFunction generator); diff --git a/user/test/com/google/gwt/emultest/EmulJava9Suite.java b/user/test/com/google/gwt/emultest/EmulJava9Suite.java index 6cdf37ed74..b2f81570e3 100644 --- a/user/test/com/google/gwt/emultest/EmulJava9Suite.java +++ b/user/test/com/google/gwt/emultest/EmulJava9Suite.java @@ -15,6 +15,11 @@ */ package com.google.gwt.emultest; +import com.google.gwt.emultest.java9.util.stream.CollectorsTest; +import com.google.gwt.emultest.java9.util.stream.DoubleStreamTest; +import com.google.gwt.emultest.java9.util.stream.IntStreamTest; +import com.google.gwt.emultest.java9.util.stream.LongStreamTest; +import com.google.gwt.emultest.java9.util.stream.StreamTest; import com.google.gwt.emultest.java9.util.ListTest; import com.google.gwt.emultest.java9.util.MapTest; import com.google.gwt.emultest.java9.util.OptionalDoubleTest; @@ -29,6 +34,11 @@ /** Test JRE emulations. */ @RunWith(Suite.class) @SuiteClasses({ + CollectorsTest.class, + DoubleStreamTest.class, + IntStreamTest.class, + LongStreamTest.class, + StreamTest.class, ListTest.class, MapTest.class, OptionalDoubleTest.class, diff --git a/user/test/com/google/gwt/emultest/java8/util/stream/CollectorsTest.java b/user/test/com/google/gwt/emultest/java8/util/stream/CollectorsTest.java index bfafad0f99..28fbf0da71 100644 --- a/user/test/com/google/gwt/emultest/java8/util/stream/CollectorsTest.java +++ b/user/test/com/google/gwt/emultest/java8/util/stream/CollectorsTest.java @@ -466,7 +466,7 @@ public void testSet() { * This method attempts to apply a collector to items as a stream might do, so that we can simply * verify the output. Taken from the Collector class's javadoc. */ - private static void applyItems( + public static void applyItems( R expected, Collector collector, T t1, T t2, BiPredicate equals) { assertTrue( "failed without splitting", @@ -479,7 +479,7 @@ private static void applyItems( * This method attempts to apply a collector to items as a stream might do, so that we * can simply verify the output. Taken from the Collector class's javadoc. */ - private static void applyItems(R expected, Collector collector, T t1, T t2) { + public static void applyItems(R expected, Collector collector, T t1, T t2) { applyItems(expected, collector, t1, t2, Object::equals); } diff --git a/user/test/com/google/gwt/emultest/java8/util/stream/DoubleStreamTest.java b/user/test/com/google/gwt/emultest/java8/util/stream/DoubleStreamTest.java index 68140c7ada..1cc6fbce97 100644 --- a/user/test/com/google/gwt/emultest/java8/util/stream/DoubleStreamTest.java +++ b/user/test/com/google/gwt/emultest/java8/util/stream/DoubleStreamTest.java @@ -17,6 +17,8 @@ package com.google.gwt.emultest.java8.util.stream; import com.google.gwt.emultest.java.util.EmulTestBase; +import com.google.gwt.junit.DoNotRunWith; +import com.google.gwt.junit.Platform; import java.util.ArrayList; import java.util.Arrays; @@ -113,10 +115,30 @@ public void testConcat() { assertEquals(Arrays.asList("first", "second"), closed); } + // Java8 has the same bug that GWT previously had here, so we're excluding Java8 from running + // this test. Presently, legacy dev mode is the only way to actually run this test using the + // JVM's own implementation, so marking this DoNotRunWith(Devel) is sufficient to avoid this. + @DoNotRunWith(Platform.Devel) public void testIterate() { assertEquals( new double[] {10d, 11d, 12d, 13d, 14d}, DoubleStream.iterate(0d, l -> l + 1d).skip(10).limit(5).toArray()); + + // Infinite stream, verify that it is correctly limited by a downstream step + assertEquals( + new double[] {0, 1, 2, 3, 4}, + DoubleStream.iterate(0, i -> i + 1).limit(5).toArray()); + + // Check that the function is called the correct number of times + int[] calledCount = {0}; + double[] array = DoubleStream.iterate(0, val -> { + calledCount[0]++; + return val + 1; + }).limit(5).toArray(); + // Verify that the function was called for each value after the seed + assertEquals(array.length - 1, calledCount[0]); + // Sanity check the values returned + assertEquals(new double[] {0, 1, 2, 3, 4}, array); } public void testGenerate() { diff --git a/user/test/com/google/gwt/emultest/java8/util/stream/IntStreamTest.java b/user/test/com/google/gwt/emultest/java8/util/stream/IntStreamTest.java index 5fea722124..d9b4ebb830 100644 --- a/user/test/com/google/gwt/emultest/java8/util/stream/IntStreamTest.java +++ b/user/test/com/google/gwt/emultest/java8/util/stream/IntStreamTest.java @@ -17,6 +17,8 @@ package com.google.gwt.emultest.java8.util.stream; import com.google.gwt.emultest.java.util.EmulTestBase; +import com.google.gwt.junit.DoNotRunWith; +import com.google.gwt.junit.Platform; import java.util.ArrayList; import java.util.Arrays; @@ -112,10 +114,30 @@ public void testConcat() { assertEquals(Arrays.asList("first", "second"), closed); } + // Java8 has the same bug that GWT previously had here, so we're excluding Java8 from running + // this test. Presently, legacy dev mode is the only way to actually run this test using the + // JVM's own implementation, so marking this DoNotRunWith(Devel) is sufficient to avoid this. + @DoNotRunWith(Platform.Devel) public void testIterate() { assertEquals( new int[] {10, 11, 12, 13, 14}, IntStream.iterate(0, i -> i + 1).skip(10).limit(5).toArray()); + + // Infinite stream, verify that it is correctly limited by a downstream step + assertEquals( + new int[] {0, 1, 2, 3, 4}, + IntStream.iterate(0, i -> i + 1).limit(5).toArray()); + + // Check that the function is called the correct number of times + int[] calledCount = {0}; + int[] array = IntStream.iterate(0, val -> { + calledCount[0]++; + return val + 1; + }).limit(5).toArray(); + // Verify that the function was called for each value after the seed + assertEquals(array.length - 1, calledCount[0]); + // Sanity check the values returned + assertEquals(new int[] {0, 1, 2, 3, 4}, array); } public void testGenerate() { diff --git a/user/test/com/google/gwt/emultest/java8/util/stream/LongStreamTest.java b/user/test/com/google/gwt/emultest/java8/util/stream/LongStreamTest.java index ff76477547..6297afdf71 100644 --- a/user/test/com/google/gwt/emultest/java8/util/stream/LongStreamTest.java +++ b/user/test/com/google/gwt/emultest/java8/util/stream/LongStreamTest.java @@ -17,6 +17,8 @@ package com.google.gwt.emultest.java8.util.stream; import com.google.gwt.emultest.java.util.EmulTestBase; +import com.google.gwt.junit.DoNotRunWith; +import com.google.gwt.junit.Platform; import java.util.ArrayList; import java.util.Arrays; @@ -111,10 +113,30 @@ public void testConcat() { assertEquals(Arrays.asList("first", "second"), closed); } + // Java8 has the same bug that GWT previously had here, so we're excluding Java8 from running + // this test. Presently, legacy dev mode is the only way to actually run this test using the + // JVM's own implementation, so marking this DoNotRunWith(Devel) is sufficient to avoid this. + @DoNotRunWith(Platform.Devel) public void testIterate() { assertEquals( new long[] {10L, 11L, 12L, 13L, 14L}, LongStream.iterate(0L, l -> l + 1L).skip(10).limit(5).toArray()); + + // Infinite stream, verify that it is correctly limited by a downstream step + assertEquals( + new long[] {0, 1, 2, 3, 4}, + LongStream.iterate(0, i -> i + 1).limit(5).toArray()); + + // Check that the function is called the correct number of times + int[] calledCount = {0}; + long[] array = LongStream.iterate(0, val -> { + calledCount[0]++; + return val + 1; + }).limit(5).toArray(); + // Verify that the function was called for each value after the seed + assertEquals(array.length - 1, calledCount[0]); + // Sanity check the values returned + assertEquals(new long[] {0, 1, 2, 3, 4}, array); } public void testGenerate() { diff --git a/user/test/com/google/gwt/emultest/java8/util/stream/StreamTest.java b/user/test/com/google/gwt/emultest/java8/util/stream/StreamTest.java index 08c4c89739..f1aea123f0 100644 --- a/user/test/com/google/gwt/emultest/java8/util/stream/StreamTest.java +++ b/user/test/com/google/gwt/emultest/java8/util/stream/StreamTest.java @@ -132,6 +132,22 @@ public void testIterate() { assertEquals( new Integer[] {10, 11, 12, 13, 14}, Stream.iterate(0, i -> i + 1).skip(10).limit(5).toArray(Integer[]::new)); + + // Infinite stream, verify that it is correctly limited by a downstream step + assertEquals( + new Integer[] {0, 1, 2, 3, 4}, + Stream.iterate(0, i -> i + 1).limit(5).toArray()); + + // Check that the function is called the correct number of times + int[] calledCount = {0}; + Integer[] array = Stream.iterate(0, val -> { + calledCount[0]++; + return val + 1; + }).limit(5).toArray(Integer[]::new); + // Verify that the function was called for each value after the seed + assertEquals(array.length - 1, calledCount[0]); + // Sanity check the values returned + assertEquals(new Integer[] {0, 1, 2, 3, 4}, array); } public void testGenerate() { diff --git a/user/test/com/google/gwt/emultest/java9/util/stream/CollectorsTest.java b/user/test/com/google/gwt/emultest/java9/util/stream/CollectorsTest.java new file mode 100644 index 0000000000..1e7adea081 --- /dev/null +++ b/user/test/com/google/gwt/emultest/java9/util/stream/CollectorsTest.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.java9.util.stream; + +import static com.google.gwt.emultest.java8.util.stream.CollectorsTest.applyItems; +import static java.util.stream.Collectors.filtering; +import static java.util.stream.Collectors.flatMapping; +import static java.util.stream.Collectors.toList; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collector; + +/** + * Tests for java.util.stream.Collectors Java 9 API emulation. + */ +public class CollectorsTest extends EmulTestBase { + + public void testFlatMapping() { + // since applyItems tests the same inputs multiple times, we need fresh stream instances as they can't be reused + Collector, ?, List> flatMapping = flatMapping(Collection::stream, + toList()); + applyItems(Arrays.asList("a", "b"), flatMapping, Collections.singletonList("a"), + Collections.singletonList("b")); + applyItems(Arrays.asList("c", "d"), flatMapping, Collections.emptyList(), Arrays.asList("c", "d")); + + Collector, ?, List> flatMappingToNull = flatMapping(items -> { + if (items.size() % 2 == 0) { + // Return null instead of empty + return null; + } + return items.stream(); + }, toList()); + applyItems(Arrays.asList("a"), flatMappingToNull, Arrays.asList("a"), Arrays.asList("b", "c")); + } + + public void testFiltering() { + Collector> filtering = filtering(s -> s.equals("a"), toList()); + applyItems(Collections.singletonList("a"), filtering, "a", "b"); + applyItems(Collections.emptyList(), filtering, "c", "d"); + applyItems(Arrays.asList("a", "a"), filtering, "a", "a"); + } +} diff --git a/user/test/com/google/gwt/emultest/java9/util/stream/DoubleStreamTest.java b/user/test/com/google/gwt/emultest/java9/util/stream/DoubleStreamTest.java new file mode 100644 index 0000000000..d3b1585567 --- /dev/null +++ b/user/test/com/google/gwt/emultest/java9/util/stream/DoubleStreamTest.java @@ -0,0 +1,104 @@ +/* + * 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.stream; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.stream.DoubleStream; + +/** + * Tests for java.util.stream.DoubleStream Java 9 API emulation. + */ +public class DoubleStreamTest extends EmulTestBase { + public void testIterate() { + // Terminating stream, based on a predicate + assertEquals( + new double[] {10, 11, 12, 13, 14}, + DoubleStream.iterate(0, i -> i < 15, i -> i + 1).skip(10).toArray()); + + // Check that the functions are called the correct number of times with a hasNext limiting + // stream size + { + int[] nextCalledCount = {0}; + int[] hasNextCalledCount = {0}; + double[] array = DoubleStream.iterate(0, val -> { + hasNextCalledCount[0]++; + return val < 5; + }, val -> { + nextCalledCount[0]++; + return val + 1; + }).toArray(); + + // Verify that the next was called for each value after the seed (plus one for testing that + // the stream is over) + assertEquals(array.length, nextCalledCount[0]); + // Verify that the hasNext function was called once for each value (plus one as above) + assertEquals(array.length + 1, hasNextCalledCount[0]); + // Sanity check the values returned + assertEquals(new double[]{0, 1, 2, 3, 4}, array); + } + + // Same test repeated, but instead limit() will stop the stream from continuing + { + int[] nextCalledCount = {0}; + int[] hasNextCalledCount = {0}; + double[] array = DoubleStream.iterate(0, val -> { + hasNextCalledCount[0]++; + return val < 5; + }, val -> { + nextCalledCount[0]++; + return val + 1; + }).limit(3).toArray(); + + // Verify that the next was called for each value after the seed + assertEquals(array.length - 1, nextCalledCount[0]); + // Verify that the hasNext function was called once for each value + assertEquals(array.length, hasNextCalledCount[0]); + // Sanity check the values returned + assertEquals(new double[]{0, 1, 2}, array); + } + } + + public void testTakeWhile() { + assertEquals( + new double[] {1, 2}, + DoubleStream.of(1, 2, 3, 4, 5).takeWhile(i -> i < 3).toArray() + ); + assertEquals(0, DoubleStream.of(1, 2, 3, 4, 5).takeWhile(i -> i > 2).count()); + + assertEquals( + new double[] {0, 1, 2, 3, 4}, + DoubleStream.iterate(0, i -> i + 1).takeWhile(i -> i < 5).toArray() + ); + } + + public void testDropWhile() { + assertEquals( + new double[] {3, 4, 5}, + DoubleStream.of(1, 2, 3, 4, 5).dropWhile(i -> i < 3).toArray() + ); + assertEquals( + new double[] {1, 2, 3, 4, 5}, + DoubleStream.of(1, 2, 3, 4, 5).dropWhile(i -> i > 2).toArray() + ); + + // pass an infinite stream to dropWhile, ensure it handles it + assertEquals( + new double[] {5, 6, 7, 8, 9}, + DoubleStream.iterate(0, i -> i + 1).dropWhile(i -> i < 5).limit(5).toArray() + ); + } +} diff --git a/user/test/com/google/gwt/emultest/java9/util/stream/IntStreamTest.java b/user/test/com/google/gwt/emultest/java9/util/stream/IntStreamTest.java new file mode 100644 index 0000000000..ced92ef0d7 --- /dev/null +++ b/user/test/com/google/gwt/emultest/java9/util/stream/IntStreamTest.java @@ -0,0 +1,103 @@ +/* + * 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.stream; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.stream.IntStream; + +/** + * Tests for java.util.stream.IntStream Java 9 API emulation. + */ +public class IntStreamTest extends EmulTestBase { + public void testIterate() { + assertEquals( + new int[] {10, 11, 12, 13, 14}, + IntStream.iterate(0, i -> i < 15, i -> i + 1).skip(10).toArray()); + + // Check that the functions are called the correct number of times with a hasNext limiting + // stream size + { + int[] nextCalledCount = {0}; + int[] hasNextCalledCount = {0}; + int[] array = IntStream.iterate(0, val -> { + hasNextCalledCount[0]++; + return val < 5; + }, val -> { + nextCalledCount[0]++; + return val + 1; + }).toArray(); + + // Verify that the next was called for each value after the seed (plus one for testing that + // the stream is over) + assertEquals(array.length, nextCalledCount[0]); + // Verify that the hasNext function was called once for each value (plus one as above) + assertEquals(array.length + 1, hasNextCalledCount[0]); + // Sanity check the values returned + assertEquals(new int[]{0, 1, 2, 3, 4}, array); + } + + // Same test repeated, but instead limit() will stop the stream from continuing + { + int[] nextCalledCount = {0}; + int[] hasNextCalledCount = {0}; + int[] array = IntStream.iterate(0, val -> { + hasNextCalledCount[0]++; + return val < 5; + }, val -> { + nextCalledCount[0]++; + return val + 1; + }).limit(3).toArray(); + + // Verify that the next was called for each value after the seed + assertEquals(array.length - 1, nextCalledCount[0]); + // Verify that the hasNext function was called once for each value + assertEquals(array.length, hasNextCalledCount[0]); + // Sanity check the values returned + assertEquals(new int[]{0, 1, 2}, array); + } + } + + public void testTakeWhile() { + assertEquals( + new int[] {1, 2}, + IntStream.of(1, 2, 3, 4, 5).takeWhile(i -> i < 3).toArray() + ); + assertEquals(0, IntStream.of(1, 2, 3, 4, 5).takeWhile(i -> i > 2).count()); + + assertEquals( + new int[] {0, 1, 2, 3, 4}, + IntStream.iterate(0, i -> i + 1).takeWhile(i -> i < 5).toArray() + ); + } + + public void testDropWhile() { + assertEquals( + new int[] {3, 4, 5}, + IntStream.of(1, 2, 3, 4, 5).dropWhile(i -> i < 3).toArray() + ); + assertEquals( + new int[] {1, 2, 3, 4, 5}, + IntStream.of(1, 2, 3, 4, 5).dropWhile(i -> i > 2).toArray() + ); + + // pass an infinite stream to dropWhile, ensure it handles it + assertEquals( + new int[] {5, 6, 7, 8, 9}, + IntStream.iterate(0, i -> i + 1).dropWhile(i -> i < 5).limit(5).toArray() + ); + } +} diff --git a/user/test/com/google/gwt/emultest/java9/util/stream/LongStreamTest.java b/user/test/com/google/gwt/emultest/java9/util/stream/LongStreamTest.java new file mode 100644 index 0000000000..26ff6b6675 --- /dev/null +++ b/user/test/com/google/gwt/emultest/java9/util/stream/LongStreamTest.java @@ -0,0 +1,103 @@ +/* + * 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.stream; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.stream.LongStream; + +/** + * Tests for java.util.stream.IntStream Java 9 API emulation. + */ +public class LongStreamTest extends EmulTestBase { + public void testIterate() { + assertEquals( + new long[] {10, 11, 12, 13, 14}, + LongStream.iterate(0, i -> i < 15, i -> i + 1).skip(10).toArray()); + + // Check that the functions are called the correct number of times with a hasNext limiting + // stream size + { + int[] nextCalledCount = {0}; + int[] hasNextCalledCount = {0}; + long[] array = LongStream.iterate(0, val -> { + hasNextCalledCount[0]++; + return val < 5; + }, val -> { + nextCalledCount[0]++; + return val + 1; + }).toArray(); + + // Verify that the next was called for each value after the seed (plus one for testing that + // the stream is over) + assertEquals(array.length, nextCalledCount[0]); + // Verify that the hasNext function was called once for each value (plus one as above) + assertEquals(array.length + 1, hasNextCalledCount[0]); + // Sanity check the values returned + assertEquals(new long[]{0, 1, 2, 3, 4}, array); + } + + // Same test repeated, but instead limit() will stop the stream from continuing + { + int[] nextCalledCount = {0}; + int[] hasNextCalledCount = {0}; + long[] array = LongStream.iterate(0, val -> { + hasNextCalledCount[0]++; + return val < 5; + }, val -> { + nextCalledCount[0]++; + return val + 1; + }).limit(3).toArray(); + + // Verify that the next was called for each value after the seed + assertEquals(array.length - 1, nextCalledCount[0]); + // Verify that the hasNext function was called once for each value + assertEquals(array.length, hasNextCalledCount[0]); + // Sanity check the values returned + assertEquals(new long[]{0, 1, 2}, array); + } + } + + public void testTakeWhile() { + assertEquals( + new long[] {1, 2}, + LongStream.of(1, 2, 3, 4, 5).takeWhile(i -> i < 3).toArray() + ); + assertEquals(0, LongStream.of(1, 2, 3, 4, 5).takeWhile(i -> i > 2).count()); + + assertEquals( + new long[] {0, 1, 2, 3, 4}, + LongStream.iterate(0, i -> i + 1).takeWhile(i -> i < 5).toArray() + ); + } + + public void testDropWhile() { + assertEquals( + new long[] {3, 4, 5}, + LongStream.of(1, 2, 3, 4, 5).dropWhile(i -> i < 3).toArray() + ); + assertEquals( + new long[] {1, 2, 3, 4, 5}, + LongStream.of(1, 2, 3, 4, 5).dropWhile(i -> i > 2).toArray() + ); + + // pass an infinite stream to dropWhile, ensure it handles it + assertEquals( + new long[] {5, 6, 7, 8, 9}, + LongStream.iterate(0, i -> i + 1).dropWhile(i -> i < 5).limit(5).toArray() + ); + } +} diff --git a/user/test/com/google/gwt/emultest/java9/util/stream/StreamTest.java b/user/test/com/google/gwt/emultest/java9/util/stream/StreamTest.java new file mode 100644 index 0000000000..fb712ec780 --- /dev/null +++ b/user/test/com/google/gwt/emultest/java9/util/stream/StreamTest.java @@ -0,0 +1,111 @@ +/* + * 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.stream; + +import com.google.gwt.emultest.java.util.EmulTestBase; + +import java.util.stream.Stream; + +/** + * Tests for java.util.stream.Stream Java 9 API emulation. + */ +public class StreamTest extends EmulTestBase { + public void testIterate() { + assertEquals( + new Integer[] {10, 11, 12, 13, 14}, + Stream.iterate(0, i -> i < 15, i -> i + 1).skip(10).toArray(Integer[]::new)); + + // Check that the functions are called the correct number of times with a hasNext limiting + // stream size + { + int[] nextCalledCount = {0}; + int[] hasNextCalledCount = {0}; + Integer[] array = Stream.iterate(0, val -> { + hasNextCalledCount[0]++; + return val < 5; + }, val -> { + nextCalledCount[0]++; + return val + 1; + }).toArray(Integer[]::new); + + // Verify that the next was called for each value after the seed (plus one for testing that + // the stream is over) + assertEquals(array.length, nextCalledCount[0]); + // Verify that the hasNext function was called once for each value (plus one as above) + assertEquals(array.length + 1, hasNextCalledCount[0]); + // Sanity check the values returned + assertEquals(new Integer[]{0, 1, 2, 3, 4}, array); + } + + // Same test repeated, but instead limit() will stop the stream from continuing + { + int[] nextCalledCount = {0}; + int[] hasNextCalledCount = {0}; + Integer[] array = Stream.iterate(0, val -> { + hasNextCalledCount[0]++; + return val < 5; + }, val -> { + nextCalledCount[0]++; + return val + 1; + }).limit(3).toArray(Integer[]::new); + + // Verify that the next was called for each value after the seed + assertEquals(array.length - 1, nextCalledCount[0]); + // Verify that the hasNext function was called once for each value + assertEquals(array.length, hasNextCalledCount[0]); + // Sanity check the values returned + assertEquals(new Integer[]{0, 1, 2}, array); + } + } + + public void testOfNullable() { + assertEquals(0, Stream.ofNullable(null).count()); + assertEquals( + new String[] {"abc"}, + Stream.ofNullable("abc").toArray(String[]::new) + ); + } + + public void testTakeWhile() { + assertEquals( + new Integer[] {1, 2}, + Stream.of(1, 2, 3, 4, 5).takeWhile(i -> i < 3).toArray(Integer[]::new) + ); + assertEquals(0, Stream.of(1, 2, 3, 4, 5).takeWhile(i -> i > 2).count()); + + assertEquals( + new Integer[] {0, 1, 2, 3, 4}, + Stream.iterate(0, i -> i + 1).takeWhile(i -> i < 5).toArray() + ); + } + + public void testDropWhile() { + assertEquals( + new Integer[] {3, 4, 5}, + Stream.of(1, 2, 3, 4, 5).dropWhile(i -> i < 3).toArray(Integer[]::new) + ); + assertEquals( + new Integer[] {1, 2, 3, 4, 5}, + Stream.of(1, 2, 3, 4, 5).dropWhile(i -> i > 2).toArray(Integer[]::new) + ); + + // pass an infinite stream to dropWhile, ensure it handles it + assertEquals( + new Integer[] {5, 6, 7, 8, 9}, + Stream.iterate(0, i -> i + 1).dropWhile(i -> i < 5).limit(5).toArray() + ); + } +} From be374733d88677f0a2c038c994c304a60d30d30d Mon Sep 17 00:00:00 2001 From: Colin Alworth Date: Sun, 12 Nov 2023 18:31:22 -0600 Subject: [PATCH 4/4] Updated Enumeration emul for Java 9 (#9861) Partial #9547 --- .../com/google/gwt/emul/java/util/Enumeration.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/user/super/com/google/gwt/emul/java/util/Enumeration.java b/user/super/com/google/gwt/emul/java/util/Enumeration.java index 1f0c8adce1..26fc44b0ee 100644 --- a/user/super/com/google/gwt/emul/java/util/Enumeration.java +++ b/user/super/com/google/gwt/emul/java/util/Enumeration.java @@ -27,4 +27,17 @@ public interface Enumeration { boolean hasMoreElements(); E nextElement(); + + default Iterator asIterator() { + return new Iterator() { + @Override + public boolean hasNext() { + return hasMoreElements(); + } + @Override + public E next() { + return nextElement(); + } + }; + } }