/* * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ import java.util.List; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.BinaryOperator; import java.util.function.Supplier; import java.util.stream.*; import java.util.stream.Gatherer; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assumptions.*; /** * @test * @summary Testing public API of Gatherer * @run junit GathererAPITest */ public class GathererAPITest { final static Supplier initializer = () -> (Void)null; final static Gatherer.Integrator integrator = (v,e,d) -> d.push(e); final static BinaryOperator combiner = (l,r) -> l; final static BiConsumer> finisher = (v,d) -> {}; final static Supplier nullInitializer = null; final static Gatherer.Integrator nullIntegrator = null; final static BinaryOperator nullCombiner = null; final static BiConsumer> nullFinisher = null; private final static Gatherer passthrough() { return Gatherer.of( () -> (Void)null, Gatherer.Integrator.ofGreedy((v,e,d) -> d.push(e)), (l,r) -> l, (v,d) -> {} ); } private final static Gatherer verifyGathererContract(Gatherer gatherer) { // basics assertNotNull(gatherer); // components assertNotNull(gatherer.initializer()); assertNotNull(gatherer.integrator()); assertNotNull(gatherer.combiner()); assertNotNull(gatherer.finisher()); assertNotNull(gatherer.andThen(passthrough())); return gatherer; } private final static Gatherer verifyGathererStructure( Gatherer gatherer, Supplier expectedSupplier, Gatherer.Integrator expectedIntegrator, BinaryOperator expectedCombiner, BiConsumer> expectedFinisher ) { // basics assertNotNull(gatherer); // components assertSame(expectedSupplier, gatherer.initializer()); assertSame(expectedIntegrator, gatherer.integrator()); assertSame(expectedCombiner, gatherer.combiner()); assertSame(expectedFinisher, gatherer.finisher()); return gatherer; } @Test public void testGathererDefaults() { final Gatherer.Integrator expectedIntegrator = (a,b,c) -> false; class Test implements Gatherer { @Override public Integrator integrator() { return expectedIntegrator; } } var t = new Test(); assertSame(Gatherer.defaultInitializer(), t.initializer()); assertSame(expectedIntegrator, t.integrator()); assertSame(Gatherer.defaultCombiner(), t.combiner()); assertSame(Gatherer.>defaultFinisher(), t.finisher()); } @Test public void testDownstreamDefaults() { class Test implements Gatherer.Downstream { @Override public boolean push(Void v) { return false; } } var t = new Test(); assertEquals(false, t.isRejecting()); } @Test public void testGathererFactoriesNPE() { assertThrows(NullPointerException.class, () -> Gatherer.of(nullInitializer, integrator, combiner, finisher)); assertThrows(NullPointerException.class, () -> Gatherer.of(initializer, nullIntegrator, combiner, finisher)); assertThrows(NullPointerException.class, () -> Gatherer.of(initializer, integrator, nullCombiner, finisher)); assertThrows(NullPointerException.class, () -> Gatherer.of(initializer, integrator, combiner, nullFinisher)); assertThrows(NullPointerException.class, () -> Gatherer.of(nullIntegrator)); assertThrows(NullPointerException.class, () -> Gatherer.of(nullIntegrator, finisher)); assertThrows(NullPointerException.class, () -> Gatherer.of(integrator, nullFinisher)); assertThrows(NullPointerException.class, () -> Gatherer.ofSequential(nullInitializer, integrator)); assertThrows(NullPointerException.class, () -> Gatherer.ofSequential(initializer, nullIntegrator)); assertThrows(NullPointerException.class, () -> Gatherer.ofSequential(nullIntegrator)); assertThrows(NullPointerException.class, () -> Gatherer.ofSequential(nullIntegrator, finisher)); assertThrows(NullPointerException.class, () -> Gatherer.ofSequential(integrator, nullFinisher)); assertThrows(NullPointerException.class, () -> Gatherer.ofSequential(nullInitializer, integrator, finisher)); assertThrows(NullPointerException.class, () -> Gatherer.ofSequential(initializer, nullIntegrator, finisher)); assertThrows(NullPointerException.class, () -> Gatherer.ofSequential(initializer, integrator, nullFinisher)); } @Test public void testGathererFactoriesAPI() { final var defaultInitializer = Gatherer.defaultInitializer(); final var defaultCombiner = Gatherer.defaultCombiner(); final var defaultFinisher = Gatherer.defaultFinisher(); var g1 = verifyGathererContract(passthrough()); // Quis custodiet ipsos custodes? verifyGathererContract(g1.andThen(g1)); var g2 = verifyGathererContract(Gatherer.of(integrator)); verifyGathererContract(g2.andThen(g2)); assertSame(defaultInitializer, g2.initializer()); assertSame(integrator, g2.integrator()); assertNotSame(defaultCombiner, g2.combiner()); assertSame(defaultFinisher, g2.finisher()); var g3 = verifyGathererContract(Gatherer.of(integrator, finisher)); verifyGathererContract(g3.andThen(g3)); assertSame(integrator, g3.integrator()); assertNotSame(defaultCombiner, g3.combiner()); assertSame(finisher, g3.finisher()); var g4 = verifyGathererContract(Gatherer.ofSequential(integrator)); verifyGathererContract(g4.andThen(g4)); verifyGathererStructure(g4, defaultInitializer, integrator, defaultCombiner, defaultFinisher); var g5 = verifyGathererContract(Gatherer.ofSequential(initializer, integrator)); verifyGathererContract(g5.andThen(g5)); verifyGathererStructure(g5, initializer, integrator, defaultCombiner, defaultFinisher); var g6 = verifyGathererContract(Gatherer.ofSequential(integrator, finisher)); verifyGathererContract(g6.andThen(g6)); verifyGathererStructure(g6, defaultInitializer, integrator, defaultCombiner, finisher); var g7 = verifyGathererContract(Gatherer.ofSequential(initializer, integrator, finisher)); verifyGathererContract(g7.andThen(g7)); verifyGathererStructure(g7, initializer, integrator, defaultCombiner, finisher); var g8 = verifyGathererContract(Gatherer.of(initializer, integrator, combiner, finisher)); verifyGathererContract(g8.andThen(g8)); verifyGathererStructure(g8, initializer, integrator, combiner, finisher); } @Test public void testGathererVariance() { // Make sure that Gatherers can pass-through type Gatherer nums = Gatherer.of((unused, element, downstream) -> downstream.push(element)); // Make sure that Gatherers can upcast the output type from the input type Gatherer upcast = Gatherer.of((unused, element, downstream) -> downstream.push(element)); // Make sure that Gatherers can consume a supertype of the Stream output assertEquals(List.of(1,2,3,4,5), Stream.of(1,2,3,4,5).gather(nums).toList()); Gatherer ints = Gatherer.of((unused, element, downstream) -> downstream.push(element)); // Make sure that Gatherers can be composed where the output is a subtype of the input type of the next Gatherer composition = ints.andThen(nums); // Make sure that composition works transitively, typing-wise Gatherer upcastComposition = ints.andThen(nums.andThen(upcast)); assertEquals(List.of(1,2,3,4,5), Stream.of(1,2,3,4,5).gather(composition).toList()); assertEquals(List.of(1,2,3,4,5), Stream.of(1,2,3,4,5).gather(upcastComposition).toList()); } }