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());