jdk-24/test/jdk/java/util/stream/GathererAPITest.java
Viktor Klang ef0dc2518e 8342707: Prepare Gatherers for graduation from Preview
Reviewed-by: alanb, liach
2024-11-11 19:57:26 +00:00

230 lines
9.7 KiB
Java

/*
* 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<Void> initializer = () -> (Void)null;
final static Gatherer.Integrator<Void, Integer, Integer> integrator = (v,e,d) -> d.push(e);
final static BinaryOperator<Void> combiner = (l,r) -> l;
final static BiConsumer<Void,Gatherer.Downstream<? super Integer>> finisher = (v,d) -> {};
final static Supplier<Void> nullInitializer = null;
final static Gatherer.Integrator<Void, Integer, Integer> nullIntegrator = null;
final static BinaryOperator<Void> nullCombiner = null;
final static BiConsumer<Void,Gatherer.Downstream<? super Integer>> nullFinisher = null;
private final static <T> Gatherer<T,?,T> passthrough() {
return Gatherer.of(
() -> (Void)null,
Gatherer.Integrator.<Void,T,T>ofGreedy((v,e,d) -> d.push(e)),
(l,r) -> l,
(v,d) -> {}
);
}
private final static <T,A,R> Gatherer<T,A,R> verifyGathererContract(Gatherer<T,A,R> 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 <T,A,R> Gatherer<T,A,R> verifyGathererStructure(
Gatherer<T,A,R> gatherer,
Supplier<A> expectedSupplier,
Gatherer.Integrator<A,T,R> expectedIntegrator,
BinaryOperator<A> expectedCombiner,
BiConsumer<A,Gatherer.Downstream<? super R>> 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<Void,Void,Void> expectedIntegrator =
(a,b,c) -> false;
class Test implements Gatherer<Void,Void,Void> {
@Override
public Integrator<Void, Void, Void> integrator() {
return expectedIntegrator;
}
}
var t = new Test();
assertSame(Gatherer.<Void>defaultInitializer(), t.initializer());
assertSame(expectedIntegrator, t.integrator());
assertSame(Gatherer.<Void>defaultCombiner(), t.combiner());
assertSame(Gatherer.<Void,Gatherer.Downstream<? super Void>>defaultFinisher(), t.finisher());
}
@Test
public void testDownstreamDefaults() {
class Test implements Gatherer.Downstream<Void> {
@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.<Void>defaultInitializer();
final var defaultCombiner = Gatherer.<Void>defaultCombiner();
final var defaultFinisher = Gatherer.<Void,Integer>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<Number,?,Number> nums = Gatherer.of((unused, element, downstream) -> downstream.push(element));
// Make sure that Gatherers can upcast the output type from the input type
Gatherer<Number,?,Object> 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.<Integer>of(1,2,3,4,5).gather(nums).toList());
Gatherer<Integer,?,Integer> 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<Integer,?,Number> composition = ints.andThen(nums);
// Make sure that composition works transitively, typing-wise
Gatherer<Integer,?,Object> upcastComposition = ints.andThen(nums.andThen(upcast));
assertEquals(List.of(1,2,3,4,5), Stream.<Integer>of(1,2,3,4,5).gather(composition).toList());
assertEquals(List.of(1,2,3,4,5), Stream.<Integer>of(1,2,3,4,5).gather(upcastComposition).toList());
}
}