OpenJDK / lambda / lambda / jdk
changeset 7823:d92f53c4c7ba
- Sync up spliterator tests into the spliterator test helper.
- Fix issues with Spliterator.getComparator implementations.
author | psandoz |
---|---|
date | Fri, 05 Apr 2013 16:09:55 +0200 |
parents | 25f122a48151 |
children | e6ce826890e0 |
files | src/share/classes/java/util/stream/StreamSpliterators.java src/share/classes/java/util/stream/Streams.java test-ng/bootlib/java/util/stream/SpliteratorTestHelper.java test-ng/tests/org/openjdk/tests/java/util/stream/StreamSpliteratorTest.java |
diffstat | 4 files changed, 173 insertions(+), 90 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/classes/java/util/stream/StreamSpliterators.java Fri Apr 05 14:34:01 2013 +0200 +++ b/src/share/classes/java/util/stream/StreamSpliterators.java Fri Apr 05 16:09:55 2013 +0200 @@ -195,6 +195,14 @@ } @Override + public Comparator<? super P_OUT> getComparator() { + if (hasCharacteristics(SORTED)) { + return null; + } + throw new IllegalStateException(); + } + + @Override public final String toString() { return getClass().getName() + "[" + spliterator + "]"; }
--- a/src/share/classes/java/util/stream/Streams.java Fri Apr 05 14:34:01 2013 +0200 +++ b/src/share/classes/java/util/stream/Streams.java Fri Apr 05 16:09:55 2013 +0200 @@ -1315,7 +1315,9 @@ @Override public Comparator<? super Integer> getComparator() { - return null; + if (step > 0) + return null; + throw new IllegalStateException(); } @Override @@ -1390,7 +1392,9 @@ @Override public Comparator<? super Long> getComparator() { - return null; + if (step > 0) + return null; + throw new IllegalStateException(); } @Override @@ -1477,7 +1481,9 @@ @Override public Comparator<? super Double> getComparator() { - return null; + if (step > 0) + return null; + throw new IllegalStateException(); } @Override
--- a/test-ng/bootlib/java/util/stream/SpliteratorTestHelper.java Fri Apr 05 14:34:01 2013 +0200 +++ b/test-ng/bootlib/java/util/stream/SpliteratorTestHelper.java Fri Apr 05 16:09:55 2013 +0200 @@ -26,12 +26,17 @@ import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.Deque; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Spliterator; import java.util.function.*; import static org.testng.Assert.*; +import static org.testng.Assert.assertEquals; import static org.testng.Assert.fail; /** @@ -119,47 +124,85 @@ static <T, S extends Spliterator<T>> void testSpliterator(Supplier<S> supplier, UnaryOperator<Consumer<T>> boxingAdapter) { - testTryAdvanceAgainstForEach("testTryAdvanceAgainstForEach", supplier, boxingAdapter); - testMixedTryAdvanceForEach("testMixedTryAdvanceForEach", supplier, boxingAdapter); - testSplitAfterFullTraversal("testSplitAfterFullTraversal", supplier, boxingAdapter); - testSplitOnce("testSplitOnce", supplier, boxingAdapter); - testSplitSixDeep("testSplitSixDeep", supplier, boxingAdapter); - testSplitUntilNull("testSplitUntilNull", supplier, boxingAdapter); + ArrayList<T> fromForEach = new ArrayList<>(); + Spliterator<T> spliterator = supplier.get(); + Consumer<T> addToFromForEach = boxingAdapter.apply(fromForEach::add); + spliterator.forEachRemaining(addToFromForEach); + + Collection<T> exp = Collections.unmodifiableList(fromForEach); + + testForEach(exp, supplier, boxingAdapter); + testTryAdvance(exp, supplier, boxingAdapter); + testMixedTryAdvanceForEach(exp, supplier, boxingAdapter); + testSplitAfterFullTraversal(supplier, boxingAdapter); + testSplitOnce(exp, supplier, boxingAdapter); + testSplitSixDeep(exp, supplier, boxingAdapter); + testSplitUntilNull(exp, supplier, boxingAdapter); } - static <T, S extends Spliterator<T>> void testTryAdvanceAgainstForEach(String name, - Supplier<S> supplier, - UnaryOperator<Consumer<T>> boxingAdapter) { - long sizeIfKnown = supplier.get().getExactSizeIfKnown(); + // + + private static <T, S extends Spliterator<T>> void testForEach( + Collection<T> exp, + Supplier<S> supplier, + UnaryOperator<Consumer<T>> boxingAdapter) { + S spliterator = supplier.get(); + long sizeIfKnown = spliterator.getExactSizeIfKnown(); + boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED); + + ArrayList<T> fromForEach = new ArrayList<>(); + spliterator = supplier.get(); + Consumer<T> addToFromForEach = boxingAdapter.apply(fromForEach::add); + spliterator.forEachRemaining(addToFromForEach); + + // Assert that forEach now produces no elements + spliterator.forEachRemaining(boxingAdapter.apply(e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e))); + // Assert that tryAdvance now produce no elements + spliterator.tryAdvance(boxingAdapter.apply(e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e))); + + // assert that size, tryAdvance, and forEach are consistent + if (sizeIfKnown >= 0) { + assertEquals(sizeIfKnown, exp.size()); + } + assertEquals(fromForEach.size(), exp.size()); + + assertContents(fromForEach, exp, isOrdered); + } + + private static <T, S extends Spliterator<T>> void testTryAdvance( + Collection<T> exp, + Supplier<S> supplier, + UnaryOperator<Consumer<T>> boxingAdapter) { + S spliterator = supplier.get(); + long sizeIfKnown = spliterator.getExactSizeIfKnown(); + boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED); + + spliterator = supplier.get(); ArrayList<T> fromTryAdvance = new ArrayList<>(); - - S spliterator = supplier.get(); Consumer<T> addToFromTryAdvance = boxingAdapter.apply(fromTryAdvance::add); while (spliterator.tryAdvance(addToFromTryAdvance)) { } - ArrayList<T> fromForEach = new ArrayList<>(); - Consumer<T> addToFromForEach = boxingAdapter.apply(fromForEach::add); - supplier.get().forEachRemaining(addToFromForEach); + // Assert that forEach now produces no elements + spliterator.forEachRemaining(boxingAdapter.apply(e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e))); + // Assert that tryAdvance now produce no elements + spliterator.tryAdvance(boxingAdapter.apply(e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e))); // assert that size, tryAdvance, and forEach are consistent if (sizeIfKnown >= 0) { - assertEquals(sizeIfKnown, fromForEach.size()); - assertEquals(sizeIfKnown, fromTryAdvance.size()); + assertEquals(sizeIfKnown, exp.size()); } - assertEquals(fromForEach, fromTryAdvance); + assertEquals(fromTryAdvance.size(), exp.size()); + + assertContents(fromTryAdvance, exp, isOrdered); } - static <T, S extends Spliterator<T>> void testMixedTryAdvanceForEach(String name, - Supplier<S> supplier, - UnaryOperator<Consumer<T>> boxingAdapter) { - long sizeIfKnown = supplier.get().getExactSizeIfKnown(); - ArrayList<T> fromTryAdvance = new ArrayList<>(); - - Spliterator<T> spliterator = supplier.get(); - Consumer<T> addToFromTryAdvance = boxingAdapter.apply(fromTryAdvance::add); - while (spliterator.tryAdvance(addToFromTryAdvance)) { } - // Assert that forEach now produces no elements - spliterator.forEachRemaining(boxingAdapter.apply(e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e))); + private static <T, S extends Spliterator<T>> void testMixedTryAdvanceForEach( + Collection<T> exp, + Supplier<S> supplier, + UnaryOperator<Consumer<T>> boxingAdapter) { + S spliterator = supplier.get(); + long sizeIfKnown = spliterator.getExactSizeIfKnown(); + boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED); // tryAdvance first few elements, then forEach rest ArrayList<T> dest = new ArrayList<>(); @@ -168,17 +211,27 @@ for (int i = 0; i < 10 && spliterator.tryAdvance(addToDest); i++) { } spliterator.forEachRemaining(addToDest); + // Assert that forEach now produces no elements + spliterator.forEachRemaining(boxingAdapter.apply(e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e))); // Assert that tryAdvance now produce no elements spliterator.tryAdvance(boxingAdapter.apply(e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e))); - if (sizeIfKnown >= 0) + if (sizeIfKnown >= 0) { assertEquals(sizeIfKnown, dest.size()); - assertEquals(fromTryAdvance, dest); + } + assertEquals(dest.size(), exp.size()); + + if (isOrdered) { + assertEquals(dest, exp); + } + else { + assertContentsUnordered(dest, exp); + } } - static <T, S extends Spliterator<T>> void testSplitAfterFullTraversal(String name, - Supplier<S> supplier, - UnaryOperator<Consumer<T>> boxingAdapter) { + private static <T, S extends Spliterator<T>> void testSplitAfterFullTraversal( + Supplier<S> supplier, + UnaryOperator<Consumer<T>> boxingAdapter) { // Full traversal using tryAdvance Spliterator<T> spliterator = supplier.get(); while (spliterator.tryAdvance(boxingAdapter.apply(e -> { }))) { } @@ -201,15 +254,13 @@ assertNull(split); } - static <T, S extends Spliterator<T>> void testSplitOnce(String name, - Supplier<S> supplier, - UnaryOperator<Consumer<T>> boxingAdapter) { - long sizeIfKnown = supplier.get().getExactSizeIfKnown(); - ArrayList<T> fromTryAdvance = new ArrayList<>(); - - Spliterator<T> spliterator = supplier.get(); - Consumer<T> addToFromTryAdvance = boxingAdapter.apply(fromTryAdvance::add); - while (spliterator.tryAdvance(addToFromTryAdvance)) { } + private static <T, S extends Spliterator<T>> void testSplitOnce( + Collection<T> exp, + Supplier<S> supplier, + UnaryOperator<Consumer<T>> boxingAdapter) { + S spliterator = supplier.get(); + long sizeIfKnown = spliterator.getExactSizeIfKnown(); + boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED); ArrayList<T> fromSplit = new ArrayList<>(); Spliterator<T> s1 = supplier.get(); @@ -226,43 +277,37 @@ if (s1Size >= 0 && s2Size >= 0) assertEquals(sizeIfKnown, s1Size + s2Size); } - assertEquals(fromSplit, fromTryAdvance); + assertContents(fromSplit, exp, isOrdered); } - static <T, S extends Spliterator<T>> void testSplitSixDeep(String name, - Supplier<S> supplier, - UnaryOperator<Consumer<T>> boxingAdapter) { - long sizeIfKnown = supplier.get().getExactSizeIfKnown(); - ArrayList<T> fromTryAdvance = new ArrayList<>(); - - Spliterator<T> spliterator = supplier.get(); - Consumer<T> addToFromTryAdvance = boxingAdapter.apply(fromTryAdvance::add); - while (spliterator.tryAdvance(addToFromTryAdvance)) { } - - if (sizeIfKnown != -1) - assertEquals(sizeIfKnown, fromTryAdvance.size()); + private static <T, S extends Spliterator<T>> void testSplitSixDeep( + Collection<T> exp, + Supplier<S> supplier, + UnaryOperator<Consumer<T>> boxingAdapter) { + S spliterator = supplier.get(); + boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED); for (int depth=0; depth < 6; depth++) { - ArrayList<T> dest = new ArrayList<>(); + List<T> dest = new ArrayList<>(); spliterator = supplier.get(); assertSpliterator(spliterator); // verify splitting with forEach visit(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), false); - assertEquals(fromTryAdvance, dest); + assertContents(dest, exp, isOrdered); // verify splitting with tryAdvance dest.clear(); spliterator = supplier.get(); visit(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), true); - assertEquals(fromTryAdvance, dest); + assertContents(dest, exp, isOrdered); } } private static <T, S extends Spliterator<T>> void visit(int depth, int curLevel, - List<T> dest, S spliterator, UnaryOperator<Consumer<T>> boxingAdapter, - int rootCharacteristics, boolean useTryAdvance) { + List<T> dest, S spliterator, UnaryOperator<Consumer<T>> boxingAdapter, + int rootCharacteristics, boolean useTryAdvance) { if (curLevel < depth) { long beforeSize = spliterator.getExactSizeIfKnown(); Spliterator<T> split = spliterator.trySplit(); @@ -315,23 +360,22 @@ } } - static <T, S extends Spliterator<T>> void testSplitUntilNull(String name, - Supplier<S> supplier, - UnaryOperator<Consumer<T>> boxingAdapter) { - List<T> root = new ArrayList<>(); - supplier.get().forEachRemaining(boxingAdapter.apply(root::add)); + private static <T, S extends Spliterator<T>> void testSplitUntilNull( + Collection<T> exp, + Supplier<S> supplier, + UnaryOperator<Consumer<T>> boxingAdapter) { + Spliterator<T> s = supplier.get(); + boolean isOrdered = s.hasCharacteristics(Spliterator.ORDERED); + assertSpliterator(s); List<T> splits = new ArrayList<>(); Consumer<T> c = boxingAdapter.apply(splits::add); - Spliterator<T> s = supplier.get(); - assertSpliterator(s); - testSplitUntilNull(new SplitNode<T>(c, s)); - assertEquals(splits, root); + assertContents(splits, exp, isOrdered); } - static class SplitNode<T> { + private static class SplitNode<T> { // Constant for every node final Consumer<T> c; final int rootCharacteristics; @@ -354,11 +398,11 @@ } /** - * Set the maximum stack capacity to 8M. This should be more than enough to detect a bad spliterator + * Set the maximum stack capacity to 0.25MB. This should be more than enough to detect a bad spliterator * while not unduly disrupting test infrastructure given the test data sizes that are used are small. * Note that j.u.c.ForkJoinPool sets the max queue size to 64M (1 << 26). */ - static final int MAXIMUM_STACK_CAPACITY = 1 << 21; // 2M + private static final int MAXIMUM_STACK_CAPACITY = 1 << 18; // 0.25MB private static <T> void testSplitUntilNull(SplitNode<T> e) { // Use an explicit stack to avoid a StackOverflowException when testing a Spliterator @@ -367,8 +411,9 @@ Deque<SplitNode<T>> stack = new ArrayDeque<>(); stack.push(e); + int iteration = 0; while (!stack.isEmpty()) { - assertTrue(stack.size() < MAXIMUM_STACK_CAPACITY, "Stack exceeded size of 2 MB"); + assertTrue(iteration++ < MAXIMUM_STACK_CAPACITY, "Exceeded maximum stack modification count of 1 << 18"); e = stack.pop(); Spliterator<T> parentAndRightSplit = e.s; @@ -391,13 +436,13 @@ assertTrue(leftSplit.estimateSize() < parentEstimateSize, String.format("Left split size estimate %d >= parent split size estimate %d", leftSplit.estimateSize(), parentEstimateSize)); assertTrue(parentAndRightSplit.estimateSize() < parentEstimateSize, - String.format("Right split size estimate %d >= parent split size estimate %d", leftSplit.estimateSize(), parentEstimateSize)); + String.format("Right split size estimate %d >= parent split size estimate %d", leftSplit.estimateSize(), parentEstimateSize)); } else { assertTrue(leftSplit.estimateSize() <= parentEstimateSize, - String.format("Left split size estimate %d > parent split size estimate %d", leftSplit.estimateSize(), parentEstimateSize)); + String.format("Left split size estimate %d > parent split size estimate %d", leftSplit.estimateSize(), parentEstimateSize)); assertTrue(parentAndRightSplit.estimateSize() <= parentEstimateSize, - String.format("Right split size estimate %d > parent split size estimate %d", leftSplit.estimateSize(), parentEstimateSize)); + String.format("Right split size estimate %d > parent split size estimate %d", leftSplit.estimateSize(), parentEstimateSize)); } long leftSize = leftSplit.getExactSizeIfKnown(); @@ -429,5 +474,34 @@ assertTrue(s.estimateSize() != Long.MAX_VALUE); assertTrue(s.getExactSizeIfKnown() >= 0); } + try { + s.getComparator(); + assertTrue(s.hasCharacteristics(Spliterator.SORTED)); + } catch (IllegalStateException e) { + assertFalse(s.hasCharacteristics(Spliterator.SORTED)); + } } + + private static<T> void assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered) { + if (isOrdered) { + assertEquals(actual, expected); + } + else { + assertContentsUnordered(actual, expected); + } + } + + private static<T> void assertContentsUnordered(Iterable<T> actual, Iterable<T> expected) { + assertEquals(toBoxedMultiset(actual), toBoxedMultiset(expected)); + } + + private static <T> Map<T, Integer> toBoxedMultiset(Iterable<T> c) { + Map<T, Integer> result = new HashMap<>(); + c.forEach(e -> { + if (result.containsKey(e)) result.put(e, result.get(e) + 1); + else result.put(e, 1); + }); + return result; + } + }
--- a/test-ng/tests/org/openjdk/tests/java/util/stream/StreamSpliteratorTest.java Fri Apr 05 14:34:01 2013 +0200 +++ b/test-ng/tests/org/openjdk/tests/java/util/stream/StreamSpliteratorTest.java Fri Apr 05 16:09:55 2013 +0200 @@ -41,6 +41,7 @@ import java.util.stream.IntStream; import java.util.stream.IntStreamTestData; import java.util.stream.IntStreamTestDataProvider; +import java.util.stream.LambdaTestHelpers; import java.util.stream.LongStream; import java.util.stream.LongStreamTestData; import java.util.stream.LongStreamTestDataProvider; @@ -314,20 +315,17 @@ } } - @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class) - public void testX(String name, StreamTestData<Integer> data) { - SpliteratorTestHelper.testSpliterator(() -> data.parallelStream().map(mDoubler).spliterator()); - } - private List<Function<Stream<Integer>, Stream<Integer>>> streamFunctions; List<Function<Stream<Integer>, Stream<Integer>>> streamFunctions() { if (streamFunctions == null) { List<Function<Stream<Integer>, Stream<Integer>>> opFunctions = Arrays.asList( - s -> s.sequential(), s -> s.filter(pEven), s -> s.map(mDoubler), - s -> s.sorted(cInteger)); + // @@@ Add distinct once asserting results with or without order + // is correctly supported +// s -> s.distinct(), + s -> s.sorted()); streamFunctions = permuteStreamFunctions(opFunctions); } @@ -410,7 +408,6 @@ List<Function<IntStream, IntStream>> intStreamFunctions() { if (intStreamFunctions == null) { List<Function<IntStream, IntStream>> opFunctions = Arrays.asList( - s -> s.sequential(), s -> s.filter(ipEven), s -> s.map(irDoubler), s -> s.sorted()); @@ -496,7 +493,6 @@ List<Function<LongStream, LongStream>> longStreamFunctions() { if (longStreamFunctions == null) { List<Function<LongStream, LongStream>> opFunctions = Arrays.asList( - s -> s.sequential(), s -> s.filter(lpEven), s -> s.map(x -> x * 2L), s -> s.sorted()); @@ -582,7 +578,6 @@ List<Function<DoubleStream, DoubleStream>> doubleStreamFunctions() { if (doubleStreamFunctions == null) { List<Function<DoubleStream, DoubleStream>> opFunctions = Arrays.asList( - s -> s.sequential(), s -> s.filter(dpEven), s -> s.map(x -> x * 2.0), s -> s.sorted());