changeset 5877:439e8ac5079d it2-bootstrap

Finish refactor of StreamOpTestCase, now can handle arbitrary combinations of ops
author briangoetz
date Wed, 29 Aug 2012 17:12:18 -0400
parents 0ac331edd500
children 9dd0188c1229
files test-ng/tests/org/openjdk/tests/java/util/streams/ReduceTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/CumulateOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/FilterOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/FlatMapOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/GroupByOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/MapOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/ReduceTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/SortedOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/StreamOpTestCase.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/ToArrayOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/UniqOpTest.java
diffstat 11 files changed, 189 insertions(+), 135 deletions(-) [+]
line wrap: on
line diff
--- a/test-ng/tests/org/openjdk/tests/java/util/streams/ReduceTest.java	Wed Aug 29 15:07:41 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2012, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.
- */
-package org.openjdk.tests.java.util.streams;
-
-import org.openjdk.tests.java.util.streams.ops.StreamOpTestCase;
-import org.testng.annotations.Test;
-
-import java.util.Iterators;
-import java.util.List;
-import java.util.Optional;
-
-import static org.openjdk.tests.java.util.LambdaTestHelpers.*;
-import static org.openjdk.tests.java.util.LambdaTestHelpers.countTo;
-import static org.openjdk.tests.java.util.LambdaTestHelpers.rPlus;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
-
-/**
- * ReduceOpTest
- *
- * @author Brian Goetz
- */
-@Test
-public class ReduceTest extends StreamOpTestCase {
-    public void testReduce() {
-        List<Integer> list = countTo(10);
-
-        assertEquals(55, (int) list.stream().reduce(rPlus).get());
-        assertEquals(10, (int) list.stream().reduce(rMax).get());
-        assertEquals(1, (int) list.stream().reduce(rMin).get());
-
-        assertEquals(0, (int) countTo(0).stream().reduce(0, rPlus));
-        assertTrue(!countTo(0).stream().reduce(rPlus).isPresent());
-    }
-}
--- a/test-ng/tests/org/openjdk/tests/java/util/streams/ops/CumulateOpTest.java	Wed Aug 29 15:07:41 2012 -0400
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/ops/CumulateOpTest.java	Wed Aug 29 17:12:18 2012 -0400
@@ -54,8 +54,8 @@
 
     @Test(dataProvider = "opArrays", dataProviderClass = StreamTestDataProvider.class)
     public void testOps(String name, TestData<Integer> data) {
-        assertConsistentOpBehavior(data, new CumulateOp<>(rPlus), l -> l);
-        assertConsistentOpBehavior(data, new CumulateOp<>(rMin), l -> l);
-        assertConsistentOpBehavior(data, new CumulateOp<>(rMax), l -> l);
+        exerciseOps(data, l -> l, new CumulateOp<>(rPlus));
+        exerciseOps(data, l -> l, new CumulateOp<>(rMin));
+        exerciseOps(data, l -> l, new CumulateOp<>(rMax));
     }
 }
--- a/test-ng/tests/org/openjdk/tests/java/util/streams/ops/FilterOpTest.java	Wed Aug 29 15:07:41 2012 -0400
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/ops/FilterOpTest.java	Wed Aug 29 17:12:18 2012 -0400
@@ -27,7 +27,6 @@
 import org.openjdk.tests.java.util.streams.StreamTestDataProvider;
 import org.testng.annotations.Test;
 
-import java.util.streams.Stream;
 import java.util.streams.ops.FilterOp;
 
 import static org.openjdk.tests.java.util.LambdaTestHelpers.*;
@@ -59,11 +58,11 @@
 
     @Test(dataProvider = "opArrays", dataProviderClass = StreamTestDataProvider.class)
     public void testOps(String name, TestData<Integer> data) {
-        assertConsistentOpBehavior(data, new FilterOp<>(pTrue), l -> l);
-        assertConsistentOpBehavior(data, new FilterOp<>(pFalse), l -> 0);
-        assertConsistentOpBehavior(data, new FilterOp<>(pEven));
-        assertConsistentOpBehavior(data, new FilterOp<>(pOdd));
-        assertConsistentOpBehavior(data, new FilterOp<>(pOdd.and(pEven)), l -> 0);
-        assertConsistentOpBehavior(data, new FilterOp<>(pOdd.or(pEven)), l -> l);
+        exerciseOps(data, l -> l, new FilterOp<>(pTrue));
+        exerciseOps(data, l -> 0, new FilterOp<>(pFalse));
+        exerciseOps(data, new FilterOp<>(pEven));
+        exerciseOps(data, new FilterOp<>(pOdd));
+        exerciseOps(data, l -> 0, new FilterOp<>(pOdd.and(pEven)));
+        exerciseOps(data, l -> l, new FilterOp<>(pOdd.or(pEven)));
     }
 }
--- a/test-ng/tests/org/openjdk/tests/java/util/streams/ops/FlatMapOpTest.java	Wed Aug 29 15:07:41 2012 -0400
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/ops/FlatMapOpTest.java	Wed Aug 29 17:12:18 2012 -0400
@@ -66,15 +66,15 @@
         assertCountSum(countTo(10).stream().flatMap(mfNull), 0, 0);
         assertCountSum(countTo(3).stream().flatMap(mfLt), 6, 4);
 
-        assertConsistentOpBehavior(new ArrayTestData<>(stringsArray), new FlatMapOp<>(flattenChars), null);
-        assertConsistentOpBehavior(new ArrayTestData<>(new String[] { LONG_STRING }), new FlatMapOp<>(flattenChars), null);
+        exerciseOps(new ArrayTestData<>(stringsArray), null, new FlatMapOp<>(flattenChars));
+        exerciseOps(new ArrayTestData<>(new String[]{LONG_STRING}), null, new FlatMapOp<>(flattenChars));
     }
 
     @Test(dataProvider = "opArrays", dataProviderClass = StreamTestDataProvider.class)
     public void testOps(String name, TestData<Integer> data) {
-        assertConsistentOpBehavior(data, new FlatMapOp<>(mfId), l -> l);
-        assertConsistentOpBehavior(data, new FlatMapOp<>(mfNull), l -> 0);
-        assertConsistentOpBehavior(data, new FlatMapOp<>(mfLt));
-        assertConsistentOpBehavior(data, new FlatMapOp<>(mfIntToBits));
+        exerciseOps(data, l -> l, new FlatMapOp<>(mfId));
+        exerciseOps(data, l -> 0, new FlatMapOp<>(mfNull));
+        exerciseOps(data, new FlatMapOp<>(mfLt));
+        exerciseOps(data, new FlatMapOp<>(mfIntToBits));
     }
 }
--- a/test-ng/tests/org/openjdk/tests/java/util/streams/ops/GroupByOpTest.java	Wed Aug 29 15:07:41 2012 -0400
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/ops/GroupByOpTest.java	Wed Aug 29 17:12:18 2012 -0400
@@ -29,7 +29,6 @@
 
 import java.util.Iterator;
 import java.util.Map;
-import java.util.functions.Mapper;
 import java.util.functions.Mappers;
 import java.util.streams.Stream;
 import java.util.streams.Streamable;
@@ -81,14 +80,14 @@
 
     @Test(dataProvider = "opArrays", dataProviderClass = StreamTestDataProvider.class)
     public void testOps(String name, TestData<Integer> data) {
-        assertConsistentOpBehavior(data, new GroupByOp<>(mId));
-        assertConsistentOpBehavior(data, new GroupByOp<>(mZero));
-        assertConsistentOpBehavior(data, new GroupByOp<>(mDoubler));
-        assertConsistentOpBehavior(data, new GroupByOp<>(mId.compose(mDoubler)));
-        assertConsistentOpBehavior(data, new GroupByOp<>(mDoubler.compose(mDoubler)));
-        assertConsistentOpBehavior(data, new GroupByOp<>(Mappers.forPredicate(pFalse, true, false)));
-        assertConsistentOpBehavior(data, new GroupByOp<>(Mappers.forPredicate(pTrue, true, false)));
-        assertConsistentOpBehavior(data, new GroupByOp<>(Mappers.forPredicate(pEven, true, false)));
-        assertConsistentOpBehavior(data, new GroupByOp<>(Mappers.forPredicate(pOdd, true, false)));
+        exerciseOps(data, new GroupByOp<>(mId));
+        exerciseOps(data, new GroupByOp<>(mZero));
+        exerciseOps(data, new GroupByOp<>(mDoubler));
+        exerciseOps(data, new GroupByOp<>(mId.compose(mDoubler)));
+        exerciseOps(data, new GroupByOp<>(mDoubler.compose(mDoubler)));
+        exerciseOps(data, new GroupByOp<>(Mappers.forPredicate(pFalse, true, false)));
+        exerciseOps(data, new GroupByOp<>(Mappers.forPredicate(pTrue, true, false)));
+        exerciseOps(data, new GroupByOp<>(Mappers.forPredicate(pEven, true, false)));
+        exerciseOps(data, new GroupByOp<>(Mappers.forPredicate(pOdd, true, false)));
     }
 }
--- a/test-ng/tests/org/openjdk/tests/java/util/streams/ops/MapOpTest.java	Wed Aug 29 15:07:41 2012 -0400
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/ops/MapOpTest.java	Wed Aug 29 17:12:18 2012 -0400
@@ -57,10 +57,10 @@
 
     @Test(dataProvider = "opArrays", dataProviderClass = StreamTestDataProvider.class)
     public void testOps(String name, TestData<Integer> data) {
-        assertConsistentOpBehavior(data, new MapOp<>(mId), l -> l);
-        assertConsistentOpBehavior(data, new MapOp<>(mZero), l -> l);
-        assertConsistentOpBehavior(data, new MapOp<>(mDoubler), l -> l);
-        assertConsistentOpBehavior(data, new MapOp<>(mId.compose(mDoubler)), l -> l);
-        assertConsistentOpBehavior(data, new MapOp<>(mDoubler.compose(mDoubler)), l -> l);
+        exerciseOps(data, l -> l, new MapOp<>(mId));
+        exerciseOps(data, l -> l, new MapOp<>(mZero));
+        exerciseOps(data, l -> l, new MapOp<>(mDoubler));
+        exerciseOps(data, l -> l, new MapOp<>(mId.compose(mDoubler)));
+        exerciseOps(data, l -> l, new MapOp<>(mDoubler.compose(mDoubler)));
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/ops/ReduceTest.java	Wed Aug 29 17:12:18 2012 -0400
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2012, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+package org.openjdk.tests.java.util.streams.ops;
+
+import org.openjdk.tests.java.util.streams.StreamTestDataProvider;
+import org.openjdk.tests.java.util.streams.ops.StreamOpTestCase;
+import org.testng.annotations.Test;
+
+import java.util.Iterators;
+import java.util.List;
+import java.util.Optional;
+import java.util.streams.ops.FoldOp;
+import java.util.streams.ops.MapOp;
+import java.util.streams.ops.SeedlessFoldOp;
+
+import static org.openjdk.tests.java.util.LambdaTestHelpers.*;
+import static org.openjdk.tests.java.util.LambdaTestHelpers.countTo;
+import static org.openjdk.tests.java.util.LambdaTestHelpers.rPlus;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * ReduceOpTest
+ *
+ * @author Brian Goetz
+ */
+@Test
+public class ReduceTest extends StreamOpTestCase {
+    public void testReduce() {
+        List<Integer> list = countTo(10);
+
+        assertEquals(55, (int) list.stream().reduce(rPlus).get());
+        assertEquals(55, (int) list.stream().reduce(0, rPlus));
+        assertEquals(10, (int) list.stream().reduce(rMax).get());
+        assertEquals(1, (int) list.stream().reduce(rMin).get());
+
+        assertEquals(0, (int) countTo(0).stream().reduce(0, rPlus));
+        assertTrue(!countTo(0).stream().reduce(rPlus).isPresent());
+    }
+
+    @Test(dataProvider = "opArrays", dataProviderClass = StreamTestDataProvider.class)
+    public void testOps(String name, TestData<Integer> data) {
+        exerciseOps(data, new SeedlessFoldOp<>(rPlus));
+        exerciseOps(data, new SeedlessFoldOp<>(rMin));
+        exerciseOps(data, new SeedlessFoldOp<>(rMax));
+
+        exerciseOps(data, new SeedlessFoldOp<>(rPlus), new MapOp<>(mDoubler));
+        exerciseOps(data, new SeedlessFoldOp<>(rMin), new MapOp<>(mDoubler));
+        exerciseOps(data, new SeedlessFoldOp<>(rMax), new MapOp<>(mDoubler));
+
+        exerciseOps(data, new FoldOp<>(() -> 0, rPlus, rPlus));
+        exerciseOps(data, new FoldOp<>(() -> 0, rMin, rMin));
+        exerciseOps(data, new FoldOp<>(() -> 0, rMax, rMax));
+
+        exerciseOps(data, new FoldOp<>(() -> 0, rPlus, rPlus), new MapOp<>(mDoubler));
+        exerciseOps(data, new FoldOp<>(() -> 0, rMin, rMin), new MapOp<>(mDoubler));
+        exerciseOps(data, new FoldOp<>(() -> 0, rMax, rMax), new MapOp<>(mDoubler));
+    }
+}
--- a/test-ng/tests/org/openjdk/tests/java/util/streams/ops/SortedOpTest.java	Wed Aug 29 15:07:41 2012 -0400
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/ops/SortedOpTest.java	Wed Aug 29 17:12:18 2012 -0400
@@ -31,8 +31,6 @@
 import java.util.Collections;
 import java.util.Comparators;
 import java.util.List;
-import java.util.streams.LinearPipeline;
-import java.util.streams.Stream;
 import java.util.streams.ops.SortedOp;
 
 import static org.openjdk.tests.java.util.LambdaTestHelpers.*;
@@ -75,7 +73,7 @@
 
         // constant iterator
         list.clear();
-        for (int i=0; i<100; i++)
+        for (int i = 0; i < 100; i++)
             list.add(1);
         assertSorted(list);
         assertSorted(SortedOp.iterator(list.iterator(), Comparators.<Integer>naturalOrder()));
@@ -95,7 +93,7 @@
 
         // constant iterator
         list.clear();
-        for (int i=0; i<100; i++)
+        for (int i = 0; i < 100; i++)
             list.add(1);
         assertSorted(list, cInteger);
         assertSorted(SortedOp.iterator(list.iterator(), cInteger));
@@ -107,7 +105,7 @@
     public void testOps(String name, TestData<Integer> data) {
         SortedOp<Integer> op = new SortedOp<>(cInteger);
         assertSorted((stream(data.seq(op))).into(new ArrayList<Integer>()).iterator());
-        assertConsistentOpBehavior(data, op, l->l);
-        assertConsistentOpBehavior(data, new SortedOp<>(cInteger.reverse()), l -> l);
+        exerciseOps(data, l -> l, op);
+        exerciseOps(data, l -> l, new SortedOp<>(cInteger.reverse()));
     }
 }
--- a/test-ng/tests/org/openjdk/tests/java/util/streams/ops/StreamOpTestCase.java	Wed Aug 29 15:07:41 2012 -0400
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/ops/StreamOpTestCase.java	Wed Aug 29 17:12:18 2012 -0400
@@ -57,18 +57,34 @@
         assertEquals(refResult, newResult);
     }
 
-    protected static <T, U> void assertConsistentOpBehavior(TestData<T> data,
-                                                            IntermediateOp<T, U> op,
-                                                            Mapper<Integer, Integer> lengthMapper) {
+    protected static <T, U> StreamResult<U> exerciseOps(TestData<T> data,
+                                                        Mapper<Integer, Integer> lengthMapper,
+                                                        IntermediateOp<T, U> op) {
+        StreamResult<U> refResult = exerciseOps(data, lengthMapper, new IntermediateOp[] { op });
+
+        // For stateful ops, validate Node contents with fake ParallelHelper
+        if (op.isStateful()) {
+            assertMatches(refResult, sink -> {
+                StatefulOp<T, U, ?> sop = (StatefulOp<T, U, ?>) op;
+                for (U u : sop.computeParallel(new DummyParallelOpHelper<>(data)))
+                    sink.accept(u);
+            });
+        }
+
+        return refResult;
+    }
+
+    protected static <T, U> StreamResult<U> exerciseOps(TestData<T> data,
+                                                        Mapper<Integer, Integer> lengthMapper,
+                                                        IntermediateOp... ops) {
         int length = (lengthMapper == null) ? 100 : lengthMapper.map(data.size());
 
         StreamResult<U> refResult = new StreamResult<>(length);
 
         // First pass -- grab an iterator and wrap it, and call that the reference result
-        Iterator<U> it = op.iterator(data.iterator());
-        while (it.hasNext()) {
+        Iterator<U> it = (Iterator<U>) data.iterator(ops);
+        while (it.hasNext())
             refResult.accept(it.next());
-        }
 
         // If a length mapper has been specified, make sure it is right
         if (lengthMapper != null) {
@@ -77,7 +93,7 @@
 
         // Second pass -- create a sink and wrap it
         assertMatches(refResult, sink -> {
-            Sink<T> wrapped = op.sink(sink);
+            Sink<T> wrapped = sink(sink, ops);
             if (wrapped instanceof StatefulSink) {
                 StatefulSink<T, ?> stateful = (StatefulSink<T, ?>)wrapped;
                 stateful.begin(-1);
@@ -89,75 +105,79 @@
         });
 
         // Third pass -- wrap with SequentialPipeline.op, and iterate in push mode
-        assertMatches(refResult, sink -> { stream(data.seq(op)).forEach(sink); });
+        assertMatches(refResult, sink -> { stream(data.seq(ops)).forEach((Sink) sink); });
 
         // Wrap as stream, and iterate in pull mode
         assertMatches(refResult, sink -> {
-            for (Iterator<U> seqIter = data.seq(op).iterator(); seqIter.hasNext(); )
-                sink.accept(seqIter.next());
+            for (Iterator<?> seqIter = data.seq(ops).iterator(); seqIter.hasNext(); )
+                sink.accept((U) seqIter.next());
         });
 
         // Wrap as stream, and iterate in mixed mode
         assertMatches(refResult, sink -> {
-            Stream<U> stream = stream(data.seq(op));
-            Iterator<U> iter = stream.iterator();
+            Stream<?> stream = stream(data.seq(ops));
+            Iterator<?> iter = stream.iterator();
             if (iter.hasNext())
-                sink.accept(iter.next());
-            stream.forEach(sink);
+                sink.accept((U) iter.next());
+            stream.forEach((Sink) sink);
         });
 
-        // For stateful ops, validate Node contents with fake ParallelHelper
-        if (op.isStateful()) {
-            assertMatches(refResult, sink -> {
-                StatefulOp<T, U, ?> sop = (StatefulOp<T, U, ?>) op;
-                for (U u : sop.computeParallel(new DummyParallelOpHelper<>(data)))
-                    sink.accept(u);
-            });
-        }
-
         // Wrap as parallel stream + sequential
-        assertMatches(refResult, sink -> { stream(data.par(op)).sequential().forEach(sink); });
+        assertMatches(refResult, sink -> { stream(data.par(ops)).sequential().forEach((Sink) sink); });
 
         // Wrap as parallel stream + toArray
         assertMatches(refResult, sink -> {
-            for (Object t : stream(data.par(op)).toArray())
+            for (Object t : stream(data.par(ops)).toArray())
                 sink.accept((U) t);
         });
 
         // Wrap as parallel stream + into
         assertMatches(refResult, sink -> {
-            for (Object u : stream(data.par(op)).sequential().into(new ArrayList()))
+            for (Object u : stream(data.par(ops)).sequential().into(new ArrayList()))
                 sink.accept((U) u);
         });
 
         // More ways to iterate the PSS: iterate result of op
         // Extends testing to test whether computation happens in- or out-of-thread
+
+        return refResult;
     }
 
-    protected <T, U> void assertConsistentOpBehavior(TestData<T> data, IntermediateOp<T, U> op) {
-        assertConsistentOpBehavior(data, op, null);
+    protected <T, U> void exerciseOps(TestData<T> data, IntermediateOp<T, U> op) {
+        exerciseOps(data, null, op);
+    }
+
+    protected <T, U> void exerciseOps(TestData<T> data, IntermediateOp... ops) {
+        exerciseOps(data, (Mapper<Integer, Integer>) null, ops);
     }
 
-    protected <T, U> void assertConsistentOpBehavior(TestData<T> data, TerminalOp<T, U> terminal) {
-        assertConsistentOpBehavior(data, (u, v) -> u.equals(v), terminal);
+    protected <T, U> void exerciseOps(TestData<T> data, TerminalOp<T, U> terminal) {
+        exerciseOps(data, terminal, new IntermediateOp[0]);
+    }
+
+    protected <T, U> void exerciseOps(TestData<T> data, TerminalOp<T, U> terminal, IntermediateOp... ops) {
+        exerciseOps(data, (u, v) -> u.equals(v), terminal, ops);
     }
 
-    protected static <T, U> void assertConsistentOpBehavior(TestData<T> data, BiPredicate<U,U> equalator, TerminalOp<T, U> op) {
+    protected static <T, U> void exerciseOps(TestData<T> data,
+                                             BiPredicate<U, U> equalator,
+                                             TerminalOp<T, U> terminalOp,
+                                             IntermediateOp[] ops) {
         final U answer1;
 
-        if (op.isShortCircuit()) {
+        if (terminalOp.isShortCircuit()) {
             // First pass -- wrap Iterator
-            answer1 = op.evaluate(data.iterator());
+            answer1 = terminalOp.evaluate(data.iterator());
         }
         else {
             // First pass -- create a sink and evaluate, with no size advice
-            StatefulSink<T, U> sink = op.sink();
+            StatefulSink<T, U> sink = terminalOp.sink();
             sink.begin(-1);
             data.forEach(sink);
             answer1 = sink.end();
 
             // Create a sink and evaluate, with size advice
-            StatefulSink<T, U> sink2 = op.sink();
+            StatefulSink<T, U> sink2 = terminalOp.sink();
             sink2.begin(data.size());
             data.forEach(sink2);
             U answer2 = sink2.end();
@@ -165,11 +185,11 @@
         }
 
         // Third pass -- wrap with SequentialPipeline.op
-        U answer3 = data.seq(op);
+        U answer3 = data.seq(terminalOp);
         Assert.assertTrue(equalator.test(answer1, answer3));
 
         // Fourth pass -- wrap with ParallelPipeline.op
-        U answer4 = data.par(op);
+        U answer4 = data.par(terminalOp);
         Assert.assertTrue(equalator.test(answer1, answer4));
     }
 
@@ -318,6 +338,12 @@
         return (MapStream<K,V>) pipe;
     }
 
+    protected static Sink sink(Sink sink, IntermediateOp[] ops) {
+        for (int i=ops.length-1; i >= 0; i--)
+            sink = ops[i].sink(sink);
+        return sink;
+    }
+
     public static interface TestData<T> {
         AbstractPipeline<?, T> seq();
         AbstractPipeline<?, T> par();
@@ -335,6 +361,14 @@
         }
 
         @SuppressWarnings({ "raw", "unchecked" })
+        Iterator<?> iterator(IntermediateOp... ops) default {
+            Iterator<T> iterator = iterator();
+            for (IntermediateOp op : ops)
+                iterator = op.iterator(iterator);
+            return iterator;
+        }
+
+        @SuppressWarnings({ "raw", "unchecked" })
         AbstractPipeline<?, ?> seq(IntermediateOp... ops) default {
             return chain(seq(), ops);
         }
--- a/test-ng/tests/org/openjdk/tests/java/util/streams/ops/ToArrayOpTest.java	Wed Aug 29 15:07:41 2012 -0400
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/ops/ToArrayOpTest.java	Wed Aug 29 17:12:18 2012 -0400
@@ -27,6 +27,8 @@
 import org.openjdk.tests.java.util.streams.StreamTestDataProvider;
 import org.testng.annotations.Test;
 
+import java.util.functions.BiPredicate;
+import java.util.streams.ops.IntermediateOp;
 import java.util.streams.ops.ToArrayOp;
 import java.util.Arrays;
 
@@ -52,6 +54,6 @@
 
     @Test(dataProvider = "opArrays", dataProviderClass = StreamTestDataProvider.class)
     public void testOps(String name, TestData<Integer> data) {
-        assertConsistentOpBehavior(data, Arrays::equals, ToArrayOp.<Integer>singleton());
+        exerciseOps(data, Arrays::equals, ToArrayOp.<Integer>singleton(), new IntermediateOp[0]);
     }
 }
--- a/test-ng/tests/org/openjdk/tests/java/util/streams/ops/UniqOpTest.java	Wed Aug 29 15:07:41 2012 -0400
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/ops/UniqOpTest.java	Wed Aug 29 17:12:18 2012 -0400
@@ -28,8 +28,6 @@
 import org.testng.annotations.Test;
 
 import java.util.ArrayList;
-import java.util.streams.LinearPipeline;
-import java.util.streams.Stream;
 import java.util.streams.ops.UniqOp;
 
 import static org.openjdk.tests.java.util.LambdaTestHelpers.*;
@@ -61,6 +59,6 @@
         UniqOp<Integer> op = UniqOp.singleton();
         ArrayList<Integer> result = (stream(data.seq(op))).into(new ArrayList<Integer>());
         assertUnique(result.iterator());
-        assertConsistentOpBehavior(data, op, null);
+        exerciseOps(data, null, op);
     }
 }