changeset 7106:6feee75b0a8b

8012664: Add tests for java.util.stream and lambda translation Reviewed-by: mduigou, briangoetz Contributed-by: Brian Goetz <brian.goetz@oracle.com>, Paul Sandoz <paul.sandoz@oracle.com>, Mike Duigou <mike.duigou@oracle.com>, Robert Field <robert.field@oracle.com>, Jim Gish <jim.gish@oracle.com>
author briangoetz
date Mon, 06 May 2013 11:43:51 -0400
parents fe4e9bc2186f
children 7d89b0dd973c
files test/Makefile test/java/util/concurrent/atomic/AtomicReferenceTest.java test/java/util/stream/bootlib/TEST.properties test/java/util/stream/bootlib/java/util/stream/CollectorOps.java test/java/util/stream/bootlib/java/util/stream/DoubleStreamTestDataProvider.java test/java/util/stream/bootlib/java/util/stream/DoubleStreamTestScenario.java test/java/util/stream/bootlib/java/util/stream/FlagDeclaringOp.java test/java/util/stream/bootlib/java/util/stream/IntStreamTestDataProvider.java test/java/util/stream/bootlib/java/util/stream/IntStreamTestScenario.java test/java/util/stream/bootlib/java/util/stream/IntermediateTestOp.java test/java/util/stream/bootlib/java/util/stream/LambdaTestHelpers.java test/java/util/stream/bootlib/java/util/stream/LongStreamTestDataProvider.java test/java/util/stream/bootlib/java/util/stream/LongStreamTestScenario.java test/java/util/stream/bootlib/java/util/stream/OpTestCase.java test/java/util/stream/bootlib/java/util/stream/SpliteratorTestHelper.java test/java/util/stream/bootlib/java/util/stream/StatefulTestOp.java test/java/util/stream/bootlib/java/util/stream/StatelessTestOp.java test/java/util/stream/bootlib/java/util/stream/StreamOpFlagTestHelper.java test/java/util/stream/bootlib/java/util/stream/StreamTestDataProvider.java test/java/util/stream/bootlib/java/util/stream/StreamTestScenario.java test/java/util/stream/bootlib/java/util/stream/TestData.java test/java/util/stream/bootlib/java/util/stream/TestFlagExpectedOp.java test/java/util/stream/boottest/TEST.properties test/java/util/stream/boottest/java/util/stream/DoubleNodeTest.java test/java/util/stream/boottest/java/util/stream/FlagOpTest.java test/java/util/stream/boottest/java/util/stream/IntNodeTest.java test/java/util/stream/boottest/java/util/stream/LongNodeTest.java test/java/util/stream/boottest/java/util/stream/NodeBuilderTest.java test/java/util/stream/boottest/java/util/stream/NodeTest.java test/java/util/stream/boottest/java/util/stream/SpinedBufferTest.java test/java/util/stream/boottest/java/util/stream/StreamFlagsTest.java test/java/util/stream/boottest/java/util/stream/StreamOpFlagsTest.java test/java/util/stream/boottest/java/util/stream/StreamReuseTest.java test/java/util/stream/boottest/java/util/stream/UnorderedTest.java test/java/util/stream/test/TEST.properties test/java/util/stream/test/org/openjdk/tests/java/lang/invoke/DeserializeMethodTest.java test/java/util/stream/test/org/openjdk/tests/java/lang/invoke/MHProxiesTest.java test/java/util/stream/test/org/openjdk/tests/java/lang/invoke/SerializedLambdaTest.java test/java/util/stream/test/org/openjdk/tests/java/util/FillableStringTest.java test/java/util/stream/test/org/openjdk/tests/java/util/MapTest.java test/java/util/stream/test/org/openjdk/tests/java/util/NullArgsTestCase.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectionAndMapModifyStreamTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/DistinctOpTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/DoublePrimitiveOpsTests.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/ExplodeOpTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/FilterOpTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/FindAnyOpTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/FindFirstOpTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/ForEachOpTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/GroupByOpTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/InfiniteStreamWithLimitOpTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/IntPrimitiveOpsTests.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/IntReduceTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/IntSliceOpTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/IntUniqOpTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/LongPrimitiveOpsTests.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/MapOpTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/MatchOpTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/MinMaxTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/PrimitiveAverageOpTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/PrimitiveSumTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/RangeTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/ReduceByOpTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/ReduceTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/SequentialOpTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/SliceOpTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/SortedOpTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/SpliteratorLateBindingFailFastTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/SpliteratorTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/SpliteratorTraversingAndSplittingTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamBuilderTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamLinkTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamParSeqTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamSpliteratorTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/SummaryStatisticsTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/TabulatorsTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/TeeOpTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/ToArrayOpTest.java test/jdk/lambda/ArrayCtorRefTest.java test/jdk/lambda/FDTest.java test/jdk/lambda/LambdaTranslationCompoundSamTest.java test/jdk/lambda/LambdaTranslationInInterface.java test/jdk/lambda/LambdaTranslationInnerConstructor.java test/jdk/lambda/LambdaTranslationTest1.java test/jdk/lambda/LambdaTranslationTest2.java test/jdk/lambda/MethodReferenceTestFDCCE.java test/jdk/lambda/MethodReferenceTestInnerDefault.java test/jdk/lambda/MethodReferenceTestInnerInstance.java test/jdk/lambda/MethodReferenceTestInnerVarArgsThis.java test/jdk/lambda/MethodReferenceTestInstance.java test/jdk/lambda/MethodReferenceTestInstanceMethod.java test/jdk/lambda/MethodReferenceTestKinds.java test/jdk/lambda/MethodReferenceTestNew.java test/jdk/lambda/MethodReferenceTestNewInner.java test/jdk/lambda/MethodReferenceTestSueCase1.java test/jdk/lambda/MethodReferenceTestSueCase2.java test/jdk/lambda/MethodReferenceTestSueCase4.java test/jdk/lambda/MethodReferenceTestSuper.java test/jdk/lambda/MethodReferenceTestSuperDefault.java test/jdk/lambda/MethodReferenceTestTypeConversion.java test/jdk/lambda/MethodReferenceTestVarArgs.java test/jdk/lambda/MethodReferenceTestVarArgsExt.java test/jdk/lambda/MethodReferenceTestVarArgsSuper.java test/jdk/lambda/MethodReferenceTestVarArgsSuperDefault.java test/jdk/lambda/MethodReferenceTestVarArgsThis.java test/jdk/lambda/TEST.properties test/jdk/lambda/TestInnerCtorRef.java test/jdk/lambda/TestPrivateCtorRef.java test/jdk/lambda/separate/AttributeInjector.java test/jdk/lambda/separate/ClassFile.java test/jdk/lambda/separate/ClassFilePreprocessor.java test/jdk/lambda/separate/ClassToInterfaceConverter.java test/jdk/lambda/separate/Compiler.java test/jdk/lambda/separate/DirectedClassLoader.java test/jdk/lambda/separate/SourceModel.java test/jdk/lambda/separate/TestHarness.java test/jdk/lambda/shapegen/ClassCase.java test/jdk/lambda/shapegen/Hierarchy.java test/jdk/lambda/shapegen/HierarchyGenerator.java test/jdk/lambda/shapegen/Rule.java test/jdk/lambda/shapegen/RuleGroup.java test/jdk/lambda/shapegen/TTNode.java test/jdk/lambda/shapegen/TTParser.java test/jdk/lambda/shapegen/TTShape.java test/jdk/lambda/vm/DefaultMethodRegressionTests.java test/jdk/lambda/vm/DefaultMethodsTest.java test/jdk/lambda/vm/InterfaceAccessFlagsTest.java test/jdk/lambda/vm/StrictfpDefault.java
diffstat 128 files changed, 23386 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/test/Makefile	Tue May 07 12:05:52 2013 -0700
+++ b/test/Makefile	Mon May 06 11:43:51 2013 -0400
@@ -517,6 +517,7 @@
 	  javax/xml/soap \
 	  javax/xml/ws com/sun/internal/ws com/sun/org/glassfish \
 	  jdk/asm \
+	  jdk/lambda \
 	  com/sun/org/apache/xerces \
           com/sun/corba \
 	  com/sun/tracing \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/concurrent/atomic/AtomicReferenceTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ *
+ * 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.concurrent.atomic.AtomicReference;
+import java.util.function.UnaryOperator;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/*
+ * @test
+ * @summary Test Map default methods
+ * @run testng AtomicReferenceTest
+ * @author Jim Gish <jim.gish@oracle.com>
+ */
+public class AtomicReferenceTest {
+
+    /**
+     * Test of updateAndGet method, of class AtomicReference.
+     */
+    @Test
+    public void testUpdateAndGet() {
+        AtomicReference<Integer> instance = new AtomicReference<>(3);
+        assertEquals((int) instance.get(), 3);
+        assertEquals((int) instance.updateAndGet(x -> x + 2), 5);
+        assertEquals((int) instance.get(), 5);
+    }
+
+    /**
+     * Test of getAndUpdate method, of class AtomicReference.
+     */
+    @Test
+    public void testGetAndUpdate() {
+        AtomicReference<Integer> instance = new AtomicReference<>(3);
+        assertEquals((int) instance.get(), 3);
+        assertEquals((int) instance.getAndUpdate(x -> x + 3), 3);
+        assertEquals((int) instance.get(), 6);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/bootlib/TEST.properties	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,3 @@
+# This file identifies root(s) of the test-ng hierarchy.
+
+bootclasspath.dirs = .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/bootlib/java/util/stream/CollectorOps.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package java.util.stream;
+
+import org.testng.Assert;
+
+import java.util.Spliterator;
+import java.util.function.IntFunction;
+
+/** Test helper class for java.util.stream test framework */
+public final class CollectorOps {
+    private CollectorOps() { }
+
+    public static <E_IN> StatefulTestOp<E_IN> collector() {
+        return new StatefulCollector<>(0, StreamShape.REFERENCE);
+    }
+
+    /* Utility classes for collecting output of intermediate pipeline stages */
+    public static class StatefulCollector<E_IN> implements StatefulTestOp<E_IN> {
+        private final int opFlags;
+        private final StreamShape inputShape;
+
+        public StatefulCollector(int opFlags, StreamShape inputShape) {
+            this.opFlags = opFlags;
+            this.inputShape = inputShape;
+        }
+
+        @Override
+        public StreamShape inputShape() {
+            return inputShape;
+        }
+
+        @Override
+        public StreamShape outputShape() {
+            return inputShape;
+        }
+
+        @Override
+        public int opGetFlags() {
+            return opFlags;
+        }
+
+        @Override
+        public Sink<E_IN> opWrapSink(int flags, boolean parallel, Sink<E_IN> sink) {
+            return sink;
+        }
+
+        @Override
+        public <P_IN> Node<E_IN> opEvaluateParallel(PipelineHelper<E_IN> helper,
+                                                    Spliterator<P_IN> spliterator,
+                                                    IntFunction<E_IN[]> generator) {
+            return helper.evaluate(spliterator, false, generator);
+        }
+    }
+
+    public static class TestParallelSizedOp<T> extends StatefulCollector<T> {
+        public TestParallelSizedOp() {
+            this(StreamShape.REFERENCE);
+        }
+
+        protected TestParallelSizedOp(StreamShape shape) {
+            super(0, shape);
+        }
+
+        @Override
+        public <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
+                                                 Spliterator<P_IN> spliterator,
+                                                 IntFunction<T[]> generator) {
+            int flags = helper.getStreamAndOpFlags();
+
+            Assert.assertTrue(StreamOpFlag.SIZED.isKnown(flags));
+            return super.opEvaluateParallel(helper, spliterator, generator);
+        }
+
+        public static class OfInt extends TestParallelSizedOp<Integer> {
+            public OfInt() {
+                super(StreamShape.INT_VALUE);
+            }
+        }
+
+        public static class OfLong extends TestParallelSizedOp<Long> {
+            public OfLong() {
+                super(StreamShape.LONG_VALUE);
+            }
+        }
+
+        public static class OfDouble extends TestParallelSizedOp<Double> {
+            public OfDouble() {
+                super(StreamShape.DOUBLE_VALUE);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/bootlib/java/util/stream/DoubleStreamTestDataProvider.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+package java.util.stream;
+
+import org.testng.annotations.DataProvider;
+
+import java.util.*;
+import java.util.Spliterators;
+import java.util.function.Supplier;
+
+/** TestNG DataProvider for double-valued streams */
+public class DoubleStreamTestDataProvider {
+    private static final double[] to0 = new double[0];
+    private static final double[] to1 = new double[1];
+    private static final double[] to10 = new double[10];
+    private static final double[] to100 = new double[100];
+    private static final double[] to1000 = new double[1000];
+    private static final double[] reversed = new double[100];
+    private static final double[] ones = new double[100];
+    private static final double[] twice = new double[200];
+    private static final double[] pseudoRandom;
+
+    private static final Object[][] testData;
+    private static final Object[][] spliteratorTestData;
+
+    static {
+        double[][] arrays = {to0, to1, to10, to100, to1000};
+        for (double[] arr : arrays) {
+            for (int i = 0; i < arr.length; i++) {
+                arr[i] = i;
+            }
+        }
+        for (int i = 0; i < reversed.length; i++) {
+            reversed[i] = reversed.length - i;
+        }
+        for (int i = 0; i < ones.length; i++) {
+            ones[i] = 1;
+        }
+        System.arraycopy(to100, 0, twice, 0, to100.length);
+        System.arraycopy(to100, 0, twice, to100.length, to100.length);
+        pseudoRandom = new double[LambdaTestHelpers.LONG_STRING.length()];
+        for (int i = 0; i < LambdaTestHelpers.LONG_STRING.length(); i++) {
+            pseudoRandom[i] = (double) LambdaTestHelpers.LONG_STRING.charAt(i);
+        }
+    }
+
+    static final Object[][] arrays = {
+            {"empty", to0},
+            {"0..1", to1},
+            {"0..10", to10},
+            {"0..100", to100},
+            {"0..1000", to1000},
+            {"100x[1]", ones},
+            {"2x[0..100]", twice},
+            {"reverse 0..100", reversed},
+            {"pseudorandom", pseudoRandom}
+    };
+
+    static {
+        {
+            List<Object[]> list = new ArrayList<>();
+            for (Object[] data : arrays) {
+                final Object name = data[0];
+                final double[] doubles = (double[]) data[1];
+
+                list.add(new Object[]{"array:" + name,
+                        TestData.Factory.ofArray("array:" + name, doubles)});
+
+                SpinedBuffer.OfDouble isl = new SpinedBuffer.OfDouble();
+                for (double i : doubles) {
+                    isl.accept(i);
+                }
+                list.add(new Object[]{"SpinedList:" + name,
+                        TestData.Factory.ofSpinedBuffer("SpinedList:" + name, isl)});
+
+                list.add(streamDataDescr("Primitives.range(0,l): " + doubles.length,
+                                         () -> DoubleStream.range(0, doubles.length)));
+                list.add(streamDataDescr("Primitives.range(0,l,2): " + doubles.length,
+                                         () -> DoubleStream.range(0, doubles.length, 2)));
+                list.add(streamDataDescr("Primitives.range(0,l,3): " + doubles.length,
+                                         () -> DoubleStream.range(0, doubles.length, 3)));
+                list.add(streamDataDescr("Primitives.range(0,l,7): " + doubles.length,
+                                         () -> DoubleStream.range(0, doubles.length, 7)));
+            }
+            testData = list.toArray(new Object[0][]);
+        }
+
+        {
+            List<Object[]> spliterators = new ArrayList<>();
+            for (Object[] data : arrays) {
+                final Object name = data[0];
+                final double[] doubles = (double[]) data[1];
+
+                SpinedBuffer.OfDouble isl = new SpinedBuffer.OfDouble();
+                for (double i : doubles) {
+                    isl.accept(i);
+                }
+
+                spliterators.add(splitDescr("Arrays.s(array):" + name,
+                                            () -> Arrays.spliterator(doubles)));
+                spliterators.add(splitDescr("Arrays.s(array,o,l):" + name,
+                                            () -> Arrays.spliterator(doubles, 0, doubles.length / 2)));
+
+                spliterators.add(splitDescr("SpinedBuffer.s():" + name,
+                                            () -> isl.spliterator()));
+
+                spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator(), size):" + name,
+                                            () -> Spliterators.spliterator(isl.iterator(), doubles.length, 0)));
+                spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator()):" + name,
+                                            () -> Spliterators.spliteratorUnknownSize(isl.iterator(), 0)));
+
+                spliterators.add(splitDescr("Primitives.range(0,l):" + name,
+                                            () -> DoubleStream.range(0, doubles.length).spliterator()));
+                spliterators.add(splitDescr("Primitives.range(0,l,2):" + name,
+                                            () -> DoubleStream.range(0, doubles.length, 2).spliterator()));
+                spliterators.add(splitDescr("Primitives.range(0,l,3):" + name,
+                                            () -> DoubleStream.range(0, doubles.length, 3).spliterator()));
+                spliterators.add(splitDescr("Primitives.range(0,l,7):" + name,
+                                            () -> DoubleStream.range(0, doubles.length, 7).spliterator()));
+                // Need more!
+            }
+            spliteratorTestData = spliterators.toArray(new Object[0][]);
+        }
+
+    }
+
+    static <T> Object[] streamDataDescr(String description, Supplier<DoubleStream> s) {
+        return new Object[] { description, TestData.Factory.ofDoubleSupplier(description, s) };
+    }
+
+    static <T> Object[] splitDescr(String description, Supplier<Spliterator.OfDouble> s) {
+        return new Object[] { description, s };
+    }
+
+    // Return an array of ( String name, DoubleStreamTestData )
+    @DataProvider(name = "DoubleStreamTestData")
+    public static Object[][] makeDoubleStreamTestData() {
+        return testData;
+    }
+
+    // returns an array of (String name, Supplier<PrimitiveSpliterator<Double>>)
+    @DataProvider(name = "DoubleSpliterator")
+    public static Object[][] spliteratorProvider() {
+        return spliteratorTestData;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/bootlib/java/util/stream/DoubleStreamTestScenario.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+package java.util.stream;
+
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.Function;
+
+/**
+ * Test scenarios for double streams.
+ *
+ * Each scenario is provided with a data source, a function that maps a fresh
+ * stream (as provided by the data source) to a new stream, and a sink to
+ * receive results.  Each scenario describes a different way of computing the
+ * stream contents.  The test driver will ensure that all scenarios produce
+ * the same output (modulo allowable differences in ordering).
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public enum DoubleStreamTestScenario implements OpTestCase.BaseStreamTestScenario {
+
+    STREAM_FOR_EACH(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            DoubleStream s = m.apply(data.stream());
+            if (s.isParallel()) {
+                s = s.sequential();
+            }
+            s.forEach(b);
+        }
+    },
+
+    STREAM_TO_ARRAY(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            for (double t : m.apply(data.stream()).toArray()) {
+                b.accept(t);
+            }
+        }
+    },
+
+    STREAM_ITERATOR(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            for (PrimitiveIterator.OfDouble seqIter = m.apply(data.stream()).iterator(); seqIter.hasNext(); )
+                b.accept(seqIter.nextDouble());
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate in pull mode
+    STREAM_SPLITERATOR(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            for (Spliterator.OfDouble spl = m.apply(data.stream()).spliterator(); spl.tryAdvance(b); ) {
+            }
+        }
+    },
+
+    // Wrap as stream, spliterate, then split a few times mixing advances with forEach
+    STREAM_SPLITERATOR_WITH_MIXED_TRAVERSE_AND_SPLIT(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            SpliteratorTestHelper.mixedTraverseAndSplit(b, m.apply(data.stream()).spliterator());
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate in pull mode
+    STREAM_SPLITERATOR_FOREACH(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            m.apply(data.stream()).spliterator().forEachRemaining(b);
+        }
+    },
+
+    PAR_STREAM_SEQUENTIAL_FOR_EACH(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            m.apply(data.parallelStream()).sequential().forEach(b);
+        }
+    },
+
+    // Wrap as parallel stream + forEachOrdered
+    PAR_STREAM_FOR_EACH_ORDERED(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            // @@@ Want to explicitly select ordered equalator
+            m.apply(data.parallelStream()).forEachOrdered(b);
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate sequentially
+    PAR_STREAM_SPLITERATOR(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            for (Spliterator.OfDouble spl = m.apply(data.parallelStream()).spliterator(); spl.tryAdvance(b); ) {
+            }
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate sequentially
+    PAR_STREAM_SPLITERATOR_FOREACH(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            m.apply(data.parallelStream()).spliterator().forEachRemaining(b);
+        }
+    },
+
+    PAR_STREAM_TO_ARRAY(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            for (double t : m.apply(data.parallelStream()).toArray())
+                b.accept(t);
+        }
+    },
+
+    // Wrap as parallel stream, get the spliterator, wrap as a stream + toArray
+    PAR_STREAM_SPLITERATOR_STREAM_TO_ARRAY(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            DoubleStream s = m.apply(data.parallelStream());
+            Spliterator.OfDouble sp = s.spliterator();
+            DoubleStream ss = StreamSupport.doubleParallelStream(() -> sp,
+                                                                 StreamOpFlag.toCharacteristics(OpTestCase.getStreamFlags(s))
+                                                                 | (sp.getExactSizeIfKnown() < 0 ? 0 : Spliterator.SIZED));
+            for (double t : ss.toArray())
+                b.accept(t);
+        }
+    },
+
+    PAR_STREAM_TO_ARRAY_CLEAR_SIZED(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            S_IN pipe1 = (S_IN) OpTestCase.chain(data.parallelStream(),
+                                                 new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+            DoubleStream pipe2 = m.apply(pipe1);
+
+            for (double t : pipe2.toArray())
+                b.accept(t);
+        }
+    },;
+
+    private boolean isParallel;
+
+    DoubleStreamTestScenario(boolean isParallel) {
+        this.isParallel = isParallel;
+    }
+
+    public StreamShape getShape() {
+        return StreamShape.DOUBLE_VALUE;
+    }
+
+    public boolean isParallel() {
+        return isParallel;
+    }
+
+    public <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+    void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m) {
+        _run(data, (DoubleConsumer) b, (Function<S_IN, DoubleStream>) m);
+    }
+
+    abstract <T, S_IN extends BaseStream<T, S_IN>>
+    void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/bootlib/java/util/stream/FlagDeclaringOp.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package java.util.stream;
+
+/**
+ * An operation that injects or clears flags but otherwise performs no operation on elements.
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class FlagDeclaringOp<T> implements StatelessTestOp<T, T> {
+    private final int flags;
+    private final StreamShape shape;
+
+    public FlagDeclaringOp(int flags) {
+        this(flags, StreamShape.REFERENCE);
+    }
+
+    public FlagDeclaringOp(int flags, StreamShape shape) {
+        this.flags = flags;
+        this.shape = shape;
+    }
+
+    @Override
+    public StreamShape outputShape() {
+        return shape;
+    }
+
+    @Override
+    public StreamShape inputShape() {
+        return shape;
+    }
+
+    @Override
+    public int opGetFlags() {
+        return flags;
+    }
+
+    @Override
+    public Sink<T> opWrapSink(int flags, boolean parallel, Sink sink) {
+        return sink;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/bootlib/java/util/stream/IntStreamTestDataProvider.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package java.util.stream;
+
+import org.testng.annotations.DataProvider;
+
+import java.util.*;
+import java.util.Spliterators;
+import java.util.function.Supplier;
+
+/** TestNG DataProvider for int-valued streams */
+public class IntStreamTestDataProvider {
+    private static final int[] to0 = new int[0];
+    private static final int[] to1 = new int[1];
+    private static final int[] to10 = new int[10];
+    private static final int[] to100 = new int[100];
+    private static final int[] to1000 = new int[1000];
+    private static final int[] reversed = new int[100];
+    private static final int[] ones = new int[100];
+    private static final int[] twice = new int[200];
+    private static final int[] pseudoRandom;
+
+    private static final Object[][] testData;
+    private static final Object[][] spliteratorTestData;
+
+    static {
+        int[][] arrays = {to0, to1, to10, to100, to1000};
+        for (int[] arr : arrays) {
+            for (int i = 0; i < arr.length; i++) {
+                arr[i] = i;
+            }
+        }
+        for (int i = 0; i < reversed.length; i++) {
+            reversed[i] = reversed.length - i;
+        }
+        for (int i = 0; i < ones.length; i++) {
+            ones[i] = 1;
+        }
+        System.arraycopy(to100, 0, twice, 0, to100.length);
+        System.arraycopy(to100, 0, twice, to100.length, to100.length);
+        pseudoRandom = new int[LambdaTestHelpers.LONG_STRING.length()];
+        for (int i = 0; i < LambdaTestHelpers.LONG_STRING.length(); i++) {
+            pseudoRandom[i] = (int) LambdaTestHelpers.LONG_STRING.charAt(i);
+        }
+    }
+
+    static final Object[][] arrays = {
+            {"empty", to0},
+            {"0..1", to1},
+            {"0..10", to10},
+            {"0..100", to100},
+            {"0..1000", to1000},
+            {"100x[1]", ones},
+            {"2x[0..100]", twice},
+            {"reverse 0..100", reversed},
+            {"pseudorandom", pseudoRandom}
+    };
+
+    static {
+        {
+            List<Object[]> list = new ArrayList<>();
+            for (Object[] data : arrays) {
+                final Object name = data[0];
+                final int[] ints = (int[]) data[1];
+
+                list.add(new Object[]{"array:" +
+                                      name, TestData.Factory.ofArray("array:" + name, ints)});
+
+                SpinedBuffer.OfInt isl = new SpinedBuffer.OfInt();
+                for (int i : ints) {
+                    isl.accept(i);
+                }
+                list.add(new Object[]{"SpinedList:" + name,
+                         TestData.Factory.ofSpinedBuffer("SpinedList:" + name, isl)});
+
+                list.add(streamDataDescr("IntStream.intRange(0,l): " + ints.length,
+                                         () -> IntStream.range(0, ints.length)));
+                list.add(streamDataDescr("IntStream.intRange(0,l,2): " + ints.length,
+                                         () -> IntStream.range(0, ints.length, 2)));
+                list.add(streamDataDescr("IntStream.intRange(0,l,3): " + ints.length,
+                                         () -> IntStream.range(0, ints.length, 3)));
+                list.add(streamDataDescr("IntStream.intRange(0,l,7): " + ints.length,
+                                         () -> IntStream.range(0, ints.length, 7)));
+            }
+            testData = list.toArray(new Object[0][]);
+        }
+
+        {
+            List<Object[]> spliterators = new ArrayList<>();
+            for (Object[] data : arrays) {
+                final Object name = data[0];
+                final int[] ints = (int[]) data[1];
+
+                SpinedBuffer.OfInt isl = new SpinedBuffer.OfInt();
+                for (int i : ints) {
+                    isl.accept(i);
+                }
+
+                spliterators.add(splitDescr("Arrays.s(array):" + name,
+                                            () -> Arrays.spliterator(ints)));
+                spliterators.add(splitDescr("Arrays.s(array,o,l):" + name,
+                                            () -> Arrays.spliterator(ints, 0, ints.length / 2)));
+
+                spliterators.add(splitDescr("SpinedBuffer.s():" + name,
+                                            () -> isl.spliterator()));
+
+                spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator(), size):" + name,
+                                            () -> Spliterators.spliterator(isl.iterator(), ints.length, 0)));
+                spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator()):" + name,
+                                            () -> Spliterators.spliteratorUnknownSize(isl.iterator(), 0)));
+
+                spliterators.add(splitDescr("IntStream.intRange(0,l):" + name,
+                                            () -> IntStream.range(0, ints.length).spliterator()));
+                spliterators.add(splitDescr("IntStream.intRange(0,l,2):" + name,
+                                            () -> IntStream.range(0, ints.length, 2).spliterator()));
+                spliterators.add(splitDescr("IntStream.intRange(0,l,3):" + name,
+                                            () -> IntStream.range(0, ints.length, 3).spliterator()));
+                spliterators.add(splitDescr("IntStream.intRange(0,l,7):" + name,
+                                            () -> IntStream.range(0, ints.length, 7).spliterator()));
+
+                // Need more!
+            }
+            spliteratorTestData = spliterators.toArray(new Object[0][]);
+        }
+
+    }
+
+    static <T> Object[] streamDataDescr(String description, Supplier<IntStream> s) {
+        return new Object[] { description, TestData.Factory.ofIntSupplier(description, s) };
+    }
+
+    static <T> Object[] splitDescr(String description, Supplier<Spliterator.OfInt> s) {
+        return new Object[] { description, s };
+    }
+
+    // Return an array of ( String name, IntStreamTestData )
+    @DataProvider(name = "IntStreamTestData")
+    public static Object[][] makeIntStreamTestData() {
+        return testData;
+    }
+
+    // returns an array of (String name, Supplier<PrimitiveSpliterator<Integer>>)
+    @DataProvider(name = "IntSpliterator")
+    public static Object[][] spliteratorProvider() {
+        return spliteratorTestData;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/bootlib/java/util/stream/IntStreamTestScenario.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package java.util.stream;
+
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.IntConsumer;
+
+/**
+ * Test scenarios for int streams.
+ *
+ * Each scenario is provided with a data source, a function that maps a fresh
+ * stream (as provided by the data source) to a new stream, and a sink to
+ * receive results.  Each scenario describes a different way of computing the
+ * stream contents.  The test driver will ensure that all scenarios produce
+ * the same output (modulo allowable differences in ordering).
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public enum IntStreamTestScenario implements OpTestCase.BaseStreamTestScenario {
+
+    STREAM_FOR_EACH(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            IntStream s = m.apply(data.stream());
+            if (s.isParallel()) {
+                s = s.sequential();
+            }
+            s.forEach(b);
+        }
+    },
+
+    STREAM_TO_ARRAY(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            for (int t : m.apply(data.stream()).toArray()) {
+                b.accept(t);
+            }
+        }
+    },
+
+    STREAM_ITERATOR(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            for (PrimitiveIterator.OfInt seqIter = m.apply(data.stream()).iterator(); seqIter.hasNext(); )
+                b.accept(seqIter.nextInt());
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate in pull mode
+    STREAM_SPLITERATOR(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            for (Spliterator.OfInt spl = m.apply(data.stream()).spliterator(); spl.tryAdvance(b); ) {
+            }
+        }
+    },
+
+    // Wrap as stream, spliterate, then split a few times mixing advances with forEach
+    STREAM_SPLITERATOR_WITH_MIXED_TRAVERSE_AND_SPLIT(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            SpliteratorTestHelper.mixedTraverseAndSplit(b, m.apply(data.stream()).spliterator());
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate in pull mode
+    STREAM_SPLITERATOR_FOREACH(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            m.apply(data.stream()).spliterator().forEachRemaining(b);
+        }
+    },
+
+    PAR_STREAM_SEQUENTIAL_FOR_EACH(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            m.apply(data.parallelStream()).sequential().forEach(b);
+        }
+    },
+
+    // Wrap as parallel stream + forEachOrdered
+    PAR_STREAM_FOR_EACH_ORDERED(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            // @@@ Want to explicitly select ordered equalator
+            m.apply(data.parallelStream()).forEachOrdered(b);
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate sequentially
+    PAR_STREAM_SPLITERATOR(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            for (Spliterator.OfInt spl = m.apply(data.parallelStream()).spliterator(); spl.tryAdvance(b); ) {
+            }
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate sequentially
+    PAR_STREAM_SPLITERATOR_FOREACH(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            m.apply(data.parallelStream()).spliterator().forEachRemaining(b);
+        }
+    },
+
+    PAR_STREAM_TO_ARRAY(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            for (int t : m.apply(data.parallelStream()).toArray())
+                b.accept(t);
+        }
+    },
+
+    // Wrap as parallel stream, get the spliterator, wrap as a stream + toArray
+    PAR_STREAM_SPLITERATOR_STREAM_TO_ARRAY(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            IntStream s = m.apply(data.parallelStream());
+            Spliterator.OfInt sp = s.spliterator();
+            IntStream ss = StreamSupport.intParallelStream(() -> sp,
+                                                           StreamOpFlag.toCharacteristics(OpTestCase.getStreamFlags(s))
+                                                           | (sp.getExactSizeIfKnown() < 0 ? 0 : Spliterator.SIZED));
+            for (int t : ss.toArray())
+                b.accept(t);
+        }
+    },
+
+    PAR_STREAM_TO_ARRAY_CLEAR_SIZED(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            S_IN pipe1 = (S_IN) OpTestCase.chain(data.parallelStream(),
+                                                 new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+            IntStream pipe2 = m.apply(pipe1);
+
+            for (int t : pipe2.toArray())
+                b.accept(t);
+        }
+    },;
+
+    private boolean isParallel;
+
+    IntStreamTestScenario(boolean isParallel) {
+        this.isParallel = isParallel;
+    }
+
+    public StreamShape getShape() {
+        return StreamShape.INT_VALUE;
+    }
+
+    public boolean isParallel() {
+        return isParallel;
+    }
+
+    public <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+    void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m) {
+        _run(data, (IntConsumer) b, (Function<S_IN, IntStream>) m);
+    }
+
+    abstract <T, S_IN extends BaseStream<T, S_IN>>
+    void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/bootlib/java/util/stream/IntermediateTestOp.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package java.util.stream;
+
+/**
+ * A base type for test operations
+ */
+interface IntermediateTestOp<E_IN, E_OUT> {
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static<T> AbstractPipeline chain(AbstractPipeline upstream,
+                                            IntermediateTestOp<?, T> op) {
+        if (op instanceof StatelessTestOp)
+            return StatelessTestOp.chain(upstream, (StatelessTestOp) op);
+
+        if (op instanceof StatefulTestOp)
+            return StatefulTestOp.chain(upstream, (StatefulTestOp) op);
+
+        throw new IllegalStateException("Unknown test op type: " + op.getClass().getName());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/bootlib/java/util/stream/LambdaTestHelpers.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,471 @@
+/*
+ * Copyright (c) 1997, 2010, 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.
+ */
+package java.util.stream;
+
+import java.util.*;
+import java.util.function.BiConsumer;
+import java.util.function.BiPredicate;
+import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.DoubleConsumer;
+import java.util.function.DoublePredicate;
+import java.util.function.Function;
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.IntPredicate;
+import java.util.function.IntUnaryOperator;
+import java.util.function.LongBinaryOperator;
+import java.util.function.LongConsumer;
+import java.util.function.LongPredicate;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * LambdaTestHelpers -- assertion methods and useful objects for lambda test cases
+ */
+public class LambdaTestHelpers {
+    public static final String LONG_STRING = "When in the Course of human events it becomes necessary for one people to dissolve the political bands which have connected them with another and to assume among the powers of the earth, the separate and equal station to which the Laws of Nature and of Nature's God entitle them, a decent respect to the opinions of mankind requires that they should declare the causes which impel them to the separation.";
+
+    @SuppressWarnings("rawtypes")
+    public static final Consumer bEmpty = x -> {  };
+    @SuppressWarnings("rawtypes")
+    public static final IntConsumer bIntEmpty = x -> {  };
+    @SuppressWarnings("rawtypes")
+    public static final BiConsumer bBiEmpty = (x,y) -> { };
+    @SuppressWarnings("rawtypes")
+    public static final Consumer bHashCode = x -> { Objects.hashCode(x); };
+    @SuppressWarnings("rawtypes")
+    public static final BiConsumer bBiHashCode = (x,y) -> { Objects.hash(x, y); };
+    public static final Function<Integer, Integer> mZero = x -> 0;
+    public static final Function<Integer, Integer> mId = x -> x;
+    public static final Function<Integer, Integer> mDoubler = x -> x * 2;
+    public static final Function<Integer, Stream<Integer>> mfId = e -> Collections.singletonList(e).stream();
+    public static final Function<Integer, Stream<Integer>> mfNull = e -> Collections.<Integer>emptyList().stream();
+    public static final Function<Integer, Stream<Integer>> mfLt = e -> {
+        List<Integer> l = new ArrayList<>();
+        for (int i=0; i<e; i++)
+            l.add(i);
+        return l.stream();
+    };
+    public static final ToIntFunction<Integer> imDoubler = x -> x * 2;
+    public static final ToLongFunction<Long> lmDoubler = x -> x * 2;
+    public static final ToDoubleFunction<Double> dmDoubler = x -> x * 2;
+    public static final Predicate<Integer> pFalse = x -> false;
+    public static final Predicate<Integer> pTrue = x -> true;
+    public static final Predicate<Integer> pEven = x -> 0 == x % 2;
+    public static final Predicate<Integer> pOdd = x -> 1 == x % 2;
+    public static final IntPredicate ipFalse = x -> false;
+    public static final IntPredicate ipTrue = x -> true;
+    public static final IntPredicate ipEven = x -> 0 == x % 2;
+    public static final IntPredicate ipOdd = x -> 1 == x % 2;
+    public static final LongPredicate lpFalse = x -> false;
+    public static final LongPredicate lpTrue = x -> true;
+    public static final LongPredicate lpEven = x -> 0 == x % 2;
+    public static final LongPredicate lpOdd = x -> 1 == x % 2;
+    public static final DoublePredicate dpFalse = x -> false;
+    public static final DoublePredicate dpTrue = x -> true;
+    public static final DoublePredicate dpEven = x -> 0 == ((long) x) % 2;
+    public static final DoublePredicate dpOdd = x -> 1 == ((long) x) % 2;
+    public static final BinaryOperator<Integer> rPlus = (x, y) -> x+y;
+    public static final BinaryOperator<Integer> rMax = (x, y) -> Math.max(x, y);
+    public static final BinaryOperator<Integer> rMin = (x, y) -> Math.min(x,y);
+    public static final IntBinaryOperator irPlus = (x, y) -> x+y;
+    public static final IntBinaryOperator irMax = (x, y) -> Math.max(x, y);
+    public static final IntBinaryOperator irMin = (x, y) -> Math.min(x,y);
+    public static final IntUnaryOperator irDoubler = x -> x * 2;
+    public static final LongBinaryOperator lrPlus = (x, y) -> x+y;
+    public static final DoubleBinaryOperator drPlus = (x, y) -> x+y;
+    public static final Comparator<Integer> cInteger = (a, b) -> Integer.compare(a, b);
+    public static final BiPredicate<?, ?> bipFalse = (x, y) -> false;
+    public static final BiPredicate<?, ?> bipTrue = (x, y) -> true;
+    public static final BiPredicate<Integer, Integer> bipBothEven = (x, y) -> 0 == (x % 2 + y % 2);
+    public static final BiPredicate<Integer, Integer> bipBothOdd = (x, y) -> 2 == (x % 2 + y % 2);
+    public static final BiPredicate<?, ?> bipSameString = (x, y) -> String.valueOf(x).equals(String.valueOf(y));
+
+    public static final IntFunction<Integer[]> integerArrayGenerator = s -> new Integer[s];
+
+    public static final IntFunction<Object[]> objectArrayGenerator = s -> new Object[s];
+
+    public static final Function<String, Stream<Character>> flattenChars = string -> {
+        List<Character> l = new ArrayList<>();
+        for (int i=0; i<string.length(); i++)
+            l.add(string.charAt(i));
+        return l.stream();
+    };
+
+    public static final Function<String, IntStream> flattenInt
+            = string -> IntStream.range(0, string.length()).map(string::charAt);
+
+    public static <T, R> Function<T, R> forPredicate(Predicate<? super T> predicate, R forTrue, R forFalse) {
+        Objects.requireNonNull(predicate);
+
+        return t -> predicate.test(t) ? forTrue : forFalse;
+    }
+
+    public static <T> Function<T, T> identity() {
+        return t -> t;
+    }
+
+    public static<V, T, R> Function<V, R> compose(Function<? super T, ? extends R> after, Function<? super V, ? extends T> before) {
+        Objects.requireNonNull(before);
+        return (V v) -> after.apply(before.apply(v));
+    }
+
+    public static List<Integer> empty() {
+        ArrayList<Integer> list = new ArrayList<>();
+        list.add(null);
+        return list;
+    }
+
+    public static List<Integer> countTo(int n) {
+        return range(1, n);
+    }
+
+    public static List<Integer> range(int l, int u) {
+        ArrayList<Integer> list = new ArrayList<>(u - l + 1);
+        for (int i=l; i<=u; i++) {
+            list.add(i);
+        }
+        return list;
+    }
+
+    public static List<Integer> repeat(int value, int n) {
+        ArrayList<Integer> list = new ArrayList<>(n);
+        for (int i=1; i<=n; i++) {
+            list.add(value);
+        }
+        return list;
+    }
+
+    public static List<Double> asDoubles(List<Integer> integers) {
+        ArrayList<Double> list = new ArrayList<>();
+        for (Integer i : integers) {
+            list.add((double) i);
+        }
+        return list;
+    }
+
+    public static List<Long> asLongs(List<Integer> integers) {
+        ArrayList<Long> list = new ArrayList<>();
+        for (Integer i : integers) {
+            list.add((long) i);
+        }
+        return list;
+    }
+
+    public static void assertCountSum(Stream<? super Integer> it, int count, int sum) {
+        assertCountSum(it.iterator(), count, sum);
+    }
+
+    public static void assertCountSum(Iterable<? super Integer> it, int count, int sum) {
+        assertCountSum(it.iterator(), count, sum);
+    }
+
+    public static void assertCountSum(Iterator<? super Integer> it, int count, int sum) {
+        int c = 0;
+        int s = 0;
+        while (it.hasNext()) {
+            int i = (Integer) it.next();
+            c++;
+            s += i;
+        }
+
+        assertEquals(c, count);
+        assertEquals(s, sum);
+    }
+
+    public static void assertConcat(Iterator<Character> it, String result) {
+        StringBuilder sb = new StringBuilder();
+        while (it.hasNext()) {
+            sb.append(it.next());
+        }
+
+        assertEquals(result, sb.toString());
+    }
+
+    public static<T extends Comparable<? super T>> void assertSorted(Iterator<T> i) {
+        i = toBoxedList(i).iterator();
+
+        if (!i.hasNext())
+            return;
+        T last = i.next();
+        while (i.hasNext()) {
+            T t = i.next();
+            assertTrue(last.compareTo(t) <= 0);
+            assertTrue(t.compareTo(last) >= 0);
+            last = t;
+        }
+    }
+
+    public static<T> void assertSorted(Iterator<T> i, Comparator<? super T> comp) {
+        if (i instanceof PrimitiveIterator.OfInt
+                || i instanceof PrimitiveIterator.OfDouble
+                || i instanceof PrimitiveIterator.OfLong) {
+            i = toBoxedList(i).iterator();
+        }
+
+        if (!i.hasNext())
+            return;
+        T last = i.next();
+        while (i.hasNext()) {
+            T t = i.next();
+            assertTrue(comp.compare(last, t) <= 0);
+            assertTrue(comp.compare(t, last) >= 0);
+            last = t;
+        }
+    }
+
+    public static<T extends Comparable<? super T>> void assertSorted(Iterable<T> iter) {
+        assertSorted(iter.iterator());
+    }
+
+    public static<T> void assertSorted(Iterable<T> iter, Comparator<? super T> comp) {
+        assertSorted(iter.iterator(), comp);
+    }
+
+    public static <T> void assertUnique(Iterable<T> iter) {
+        assertUnique(iter.iterator());
+    }
+
+    public static<T> void assertUnique(Iterator<T> iter) {
+        if (!iter.hasNext()) {
+            return;
+        }
+
+        if (iter instanceof PrimitiveIterator.OfInt
+            || iter instanceof PrimitiveIterator.OfDouble
+            || iter instanceof PrimitiveIterator.OfLong) {
+            iter = toBoxedList(iter).iterator();
+        }
+
+        Set<T> uniq = new HashSet<>();
+        while(iter.hasNext()) {
+            T each = iter.next();
+            assertTrue(!uniq.contains(each));
+            uniq.add(each);
+        }
+    }
+
+    public static<T> void assertContents(Iterable<T> actual, Iterable<T> expected) {
+        if (actual instanceof Collection && expected instanceof Collection) {
+            assertEquals(actual, expected);
+        } else {
+            assertContents(actual.iterator(), expected.iterator());
+        }
+    }
+
+    public static<T> void assertContents(Iterator<T> actual, Iterator<T> expected) {
+        assertEquals(toBoxedList(actual), toBoxedList(expected));
+    }
+
+    @SafeVarargs
+    @SuppressWarnings("varargs")
+    public static<T> void assertContents(Iterator<T> actual, T... expected) {
+        assertContents(actual, Arrays.asList(expected).iterator());
+    }
+
+    /**
+     * The all consuming consumer (rampant capitalist) that can accepting a reference or any primitive value.
+     */
+    private static interface OmnivorousConsumer<T>
+            extends Consumer<T>, IntConsumer, LongConsumer, DoubleConsumer { }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static<T> Consumer<T> toBoxingConsumer(Consumer<? super T> c) {
+        return (Consumer<T>) new OmnivorousConsumer() {
+            @Override
+            public void accept(Object t) {
+                c.accept((T) t);
+            }
+
+            @Override
+            public void accept(int t) {
+                accept((Object) t);
+            }
+
+            @Override
+            public void accept(long t) {
+                accept((Object) t);
+            }
+
+            @Override
+            public void accept(double t) {
+                accept((Object) t);
+            }
+        };
+    }
+
+    /**
+     * Convert an iterator to a list using forEach with an implementation of
+     * {@link java.util.stream.LambdaTestHelpers.OmnivorousConsumer}.
+     *
+     * This ensures equality comparisons for test results do not trip
+     * the boxing trip-wires.
+     */
+    private static<T> List<T> toBoxedList(Iterator<T> it) {
+        List<T> l = new ArrayList<>();
+        it.forEachRemaining(toBoxingConsumer(l::add));
+        return l;
+    }
+
+    /**
+     * Convert a spliterator to a list using forEach with an implementation of
+     * {@link java.util.stream.LambdaTestHelpers.OmnivorousConsumer}.
+     *
+     * This ensures equality comparisons for test results do not trip
+     * the boxing trip-wires.
+     */
+    public static<T> List<T> toBoxedList(Spliterator<T> sp) {
+        List<T> l = new ArrayList<>();
+        sp.forEachRemaining(toBoxingConsumer(l::add));
+        return l;
+    }
+
+    /**
+     * Convert an iterator to a multi-set, represented as a Map, using forEach with an implementation of
+     * {@link java.util.stream.LambdaTestHelpers.OmnivorousConsumer}.
+     *
+     * This ensures equality comparisons for test results do not trip
+     * the boxing trip-wires.
+     */
+    @SuppressWarnings("unchecked")
+    private static<T> Map<T, Integer> toBoxedMultiset(Iterator<T> it) {
+        Map<Object, Integer> result = new HashMap<>();
+
+        it.forEachRemaining(new OmnivorousConsumer<T>() {
+            @Override
+            public void accept(T t) {
+                add(t);
+            }
+
+            @Override
+            public void accept(int value) {
+                add(value);
+            }
+
+            @Override
+            public void accept(long value) {
+                add(value);
+            }
+
+            @Override
+            public void accept(double value) {
+                add(value);
+            }
+
+            void add(Object o) {
+                if (result.containsKey(o))
+                    result.put(o, result.get(o) + 1);
+                else
+                    result.put(o, 1);
+            }
+
+        });
+
+        return (Map<T, Integer>) result;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static void assertContentsEqual(Object a, Object b) {
+        if (a instanceof Iterable && b instanceof Iterable)
+            assertContents((Iterable) a, (Iterable) b);
+        else
+            assertEquals(a, b);
+    }
+
+    public static<T> void assertContentsUnordered(Iterable<T> actual, Iterable<T> expected) {
+        assertContentsUnordered(actual.iterator(), expected.iterator());
+    }
+
+    public static<T> void assertContentsUnordered(Iterator<T> actual, Iterator<T> expected) {
+        assertEquals(toBoxedMultiset(actual), toBoxedMultiset(expected));
+    }
+
+    public static void launderAssertion(Runnable r, Supplier<String> additionalInfo) {
+        try {
+            r.run();
+        }
+        catch (AssertionError ae) {
+            AssertionError cloned = new AssertionError(ae.getMessage() + String.format("%n%s", additionalInfo.get()));
+            cloned.setStackTrace(ae.getStackTrace());
+            if (ae.getCause() != null)
+                cloned.initCause(ae.getCause());
+            throw cloned;
+        }
+    }
+
+    public static <T, S extends BaseStream<T, S>>
+    List<Function<S, S>> permuteStreamFunctions(List<Function<S, S>> opFunctions) {
+        List<List<Function<S, S>>> opFunctionPermutations = perm(opFunctions);
+
+        List<Function<S, S>> appliedFunctions = new ArrayList<>();
+        for (List<Function<S, S>> fs : opFunctionPermutations) {
+            Function<S, S> applied = s -> {
+                for (Function<S, S> f : fs) {
+                    s = f.apply(s);
+                }
+                return s;
+            };
+            appliedFunctions.add(applied);
+        }
+
+        return appliedFunctions;
+    }
+
+    private static <T> List<T> sub(List<T> l, int index) {
+        List<T> subL = new ArrayList<>(l);
+        subL.remove(index);
+        return subL;
+    }
+
+    public static <T> List<List<T>> perm(List<T> l) {
+        List<List<T>> result = new ArrayList<>();
+        for (int i = 0; i < l.size(); i++) {
+            for (List<T> perm : perm(sub(l, i))) {
+                perm.add(0, l.get(i));
+                result.add(perm);
+            }
+        }
+        result.add(new ArrayList<T>());
+
+        return result;
+    }
+
+    public static String flagsToString(int flags) {
+        StringJoiner sj = new StringJoiner(", ", "StreamOpFlag[", "]");
+        if (StreamOpFlag.DISTINCT.isKnown(flags)) sj.add("IS_DISTINCT");
+        if (StreamOpFlag.ORDERED.isKnown(flags)) sj.add("IS_ORDERED");
+        if (StreamOpFlag.SIZED.isKnown(flags)) sj.add("IS_SIZED");
+        if (StreamOpFlag.SORTED.isKnown(flags)) sj.add("IS_SORTED");
+        if (StreamOpFlag.SHORT_CIRCUIT.isKnown(flags)) sj.add("IS_SHORT_CIRCUIT");
+        return sj.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/bootlib/java/util/stream/LongStreamTestDataProvider.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+package java.util.stream;
+
+import org.testng.annotations.DataProvider;
+
+import java.util.*;
+import java.util.Spliterators;
+import java.util.function.Supplier;
+
+/** TestNG DataProvider for long-valued streams */
+public class LongStreamTestDataProvider {
+    private static final long[] to0 = new long[0];
+    private static final long[] to1 = new long[1];
+    private static final long[] to10 = new long[10];
+    private static final long[] to100 = new long[100];
+    private static final long[] to1000 = new long[1000];
+    private static final long[] reversed = new long[100];
+    private static final long[] ones = new long[100];
+    private static final long[] twice = new long[200];
+    private static final long[] pseudoRandom;
+
+    private static final Object[][] testData;
+    private static final Object[][] spliteratorTestData;
+
+    static {
+        long[][] arrays = {to0, to1, to10, to100, to1000};
+        for (long[] arr : arrays) {
+            for (int i = 0; i < arr.length; i++) {
+                arr[i] = i;
+            }
+        }
+        for (int i = 0; i < reversed.length; i++) {
+            reversed[i] = reversed.length - i;
+        }
+        for (int i = 0; i < ones.length; i++) {
+            ones[i] = 1;
+        }
+        System.arraycopy(to100, 0, twice, 0, to100.length);
+        System.arraycopy(to100, 0, twice, to100.length, to100.length);
+        pseudoRandom = new long[LambdaTestHelpers.LONG_STRING.length()];
+        for (int i = 0; i < LambdaTestHelpers.LONG_STRING.length(); i++) {
+            pseudoRandom[i] = (long) LambdaTestHelpers.LONG_STRING.charAt(i);
+        }
+    }
+
+    static final Object[][] arrays = {
+            {"empty", to0},
+            {"0..1", to1},
+            {"0..10", to10},
+            {"0..100", to100},
+            {"0..1000", to1000},
+            {"100x[1]", ones},
+            {"2x[0..100]", twice},
+            {"reverse 0..100", reversed},
+            {"pseudorandom", pseudoRandom}
+    };
+
+    static {
+        {
+            List<Object[]> list = new ArrayList<>();
+            for (Object[] data : arrays) {
+                final Object name = data[0];
+                final long[] longs = (long[]) data[1];
+
+                list.add(new Object[]{"array:" + name,
+                        TestData.Factory.ofArray("array:" + name, longs)});
+
+                SpinedBuffer.OfLong isl = new SpinedBuffer.OfLong();
+                for (long i : longs) {
+                    isl.accept(i);
+                }
+                list.add(new Object[]{"SpinedList:" + name,
+                        TestData.Factory.ofSpinedBuffer("SpinedList:" + name, isl)});
+
+                list.add(streamDataDescr("LongStream.longRange(0,l): " + longs.length,
+                                         () -> LongStream.range(0, longs.length)));
+                list.add(streamDataDescr("LongStream.longRange(0,l,2): " + longs.length,
+                                         () -> LongStream.range(0, longs.length, 2)));
+                list.add(streamDataDescr("LongStream.longRange(0,l,3): " + longs.length,
+                                         () -> LongStream.range(0, longs.length, 3)));
+                list.add(streamDataDescr("LongStream.longRange(0,l,7): " + longs.length,
+                                         () -> LongStream.range(0, longs.length, 7)));
+            }
+            testData = list.toArray(new Object[0][]);
+        }
+
+        {
+            List<Object[]> spliterators = new ArrayList<>();
+            for (Object[] data : arrays) {
+                final Object name = data[0];
+                final long[] longs = (long[]) data[1];
+
+                SpinedBuffer.OfLong isl = new SpinedBuffer.OfLong();
+                for (long i : longs) {
+                    isl.accept(i);
+                }
+
+                spliterators.add(splitDescr("Arrays.s(array):" + name,
+                                            () -> Arrays.spliterator(longs)));
+                spliterators.add(splitDescr("Arrays.s(array,o,l):" + name,
+                                            () -> Arrays.spliterator(longs, 0, longs.length / 2)));
+
+                spliterators.add(splitDescr("SpinedBuffer.s():" + name,
+                                            () -> isl.spliterator()));
+
+                spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator(), size):" + name,
+                                            () -> Spliterators.spliterator(isl.iterator(), longs.length, 0)));
+                spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator()):" + name,
+                                            () -> Spliterators.spliteratorUnknownSize(isl.iterator(), 0)));
+
+                spliterators.add(splitDescr("LongStream.longRange(0,l):" + name,
+                                            () -> LongStream.range(0, longs.length).spliterator()));
+                spliterators.add(splitDescr("LongStream.longRange(0,l,2):" + name,
+                                            () -> LongStream.range(0, longs.length, 2).spliterator()));
+                spliterators.add(splitDescr("LongStream.longRange(0,l,3):" + name,
+                                            () -> LongStream.range(0, longs.length, 3).spliterator()));
+                spliterators.add(splitDescr("LongStream.longRange(0,l,7):" + name,
+                                            () -> LongStream.range(0, longs.length, 7).spliterator()));
+                // Need more!
+            }
+            spliteratorTestData = spliterators.toArray(new Object[0][]);
+        }
+
+    }
+
+    static <T> Object[] streamDataDescr(String description, Supplier<LongStream> s) {
+        return new Object[] { description, TestData.Factory.ofLongSupplier(description, s) };
+    }
+
+    static <T> Object[] splitDescr(String description, Supplier<Spliterator.OfLong> s) {
+        return new Object[] { description, s };
+    }
+
+    // Return an array of ( String name, LongStreamTestData )
+    @DataProvider(name = "LongStreamTestData")
+    public static Object[][] makeLongStreamTestData() {
+        return testData;
+    }
+
+    // returns an array of (String name, Supplier<PrimitiveSpliterator<Long>>)
+    @DataProvider(name = "LongSpliterator")
+    public static Object[][] spliteratorProvider() {
+        return spliteratorTestData;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/bootlib/java/util/stream/LongStreamTestScenario.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+package java.util.stream;
+
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.LongConsumer;
+
+/**
+ * Test scenarios for long streams.
+ *
+ * Each scenario is provided with a data source, a function that maps a fresh
+ * stream (as provided by the data source) to a new stream, and a sink to
+ * receive results.  Each scenario describes a different way of computing the
+ * stream contents.  The test driver will ensure that all scenarios produce
+ * the same output (modulo allowable differences in ordering).
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public enum LongStreamTestScenario implements OpTestCase.BaseStreamTestScenario {
+
+    STREAM_FOR_EACH(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            LongStream s = m.apply(data.stream());
+            if (s.isParallel()) {
+                s = s.sequential();
+            }
+            s.forEach(b);
+        }
+    },
+
+    STREAM_TO_ARRAY(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            for (long t : m.apply(data.stream()).toArray()) {
+                b.accept(t);
+            }
+        }
+    },
+
+    STREAM_ITERATOR(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            for (PrimitiveIterator.OfLong seqIter = m.apply(data.stream()).iterator(); seqIter.hasNext(); )
+                b.accept(seqIter.nextLong());
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate in pull mode
+    STREAM_SPLITERATOR(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            for (Spliterator.OfLong spl = m.apply(data.stream()).spliterator(); spl.tryAdvance(b); ) {
+            }
+        }
+    },
+
+    // Wrap as stream, spliterate, then split a few times mixing advances with forEach
+    STREAM_SPLITERATOR_WITH_MIXED_TRAVERSE_AND_SPLIT(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            SpliteratorTestHelper.mixedTraverseAndSplit(b, m.apply(data.stream()).spliterator());
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate in pull mode
+    STREAM_SPLITERATOR_FOREACH(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            m.apply(data.stream()).spliterator().forEachRemaining(b);
+        }
+    },
+
+    PAR_STREAM_SEQUENTIAL_FOR_EACH(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            m.apply(data.parallelStream()).sequential().forEach(b);
+        }
+    },
+
+    // Wrap as parallel stream + forEachOrdered
+    PAR_STREAM_FOR_EACH_ORDERED(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            // @@@ Want to explicitly select ordered equalator
+            m.apply(data.parallelStream()).forEachOrdered(b);
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate sequentially
+    PAR_STREAM_SPLITERATOR(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            for (Spliterator.OfLong spl = m.apply(data.parallelStream()).spliterator(); spl.tryAdvance(b); ) {
+            }
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate sequentially
+    PAR_STREAM_SPLITERATOR_FOREACH(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            m.apply(data.parallelStream()).spliterator().forEachRemaining(b);
+        }
+    },
+
+    PAR_STREAM_TO_ARRAY(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            for (long t : m.apply(data.parallelStream()).toArray())
+                b.accept(t);
+        }
+    },
+
+    // Wrap as parallel stream, get the spliterator, wrap as a stream + toArray
+    PAR_STREAM_SPLITERATOR_STREAM_TO_ARRAY(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            LongStream s = m.apply(data.parallelStream());
+            Spliterator.OfLong sp = s.spliterator();
+            LongStream ss = StreamSupport.longParallelStream(() -> sp,
+                                                             StreamOpFlag.toCharacteristics(OpTestCase.getStreamFlags(s))
+                                                             | (sp.getExactSizeIfKnown() < 0 ? 0 : Spliterator.SIZED));
+            for (long t : ss.toArray())
+                b.accept(t);
+        }
+    },
+
+    PAR_STREAM_TO_ARRAY_CLEAR_SIZED(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            S_IN pipe1 = (S_IN) OpTestCase.chain(data.parallelStream(),
+                                                 new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+            LongStream pipe2 = m.apply(pipe1);
+
+            for (long t : pipe2.toArray())
+                b.accept(t);
+        }
+    },;
+
+    private boolean isParallel;
+
+    LongStreamTestScenario(boolean isParallel) {
+        this.isParallel = isParallel;
+    }
+
+    public StreamShape getShape() {
+        return StreamShape.LONG_VALUE;
+    }
+
+    public boolean isParallel() {
+        return isParallel;
+    }
+
+    public <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+    void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m) {
+        _run(data, (LongConsumer) b, (Function<S_IN, LongStream>) m);
+    }
+
+    abstract <T, S_IN extends BaseStream<T, S_IN>>
+    void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/bootlib/java/util/stream/OpTestCase.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,633 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package java.util.stream;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * Base class for streams test cases.  Provides 'exercise' methods for taking
+ * lambdas that construct and modify streams, and evaluates them in different
+ * ways and asserts that they produce equivalent results.
+ */
+@Test
+public abstract class OpTestCase extends Assert {
+
+    private final Map<StreamShape, Set<? extends BaseStreamTestScenario>> testScenarios;
+
+    protected OpTestCase() {
+        testScenarios = new EnumMap<>(StreamShape.class);
+        testScenarios.put(StreamShape.REFERENCE, Collections.unmodifiableSet(EnumSet.allOf(StreamTestScenario.class)));
+        testScenarios.put(StreamShape.INT_VALUE, Collections.unmodifiableSet(EnumSet.allOf(IntStreamTestScenario.class)));
+        testScenarios.put(StreamShape.LONG_VALUE, Collections.unmodifiableSet(EnumSet.allOf(LongStreamTestScenario.class)));
+        testScenarios.put(StreamShape.DOUBLE_VALUE, Collections.unmodifiableSet(EnumSet.allOf(DoubleStreamTestScenario.class)));
+    }
+
+    @SuppressWarnings("rawtypes")
+    public static int getStreamFlags(BaseStream s) {
+        return ((AbstractPipeline) s).getStreamFlags();
+    }
+
+    // Exercise stream operations
+
+    public interface BaseStreamTestScenario {
+        StreamShape getShape();
+
+        boolean isParallel();
+
+        abstract <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+        void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m);
+    }
+
+    public <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+    Collection<U> exerciseOps(TestData<T, S_IN> data, Function<S_IN, S_OUT> m) {
+        return withData(data).stream(m).exercise();
+    }
+
+    // Run multiple versions of exercise(), returning the result of the first, and asserting that others return the same result
+    // If the first version is s -> s.foo(), can be used with s -> s.mapToInt(i -> i).foo().mapToObj(i -> i) to test all shape variants
+    @SafeVarargs
+    public final<T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+    Collection<U> exerciseOpsMulti(TestData<T, S_IN> data,
+                                   Function<S_IN, S_OUT>... ms) {
+        Collection<U> result = null;
+        for (Function<S_IN, S_OUT> m : ms) {
+            if (result == null)
+                result = withData(data).stream(m).exercise();
+            else {
+                Collection<U> r2 = withData(data).stream(m).exercise();
+                assertEquals(result, r2);
+            }
+        }
+        return result;
+    }
+
+    // Run multiple versions of exercise() for an Integer stream, returning the result of the first, and asserting that others return the same result
+    // Automates the conversion between Stream<Integer> and {Int,Long,Double}Stream and back, so client sites look like you are passing the same
+    // lambda four times, but in fact they are four different lambdas since they are transforming four different kinds of streams
+    public final
+    Collection<Integer> exerciseOpsInt(TestData.OfRef<Integer> data,
+                                       Function<Stream<Integer>, Stream<Integer>> mRef,
+                                       Function<IntStream, IntStream> mInt,
+                                       Function<LongStream, LongStream> mLong,
+                                       Function<DoubleStream, DoubleStream> mDouble) {
+        @SuppressWarnings({ "rawtypes", "unchecked" })
+        Function<Stream<Integer>, Stream<Integer>>[] ms = new Function[4];
+        ms[0] = mRef;
+        ms[1] = s -> mInt.apply(s.mapToInt(e -> e)).mapToObj(e -> e);
+        ms[2] = s -> mLong.apply(s.mapToLong(e -> e)).mapToObj(e -> (int) e);
+        ms[3] = s -> mDouble.apply(s.mapToDouble(e -> e)).mapToObj(e -> (int) e);
+        return exerciseOpsMulti(data, ms);
+    }
+
+    public <T, U, S_OUT extends BaseStream<U, S_OUT>>
+    Collection<U> exerciseOps(Collection<T> data, Function<Stream<T>, S_OUT> m) {
+        TestData.OfRef<T> data1 = TestData.Factory.ofCollection("Collection of type " + data.getClass().getName(), data);
+        return withData(data1).stream(m).exercise();
+    }
+
+    public <T, U, S_OUT extends BaseStream<U, S_OUT>, I extends Iterable<U>>
+    Collection<U> exerciseOps(Collection<T> data, Function<Stream<T>, S_OUT> m, I expected) {
+        TestData.OfRef<T> data1 = TestData.Factory.ofCollection("Collection of type " + data.getClass().getName(), data);
+        return withData(data1).stream(m).expectedResult(expected).exercise();
+    }
+
+    @SuppressWarnings("unchecked")
+    public <U, S_OUT extends BaseStream<U, S_OUT>>
+    Collection<U> exerciseOps(int[] data, Function<IntStream, S_OUT> m) {
+        return withData(TestData.Factory.ofArray("int array", data)).stream(m).exercise();
+    }
+
+    public Collection<Integer> exerciseOps(int[] data, Function<IntStream, IntStream> m, int[] expected) {
+        TestData.OfInt data1 = TestData.Factory.ofArray("int array", data);
+        return withData(data1).stream(m).expectedResult(expected).exercise();
+    }
+
+    public <T, S_IN extends BaseStream<T, S_IN>> DataStreamBuilder<T, S_IN> withData(TestData<T, S_IN> data) {
+        Objects.requireNonNull(data);
+        return new DataStreamBuilder<>(data);
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public class DataStreamBuilder<T, S_IN extends BaseStream<T, S_IN>> {
+        final TestData<T, S_IN> data;
+
+        private DataStreamBuilder(TestData<T, S_IN> data) {
+            this.data = Objects.requireNonNull(data);
+        }
+
+        public <U, S_OUT extends BaseStream<U, S_OUT>>
+        ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> ops(IntermediateTestOp... ops) {
+            return new ExerciseDataStreamBuilder<>(data, (S_IN s) -> (S_OUT) chain(s, ops));
+        }
+
+        public <U, S_OUT extends BaseStream<U, S_OUT>> ExerciseDataStreamBuilder<T, U, S_IN, S_OUT>
+        stream(Function<S_IN, S_OUT> m) {
+            return new ExerciseDataStreamBuilder<>(data, m);
+        }
+
+        public <U, S_OUT extends BaseStream<U, S_OUT>> ExerciseDataStreamBuilder<T, U, S_IN, S_OUT>
+        stream(Function<S_IN, S_OUT> m, IntermediateTestOp<U, U> additionalOp) {
+            return new ExerciseDataStreamBuilder<>(data, s -> (S_OUT) chain(m.apply(s), additionalOp));
+        }
+
+        public <R> ExerciseDataTerminalBuilder<T, T, R, S_IN, S_IN>
+        terminal(Function<S_IN, R> terminalF) {
+            return new ExerciseDataTerminalBuilder<>(data, s -> s, terminalF);
+        }
+
+        public <U, R, S_OUT extends BaseStream<U, S_OUT>> ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT>
+        terminal(Function<S_IN, S_OUT> streamF, Function<S_OUT, R> terminalF) {
+            return new ExerciseDataTerminalBuilder<>(data, streamF, terminalF);
+        }
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public class ExerciseDataStreamBuilder<T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>> {
+        final TestData<T, S_IN> data;
+        final Function<S_IN, S_OUT> m;
+        final StreamShape shape;
+
+        Set<BaseStreamTestScenario> testSet = new HashSet<>();
+
+        Collection<U> refResult;
+        boolean isOrdered;
+
+        Consumer<TestData<T, S_IN>> before = LambdaTestHelpers.bEmpty;
+
+        Consumer<TestData<T, S_IN>> after = LambdaTestHelpers.bEmpty;
+
+        BiConsumer<Iterable<U>, Iterable<U>> sequentialEqualityAsserter = LambdaTestHelpers::assertContentsEqual;
+        BiConsumer<Iterable<U>, Iterable<U>> parallelEqualityAsserter = LambdaTestHelpers::assertContentsEqual;
+
+        private ExerciseDataStreamBuilder(TestData<T, S_IN> data, Function<S_IN, S_OUT> m) {
+            this.data = data;
+
+            this.m = Objects.requireNonNull(m);
+
+            this.shape = ((AbstractPipeline<?, U, ?>) m.apply(data.stream())).getOutputShape();
+
+            // Have to initiate from the output shape of the last stream
+            // This means the stream mapper is required first rather than last
+            testSet.addAll(testScenarios.get(shape));
+        }
+
+        public BiConsumer<Iterable<U>, Iterable<U>> getEqualityAsserter(BaseStreamTestScenario t) {
+            return t.isParallel() ? parallelEqualityAsserter : sequentialEqualityAsserter;
+        }
+
+        //
+
+        public <I extends Iterable<U>> ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> expectedResult(I expectedResult) {
+            List<U> l = new ArrayList<>();
+            expectedResult.forEach(l::add);
+            refResult = l;
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> expectedResult(int[] expectedResult) {
+            List l = new ArrayList();
+            for (int anExpectedResult : expectedResult) {
+                l.add(anExpectedResult);
+            }
+            refResult = l;
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> expectedResult(long[] expectedResult) {
+            List l = new ArrayList();
+            for (long anExpectedResult : expectedResult) {
+                l.add(anExpectedResult);
+            }
+            refResult = l;
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> expectedResult(double[] expectedResult) {
+            List l = new ArrayList();
+            for (double anExpectedResult : expectedResult) {
+                l.add(anExpectedResult);
+            }
+            refResult = l;
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> before(Consumer<TestData<T, S_IN>> before) {
+            this.before = Objects.requireNonNull(before);
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> after(Consumer<TestData<T, S_IN>> after) {
+            this.after = Objects.requireNonNull(after);
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> without(BaseStreamTestScenario... tests) {
+            return without(Arrays.asList(tests));
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> without(Collection<? extends BaseStreamTestScenario> tests) {
+            for (BaseStreamTestScenario ts : tests) {
+                if (ts.getShape() == shape) {
+                    testSet.remove(ts);
+                }
+            }
+
+            if (testSet.isEmpty()) {
+                throw new IllegalStateException("Test scenario set is empty");
+            }
+
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> with(BaseStreamTestScenario... tests) {
+            return with(Arrays.asList(tests));
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> with(Collection<? extends BaseStreamTestScenario> tests) {
+            testSet = new HashSet<>();
+
+            for (BaseStreamTestScenario ts : tests) {
+                if (ts.getShape() == shape) {
+                    testSet.add(ts);
+                }
+            }
+
+            if (testSet.isEmpty()) {
+                throw new IllegalStateException("Test scenario set is empty");
+            }
+
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> sequentialEqualityAsserter(BiConsumer<Iterable<U>, Iterable<U>> equalator) {
+            this.sequentialEqualityAsserter = equalator;
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> parallelEqualityAsserter(BiConsumer<Iterable<U>, Iterable<U>> equalator) {
+            this.parallelEqualityAsserter = equalator;
+            return this;
+        }
+
+        // Build method
+
+        private long count(StreamShape shape, BaseStream s) {
+            switch (shape) {
+                case REFERENCE:    return ((Stream) s).count();
+                case INT_VALUE:    return ((IntStream) s).count();
+                case LONG_VALUE:   return ((LongStream) s).count();
+                case DOUBLE_VALUE: return ((DoubleStream) s).count();
+                default: throw new IllegalStateException("Unknown shape: " + shape);
+            }
+        }
+
+        public Collection<U> exercise() {
+            if (refResult == null) {
+                // Induce the reference result
+                before.accept(data);
+                S_OUT sOut = m.apply(data.stream());
+                isOrdered = StreamOpFlag.ORDERED.isKnown(((AbstractPipeline) sOut).getStreamFlags());
+                Node<U> refNodeResult = ((AbstractPipeline<?, U, ?>) sOut).evaluateToArrayNode(size -> (U[]) new Object[size]);
+                refResult = LambdaTestHelpers.toBoxedList(refNodeResult.spliterator());
+                after.accept(data);
+                S_OUT anotherCopy = m.apply(data.stream());
+                long count = count(((AbstractPipeline) anotherCopy).getOutputShape(), anotherCopy);
+                assertEquals(count, refNodeResult.count());
+            }
+
+            List<Error> errors = new ArrayList<>();
+            for (BaseStreamTestScenario test : testSet) {
+                try {
+                    before.accept(data);
+
+                    List<U> result = new ArrayList<>();
+                    test.run(data, LambdaTestHelpers.<U>toBoxingConsumer(result::add), m);
+
+                    Runnable asserter = () -> getEqualityAsserter(test).accept(result, refResult);
+                    if (test.isParallel() && !isOrdered)
+                        asserter = () -> LambdaTestHelpers.assertContentsUnordered(result, refResult);
+                    LambdaTestHelpers.launderAssertion(
+                            asserter,
+                            () -> String.format("%n%s: %s != %s", test, refResult, result));
+
+                    after.accept(data);
+//                } catch (AssertionError ae) {
+//                    errors.add(ae);
+                } catch (Throwable t) {
+                    errors.add(new Error(String.format("%s: %s", test, t), t));
+                }
+            }
+
+            if (!errors.isEmpty()) {
+                StringBuilder sb = new StringBuilder();
+                int i = 1;
+                for (Error t : errors) {
+                    sb.append(i++).append(": ");
+                    if (t instanceof AssertionError) {
+                        sb.append(t).append("\n");
+                    }
+                    else {
+                        StringWriter sw = new StringWriter();
+                        PrintWriter pw = new PrintWriter(sw);
+
+                        t.getCause().printStackTrace(pw);
+                        pw.flush();
+                        sb.append(t).append("\n").append(sw);
+                    }
+                }
+                sb.append("--");
+
+                fail(String.format("%d failure(s) for test data: %s\n%s", i - 1, data.toString(), sb));
+            }
+
+            return refResult;
+        }
+    }
+
+    // Exercise terminal operations
+
+    static enum TerminalTestScenario {
+        SINGLE_SEQUENTIAL,
+        SINGLE_SEQUENTIAL_SHORT_CIRCUIT,
+        SINGLE_PARALLEL,
+        ALL_SEQUENTIAL,
+        ALL_SEQUENTIAL_SHORT_CIRCUIT,
+        ALL_PARALLEL,
+        ALL_PARALLEL_SEQUENTIAL,
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public class ExerciseDataTerminalBuilder<T, U, R, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>> {
+        final TestData<T, S_IN> data;
+        final Function<S_IN, S_OUT> streamF;
+        final Function<S_OUT, R> terminalF;
+
+        R refResult;
+
+        Set<TerminalTestScenario> testSet = EnumSet.allOf(TerminalTestScenario.class);
+
+        Function<S_OUT, BiConsumer<R, R>> sequentialEqualityAsserter = s -> LambdaTestHelpers::assertContentsEqual;
+        Function<S_OUT, BiConsumer<R, R>> parallelEqualityAsserter = s -> LambdaTestHelpers::assertContentsEqual;
+
+        private ExerciseDataTerminalBuilder(TestData<T, S_IN> data, Function<S_IN, S_OUT> streamF, Function<S_OUT, R> terminalF) {
+            this.data = data;
+            this.streamF = Objects.requireNonNull(streamF);
+            this.terminalF = Objects.requireNonNull(terminalF);
+        }
+
+        //
+
+        public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> expectedResult(R expectedResult) {
+            this.refResult = expectedResult;
+            return this;
+        }
+
+        public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> equalator(BiConsumer<R, R> equalityAsserter) {
+            this.sequentialEqualityAsserter = s -> equalityAsserter;
+            this.parallelEqualityAsserter = s -> equalityAsserter;
+            return this;
+        }
+
+        public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> sequentialEqualityAsserter(BiConsumer<R, R> equalityAsserter) {
+            this.sequentialEqualityAsserter = s -> equalityAsserter;
+            return this;
+        }
+
+        public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> parallelEqualityAsserter(BiConsumer<R, R> equalityAsserter) {
+            this.parallelEqualityAsserter = s -> equalityAsserter;
+            return this;
+        }
+
+        public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> parallelEqualityAsserter(Function<S_OUT, BiConsumer<R, R>> equalatorProvider) {
+            this.parallelEqualityAsserter = equalatorProvider;
+            return this;
+        }
+
+        public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> without(TerminalTestScenario... tests) {
+            return without(Arrays.asList(tests));
+        }
+
+        public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> without(Collection<TerminalTestScenario> tests) {
+            testSet.removeAll(tests);
+            if (testSet.isEmpty()) {
+                throw new IllegalStateException("Terminal test scenario set is empty");
+            }
+            return this;
+        }
+
+        public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> with(TerminalTestScenario... tests) {
+            return with(Arrays.asList(tests));
+        }
+
+        public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> with(Collection<TerminalTestScenario> tests) {
+            testSet.addAll(tests);
+            return this;
+        }
+
+        // Build method
+
+        public R exercise() {
+            S_OUT out = streamF.apply(data.stream());
+            AbstractPipeline ap = (AbstractPipeline) out;
+            StreamShape shape = ap.getOutputShape();
+
+            Node<U> node = ap.evaluateToArrayNode(size -> (U[]) new Object[size]);
+            if (refResult == null) {
+                // Sequentially collect the output that will be input to the terminal op
+                refResult = terminalF.apply((S_OUT) createPipeline(shape, node.spliterator(),
+                                                                   StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SIZED,
+                                                                   false));
+            } else if (testSet.contains(TerminalTestScenario.SINGLE_SEQUENTIAL)) {
+                S_OUT source = (S_OUT) createPipeline(shape, node.spliterator(),
+                                                      StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SIZED,
+                                                      false);
+                BiConsumer<R, R> asserter = sequentialEqualityAsserter.apply(source);
+                R result = terminalF.apply(source);
+                LambdaTestHelpers.launderAssertion(() -> asserter.accept(refResult, result),
+                                                   () -> String.format("Single sequential: %s != %s", refResult, result));
+            }
+
+            if (testSet.contains(TerminalTestScenario.SINGLE_SEQUENTIAL_SHORT_CIRCUIT)) {
+                S_OUT source = (S_OUT) createPipeline(shape, node.spliterator(),
+                                                      StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SIZED,
+                                                      false);
+                // Force short-curcuit
+                source = (S_OUT) chain(source, new ShortCircuitOp<U>(shape));
+                BiConsumer<R, R> asserter = sequentialEqualityAsserter.apply(source);
+                R result = terminalF.apply(source);
+                LambdaTestHelpers.launderAssertion(() -> asserter.accept(refResult, result),
+                                                   () -> String.format("Single sequential pull: %s != %s", refResult, result));
+            }
+
+            if (testSet.contains(TerminalTestScenario.SINGLE_PARALLEL)) {
+                S_OUT source = (S_OUT) createPipeline(shape, node.spliterator(),
+                                                      StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SIZED,
+                                                      true);
+                BiConsumer<R, R> asserter = parallelEqualityAsserter.apply(source);
+                R result = terminalF.apply(source);
+                LambdaTestHelpers.launderAssertion(() -> asserter.accept(refResult, result),
+                                                   () -> String.format("Single parallel: %s != %s", refResult, result));
+            }
+
+            if (testSet.contains(TerminalTestScenario.ALL_SEQUENTIAL)) {
+                // This may forEach or tryAdvance depending on the terminal op implementation
+                S_OUT source = streamF.apply(data.stream());
+                BiConsumer<R, R> asserter = sequentialEqualityAsserter.apply(source);
+                R result = terminalF.apply(source);
+                LambdaTestHelpers.launderAssertion(() -> asserter.accept(refResult, result),
+                                                   () -> String.format("All sequential: %s != %s", refResult, result));
+            }
+
+            if (testSet.contains(TerminalTestScenario.ALL_SEQUENTIAL_SHORT_CIRCUIT)) {
+                S_OUT source = streamF.apply(data.stream());
+                // Force short-curcuit
+                source = (S_OUT) chain(source, new ShortCircuitOp<U>(shape));
+                BiConsumer<R, R> asserter = sequentialEqualityAsserter.apply(source);
+                R result = terminalF.apply(source);
+                LambdaTestHelpers.launderAssertion(() -> asserter.accept(refResult, result),
+                                                   () -> String.format("All sequential pull: %s != %s", refResult, result));
+            }
+
+            if (testSet.contains(TerminalTestScenario.ALL_PARALLEL)) {
+                S_OUT source = streamF.apply(data.parallelStream());
+                BiConsumer<R, R> asserter = parallelEqualityAsserter.apply(source);
+                R result = terminalF.apply(source);
+                LambdaTestHelpers.launderAssertion(() -> asserter.accept(refResult, result),
+                                                   () -> String.format("All parallel: %s != %s", refResult, result));
+            }
+
+            if (testSet.contains(TerminalTestScenario.ALL_PARALLEL_SEQUENTIAL)) {
+                S_OUT source = streamF.apply(data.parallelStream());
+                BiConsumer<R, R> asserter = parallelEqualityAsserter.apply(source);
+                R result = terminalF.apply(source.sequential());
+                LambdaTestHelpers.launderAssertion(() -> asserter.accept(refResult, result),
+                                                   () -> String.format("All parallel then sequential: %s != %s", refResult, result));
+            }
+
+            return refResult;
+        }
+
+        AbstractPipeline createPipeline(StreamShape shape, Spliterator s, int flags, boolean parallel) {
+            switch (shape) {
+                case REFERENCE:    return new ReferencePipeline.Head<>(s, flags, parallel);
+                case INT_VALUE:    return new IntPipeline.Head(s, flags, parallel);
+                case LONG_VALUE:   return new LongPipeline.Head(s, flags, parallel);
+                case DOUBLE_VALUE: return new DoublePipeline.Head(s, flags, parallel);
+                default: throw new IllegalStateException("Unknown shape: " + shape);
+            }
+        }
+    }
+
+    public <T, R> R exerciseTerminalOps(Collection<T> data, Function<Stream<T>, R> m, R expected) {
+        TestData.OfRef<T> data1
+                = TestData.Factory.ofCollection("Collection of type " + data.getClass().getName(), data);
+        return withData(data1).terminal(m).expectedResult(expected).exercise();
+    }
+
+    public <T, R, S_IN extends BaseStream<T, S_IN>> R
+    exerciseTerminalOps(TestData<T, S_IN> data,
+                        Function<S_IN, R> terminalF) {
+        return withData(data).terminal(terminalF).exercise();
+    }
+
+    public <T, U, R, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>> R
+    exerciseTerminalOps(TestData<T, S_IN> data,
+                        Function<S_IN, S_OUT> streamF,
+                        Function<S_OUT, R> terminalF) {
+        return withData(data).terminal(streamF, terminalF).exercise();
+    }
+
+    //
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    private static <T> AbstractPipeline<?, T, ?> chain(AbstractPipeline upstream, IntermediateTestOp<?, T> op) {
+        return (AbstractPipeline<?, T, ?>) IntermediateTestOp.chain(upstream, op);
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    private static AbstractPipeline<?, ?, ?> chain(AbstractPipeline pipe, IntermediateTestOp... ops) {
+        for (IntermediateTestOp op : ops)
+            pipe = chain(pipe, op);
+        return pipe;
+    }
+
+    @SuppressWarnings("rawtypes")
+    private static <T> AbstractPipeline<?, T, ?> chain(BaseStream pipe, IntermediateTestOp<?, T> op) {
+        return chain((AbstractPipeline) pipe, op);
+    }
+
+    @SuppressWarnings("rawtypes")
+    public static AbstractPipeline<?, ?, ?> chain(BaseStream pipe, IntermediateTestOp... ops) {
+        return chain((AbstractPipeline) pipe, ops);
+    }
+
+    // Test data
+
+    private class ShortCircuitOp<T> implements StatelessTestOp<T,T> {
+        private final StreamShape shape;
+
+        private ShortCircuitOp(StreamShape shape) {
+            this.shape = shape;
+        }
+
+        @Override
+        public Sink<T> opWrapSink(int flags, boolean parallel, Sink<T> sink) {
+            return sink;
+        }
+
+        @Override
+        public int opGetFlags() {
+            return StreamOpFlag.IS_SHORT_CIRCUIT;
+        }
+
+        @Override
+        public StreamShape outputShape() {
+            return shape;
+        }
+
+        @Override
+        public StreamShape inputShape() {
+            return shape;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/bootlib/java/util/stream/SpliteratorTestHelper.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,654 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package java.util.stream;
+
+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;
+
+/**
+ * Assertion methods for spliterators, to be called from other tests
+ */
+public class SpliteratorTestHelper {
+
+    public static void testSpliterator(Supplier<Spliterator<Integer>> supplier) {
+        testSpliterator(supplier, (Consumer<Integer> b) -> b);
+    }
+
+    public static void testIntSpliterator(Supplier<Spliterator.OfInt> supplier) {
+        class BoxingAdapter implements Consumer<Integer>, IntConsumer {
+            private final Consumer<Integer> b;
+
+            BoxingAdapter(Consumer<Integer> b) {
+                this.b = b;
+            }
+
+            @Override
+            public void accept(Integer value) {
+                throw new IllegalStateException();
+            }
+
+            @Override
+            public void accept(int value) {
+                b.accept(value);
+            }
+        }
+
+        testSpliterator(supplier, c -> new BoxingAdapter(c));
+    }
+
+    public static void testLongSpliterator(Supplier<Spliterator.OfLong> supplier) {
+        class BoxingAdapter implements Consumer<Long>, LongConsumer {
+            private final Consumer<Long> b;
+
+            BoxingAdapter(Consumer<Long> b) {
+                this.b = b;
+            }
+
+            @Override
+            public void accept(Long value) {
+                throw new IllegalStateException();
+            }
+
+            @Override
+            public void accept(long value) {
+                b.accept(value);
+            }
+        }
+
+        testSpliterator(supplier, c -> new BoxingAdapter(c));
+    }
+
+    public static void testDoubleSpliterator(Supplier<Spliterator.OfDouble> supplier) {
+        class BoxingAdapter implements Consumer<Double>, DoubleConsumer {
+            private final Consumer<Double> b;
+
+            BoxingAdapter(Consumer<Double> b) {
+                this.b = b;
+            }
+
+            @Override
+            public void accept(Double value) {
+                throw new IllegalStateException();
+            }
+
+            @Override
+            public void accept(double value) {
+                b.accept(value);
+            }
+        }
+
+        testSpliterator(supplier, c -> new BoxingAdapter(c));
+    }
+
+    static <T, S extends Spliterator<T>> void testSpliterator(Supplier<S> supplier,
+                                                              UnaryOperator<Consumer<T>> 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);
+        testMixedTraverseAndSplit(exp, supplier, boxingAdapter);
+        testSplitAfterFullTraversal(supplier, boxingAdapter);
+        testSplitOnce(exp, supplier, boxingAdapter);
+        testSplitSixDeep(exp, supplier, boxingAdapter);
+        testSplitUntilNull(exp, supplier, boxingAdapter);
+    }
+
+    //
+
+    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<>();
+        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)));
+        // 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(fromTryAdvance.size(), exp.size());
+
+        assertContents(fromTryAdvance, exp, isOrdered);
+    }
+
+    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<>();
+        spliterator = supplier.get();
+        Consumer<T> addToDest = boxingAdapter.apply(dest::add);
+        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) {
+            assertEquals(sizeIfKnown, dest.size());
+        }
+        assertEquals(dest.size(), exp.size());
+
+        if (isOrdered) {
+            assertEquals(dest, exp);
+        }
+        else {
+            assertContentsUnordered(dest, exp);
+        }
+    }
+
+    private static <T, S extends Spliterator<T>> void testMixedTraverseAndSplit(
+            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<>();
+        spliterator = supplier.get();
+        Consumer<T> b = boxingAdapter.apply(dest::add);
+
+        Spliterator<T> spl1, spl2, spl3;
+        spliterator.tryAdvance(b);
+        spl2 = spliterator.trySplit();
+        if (spl2 != null) {
+            spl2.tryAdvance(b);
+            spl1 = spl2.trySplit();
+            if (spl1 != null) {
+                spl1.tryAdvance(b);
+                spl1.forEachRemaining(b);
+            }
+            spl2.tryAdvance(b);
+            spl2.forEachRemaining(b);
+        }
+        spliterator.tryAdvance(b);
+        spl3 = spliterator.trySplit();
+        if (spl3 != null) {
+            spl3.tryAdvance(b);
+            spl3.forEachRemaining(b);
+        }
+        spliterator.tryAdvance(b);
+        spliterator.forEachRemaining(b);
+
+        if (sizeIfKnown >= 0) {
+            assertEquals(sizeIfKnown, dest.size());
+        }
+        assertEquals(dest.size(), exp.size());
+
+        if (isOrdered) {
+            assertEquals(dest, exp);
+        }
+        else {
+            assertContentsUnordered(dest, exp);
+        }
+    }
+
+    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 -> { }))) { }
+        Spliterator<T> split = spliterator.trySplit();
+        assertNull(split);
+
+        // Full traversal using forEach
+        spliterator = supplier.get();
+        spliterator.forEachRemaining(boxingAdapter.apply(e -> {
+        }));
+        split = spliterator.trySplit();
+        assertNull(split);
+
+        // Full traversal using tryAdvance then forEach
+        spliterator = supplier.get();
+        spliterator.tryAdvance(boxingAdapter.apply(e -> { }));
+        spliterator.forEachRemaining(boxingAdapter.apply(e -> {
+        }));
+        split = spliterator.trySplit();
+        assertNull(split);
+    }
+
+    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();
+        Spliterator<T> s2 = s1.trySplit();
+        long s1Size = s1.getExactSizeIfKnown();
+        long s2Size = (s2 != null) ? s2.getExactSizeIfKnown() : 0;
+        Consumer<T> addToFromSplit = boxingAdapter.apply(fromSplit::add);
+        if (s2 != null)
+            s2.forEachRemaining(addToFromSplit);
+        s1.forEachRemaining(addToFromSplit);
+
+        if (sizeIfKnown >= 0) {
+            assertEquals(sizeIfKnown, fromSplit.size());
+            if (s1Size >= 0 && s2Size >= 0)
+                assertEquals(sizeIfKnown, s1Size + s2Size);
+        }
+        assertContents(fromSplit, exp, isOrdered);
+    }
+
+    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++) {
+            List<T> dest = new ArrayList<>();
+            spliterator = supplier.get();
+
+            assertSpliterator(spliterator);
+
+            // verify splitting with forEach
+            splitSixDeepVisitor(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), false);
+            assertContents(dest, exp, isOrdered);
+
+            // verify splitting with tryAdvance
+            dest.clear();
+            spliterator = supplier.get();
+            splitSixDeepVisitor(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), true);
+            assertContents(dest, exp, isOrdered);
+        }
+    }
+
+    private static <T, S extends Spliterator<T>>
+    void splitSixDeepVisitor(int depth, int curLevel,
+                             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();
+            if (split != null) {
+                assertSpliterator(split, rootCharacteristics);
+                assertSpliterator(spliterator, rootCharacteristics);
+
+                if ((rootCharacteristics & Spliterator.SUBSIZED) != 0 &&
+                    (rootCharacteristics & Spliterator.SIZED) != 0) {
+                    assertEquals(beforeSize, split.estimateSize() + spliterator.estimateSize());
+                }
+                splitSixDeepVisitor(depth, curLevel + 1, dest, split, boxingAdapter, rootCharacteristics, useTryAdvance);
+            }
+            splitSixDeepVisitor(depth, curLevel + 1, dest, spliterator, boxingAdapter, rootCharacteristics, useTryAdvance);
+        }
+        else {
+            long sizeIfKnown = spliterator.getExactSizeIfKnown();
+            if (useTryAdvance) {
+                Consumer<T> addToDest = boxingAdapter.apply(dest::add);
+                int count = 0;
+                while (spliterator.tryAdvance(addToDest)) {
+                    ++count;
+                }
+
+                if (sizeIfKnown >= 0)
+                    assertEquals(sizeIfKnown, count);
+
+                // Assert that forEach now produces no elements
+                spliterator.forEachRemaining(boxingAdapter.apply(
+                        e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
+
+                Spliterator<T> split = spliterator.trySplit();
+                assertNull(split);
+            }
+            else {
+                List<T> leafDest = new ArrayList<>();
+                Consumer<T> addToLeafDest = boxingAdapter.apply(leafDest::add);
+                spliterator.forEachRemaining(addToLeafDest);
+
+                if (sizeIfKnown >= 0)
+                    assertEquals(sizeIfKnown, leafDest.size());
+
+                // Assert that forEach now produces no elements
+                spliterator.tryAdvance(boxingAdapter.apply(
+                        e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
+
+                Spliterator<T> split = spliterator.trySplit();
+                assertNull(split);
+
+                dest.addAll(leafDest);
+            }
+        }
+    }
+
+    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);
+
+        testSplitUntilNull(new SplitNode<T>(c, s));
+        assertContents(splits, exp, isOrdered);
+    }
+
+    private static class SplitNode<T> {
+        // Constant for every node
+        final Consumer<T> c;
+        final int rootCharacteristics;
+
+        final Spliterator<T> s;
+
+        SplitNode(Consumer<T> c, Spliterator<T> s) {
+            this(c, s.characteristics(), s);
+        }
+
+        private SplitNode(Consumer<T> c, int rootCharacteristics, Spliterator<T> s) {
+            this.c = c;
+            this.rootCharacteristics = rootCharacteristics;
+            this.s = s;
+        }
+
+        SplitNode<T> fromSplit(Spliterator<T> split) {
+            return new SplitNode<>(c, rootCharacteristics, split);
+        }
+    }
+
+    /**
+     * 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).
+     */
+    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
+        // that when repeatedly split produces a right-balanced (and maybe degenerate) tree, or
+        // for a spliterator that is badly behaved.
+        Deque<SplitNode<T>> stack = new ArrayDeque<>();
+        stack.push(e);
+
+        int iteration = 0;
+        while (!stack.isEmpty()) {
+            assertTrue(iteration++ < MAXIMUM_STACK_CAPACITY, "Exceeded maximum stack modification count of 1 << 18");
+
+            e = stack.pop();
+            Spliterator<T> parentAndRightSplit = e.s;
+
+            long parentEstimateSize = parentAndRightSplit.estimateSize();
+            assertTrue(parentEstimateSize >= 0,
+                       String.format("Split size estimate %d < 0", parentEstimateSize));
+
+            long parentSize = parentAndRightSplit.getExactSizeIfKnown();
+            Spliterator<T> leftSplit = parentAndRightSplit.trySplit();
+            if (leftSplit == null) {
+                parentAndRightSplit.forEachRemaining(e.c);
+                continue;
+            }
+
+            assertSpliterator(leftSplit, e.rootCharacteristics);
+            assertSpliterator(parentAndRightSplit, e.rootCharacteristics);
+
+            if (parentEstimateSize != Long.MAX_VALUE && leftSplit.estimateSize() > 0
+                && parentAndRightSplit.estimateSize() > 0) {
+                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));
+            }
+            else {
+                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));
+            }
+
+            long leftSize = leftSplit.getExactSizeIfKnown();
+            long rightSize = parentAndRightSplit.getExactSizeIfKnown();
+            if (parentSize >= 0 && leftSize >= 0 && rightSize >= 0)
+                assertEquals(parentSize, leftSize + rightSize,
+                             String.format("exact left split size %d + exact right split size %d != parent exact split size %d",
+                                           leftSize, rightSize, parentSize));
+
+            // Add right side to stack first so left side is popped off first
+            stack.push(e.fromSplit(parentAndRightSplit));
+            stack.push(e.fromSplit(leftSplit));
+        }
+    }
+
+    private static void assertSpliterator(Spliterator<?> s, int rootCharacteristics) {
+        if ((rootCharacteristics & Spliterator.SUBSIZED) != 0) {
+            assertTrue(s.hasCharacteristics(Spliterator.SUBSIZED),
+                       "Child split is not SUBSIZED when root split is SUBSIZED");
+        }
+        assertSpliterator(s);
+    }
+
+    private static void assertSpliterator(Spliterator<?> s) {
+        if (s.hasCharacteristics(Spliterator.SUBSIZED)) {
+            assertTrue(s.hasCharacteristics(Spliterator.SIZED));
+        }
+        if (s.hasCharacteristics(Spliterator.SIZED)) {
+            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;
+    }
+
+    static<U> void mixedTraverseAndSplit(Consumer<U> b, Spliterator<U> splTop) {
+        Spliterator<U> spl1, spl2, spl3;
+        splTop.tryAdvance(b);
+        spl2 = splTop.trySplit();
+        if (spl2 != null) {
+            spl2.tryAdvance(b);
+            spl1 = spl2.trySplit();
+            if (spl1 != null) {
+                spl1.tryAdvance(b);
+                spl1.forEachRemaining(b);
+            }
+            spl2.tryAdvance(b);
+            spl2.forEachRemaining(b);
+        }
+        splTop.tryAdvance(b);
+        spl3 = splTop.trySplit();
+        if (spl3 != null) {
+            spl3.tryAdvance(b);
+            spl3.forEachRemaining(b);
+        }
+        splTop.tryAdvance(b);
+        splTop.forEachRemaining(b);
+    }
+
+    static void mixedTraverseAndSplit(IntConsumer b, Spliterator.OfInt splTop) {
+        Spliterator.OfInt spl1, spl2, spl3;
+        splTop.tryAdvance(b);
+        spl2 = splTop.trySplit();
+        if (spl2 != null) {
+            spl2.tryAdvance(b);
+            spl1 = spl2.trySplit();
+            if (spl1 != null) {
+                spl1.tryAdvance(b);
+                spl1.forEachRemaining(b);
+            }
+            spl2.tryAdvance(b);
+            spl2.forEachRemaining(b);
+        }
+        splTop.tryAdvance(b);
+        spl3 = splTop.trySplit();
+        if (spl3 != null) {
+            spl3.tryAdvance(b);
+            spl3.forEachRemaining(b);
+        }
+        splTop.tryAdvance(b);
+        splTop.forEachRemaining(b);
+    }
+    static void mixedTraverseAndSplit(LongConsumer b, Spliterator.OfLong splTop) {
+        Spliterator.OfLong spl1, spl2, spl3;
+        splTop.tryAdvance(b);
+        spl2 = splTop.trySplit();
+        if (spl2 != null) {
+            spl2.tryAdvance(b);
+            spl1 = spl2.trySplit();
+            if (spl1 != null) {
+                spl1.tryAdvance(b);
+                spl1.forEachRemaining(b);
+            }
+            spl2.tryAdvance(b);
+            spl2.forEachRemaining(b);
+        }
+        splTop.tryAdvance(b);
+        spl3 = splTop.trySplit();
+        if (spl3 != null) {
+            spl3.tryAdvance(b);
+            spl3.forEachRemaining(b);
+        }
+        splTop.tryAdvance(b);
+        splTop.forEachRemaining(b);
+    }
+
+    static void mixedTraverseAndSplit(DoubleConsumer b, Spliterator.OfDouble splTop) {
+        Spliterator.OfDouble spl1, spl2, spl3;
+        splTop.tryAdvance(b);
+        spl2 = splTop.trySplit();
+        if (spl2 != null) {
+            spl2.tryAdvance(b);
+            spl1 = spl2.trySplit();
+            if (spl1 != null) {
+                spl1.tryAdvance(b);
+                spl1.forEachRemaining(b);
+            }
+            spl2.tryAdvance(b);
+            spl2.forEachRemaining(b);
+        }
+        splTop.tryAdvance(b);
+        spl3 = splTop.trySplit();
+        if (spl3 != null) {
+            spl3.tryAdvance(b);
+            spl3.forEachRemaining(b);
+        }
+        splTop.tryAdvance(b);
+        splTop.forEachRemaining(b);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/bootlib/java/util/stream/StatefulTestOp.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+import java.util.function.IntFunction;
+
+/**
+ * The base type for a stateful test operation.
+ */
+interface StatefulTestOp<E> extends IntermediateTestOp<E, E> {
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static<T> AbstractPipeline chain(AbstractPipeline upstream,
+                                            StatefulTestOp op) {
+        switch (op.outputShape()) {
+            case REFERENCE:
+                return new ReferencePipeline.StatefulOp<Object, T>(upstream, op.inputShape(), op.opGetFlags()) {
+                    @Override
+                    Sink opWrapSink(int flags, Sink sink) {
+                        return op.opWrapSink(flags, isParallel(), sink);
+                    }
+
+                    @Override
+                    <P_IN> Spliterator<T> opEvaluateParallelLazy(PipelineHelper<T> helper,
+                                                                 Spliterator<P_IN> spliterator) {
+                        return op.opEvaluateParallelLazy(helper, spliterator);
+                    }
+
+                    @Override
+                    <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
+                                                      Spliterator<P_IN> spliterator,
+                                                      IntFunction<T[]> generator) {
+                        return op.opEvaluateParallel(helper, spliterator, generator);
+                    }
+                };
+            case INT_VALUE:
+                return new IntPipeline.StatefulOp<Object>(upstream, op.inputShape(), op.opGetFlags()) {
+                    @Override
+                    Sink opWrapSink(int flags, Sink sink) {
+                        return op.opWrapSink(flags, isParallel(), sink);
+                    }
+
+                    @Override
+                    <P_IN> Spliterator<Integer> opEvaluateParallelLazy(PipelineHelper<Integer> helper,
+                                                                 Spliterator<P_IN> spliterator) {
+                        return op.opEvaluateParallelLazy(helper, spliterator);
+                    }
+
+                    @Override
+                    <P_IN> Node<Integer> opEvaluateParallel(PipelineHelper<Integer> helper,
+                                                            Spliterator<P_IN> spliterator,
+                                                            IntFunction<Integer[]> generator) {
+                        return (Node<Integer>) op.opEvaluateParallel(helper, spliterator, generator);
+                    }
+                };
+            case LONG_VALUE:
+                return new LongPipeline.StatefulOp<Object>(upstream, op.inputShape(), op.opGetFlags()) {
+                    @Override
+                    Sink opWrapSink(int flags, Sink sink) {
+                        return op.opWrapSink(flags, isParallel(), sink);
+                    }
+
+                    @Override
+                    <P_IN> Spliterator<Long> opEvaluateParallelLazy(PipelineHelper<Long> helper,
+                                                                 Spliterator<P_IN> spliterator) {
+                        return op.opEvaluateParallelLazy(helper, spliterator);
+                    }
+
+                    @Override
+                    <P_IN> Node<Long> opEvaluateParallel(PipelineHelper<Long> helper,
+                                                         Spliterator<P_IN> spliterator,
+                                                         IntFunction<Long[]> generator) {
+                        return (Node<Long>) op.opEvaluateParallel(helper, spliterator, generator);
+                    }
+                };
+            case DOUBLE_VALUE:
+                return new DoublePipeline.StatefulOp<Object>(upstream, op.inputShape(), op.opGetFlags()) {
+                    @Override
+                    Sink opWrapSink(int flags, Sink sink) {
+                        return op.opWrapSink(flags, isParallel(), sink);
+                    }
+
+                    @Override
+                    <P_IN> Spliterator<Double> opEvaluateParallelLazy(PipelineHelper<Double> helper,
+                                                                    Spliterator<P_IN> spliterator) {
+                        return op.opEvaluateParallelLazy(helper, spliterator);
+                    }
+
+                    @Override
+                    <P_IN> Node<Double> opEvaluateParallel(PipelineHelper<Double> helper,
+                                                           Spliterator<P_IN> spliterator,
+                                                           IntFunction<Double[]> generator) {
+                        return (Node<Double>) op.opEvaluateParallel(helper, spliterator, generator);
+                    }
+                };
+            default: throw new IllegalStateException(op.outputShape().toString());
+        }
+    }
+
+    default StreamShape inputShape() { return StreamShape.REFERENCE; }
+
+    default StreamShape outputShape() { return StreamShape.REFERENCE; }
+
+    default int opGetFlags() { return 0; }
+
+    Sink<E> opWrapSink(int flags, boolean parallel, Sink<E> sink);
+
+    @SuppressWarnings("unchecked")
+    default <P_IN> Spliterator<E> opEvaluateParallelLazy(PipelineHelper<E> helper,
+                                                         Spliterator<P_IN> spliterator) {
+        return opEvaluateParallel(helper, spliterator, i -> (E[]) new Object[i]).spliterator();
+    }
+
+    <P_IN> Node<E> opEvaluateParallel(PipelineHelper<E> helper,
+                                      Spliterator<P_IN> spliterator,
+                                      IntFunction<E[]> generator);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/bootlib/java/util/stream/StatelessTestOp.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+package java.util.stream;
+
+/**
+ * The base type of a stateless test operation
+ */
+interface StatelessTestOp<E_IN, E_OUT> extends IntermediateTestOp<E_IN, E_OUT> {
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static<T> AbstractPipeline chain(AbstractPipeline upstream,
+                                            StatelessTestOp<?, T> op) {
+        int flags = op.opGetFlags();
+        switch (op.outputShape()) {
+            case REFERENCE:
+                return new ReferencePipeline.StatelessOp<Object, T>(upstream, op.inputShape(), flags) {
+                    public Sink opWrapSink(int flags, Sink<T> sink) {
+                        return op.opWrapSink(flags, isParallel(), sink);
+                    }
+                };
+            case INT_VALUE:
+                return new IntPipeline.StatelessOp<Object>(upstream, op.inputShape(), flags) {
+                    public Sink opWrapSink(int flags, Sink sink) {
+                        return op.opWrapSink(flags, isParallel(), sink);
+                    }
+                };
+            case LONG_VALUE:
+                return new LongPipeline.StatelessOp<Object>(upstream, op.inputShape(), flags) {
+                    @Override
+                    Sink opWrapSink(int flags, Sink sink) {
+                        return op.opWrapSink(flags, isParallel(), sink);
+                    }
+                };
+            case DOUBLE_VALUE:
+                return new DoublePipeline.StatelessOp<Object>(upstream, op.inputShape(), flags) {
+                    @Override
+                    Sink opWrapSink(int flags, Sink sink) {
+                        return op.opWrapSink(flags, isParallel(), sink);
+                    }
+                };
+            default: throw new IllegalStateException(op.outputShape().toString());
+        }
+    }
+
+    default StreamShape inputShape() { return StreamShape.REFERENCE; }
+
+    default StreamShape outputShape() { return StreamShape.REFERENCE; }
+
+    default int opGetFlags() { return 0; }
+
+    Sink<E_IN> opWrapSink(int flags, boolean parallel, Sink<E_OUT> sink);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/bootlib/java/util/stream/StreamOpFlagTestHelper.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package java.util.stream;
+
+import java.util.EnumSet;
+
+public class StreamOpFlagTestHelper {
+
+    /** EnumSet containing stream flags */
+    private static final EnumSet<StreamOpFlag> allStreamFlags;
+
+    static {
+        allStreamFlags = EnumSet.allOf(StreamOpFlag.class);
+        for (StreamOpFlag f : EnumSet.allOf(StreamOpFlag.class))
+            if (!f.isStreamFlag())
+                allStreamFlags.remove(f);
+    }
+
+
+    static EnumSet<StreamOpFlag> allStreamFlags() {
+        // EnumSet is mutable
+        return allStreamFlags.clone();
+    }
+
+    public static boolean isStreamOrdered(Stream<?> s) {
+        return StreamOpFlag.ORDERED.isKnown(OpTestCase.getStreamFlags(s));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/bootlib/java/util/stream/StreamTestDataProvider.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package java.util.stream;
+
+import org.testng.annotations.DataProvider;
+
+import java.util.*;
+import java.util.Spliterators;
+import java.util.function.Supplier;
+
+/**
+ * StreamTestDataProvider
+ *
+ * @author Brian Goetz
+ */
+/** TestNG DataProvider for ref-valued streams */
+public class StreamTestDataProvider {
+    private static final Integer[] to0 = new Integer[0];
+    private static final Integer[] to1 = new Integer[1];
+    private static final Integer[] to10 = new Integer[10];
+    private static final Integer[] to100 = new Integer[100];
+    private static final Integer[] to1000 = new Integer[1000];
+    private static final Integer[] reversed = new Integer[100];
+    private static final Integer[] ones = new Integer[100];
+    private static final Integer[] twice = new Integer[200];
+    private static final Integer[] pseudoRandom;
+
+    private static final Object[][] testData;
+    private static final Object[][] withNullTestData;
+    private static final Object[][] spliteratorTestData;
+
+    static {
+        Integer[][] arrays = {to0, to1, to10, to100, to1000};
+        for (Integer[] arr : arrays) {
+            for (int i = 0; i < arr.length; i++) {
+                arr[i] = i;
+            }
+        }
+        for (int i = 0; i < reversed.length; i++) {
+            reversed[i] = reversed.length - i;
+        }
+        for (int i = 0; i < ones.length; i++) {
+            ones[i] = 1;
+        }
+        System.arraycopy(to100, 0, twice, 0, to100.length);
+        System.arraycopy(to100, 0, twice, to100.length, to100.length);
+        pseudoRandom = new Integer[LambdaTestHelpers.LONG_STRING.length()];
+        for (int i = 0; i < LambdaTestHelpers.LONG_STRING.length(); i++) {
+            pseudoRandom[i] = (int) LambdaTestHelpers.LONG_STRING.charAt(i);
+        }
+    }
+
+    static final Object[][] arrays = {
+            {"empty", to0},
+            {"0..1", to1},
+            {"0..10", to10},
+            {"0..100", to100},
+            {"0..1000", to1000},
+            {"100x[1]", ones},
+            {"2x[0..100]", twice},
+            {"reverse 0..100", reversed},
+            {"pseudorandom", pseudoRandom}
+    };
+
+    static {
+        {
+            List<Object[]> list = new ArrayList<>();
+            for (Object[] data : arrays) {
+                final Object name = data[0];
+                final Integer[] ints = (Integer[])data[1];
+                final List<Integer> intsAsList = Arrays.asList(ints);
+
+                list.add(arrayDataDescr("array:" + name, ints));
+                list.add(collectionDataDescr("ArrayList.asList:" + name, intsAsList));
+                list.add(collectionDataDescr("ArrayList:" + name, new ArrayList<>(intsAsList)));
+                list.add(streamDataDescr("DelegatingStream(ArrayList):" + name,
+                                         () -> new ArrayList<>(intsAsList).stream()));
+                List<Integer> aList = new ArrayList<>(intsAsList);
+                list.add(collectionDataDescr("ArrayList.Sublist:" + name,
+                                             (ints.length) <= 1 ? aList.subList(0, 0) : aList.subList(1, ints.length / 2)));
+                list.add(collectionDataDescr("LinkedList:" + name, new LinkedList<>(intsAsList)));
+                list.add(collectionDataDescr("HashSet:" + name, new HashSet<>(intsAsList)));
+                list.add(collectionDataDescr("LinkedHashSet:" + name, new LinkedHashSet<>(intsAsList)));
+                list.add(collectionDataDescr("TreeSet:" + name, new TreeSet<>(intsAsList)));
+                SpinedBuffer<Integer> spinedBuffer = new SpinedBuffer<>();
+                intsAsList.forEach(spinedBuffer);
+                list.add(sbDataDescr("SpinedBuffer:" + name, spinedBuffer));
+
+                // @@@ Add more
+            }
+            testData = list.toArray(new Object[0][]);
+        }
+
+        // Simple combination of numbers and null values, probably excessive but may catch
+        // errors for initialization/termination/sequence
+        // @@@ This is separate from the other data for now until nulls are consitently supported by
+        // all operations
+        {
+            List<Object[]> list = new ArrayList<>();
+            int size = 5;
+            for (int i = 0; i < (1 << size) - 2; i++) {
+                Integer[] content = new Integer[size];
+                for (int e = 0; e < size; e++) {
+                    content[e] = (i & (1 << e)) > 0 ? e + 1 : null;
+                }
+
+                // ORDERED
+                list.add(arrayDataDescr("array:" + i, content));
+                // not ORDERED, DISTINCT
+                list.add(collectionDataDescr("HashSet:" + i, new HashSet<>(Arrays.asList(content))));
+            }
+
+            withNullTestData = list.toArray(new Object[0][]);
+        }
+
+        {
+            List<Object[]> spliterators = new ArrayList<>();
+            for (Object[] data : arrays) {
+                final Object name = data[0];
+                final Integer[] ints = (Integer[])data[1];
+
+                spliterators.add(splitDescr("Arrays.s(array):" + name,
+                                            () -> Arrays.spliterator(ints)));
+                spliterators.add(splitDescr("arrays.s(array,o,l):" + name,
+                                            () -> Arrays.spliterator(ints, 0, ints.length/2)));
+                spliterators.add(splitDescr("SpinedBuffer.s():" + name,
+                                            () -> {
+                                                SpinedBuffer<Integer> sb = new SpinedBuffer<>();
+                                                for (Integer i : ints)
+                                                    sb.accept(i);
+                                                return sb.spliterator();
+                                            }));
+                spliterators.add(splitDescr("Iterators.s(Arrays.s(array).iterator(), size):" + name,
+                                            () -> Spliterators.spliterator(Arrays.asList(ints).iterator(), ints.length, 0)));
+                spliterators.add(splitDescr("Iterators.s(Arrays.s(array).iterator()):" + name,
+                                            () -> Spliterators.spliteratorUnknownSize(Arrays.asList(ints).iterator(), 0)));
+                // @@@ Add map and collection spliterators when spliterator() is exposed on Collection or Iterable
+            }
+            spliteratorTestData = spliterators.toArray(new Object[0][]);
+        }
+    }
+
+    static <T> Object[] arrayDataDescr(String description, T[] data) {
+        return new Object[] { description, TestData.Factory.ofArray(description, data)};
+    }
+
+    static <T> Object[] streamDataDescr(String description, Supplier<Stream<T>> supplier) {
+        return new Object[] { description, TestData.Factory.ofSupplier(description, supplier)};
+    }
+
+    static <T> Object[] collectionDataDescr(String description, Collection<T> data) {
+        return new Object[] { description, TestData.Factory.ofCollection(description, data)};
+    }
+
+    static <T> Object[] sbDataDescr(String description, SpinedBuffer<T> data) {
+        return new Object[] { description, TestData.Factory.ofSpinedBuffer(description, data)};
+    }
+
+    static <T> Object[] splitDescr(String description, Supplier<Spliterator<T>> ss) {
+        return new Object[] { description, ss };
+    }
+
+    // Return an array of ( String name, StreamTestData<Integer> )
+    @DataProvider(name = "StreamTestData<Integer>")
+    public static Object[][] makeStreamTestData() {
+        return testData;
+    }
+
+    @DataProvider(name = "withNull:StreamTestData<Integer>")
+    public static Object[][] makeStreamWithNullTestData() {
+        return withNullTestData;
+    }
+
+    // returns an array of (String name, Supplier<Spliterator<Integer>>)
+    @DataProvider(name = "Spliterator<Integer>")
+    public static Object[][] spliteratorProvider() {
+        return spliteratorTestData;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/bootlib/java/util/stream/StreamTestScenario.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package java.util.stream;
+
+import java.util.Iterator;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * Test scenarios for reference streams.
+ *
+ * Each scenario is provided with a data source, a function that maps a fresh
+ * stream (as provided by the data source) to a new stream, and a sink to
+ * receive results.  Each scenario describes a different way of computing the
+ * stream contents.  The test driver will ensure that all scenarios produce
+ * the same output (modulo allowable differences in ordering).
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public enum StreamTestScenario implements OpTestCase.BaseStreamTestScenario {
+
+    STREAM_FOR_EACH(false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            Stream<U> s = m.apply(data.stream());
+            if (s.isParallel()) {
+                s = s.sequential();
+            }
+            s.forEach(b);
+        }
+    },
+
+    // Collec to list
+    STREAM_COLLECT(false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (U t : m.apply(data.stream()).collect(Collectors.toList())) {
+                b.accept(t);
+            }
+        }
+    },
+
+    // To array
+    STREAM_TO_ARRAY(false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (Object t : m.apply(data.stream()).toArray()) {
+                b.accept((U) t);
+            }
+        }
+    },
+
+    // Wrap as stream, and iterate in pull mode
+    STREAM_ITERATOR(false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (Iterator<U> seqIter = m.apply(data.stream()).iterator(); seqIter.hasNext(); )
+                b.accept(seqIter.next());
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate in pull mode
+    STREAM_SPLITERATOR(false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (Spliterator<U> spl = m.apply(data.stream()).spliterator(); spl.tryAdvance(b); ) { }
+        }
+    },
+
+    // Wrap as stream, spliterate, then split a few times mixing advances with forEach
+    STREAM_SPLITERATOR_WITH_MIXED_TRAVERSE_AND_SPLIT(false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            SpliteratorTestHelper.mixedTraverseAndSplit(b, m.apply(data.stream()).spliterator());
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate in pull mode
+    STREAM_SPLITERATOR_FOREACH(false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            m.apply(data.stream()).spliterator().forEachRemaining(b);
+        }
+    },
+
+    // Wrap as parallel stream + sequential
+    PAR_STREAM_SEQUENTIAL_FOR_EACH(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            m.apply(data.parallelStream()).sequential().forEach(b);
+        }
+    },
+
+    // Wrap as parallel stream + forEachOrdered
+    PAR_STREAM_FOR_EACH_ORDERED(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            // @@@ Want to explicitly select ordered equalator
+            m.apply(data.parallelStream()).forEachOrdered(b);
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate sequentially
+    PAR_STREAM_SPLITERATOR(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (Spliterator<U> spl = m.apply(data.parallelStream()).spliterator(); spl.tryAdvance(b); ) { }
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate sequentially
+    PAR_STREAM_SPLITERATOR_FOREACH(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            m.apply(data.parallelStream()).spliterator().forEachRemaining(b);
+        }
+    },
+
+    // Wrap as parallel stream + toArray
+    PAR_STREAM_TO_ARRAY(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (Object t : m.apply(data.parallelStream()).toArray())
+                b.accept((U) t);
+        }
+    },
+
+    // Wrap as parallel stream, get the spliterator, wrap as a stream + toArray
+    PAR_STREAM_SPLITERATOR_STREAM_TO_ARRAY(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            Stream<U> s = m.apply(data.parallelStream());
+            Spliterator<U> sp = s.spliterator();
+            Stream<U> ss = StreamSupport.parallelStream(() -> sp,
+                                                        StreamOpFlag.toCharacteristics(OpTestCase.getStreamFlags(s))
+                                                        | (sp.getExactSizeIfKnown() < 0 ? 0 : Spliterator.SIZED));
+            for (Object t : ss.toArray())
+                b.accept((U) t);
+        }
+    },
+
+    // Wrap as parallel stream + toArray and clear SIZED flag
+    PAR_STREAM_TO_ARRAY_CLEAR_SIZED(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            S_IN pipe1 = (S_IN) OpTestCase.chain(data.parallelStream(),
+                                                 new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+            Stream<U> pipe2 = m.apply(pipe1);
+
+            for (Object t : pipe2.toArray())
+                b.accept((U) t);
+        }
+    },
+
+    // Wrap as parallel + collect
+    PAR_STREAM_COLLECT(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (U u : m.apply(data.parallelStream()).collect(Collectors.toList()))
+                b.accept(u);
+        }
+    },
+
+    // Wrap sequential as parallel, + collect
+    STREAM_TO_PAR_STREAM_COLLECT(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (U u : m.apply(data.stream().parallel()).collect(Collectors.toList()))
+                b.accept(u);
+        }
+    },
+
+    // Wrap parallel as sequential,, + collect
+    PAR_STREAM_TO_STREAM_COLLECT(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (U u : m.apply(data.parallelStream().sequential()).collect(Collectors.toList()))
+                b.accept(u);
+        }
+    },
+    ;
+
+    private boolean isParallel;
+
+    StreamTestScenario(boolean isParallel) {
+        this.isParallel = isParallel;
+    }
+
+    public StreamShape getShape() {
+        return StreamShape.REFERENCE;
+    }
+
+    public boolean isParallel() {
+        return isParallel;
+    }
+
+    public <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+    void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m) {
+        _run(data, b, (Function<S_IN, Stream<U>>) m);
+    }
+
+    abstract <T, U, S_IN extends BaseStream<T, S_IN>>
+    void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/bootlib/java/util/stream/TestData.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,355 @@
+/*
+ * 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.
+ *
+ * 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 java.util.stream;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.DoubleConsumer;
+import java.util.function.Function;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+import java.util.function.Supplier;
+import java.util.function.ToIntFunction;
+
+/** Describes a test data set for use in stream tests */
+public interface TestData<T, S extends BaseStream<T, S>>
+        extends Iterable<T> {
+
+    default int size() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    default Iterator<T> iterator() {
+        return Spliterators.iteratorFromSpliterator(spliterator());
+    }
+
+    Spliterator<T> spliterator();
+
+    default boolean isOrdered() {
+        return spliterator().hasCharacteristics(Spliterator.ORDERED);
+    }
+
+    StreamShape getShape();
+
+    default <A extends Collection<? super T>> A into(A target) {
+        spliterator().forEachRemaining(target::add);
+        return target;
+    }
+
+    S stream();
+
+    S parallelStream();
+
+    public interface OfRef<T> extends TestData<T, Stream<T>> { }
+
+    public interface OfInt extends TestData<Integer, IntStream> { }
+
+    public interface OfLong extends TestData<Long, LongStream> { }
+
+    public interface OfDouble extends TestData<Double, DoubleStream> { }
+
+    // @@@ Temporary garbage class to avoid triggering bugs with lambdas in static methods in interfaces
+    public static class Factory {
+        public static <T> OfRef<T> ofArray(String name, T[] array) {
+            return new AbstractTestData.RefTestData<>(name, array, Arrays::stream, a -> Arrays.stream(a).parallel(),
+                                                      Arrays::spliterator, a -> a.length);
+        }
+
+        public static <T> OfRef<T> ofCollection(String name, Collection<T> collection) {
+            return new AbstractTestData.RefTestData<>(name, collection, Collection::stream, Collection::parallelStream,
+                                                      Collection::spliterator, Collection::size);
+        }
+
+        public static <T> OfRef<T> ofSpinedBuffer(String name, SpinedBuffer<T> buffer) {
+            return new AbstractTestData.RefTestData<>(name, buffer,
+                                                      b -> StreamSupport.stream(b.spliterator()),
+                                                      b -> StreamSupport.parallelStream(b.spliterator()),
+                                                      SpinedBuffer::spliterator,
+                                                      b -> (int) b.count());
+        }
+
+        public static <T> OfRef<T> ofSupplier(String name, Supplier<Stream<T>> supplier) {
+            return new AbstractTestData.RefTestData<>(name, supplier,
+                                                      Supplier::get,
+                                                      s -> s.get().parallel(),
+                                                      s -> s.get().spliterator(),
+                                                      s -> (int) s.get().spliterator().getExactSizeIfKnown());
+        }
+
+        public static <T> OfRef<T> ofRefNode(String name, Node<T> node) {
+            return new AbstractTestData.RefTestData<>(name, node,
+                                                      n -> StreamSupport.stream(n::spliterator, Spliterator.SIZED | Spliterator.ORDERED),
+                                                      n -> StreamSupport.parallelStream(n::spliterator, Spliterator.SIZED | Spliterator.ORDERED),
+                                                      Node::spliterator,
+                                                      n -> (int) n.count());
+        }
+
+        // int factories
+        public static <T> OfInt ofArray(String name, int[] array) {
+            return new AbstractTestData.IntTestData<>(name, array, Arrays::stream, a -> Arrays.stream(a).parallel(),
+                                                      Arrays::spliterator, a -> a.length);
+        }
+
+        public static OfInt ofSpinedBuffer(String name, SpinedBuffer.OfInt buffer) {
+            return new AbstractTestData.IntTestData<>(name, buffer,
+                                                      b -> StreamSupport.intStream(b.spliterator()),
+                                                      b -> StreamSupport.intParallelStream(b.spliterator()),
+                                                      SpinedBuffer.OfInt::spliterator,
+                                                      b -> (int) b.count());
+        }
+
+        public static OfInt ofIntSupplier(String name, Supplier<IntStream> supplier) {
+            return new AbstractTestData.IntTestData<>(name, supplier,
+                                                      Supplier::get,
+                                                      s -> s.get().parallel(),
+                                                      s -> s.get().spliterator(),
+                                                      s -> (int) s.get().spliterator().getExactSizeIfKnown());
+        }
+
+        public static OfInt ofNode(String name, Node.OfInt node) {
+            int characteristics = Spliterator.SIZED | Spliterator.ORDERED;
+            return new AbstractTestData.IntTestData<>(name, node,
+                                                      n -> StreamSupport.intStream(n::spliterator, characteristics),
+                                                      n -> StreamSupport.intParallelStream(n::spliterator, characteristics),
+                                                      Node.OfInt::spliterator,
+                                                      n -> (int) n.count());
+        }
+
+        // long factories
+        public static <T> OfLong ofArray(String name, long[] array) {
+            return new AbstractTestData.LongTestData<>(name, array, Arrays::stream, a -> Arrays.stream(a).parallel(),
+                                                       Arrays::spliterator, a -> a.length);
+        }
+
+        public static OfLong ofSpinedBuffer(String name, SpinedBuffer.OfLong buffer) {
+            return new AbstractTestData.LongTestData<>(name, buffer,
+                                                      b -> StreamSupport.longStream(b.spliterator()),
+                                                      b -> StreamSupport.longParallelStream(b.spliterator()),
+                                                      SpinedBuffer.OfLong::spliterator,
+                                                      b -> (int) b.count());
+        }
+
+        public static OfLong ofLongSupplier(String name, Supplier<LongStream> supplier) {
+            return new AbstractTestData.LongTestData<>(name, supplier,
+                                                      Supplier::get,
+                                                      s -> s.get().parallel(),
+                                                      s -> s.get().spliterator(),
+                                                      s -> (int) s.get().spliterator().getExactSizeIfKnown());
+        }
+
+        public static OfLong ofNode(String name, Node.OfLong node) {
+            int characteristics = Spliterator.SIZED | Spliterator.ORDERED;
+            return new AbstractTestData.LongTestData<>(name, node,
+                                                      n -> StreamSupport.longStream(n::spliterator, characteristics),
+                                                      n -> StreamSupport.longParallelStream(n::spliterator, characteristics),
+                                                      Node.OfLong::spliterator,
+                                                      n -> (int) n.count());
+        }
+
+        // double factories
+        public static <T> OfDouble ofArray(String name, double[] array) {
+            return new AbstractTestData.DoubleTestData<>(name, array, Arrays::stream, a -> Arrays.stream(a).parallel(),
+                                                         Arrays::spliterator, a -> a.length);
+        }
+
+        public static OfDouble ofSpinedBuffer(String name, SpinedBuffer.OfDouble buffer) {
+            return new AbstractTestData.DoubleTestData<>(name, buffer,
+                                                         b -> StreamSupport.doubleStream(b.spliterator()),
+                                                         b -> StreamSupport.doubleParallelStream(b.spliterator()),
+                                                         SpinedBuffer.OfDouble::spliterator,
+                                                         b -> (int) b.count());
+        }
+
+        public static OfDouble ofDoubleSupplier(String name, Supplier<DoubleStream> supplier) {
+            return new AbstractTestData.DoubleTestData<>(name, supplier,
+                                                         Supplier::get,
+                                                         s -> s.get().parallel(),
+                                                         s -> s.get().spliterator(),
+                                                         s -> (int) s.get().spliterator().getExactSizeIfKnown());
+        }
+
+        public static OfDouble ofNode(String name, Node.OfDouble node) {
+            int characteristics = Spliterator.SIZED | Spliterator.ORDERED;
+            return new AbstractTestData.DoubleTestData<>(name, node,
+                                                         n -> StreamSupport.doubleStream(n::spliterator, characteristics),
+                                                         n -> StreamSupport.doubleParallelStream(n::spliterator, characteristics),
+                                                         Node.OfDouble::spliterator,
+                                                         n -> (int) n.count());
+        }
+    }
+
+
+    abstract class AbstractTestData<T, S extends BaseStream<T, S>,
+            T_STATE,
+                                    T_SPLITR extends Spliterator<T>>
+            implements TestData<T, S> {
+        private final String name;
+        private final StreamShape shape;
+        protected final T_STATE state;
+        private final ToIntFunction<T_STATE> sizeFn;
+        private final Function<T_STATE, S> streamFn;
+        private final Function<T_STATE, S> parStreamFn;
+        private final Function<T_STATE, T_SPLITR> splitrFn;
+
+        AbstractTestData(String name,
+                         StreamShape shape,
+                         T_STATE state,
+                         Function<T_STATE, S> streamFn,
+                         Function<T_STATE, S> parStreamFn,
+                         Function<T_STATE, T_SPLITR> splitrFn,
+                         ToIntFunction<T_STATE> sizeFn) {
+            this.name = name;
+            this.shape = shape;
+            this.state = state;
+            this.streamFn = streamFn;
+            this.parStreamFn = parStreamFn;
+            this.splitrFn = splitrFn;
+            this.sizeFn = sizeFn;
+        }
+
+        @Override
+        public StreamShape getShape() {
+            return shape;
+        }
+
+        @Override
+        public String toString() {
+            return getClass().getSimpleName() + "[" + name + "]";
+        }
+
+        @Override
+        public int size() {
+            return sizeFn.applyAsInt(state);
+        }
+
+        @Override
+        public T_SPLITR spliterator() {
+            return splitrFn.apply(state);
+        }
+
+        @Override
+        public S stream() {
+            return streamFn.apply(state);
+        }
+
+        @Override
+        public S parallelStream() {
+            return parStreamFn.apply(state);
+        }
+
+        public static class RefTestData<T, I>
+                extends AbstractTestData<T, Stream<T>, I, Spliterator<T>>
+                implements TestData.OfRef<T> {
+
+            protected RefTestData(String name,
+                                  I state,
+                                  Function<I, Stream<T>> streamFn,
+                                  Function<I, Stream<T>> parStreamFn,
+                                  Function<I, Spliterator<T>> splitrFn,
+                                  ToIntFunction<I> sizeFn) {
+                super(name, StreamShape.REFERENCE, state, streamFn, parStreamFn, splitrFn, sizeFn);
+            }
+
+        }
+
+        static class IntTestData<I>
+                extends AbstractTestData<Integer, IntStream, I, Spliterator.OfInt>
+                implements TestData.OfInt {
+
+            protected IntTestData(String name,
+                                  I state,
+                                  Function<I, IntStream> streamFn,
+                                  Function<I, IntStream> parStreamFn,
+                                  Function<I, Spliterator.OfInt> splitrFn,
+                                  ToIntFunction<I> sizeFn) {
+                super(name, StreamShape.INT_VALUE, state, streamFn, parStreamFn, splitrFn, sizeFn);
+            }
+
+            @Override
+            public PrimitiveIterator.OfInt iterator() {
+                return Spliterators.iteratorFromSpliterator(spliterator());
+            }
+
+            @Override
+            public <A extends Collection<? super Integer>> A into(A target) {
+                spliterator().forEachRemaining((IntConsumer) target::add);
+                return target;
+            }
+        }
+
+        static class LongTestData<I>
+                extends AbstractTestData<Long, LongStream, I, Spliterator.OfLong>
+                implements TestData.OfLong {
+
+            protected LongTestData(String name,
+                                   I state,
+                                   Function<I, LongStream> streamFn,
+                                   Function<I, LongStream> parStreamFn,
+                                   Function<I, Spliterator.OfLong> splitrFn,
+                                   ToIntFunction<I> sizeFn) {
+                super(name, StreamShape.LONG_VALUE, state, streamFn, parStreamFn, splitrFn, sizeFn);
+            }
+
+            @Override
+            public PrimitiveIterator.OfLong iterator() {
+                return Spliterators.iteratorFromSpliterator(spliterator());
+            }
+
+            @Override
+            public <A extends Collection<? super Long>> A into(A target) {
+                spliterator().forEachRemaining((LongConsumer) target::add);
+                return target;
+            }
+        }
+
+        static class DoubleTestData<I>
+                extends AbstractTestData<Double, DoubleStream, I, Spliterator.OfDouble>
+                implements OfDouble {
+
+            protected DoubleTestData(String name,
+                                     I state,
+                                     Function<I, DoubleStream> streamFn,
+                                     Function<I, DoubleStream> parStreamFn,
+                                     Function<I, Spliterator.OfDouble> splitrFn,
+                                     ToIntFunction<I> sizeFn) {
+                super(name, StreamShape.DOUBLE_VALUE, state, streamFn, parStreamFn, splitrFn, sizeFn);
+            }
+
+            @Override
+            public PrimitiveIterator.OfDouble iterator() {
+                return Spliterators.iteratorFromSpliterator(spliterator());
+            }
+
+            @Override
+            public <A extends Collection<? super Double>> A into(A target) {
+                spliterator().forEachRemaining((DoubleConsumer) target::add);
+                return target;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/bootlib/java/util/stream/TestFlagExpectedOp.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package java.util.stream;
+
+import org.testng.Assert;
+
+import java.util.EnumSet;
+
+class TestFlagExpectedOp<T> extends FlagDeclaringOp<T> {
+
+    static class Builder<T> {
+        final int flags;
+        StreamShape shape = StreamShape.REFERENCE;
+
+        EnumSet<StreamOpFlag> known = EnumSet.noneOf(StreamOpFlag.class);
+        EnumSet<StreamOpFlag> preserve = EnumSet.noneOf(StreamOpFlag.class);
+        EnumSet<StreamOpFlag> notKnown = EnumSet.noneOf(StreamOpFlag.class);
+
+        Builder(int flags) {
+            this.flags = flags;
+        }
+
+        Builder<T> known(EnumSet<StreamOpFlag> known) {
+            this.known = known;
+            return this;
+        }
+
+        Builder<T> preserve(EnumSet<StreamOpFlag> preserve) {
+            this.preserve = preserve;
+            return this;
+        }
+
+        Builder<T> notKnown(EnumSet<StreamOpFlag> notKnown) {
+            this.notKnown = notKnown;
+            return this;
+        }
+
+        Builder<T> shape(StreamShape shape) {
+            this.shape = shape;
+            return this;
+        }
+
+        TestFlagExpectedOp<T> build() {
+            return new TestFlagExpectedOp<>(flags, known, preserve, notKnown, shape);
+        }
+    }
+
+    final EnumSet<StreamOpFlag> known;
+    final EnumSet<StreamOpFlag> preserve;
+    final EnumSet<StreamOpFlag> notKnown;
+    final StreamShape shape;
+
+    TestFlagExpectedOp(int flags,
+                       EnumSet<StreamOpFlag> known,
+                       EnumSet<StreamOpFlag> preserve,
+                       EnumSet<StreamOpFlag> notKnown) {
+        this(flags, known, preserve, notKnown, StreamShape.REFERENCE);
+    }
+
+    TestFlagExpectedOp(int flags,
+                       EnumSet<StreamOpFlag> known,
+                       EnumSet<StreamOpFlag> preserve,
+                       EnumSet<StreamOpFlag> notKnown,
+                       StreamShape shape) {
+        super(flags);
+        this.known = known;
+        this.preserve = preserve;
+        this.notKnown = notKnown;
+        this.shape = shape;
+    }
+
+    @Override
+    public StreamShape outputShape() {
+        return shape;
+    }
+
+    @Override
+    public StreamShape inputShape() {
+        return shape;
+    }
+
+    @Override
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public Sink<T> opWrapSink(int flags, boolean parallel, Sink upstream) {
+        assertFlags(flags);
+        return upstream;
+    }
+
+    private void assertFlags(int flags) {
+        for (StreamOpFlag f : known) {
+            Assert.assertTrue(f.isKnown(flags),
+                              String.format("Flag %s is not known, but should be known.", f.toString()));
+        }
+
+        for (StreamOpFlag f : preserve) {
+            Assert.assertTrue(f.isPreserved(flags),
+                              String.format("Flag %s is not preserved, but should be preserved.", f.toString()));
+        }
+
+        for (StreamOpFlag f : notKnown) {
+            Assert.assertFalse(f.isKnown(flags),
+                               String.format("Flag %s is known, but should be not known.", f.toString()));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/boottest/TEST.properties	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,5 @@
+# This file identifies root(s) of the test-ng hierarchy.
+
+TestNG.dirs = .
+bootclasspath.dirs = .
+lib.dirs = /java/util/stream/bootlib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/boottest/java/util/stream/DoubleNodeTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.PrimitiveIterator;
+import java.util.Spliterators;
+import java.util.function.Function;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+@Test
+public class DoubleNodeTest extends OpTestCase {
+
+    @DataProvider(name = "nodes")
+    public Object[][] createSizes() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : Arrays.asList(0, 1, 4, 15, 16, 17, 127, 128, 129, 1000)) {
+            double[] array = new double[size];
+            for (int i = 0; i < array.length; i++) {
+                array[i] = i;
+            }
+
+            List<Node<Double>> nodes = new ArrayList<>();
+
+            nodes.add(Nodes.node(array));
+            nodes.add(degenerateTree(Spliterators.iteratorFromSpliterator(Arrays.spliterator(array))));
+            nodes.add(tree(toList(array), l -> Nodes.node(toDoubleArray(l))));
+            nodes.add(fill(array, Nodes.doubleBuilder(array.length)));
+            nodes.add(fill(array, Nodes.doubleBuilder()));
+
+            for (Node<Double> node : nodes) {
+                params.add(new Object[]{array, node});
+            }
+
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    private static void assertEqualsListDoubleArray(List<Double> list, double[] array) {
+        assertEquals(list.size(), array.length);
+        for (int i = 0; i < array.length; i++)
+            assertEquals(array[i], list.get(i));
+    }
+
+    private List<Double> toList(double[] a) {
+        List<Double> l = new ArrayList<>();
+        for (double i : a) {
+            l.add(i);
+        }
+
+        return l;
+    }
+
+    private double[] toDoubleArray(List<Double> l) {
+        double[] a = new double[l.size()];
+
+        int i = 0;
+        for (Double e : l) {
+            a[i++] = e;
+        }
+        return a;
+    }
+
+    private Node.OfDouble fill(double[] array, Node.Builder.OfDouble nb) {
+        nb.begin(array.length);
+        for (double i : array)
+            nb.accept(i);
+        nb.end();
+        return nb.build();
+    }
+
+    private Node.OfDouble degenerateTree(PrimitiveIterator.OfDouble it) {
+        if (!it.hasNext()) {
+            return Nodes.node(new double[0]);
+        }
+
+        double i = it.nextDouble();
+        if (it.hasNext()) {
+            return new Nodes.DoubleConcNode(Nodes.node(new double[] {i}), degenerateTree(it));
+        }
+        else {
+            return Nodes.node(new double[] {i});
+        }
+    }
+
+    private Node.OfDouble tree(List<Double> l, Function<List<Double>, Node.OfDouble> m) {
+        if (l.size() < 3) {
+            return m.apply(l);
+        }
+        else {
+            return new Nodes.DoubleConcNode(
+                    tree(l.subList(0, l.size() / 2), m),
+                    tree(l.subList(l.size() / 2, l.size()), m));
+        }
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testAsArray(double[] array, Node.OfDouble n) {
+        assertEquals(n.asDoubleArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testFlattenAsArray(double[] array, Node.OfDouble n) {
+        assertEquals(Nodes.flattenDouble(n).asDoubleArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testCopyTo(double[] array, Node.OfDouble n) {
+        double[] copy = new double[(int) n.count()];
+        n.copyInto(copy, 0);
+
+        assertEquals(copy, array);
+    }
+
+    @Test(dataProvider = "nodes", groups = { "serialization-hostile" })
+    public void testForEach(double[] array, Node.OfDouble n) {
+        List<Double> l = new ArrayList<>((int) n.count());
+        n.forEach((double e) -> {
+            l.add(e);
+        });
+
+        assertEqualsListDoubleArray(l, array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testStreams(double[] array, Node.OfDouble n) {
+        TestData.OfDouble data = TestData.Factory.ofNode("Node", n);
+
+        exerciseOps(data, s -> s);
+
+        exerciseTerminalOps(data, s -> s.toArray());
+    }
+
+    @Test(dataProvider = "nodes", groups={ "serialization-hostile" })
+    // throws SOE on serialization of DoubleConcNode[size=1000]
+    public void testSpliterator(double[] array, Node.OfDouble n) {
+        SpliteratorTestHelper.testDoubleSpliterator(n::spliterator);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/boottest/java/util/stream/FlagOpTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package java.util.stream;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.function.Supplier;
+
+import static java.util.stream.LambdaTestHelpers.countTo;
+
+@Test
+public class FlagOpTest extends OpTestCase {
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testFlagsPassThrough(String name, TestData<Integer, Stream<Integer>> data) {
+
+        @SuppressWarnings({"unchecked", "rawtypes"})
+        TestFlagPassThroughOp<Integer>[] ops = new TestFlagPassThroughOp[3];
+        ops[0] = new TestFlagPassThroughOp<>();
+        ops[1] = new TestFlagPassThroughOp<>();
+        ops[2] = new TestFlagPassThroughOp<>();
+
+        ops[0].set(null, ops[1]);
+        ops[1].set(ops[0], ops[2]);
+        ops[2].set(ops[1], null);
+
+        withData(data).ops(ops).exercise();
+    }
+
+    static class TestFlagPassThroughOp<T> extends FlagDeclaringOp<T> {
+        TestFlagPassThroughOp<T> upstream;
+        TestFlagPassThroughOp<T> downstream;
+
+        TestFlagPassThroughOp() {
+            super(0);
+        }
+
+        void set(TestFlagPassThroughOp<T> upstream, TestFlagPassThroughOp<T> downstream)  {
+            this.upstream = upstream;
+            this.downstream = downstream;
+        }
+
+        int wrapFlags;
+
+        @Override
+        @SuppressWarnings({"unchecked", "rawtypes"})
+        public Sink<T> opWrapSink(int flags, boolean parallel, Sink sink) {
+            this.wrapFlags = flags;
+
+            if (downstream != null) {
+                assertTrue(flags == downstream.wrapFlags);
+            }
+
+            return sink;
+        }
+    }
+
+    public void testFlagsClearAllSet() {
+        int clearAllFlags = 0;
+        for (StreamOpFlag f : EnumSet.allOf(StreamOpFlag.class)) {
+            if (f.isStreamFlag()) {
+                clearAllFlags |= f.clear();
+            }
+        }
+
+        EnumSet<StreamOpFlag> known = EnumSet.noneOf(StreamOpFlag.class);
+        EnumSet<StreamOpFlag> notKnown = StreamOpFlagTestHelper.allStreamFlags();
+
+        List<FlagDeclaringOp<Integer>> ops = new ArrayList<>();
+        ops.add(new FlagDeclaringOp<>(clearAllFlags));
+        for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
+            if (f.canSet(StreamOpFlag.Type.OP)) {
+                ops.add(new TestFlagExpectedOp<>(f.set(),
+                                             known.clone(),
+                                             EnumSet.noneOf(StreamOpFlag.class),
+                                             notKnown.clone()));
+                known.add(f);
+                notKnown.remove(f);
+            }
+        }
+        ops.add(new TestFlagExpectedOp<>(0,
+                                         known.clone(),
+                                         EnumSet.noneOf(StreamOpFlag.class),
+                                         notKnown.clone()));
+
+        TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
+        @SuppressWarnings("rawtypes")
+        FlagDeclaringOp[] opsArray = ops.toArray(new FlagDeclaringOp[ops.size()]);
+
+        withData(data).ops(opsArray).
+                without(StreamTestScenario.PAR_STREAM_TO_ARRAY_CLEAR_SIZED).
+                exercise();
+    }
+
+    public void testFlagsSetAllClear() {
+        EnumSet<StreamOpFlag> known = StreamOpFlagTestHelper.allStreamFlags();
+        int setAllFlags = 0;
+        for (StreamOpFlag f : EnumSet.allOf(StreamOpFlag.class)) {
+            if (f.isStreamFlag()) {
+                if (f.canSet(StreamOpFlag.Type.OP)) {
+                    setAllFlags |= f.set();
+                } else {
+                    known.remove(f);
+                }
+            }
+        }
+
+        EnumSet<StreamOpFlag> notKnown = EnumSet.noneOf(StreamOpFlag.class);
+
+        List<FlagDeclaringOp<Integer>> ops = new ArrayList<>();
+        ops.add(new FlagDeclaringOp<>(setAllFlags));
+        for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
+            ops.add(new TestFlagExpectedOp<>(f.clear(),
+                                             known.clone(),
+                                             EnumSet.noneOf(StreamOpFlag.class),
+                                             notKnown.clone()));
+            known.remove(f);
+            notKnown.add(f);
+        }
+        ops.add(new TestFlagExpectedOp<>(0,
+                                         known.clone(),
+                                         EnumSet.noneOf(StreamOpFlag.class),
+                                         notKnown.clone()));
+
+        TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
+        @SuppressWarnings("rawtypes")
+        FlagDeclaringOp[] opsArray = ops.toArray(new FlagDeclaringOp[ops.size()]);
+
+
+        withData(data).ops(opsArray).
+                without(StreamTestScenario.PAR_STREAM_TO_ARRAY_CLEAR_SIZED).
+                exercise();
+    }
+
+    public void testFlagsParallelCollect() {
+        testFlagsSetSequence(CollectorOps::collector);
+    }
+
+    private void testFlagsSetSequence(Supplier<StatefulTestOp<Integer>> cf) {
+        EnumSet<StreamOpFlag> known = EnumSet.of(StreamOpFlag.ORDERED, StreamOpFlag.SIZED);
+        EnumSet<StreamOpFlag> preserve = EnumSet.of(StreamOpFlag.DISTINCT, StreamOpFlag.SORTED);
+
+        List<IntermediateTestOp<Integer, Integer>> ops = new ArrayList<>();
+        for (StreamOpFlag f : EnumSet.of(StreamOpFlag.DISTINCT, StreamOpFlag.SORTED)) {
+            ops.add(cf.get());
+            ops.add(new TestFlagExpectedOp<>(f.set(),
+                                             known.clone(),
+                                             preserve.clone(),
+                                             EnumSet.noneOf(StreamOpFlag.class)));
+            known.add(f);
+            preserve.remove(f);
+        }
+        ops.add(cf.get());
+        ops.add(new TestFlagExpectedOp<>(0,
+                                         known.clone(),
+                                         preserve.clone(),
+                                         EnumSet.noneOf(StreamOpFlag.class)));
+
+        TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
+        @SuppressWarnings("rawtypes")
+        IntermediateTestOp[] opsArray = ops.toArray(new IntermediateTestOp[ops.size()]);
+
+        withData(data).ops(opsArray).
+                without(StreamTestScenario.PAR_STREAM_TO_ARRAY_CLEAR_SIZED).
+                exercise();
+    }
+
+
+    public void testFlagsClearParallelCollect() {
+        testFlagsClearSequence(CollectorOps::collector);
+    }
+
+    protected void testFlagsClearSequence(Supplier<StatefulTestOp<Integer>> cf) {
+        EnumSet<StreamOpFlag> known = EnumSet.of(StreamOpFlag.ORDERED, StreamOpFlag.SIZED);
+        EnumSet<StreamOpFlag> preserve = EnumSet.of(StreamOpFlag.DISTINCT, StreamOpFlag.SORTED);
+        EnumSet<StreamOpFlag> notKnown = EnumSet.noneOf(StreamOpFlag.class);
+
+        List<IntermediateTestOp<Integer, Integer>> ops = new ArrayList<>();
+        for (StreamOpFlag f : EnumSet.of(StreamOpFlag.ORDERED, StreamOpFlag.DISTINCT, StreamOpFlag.SORTED)) {
+            ops.add(cf.get());
+            ops.add(new TestFlagExpectedOp<>(f.clear(),
+                                             known.clone(),
+                                             preserve.clone(),
+                                             notKnown.clone()));
+            known.remove(f);
+            preserve.remove(f);
+            notKnown.add(f);
+        }
+        ops.add(cf.get());
+        ops.add(new TestFlagExpectedOp<>(0,
+                                         known.clone(),
+                                         preserve.clone(),
+                                         notKnown.clone()));
+
+        TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
+        @SuppressWarnings("rawtypes")
+        IntermediateTestOp[] opsArray = ops.toArray(new IntermediateTestOp[ops.size()]);
+
+        withData(data).ops(opsArray).
+                without(StreamTestScenario.PAR_STREAM_TO_ARRAY_CLEAR_SIZED).
+                exercise();
+    }
+
+    public void testFlagsSizedOrderedParallelCollect() {
+        EnumSet<StreamOpFlag> parKnown = EnumSet.of(StreamOpFlag.SIZED);
+        EnumSet<StreamOpFlag> serKnown = parKnown.clone();
+
+        List<IntermediateTestOp<Integer, Integer>> ops = new ArrayList<>();
+        for (StreamOpFlag f : parKnown) {
+            ops.add(CollectorOps.collector());
+            ops.add(new ParSerTestFlagExpectedOp<>(f.clear(),
+                                             parKnown,
+                                             serKnown));
+            serKnown.remove(f);
+        }
+        ops.add(CollectorOps.collector());
+        ops.add(new ParSerTestFlagExpectedOp<>(0,
+                                         parKnown,
+                                         EnumSet.noneOf(StreamOpFlag.class)));
+
+        TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
+        @SuppressWarnings("rawtypes")
+        IntermediateTestOp[] opsArray = ops.toArray(new IntermediateTestOp[ops.size()]);
+
+        withData(data).ops(opsArray).exercise();
+    }
+
+    static class ParSerTestFlagExpectedOp<T> extends FlagDeclaringOp<T> {
+        final EnumSet<StreamOpFlag> parKnown;
+        final EnumSet<StreamOpFlag> serKnown;
+
+        ParSerTestFlagExpectedOp(int flags, EnumSet<StreamOpFlag> known, EnumSet<StreamOpFlag> serKnown) {
+            super(flags);
+            this.parKnown = known;
+            this.serKnown = serKnown;
+        }
+
+        @Override
+        @SuppressWarnings({"unchecked", "rawtypes"})
+        public Sink<T> opWrapSink(int flags, boolean parallel, Sink upstream) {
+            assertFlags(flags, parallel);
+            return upstream;
+        }
+
+        protected void assertFlags(int flags, boolean parallel) {
+            if (parallel) {
+                for (StreamOpFlag f : parKnown) {
+                    Assert.assertTrue(f.isKnown(flags), String.format("Flag %s is not known, but should be known.", f.toString()));
+                }
+
+            } else {
+                for (StreamOpFlag f : serKnown) {
+                    Assert.assertTrue(f.isKnown(flags), String.format("Flag %s is not known, but should be known.", f.toString()));
+                }
+
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/boottest/java/util/stream/IntNodeTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.PrimitiveIterator;
+import java.util.Spliterators;
+import java.util.function.Function;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+@Test
+public class IntNodeTest extends OpTestCase {
+
+    @DataProvider(name = "nodes")
+    public Object[][] createSizes() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : Arrays.asList(0, 1, 4, 15, 16, 17, 127, 128, 129, 1000)) {
+            int[] array = new int[size];
+            for (int i = 0; i < array.length; i++) {
+                array[i] = i;
+            }
+
+            List<Node<Integer>> nodes = new ArrayList<>();
+
+            nodes.add(Nodes.node(array));
+            nodes.add(degenerateTree(Spliterators.iteratorFromSpliterator(Arrays.spliterator(array))));
+            nodes.add(tree(toList(array), l -> Nodes.node(toIntArray(l))));
+            nodes.add(fill(array, Nodes.intBuilder(array.length)));
+            nodes.add(fill(array, Nodes.intBuilder()));
+
+            for (Node<Integer> node : nodes) {
+                params.add(new Object[]{array, node});
+            }
+
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    private static void assertEqualsListIntArray(List<Integer> list, int[] array) {
+        assertEquals(list.size(), array.length);
+        for (int i = 0; i < array.length; i++)
+            assertEquals(array[i], (int) list.get(i));
+    }
+
+    private List<Integer> toList(int[] a) {
+        List<Integer> l = new ArrayList<>();
+        for (int i : a) {
+            l.add(i);
+        }
+
+        return l;
+    }
+
+    private int[] toIntArray(List<Integer> l) {
+        int[] a = new int[l.size()];
+
+        int i = 0;
+        for (Integer e : l) {
+            a[i++] = e;
+        }
+        return a;
+    }
+
+    private Node.OfInt fill(int[] array, Node.Builder.OfInt nb) {
+        nb.begin(array.length);
+        for (int i : array)
+            nb.accept(i);
+        nb.end();
+        return nb.build();
+    }
+
+    private Node.OfInt degenerateTree(PrimitiveIterator.OfInt it) {
+        if (!it.hasNext()) {
+            return Nodes.node(new int[0]);
+        }
+
+        int i = it.nextInt();
+        if (it.hasNext()) {
+            return new Nodes.IntConcNode(Nodes.node(new int[] {i}), degenerateTree(it));
+        }
+        else {
+            return Nodes.node(new int[] {i});
+        }
+    }
+
+    private Node.OfInt tree(List<Integer> l, Function<List<Integer>, Node.OfInt> m) {
+        if (l.size() < 3) {
+            return m.apply(l);
+        }
+        else {
+            return new Nodes.IntConcNode(
+                    tree(l.subList(0, l.size() / 2), m),
+                    tree(l.subList(l.size() / 2, l.size()), m));
+        }
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testAsArray(int[] array, Node.OfInt n) {
+        assertEquals(n.asIntArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testFlattenAsArray(int[] array, Node.OfInt n) {
+        assertEquals(Nodes.flattenInt(n).asIntArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testCopyTo(int[] array, Node.OfInt n) {
+        int[] copy = new int[(int) n.count()];
+        n.copyInto(copy, 0);
+
+        assertEquals(copy, array);
+    }
+
+    @Test(dataProvider = "nodes", groups = { "serialization-hostile" })
+    public void testForEach(int[] array, Node.OfInt n) {
+        List<Integer> l = new ArrayList<>((int) n.count());
+        n.forEach((int e) -> {
+            l.add(e);
+        });
+
+        assertEqualsListIntArray(l, array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testStreams(int[] array, Node.OfInt n) {
+        TestData.OfInt data = TestData.Factory.ofNode("Node", n);
+
+        exerciseOps(data, s -> s);
+        exerciseTerminalOps(data, s -> s.toArray());
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testSpliterator(int[] array, Node.OfInt n) {
+        SpliteratorTestHelper.testIntSpliterator(n::spliterator);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/boottest/java/util/stream/LongNodeTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.PrimitiveIterator;
+import java.util.Spliterators;
+import java.util.function.Function;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+@Test
+public class LongNodeTest extends OpTestCase {
+
+    @DataProvider(name = "nodes")
+    public Object[][] createSizes() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : Arrays.asList(0, 1, 4, 15, 16, 17, 127, 128, 129, 1000)) {
+            long[] array = new long[size];
+            for (int i = 0; i < array.length; i++) {
+                array[i] = i;
+            }
+
+            List<Node<Long>> nodes = new ArrayList<>();
+
+            nodes.add(Nodes.node(array));
+            nodes.add(degenerateTree(Spliterators.iteratorFromSpliterator(Arrays.spliterator(array))));
+            nodes.add(tree(toList(array), l -> Nodes.node(toLongArray(l))));
+            nodes.add(fill(array, Nodes.longBuilder(array.length)));
+            nodes.add(fill(array, Nodes.longBuilder()));
+
+            for (Node<Long> node : nodes) {
+                params.add(new Object[]{array, node});
+            }
+
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    private static void assertEqualsListLongArray(List<Long> list, long[] array) {
+        assertEquals(list.size(), array.length);
+        for (int i = 0; i < array.length; i++)
+            assertEquals(array[i], (long) list.get(i));
+    }
+
+    private List<Long> toList(long[] a) {
+        List<Long> l = new ArrayList<>();
+        for (long i : a) {
+            l.add(i);
+        }
+
+        return l;
+    }
+
+    private long[] toLongArray(List<Long> l) {
+        long[] a = new long[l.size()];
+
+        int i = 0;
+        for (Long e : l) {
+            a[i++] = e;
+        }
+        return a;
+    }
+
+    private Node.OfLong fill(long[] array, Node.Builder.OfLong nb) {
+        nb.begin(array.length);
+        for (long i : array)
+            nb.accept(i);
+        nb.end();
+        return nb.build();
+    }
+
+    private Node.OfLong degenerateTree(PrimitiveIterator.OfLong it) {
+        if (!it.hasNext()) {
+            return Nodes.node(new long[0]);
+        }
+
+        long i = it.nextLong();
+        if (it.hasNext()) {
+            return new Nodes.LongConcNode(Nodes.node(new long[] {i}), degenerateTree(it));
+        }
+        else {
+            return Nodes.node(new long[] {i});
+        }
+    }
+
+    private Node.OfLong tree(List<Long> l, Function<List<Long>, Node.OfLong> m) {
+        if (l.size() < 3) {
+            return m.apply(l);
+        }
+        else {
+            return new Nodes.LongConcNode(
+                    tree(l.subList(0, l.size() / 2), m),
+                    tree(l.subList(l.size() / 2, l.size()), m));
+        }
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testAsArray(long[] array, Node.OfLong n) {
+        assertEquals(n.asLongArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testFlattenAsArray(long[] array, Node.OfLong n) {
+        assertEquals(Nodes.flattenLong(n).asLongArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testCopyTo(long[] array, Node.OfLong n) {
+        long[] copy = new long[(int) n.count()];
+        n.copyInto(copy, 0);
+
+        assertEquals(copy, array);
+    }
+
+    @Test(dataProvider = "nodes", groups = { "serialization-hostile" })
+    public void testForEach(long[] array, Node.OfLong n) {
+        List<Long> l = new ArrayList<>((int) n.count());
+        n.forEach((long e) -> {
+            l.add(e);
+        });
+
+        assertEqualsListLongArray(l, array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testStreams(long[] array, Node.OfLong n) {
+        TestData.OfLong data = TestData.Factory.ofNode("Node", n);
+
+        exerciseOps(data, s -> s);
+
+        exerciseTerminalOps(data, s -> s.toArray());
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testSpliterator(long[] array, Node.OfLong n) {
+        SpliteratorTestHelper.testLongSpliterator(n::spliterator);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/boottest/java/util/stream/NodeBuilderTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.DoubleConsumer;
+import java.util.function.Function;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static java.util.stream.LambdaTestHelpers.assertContents;
+import static java.util.stream.LambdaTestHelpers.countTo;
+import static org.testng.Assert.assertEquals;
+
+@Test
+public class NodeBuilderTest {
+
+    List<Integer> sizes = Arrays.asList(0, 1, 4, 16, 256,
+                                        1023, 1024, 1025,
+                                        2047, 2048, 2049,
+                                        1024 * 32 - 1, 1024 * 32, 1024 * 32 + 1);
+
+    @DataProvider(name = "Node.Builder")
+    public Object[][] createNodeBuilders() {
+        List<List<Integer>> ls = new ArrayList<>();
+        for (int size : sizes) {
+            ls.add(countTo(size));
+        }
+
+        List<Function<Integer, Node.Builder<Integer>>> ms = Arrays.asList(
+                s -> Nodes.builder(),
+                s -> Nodes.builder(s, LambdaTestHelpers.integerArrayGenerator)
+        );
+
+        Object[][] params = new Object[ls.size() * ms.size()][];
+        int i = 0;
+        for (List<Integer> l : ls) {
+            for (Function<Integer, Node.Builder<Integer>> m : ms) {
+                params[i++] = new Object[]{l, m};
+            }
+        }
+
+        return params;
+    }
+
+    @Test(dataProvider = "Node.Builder", groups = { "serialization-hostile" })
+    public void testIteration(List<Integer> l, Function<Integer, Node.Builder<Integer>> m) {
+        Node.Builder<Integer> nb = m.apply(l.size());
+        nb.begin(l.size());
+        for (Integer i : l) {
+            nb.accept(i);
+        }
+        nb.end();
+
+        Node<Integer> n = nb.build();
+        assertEquals(n.count(), l.size());
+
+        {
+            List<Integer> _l = new ArrayList<>();
+            n.forEach(_l::add);
+
+            assertContents(_l, l);
+        }
+    }
+
+    // Node.Builder.OfInt
+
+    @DataProvider(name = "Node.Builder<Integer>")
+    public Object[][] createIntNodeBuilders() {
+        List<List<Integer>> ls = new ArrayList<>();
+        for (int size : sizes) {
+            ls.add(countTo(size));
+        }
+
+        List<Function<Integer, Node.Builder<Integer>>> ms = Arrays.asList(
+                s -> Nodes.intBuilder(),
+                s -> Nodes.intBuilder(s)
+        );
+
+        Object[][] params = new Object[ls.size() * ms.size()][];
+        int i = 0;
+        for (List<Integer> l : ls) {
+            for (Function<Integer, Node.Builder<Integer>> m : ms) {
+                params[i++] = new Object[]{l, m};
+            }
+        }
+
+        return params;
+    }
+
+    @Test(dataProvider = "Node.Builder<Integer>", groups = { "serialization-hostile" })
+    public void testIntIteration(List<Integer> l, Function<Integer, Node.Builder.OfInt> m) {
+        Node.Builder.OfInt nb = m.apply(l.size());
+        nb.begin(l.size());
+        for (Integer i : l) {
+            nb.accept((int) i);
+        }
+        nb.end();
+
+        Node.OfInt n = nb.build();
+        assertEquals(n.count(), l.size());
+
+        {
+            List<Integer> _l = new ArrayList<>();
+            n.forEach((IntConsumer) _l::add);
+
+            assertContents(_l, l);
+        }
+
+    }
+
+    // Node.Builder.OfLong
+
+    @DataProvider(name = "Node.Builder<Long>")
+    public Object[][] createLongNodeBuilders() {
+        List<List<Long>> ls = new ArrayList<>();
+        for (int size : sizes) {
+            List<Long> l = new ArrayList<>();
+            for (long i = 0; i < size; i++) {
+                l.add(i);
+            }
+            ls.add(l);
+        }
+
+        List<Function<Integer, Node.Builder<Long>>> ms = Arrays.asList(
+                s -> Nodes.longBuilder(),
+                s -> Nodes.longBuilder(s)
+        );
+
+        Object[][] params = new Object[ls.size() * ms.size()][];
+        int i = 0;
+        for (List<Long> l : ls) {
+            for (Function<Integer, Node.Builder<Long>> m : ms) {
+                params[i++] = new Object[]{l, m};
+            }
+        }
+
+        return params;
+    }
+
+    @Test(dataProvider = "Node.Builder<Long>")
+    public void testLongIteration(List<Long> l, Function<Integer, Node.Builder.OfLong> m) {
+        Node.Builder.OfLong nb = m.apply(l.size());
+        nb.begin(l.size());
+        for (Long i : l) {
+            nb.accept((long) i);
+        }
+        nb.end();
+
+        Node.OfLong n = nb.build();
+        assertEquals(n.count(), l.size());
+
+        {
+            List<Long> _l = new ArrayList<>();
+            n.forEach((LongConsumer) _l::add);
+
+            assertContents(_l, l);
+        }
+
+    }
+
+    // Node.Builder.OfDouble
+
+    @DataProvider(name = "Node.Builder<Double>")
+    public Object[][] createDoubleNodeBuilders() {
+        List<List<Double>> ls = new ArrayList<>();
+        for (int size : sizes) {
+            List<Double> l = new ArrayList<>();
+            for (long i = 0; i < size; i++) {
+                l.add((double) i);
+            }
+            ls.add(l);
+        }
+
+        List<Function<Integer, Node.Builder<Double>>> ms = Arrays.asList(
+                s -> Nodes.doubleBuilder(),
+                s -> Nodes.doubleBuilder(s)
+        );
+
+        Object[][] params = new Object[ls.size() * ms.size()][];
+        int i = 0;
+        for (List<Double> l : ls) {
+            for (Function<Integer, Node.Builder<Double>> m : ms) {
+                params[i++] = new Object[]{l, m};
+            }
+        }
+
+        return params;
+    }
+
+    @Test(dataProvider = "Node.Builder<Double>")
+    public void testDoubleIteration(List<Double> l, Function<Integer, Node.Builder.OfDouble> m) {
+        Node.Builder.OfDouble nb = m.apply(l.size());
+        nb.begin(l.size());
+        for (Double i : l) {
+            nb.accept((double) i);
+        }
+        nb.end();
+
+        Node.OfDouble n = nb.build();
+        assertEquals(n.count(), l.size());
+
+        {
+            List<Double> _l = new ArrayList<>();
+            n.forEach((DoubleConsumer) _l::add);
+
+            assertContents(_l, l);
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/boottest/java/util/stream/NodeTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.function.Function;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+@Test
+public class NodeTest extends OpTestCase {
+
+    @DataProvider(name = "nodes")
+    public Object[][] createSizes() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : Arrays.asList(0, 1, 4, 15, 16, 17, 127, 128, 129, 1000)) {
+            Integer[] array = new Integer[size];
+            for (int i = 0; i < array.length; i++) {
+                array[i] = i;
+            }
+
+            List<Node<Integer>> nodes = new ArrayList<>();
+            nodes.add(Nodes.node(array));
+            nodes.add(Nodes.node(Arrays.asList(array)));
+            nodes.add(degenerateTree(Arrays.asList(array).iterator()));
+            nodes.add(tree(Arrays.asList(array), l -> Nodes.node(l.toArray(new Integer[l.size()]))));
+            nodes.add(tree(Arrays.asList(array), l -> Nodes.node(l)));
+            nodes.add(fill(array, Nodes.builder(array.length, LambdaTestHelpers.integerArrayGenerator)));
+            nodes.add(fill(array, Nodes.builder()));
+
+            for (int i = 0; i < nodes.size(); i++) {
+                params.add(new Object[]{array, nodes.get(i)});
+            }
+
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    Node<Integer> fill(Integer[] array, Node.Builder<Integer> nb) {
+        nb.begin(array.length);
+        for (Integer i : array) {
+            nb.accept(i);
+        }
+        nb.end();
+        return nb.build();
+    }
+
+    Node<Integer> degenerateTree(Iterator<Integer> it) {
+        if (!it.hasNext()) {
+            return Nodes.node(Collections.emptyList());
+        }
+
+        Integer i = it.next();
+        if (it.hasNext()) {
+            return new Nodes.ConcNode<Integer>(Nodes.node(new Integer[] {i}), degenerateTree(it));
+        }
+        else {
+            return Nodes.node(new Integer[]{i});
+        }
+    }
+
+    Node<Integer> tree(List<Integer> l, Function<List<Integer>, Node<Integer>> m) {
+        if (l.size() < 3) {
+            return m.apply(l);
+        }
+        else {
+            return new Nodes.ConcNode<>(
+                    tree(l.subList(0, l.size() / 2), m),
+                    tree(l.subList(l.size() / 2, l.size()), m ));
+        }
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testAsArray(Integer[] array, Node<Integer> n) {
+        assertEquals(n.asArray(LambdaTestHelpers.integerArrayGenerator), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testFlattenAsArray(Integer[] array, Node<Integer> n) {
+        assertEquals(Nodes.flatten(n, LambdaTestHelpers.integerArrayGenerator)
+                          .asArray(LambdaTestHelpers.integerArrayGenerator), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testCopyTo(Integer[] array, Node<Integer> n) {
+        Integer[] copy = new Integer[(int) n.count()];
+        n.copyInto(copy, 0);
+
+        assertEquals(copy, array);
+    }
+
+    @Test(dataProvider = "nodes", groups = { "serialization-hostile" })
+    public void testForEach(Integer[] array, Node<Integer> n) {
+        List<Integer> l = new ArrayList<>((int) n.count());
+        n.forEach(e -> l.add(e));
+
+        assertEquals(l.toArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testStreams(Integer[] array, Node<Integer> n) {
+        TestData<Integer, Stream<Integer>> data = TestData.Factory.ofRefNode("Node", n);
+
+        exerciseOps(data, s -> s);
+
+        exerciseTerminalOps(data, s -> s.toArray());
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testSpliterator(Integer[] array, Node<Integer> n) {
+        SpliteratorTestHelper.testSpliterator(n::spliterator);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/boottest/java/util/stream/SpinedBufferTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package java.util.stream;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.*;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+
+@Test
+public class SpinedBufferTest {
+
+    // Create sizes around the boundary of spines
+    static List<Integer> sizes;
+    static {
+        try {
+            sizes = IntStream.range(0, 15)
+                             .map(i -> 1 << i)
+                             .flatMap(i -> Arrays.stream(new int[] { i-2, i-1, i, i+1, i+2 }))
+                             .filter(i -> i >= 0)
+                             .boxed()
+                             .distinct()
+                             .collect(Collectors.toList());
+        }
+        catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    private static final int TEST_SIZE = 5000;
+
+    // SpinedBuffer
+
+    @DataProvider(name = "SpinedBuffer")
+    public Object[][] createSpinedBuffer() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : sizes) {
+            int[] array = IntStream.range(0, size).toArray();
+
+            SpinedBuffer<Integer> sb = new SpinedBuffer<>();
+            Arrays.stream(array).boxed().forEach(sb);
+            params.add(new Object[]{array, sb});
+
+            sb = new SpinedBuffer<>(size / 2);
+            Arrays.stream(array).boxed().forEach(sb);
+            params.add(new Object[]{array, sb});
+
+            sb = new SpinedBuffer<>(size);
+            Arrays.stream(array).boxed().forEach(sb);
+            params.add(new Object[]{array, sb});
+
+            sb = new SpinedBuffer<>(size * 2);
+            Arrays.stream(array).boxed().forEach(sb);
+            params.add(new Object[]{array, sb});
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    @Test(dataProvider = "SpinedBuffer")
+    public void testSpliterator(int[] array, SpinedBuffer<Integer> sb) {
+        assertEquals(sb.count(), array.length);
+        assertEquals(sb.count(), sb.spliterator().getExactSizeIfKnown());
+
+        SpliteratorTestHelper.testSpliterator(sb::spliterator);
+    }
+
+    @Test(dataProvider = "SpinedBuffer", groups = { "serialization-hostile" })
+    public void testLastSplit(int[] array, SpinedBuffer<Integer> sb) {
+        Spliterator<Integer> spliterator = sb.spliterator();
+        Spliterator<Integer> split = spliterator.trySplit();
+        long splitSizes = (split == null) ? 0 : split.getExactSizeIfKnown();
+        long lastSplitSize = spliterator.getExactSizeIfKnown();
+        splitSizes += lastSplitSize;
+
+        assertEquals(splitSizes, array.length);
+
+        List<Integer> contentOfLastSplit = new ArrayList<>();
+        spliterator.forEachRemaining(contentOfLastSplit::add);
+
+        assertEquals(contentOfLastSplit.size(), lastSplitSize);
+
+        List<Integer> end = Arrays.stream(array)
+                .boxed()
+                .substream(array.length - lastSplitSize)
+                .collect(Collectors.toList());
+        assertEquals(contentOfLastSplit, end);
+    }
+
+    @Test(groups = { "serialization-hostile" })
+    public void testSpinedBuffer() {
+        List<Integer> list1 = new ArrayList<>();
+        List<Integer> list2 = new ArrayList<>();
+        SpinedBuffer<Integer> sb = new SpinedBuffer<>();
+        for (int i = 0; i < TEST_SIZE; i++) {
+            list1.add(i);
+            sb.accept(i);
+        }
+        Iterator<Integer> it = sb.iterator();
+        for (int i = 0; i < TEST_SIZE; i++)
+            list2.add(it.next());
+        assertFalse(it.hasNext());
+        assertEquals(list1, list2);
+
+        for (int i = 0; i < TEST_SIZE; i++)
+            assertEquals(sb.get(i), (Integer) i, Integer.toString(i));
+
+        list2.clear();
+        sb.forEach(list2::add);
+        assertEquals(list1, list2);
+        Integer[] array = sb.asArray(LambdaTestHelpers.integerArrayGenerator);
+        list2.clear();
+        for (Integer i : array)
+            list2.add(i);
+        assertEquals(list1, list2);
+    }
+
+    // IntSpinedBuffer
+
+    @DataProvider(name = "IntSpinedBuffer")
+    public Object[][] createIntSpinedBuffer() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : sizes) {
+            int[] array = IntStream.range(0, size).toArray();
+            SpinedBuffer.OfInt sb = new SpinedBuffer.OfInt();
+            Arrays.stream(array).forEach(sb);
+
+            params.add(new Object[]{array, sb});
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    @Test(dataProvider = "IntSpinedBuffer")
+    public void testIntSpliterator(int[] array, SpinedBuffer.OfInt sb) {
+        assertEquals(sb.count(), array.length);
+        assertEquals(sb.count(), sb.spliterator().getExactSizeIfKnown());
+
+        SpliteratorTestHelper.testIntSpliterator(sb::spliterator);
+    }
+
+    @Test(dataProvider = "IntSpinedBuffer", groups = { "serialization-hostile" })
+    public void testIntLastSplit(int[] array, SpinedBuffer.OfInt sb) {
+        Spliterator.OfInt spliterator = sb.spliterator();
+        Spliterator.OfInt split = spliterator.trySplit();
+        long splitSizes = (split == null) ? 0 : split.getExactSizeIfKnown();
+        long lastSplitSize = spliterator.getExactSizeIfKnown();
+        splitSizes += lastSplitSize;
+
+        assertEquals(splitSizes, array.length);
+
+        List<Integer> contentOfLastSplit = new ArrayList<>();
+        spliterator.forEachRemaining((IntConsumer) contentOfLastSplit::add);
+
+        assertEquals(contentOfLastSplit.size(), lastSplitSize);
+
+        List<Integer> end = Arrays.stream(array)
+                .boxed()
+                .substream(array.length - lastSplitSize)
+                .collect(Collectors.toList());
+        assertEquals(contentOfLastSplit, end);
+    }
+
+    @Test(groups = { "serialization-hostile" })
+    public void testIntSpinedBuffer() {
+        List<Integer> list1 = new ArrayList<>();
+        List<Integer> list2 = new ArrayList<>();
+        SpinedBuffer.OfInt sb = new SpinedBuffer.OfInt();
+        for (int i = 0; i < TEST_SIZE; i++) {
+            list1.add(i);
+            sb.accept(i);
+        }
+        PrimitiveIterator.OfInt it = sb.iterator();
+        for (int i = 0; i < TEST_SIZE; i++)
+            list2.add(it.nextInt());
+        assertFalse(it.hasNext());
+        assertEquals(list1, list2);
+
+        for (int i = 0; i < TEST_SIZE; i++)
+            assertEquals(sb.get(i), i, Integer.toString(i));
+
+        list2.clear();
+        sb.forEach((int i) -> list2.add(i));
+        assertEquals(list1, list2);
+        int[] array = sb.asIntArray();
+        list2.clear();
+        for (int i : array)
+            list2.add(i);
+        assertEquals(list1, list2);
+    }
+
+    // LongSpinedBuffer
+
+    @DataProvider(name = "LongSpinedBuffer")
+    public Object[][] createLongSpinedBuffer() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : sizes) {
+            long[] array = LongStream.range(0, size).toArray();
+            SpinedBuffer.OfLong sb = new SpinedBuffer.OfLong();
+            Arrays.stream(array).forEach(sb);
+
+            params.add(new Object[]{array, sb});
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    @Test(dataProvider = "LongSpinedBuffer")
+    public void testLongSpliterator(long[] array, SpinedBuffer.OfLong sb) {
+        assertEquals(sb.count(), array.length);
+        assertEquals(sb.count(), sb.spliterator().getExactSizeIfKnown());
+
+        SpliteratorTestHelper.testLongSpliterator(sb::spliterator);
+    }
+
+    @Test(dataProvider = "LongSpinedBuffer", groups = { "serialization-hostile" })
+    public void testLongLastSplit(long[] array, SpinedBuffer.OfLong sb) {
+        Spliterator.OfLong spliterator = sb.spliterator();
+        Spliterator.OfLong split = spliterator.trySplit();
+        long splitSizes = (split == null) ? 0 : split.getExactSizeIfKnown();
+        long lastSplitSize = spliterator.getExactSizeIfKnown();
+        splitSizes += lastSplitSize;
+
+        assertEquals(splitSizes, array.length);
+
+        List<Long> contentOfLastSplit = new ArrayList<>();
+        spliterator.forEachRemaining((LongConsumer) contentOfLastSplit::add);
+
+        assertEquals(contentOfLastSplit.size(), lastSplitSize);
+
+        List<Long> end = Arrays.stream(array)
+                .boxed()
+                .substream(array.length - lastSplitSize)
+                .collect(Collectors.toList());
+        assertEquals(contentOfLastSplit, end);
+    }
+
+    @Test(groups = { "serialization-hostile" })
+    public void testLongSpinedBuffer() {
+        List<Long> list1 = new ArrayList<>();
+        List<Long> list2 = new ArrayList<>();
+        SpinedBuffer.OfLong sb = new SpinedBuffer.OfLong();
+        for (long i = 0; i < TEST_SIZE; i++) {
+            list1.add(i);
+            sb.accept(i);
+        }
+        PrimitiveIterator.OfLong it = sb.iterator();
+        for (int i = 0; i < TEST_SIZE; i++)
+            list2.add(it.nextLong());
+        assertFalse(it.hasNext());
+        assertEquals(list1, list2);
+
+        for (int i = 0; i < TEST_SIZE; i++)
+            assertEquals(sb.get(i), i, Long.toString(i));
+
+        list2.clear();
+        sb.forEach((long i) -> list2.add(i));
+        assertEquals(list1, list2);
+        long[] array = sb.asLongArray();
+        list2.clear();
+        for (long i : array)
+            list2.add(i);
+        assertEquals(list1, list2);
+    }
+
+    // DoubleSpinedBuffer
+
+    @DataProvider(name = "DoubleSpinedBuffer")
+    public Object[][] createDoubleSpinedBuffer() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : sizes) {
+            // @@@ replace with double range when implemented
+            double[] array = LongStream.range(0, size).doubles().toArray();
+            SpinedBuffer.OfDouble sb = new SpinedBuffer.OfDouble();
+            Arrays.stream(array).forEach(sb);
+
+            params.add(new Object[]{array, sb});
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    @Test(dataProvider = "DoubleSpinedBuffer")
+    public void testDoubleSpliterator(double[] array, SpinedBuffer.OfDouble sb) {
+        assertEquals(sb.count(), array.length);
+        assertEquals(sb.count(), sb.spliterator().getExactSizeIfKnown());
+
+        SpliteratorTestHelper.testDoubleSpliterator(sb::spliterator);
+    }
+
+    @Test(dataProvider = "DoubleSpinedBuffer", groups = { "serialization-hostile" })
+    public void testLongLastSplit(double[] array, SpinedBuffer.OfDouble sb) {
+        Spliterator.OfDouble spliterator = sb.spliterator();
+        Spliterator.OfDouble split = spliterator.trySplit();
+        long splitSizes = (split == null) ? 0 : split.getExactSizeIfKnown();
+        long lastSplitSize = spliterator.getExactSizeIfKnown();
+        splitSizes += lastSplitSize;
+
+        assertEquals(splitSizes, array.length);
+
+        List<Double> contentOfLastSplit = new ArrayList<>();
+        spliterator.forEachRemaining((DoubleConsumer) contentOfLastSplit::add);
+
+        assertEquals(contentOfLastSplit.size(), lastSplitSize);
+
+        List<Double> end = Arrays.stream(array)
+                .boxed()
+                .substream(array.length - lastSplitSize)
+                .collect(Collectors.toList());
+        assertEquals(contentOfLastSplit, end);
+    }
+
+    @Test(groups = { "serialization-hostile" })
+    public void testDoubleSpinedBuffer() {
+        List<Double> list1 = new ArrayList<>();
+        List<Double> list2 = new ArrayList<>();
+        SpinedBuffer.OfDouble sb = new SpinedBuffer.OfDouble();
+        for (long i = 0; i < TEST_SIZE; i++) {
+            list1.add((double) i);
+            sb.accept((double) i);
+        }
+        PrimitiveIterator.OfDouble it = sb.iterator();
+        for (int i = 0; i < TEST_SIZE; i++)
+            list2.add(it.nextDouble());
+        assertFalse(it.hasNext());
+        assertEquals(list1, list2);
+
+        for (int i = 0; i < TEST_SIZE; i++)
+            assertEquals(sb.get(i), (double) i, Double.toString(i));
+
+        list2.clear();
+        sb.forEach((double i) -> list2.add(i));
+        assertEquals(list1, list2);
+        double[] array = sb.asDoubleArray();
+        list2.clear();
+        for (double i : array)
+            list2.add(i);
+        assertEquals(list1, list2);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/boottest/java/util/stream/StreamFlagsTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package java.util.stream;
+
+import org.testng.annotations.Test;
+
+import java.util.*;
+import java.util.stream.Stream;
+import java.util.stream.StreamOpFlag;
+import java.util.stream.Streams;
+
+import static java.util.stream.StreamOpFlag.*;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * StreamFlagsTest
+ *
+ * @author Brian Goetz
+ */
+@Test
+public class StreamFlagsTest {
+    Stream<String> arrayList = new ArrayList<String>().stream();
+    Stream<String> linkedList = new LinkedList<String>().stream();
+    Stream<String> hashSet = new HashSet<String>().stream();
+    Stream<String> treeSet = new TreeSet<String>().stream();
+    Stream<String> linkedHashSet = new LinkedHashSet<String>().stream();
+    Stream<String> repeat = Stream.generate(() -> "");
+
+    Stream<?>[] streams = { arrayList, linkedList, hashSet, treeSet, linkedHashSet, repeat };
+
+    private void assertFlags(int value, EnumSet<StreamOpFlag> setFlags, EnumSet<StreamOpFlag> clearFlags) {
+        for (StreamOpFlag flag : setFlags)
+            assertTrue(flag.isKnown(value));
+        for (StreamOpFlag flag : clearFlags)
+            assertTrue(!flag.isKnown(value));
+    }
+
+    public void testBaseStreams() {
+        Stream<String> arrayList = new ArrayList<String>().stream();
+        Stream<String> linkedList = new LinkedList<String>().stream();
+        Stream<String> hashSet = new HashSet<String>().stream();
+        Stream<String> treeSet = new TreeSet<String>().stream();
+        Stream<String> linkedHashSet = new LinkedHashSet<String>().stream();
+        Stream<String> repeat = Stream.generate(() -> "");
+
+        assertFlags(OpTestCase.getStreamFlags(arrayList),
+                    EnumSet.of(ORDERED, SIZED),
+                    EnumSet.of(DISTINCT, SORTED, SHORT_CIRCUIT));
+        assertFlags(OpTestCase.getStreamFlags(linkedList),
+                    EnumSet.of(ORDERED, SIZED),
+                    EnumSet.of(DISTINCT, SORTED, SHORT_CIRCUIT));
+        assertFlags(OpTestCase.getStreamFlags(hashSet),
+                    EnumSet.of(SIZED, DISTINCT),
+                    EnumSet.of(ORDERED, SORTED, SHORT_CIRCUIT));
+        assertFlags(OpTestCase.getStreamFlags(treeSet),
+                    EnumSet.of(ORDERED, SIZED, DISTINCT, SORTED),
+                    EnumSet.of(SHORT_CIRCUIT));
+        assertFlags(OpTestCase.getStreamFlags(linkedHashSet),
+                    EnumSet.of(ORDERED, DISTINCT, SIZED),
+                    EnumSet.of(SORTED, SHORT_CIRCUIT));
+        assertFlags(OpTestCase.getStreamFlags(repeat),
+                    EnumSet.of(ORDERED),
+                    EnumSet.of(SIZED, DISTINCT, SORTED, SHORT_CIRCUIT));
+    }
+
+    public void testFilter() {
+        for (Stream<?> s : streams) {
+            int baseFlags = OpTestCase.getStreamFlags(s);
+            int filteredFlags = OpTestCase.getStreamFlags(s.filter((Object e) -> true));
+            int expectedFlags = baseFlags & ~SIZED.set();
+
+            assertEquals(filteredFlags, expectedFlags);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/boottest/java/util/stream/StreamOpFlagsTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package java.util.stream;
+
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.StreamOpFlag.*;
+import static org.testng.Assert.*;
+import static org.testng.Assert.assertEquals;
+
+@Test
+public class StreamOpFlagsTest {
+
+    public void testNullCombine() {
+        int sourceFlags = StreamOpFlag.IS_SIZED;
+
+        assertEquals(sourceFlags, toStreamFlags(combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE)));
+    }
+
+    public void testInitialOpFlagsFromSourceFlags() {
+        List<StreamOpFlag> flags = new ArrayList<>(StreamOpFlagTestHelper.allStreamFlags());
+        for (int i = 0; i < (1 << flags.size()); i++)  {
+            int sourceFlags = 0;
+            for (int f = 0; f < flags.size(); f++) {
+                if ((i & (1 << f)) != 0)  {
+                    sourceFlags |= flags.get(f).set();
+                }
+            }
+
+            int opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+            assertEquals(opsFlags, (~(sourceFlags << 1)) & StreamOpFlag.INITIAL_OPS_VALUE);
+        }
+    }
+
+    public void testSameCombine() {
+        for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
+            int sourceFlags = f.set();
+            int opsFlags;
+
+            opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+            opsFlags = combineOpFlags(f.set(), opsFlags);
+            assertEquals(sourceFlags, toStreamFlags(opsFlags));
+        }
+    }
+
+    public void testOpClear() {
+        for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
+            // Clear when source not set
+            int sourceFlags = 0;
+            int opsFlags;
+
+            opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+            opsFlags = combineOpFlags(f.clear(), opsFlags);
+            assertEquals(sourceFlags, toStreamFlags(opsFlags));
+
+            // Clear when source set
+            sourceFlags = f.set();
+
+            opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+            opsFlags = combineOpFlags(f.clear(), opsFlags);
+            assertEquals(0, toStreamFlags(opsFlags));
+        }
+    }
+
+    public void testOpInject() {
+        for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
+            // Set when source not set
+            int sourceFlags = 0;
+            int opsFlags;
+
+            opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+            opsFlags = combineOpFlags(f.set(), opsFlags);
+            assertEquals(f.set(), toStreamFlags(opsFlags));
+
+            // Set when source set
+            sourceFlags = f.set();
+
+            opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+            opsFlags = combineOpFlags(f.set(), opsFlags);
+            assertEquals(sourceFlags, toStreamFlags(opsFlags));
+        }
+    }
+
+    public void testPairSet() {
+        List<Integer> sourceFlagsList
+                = StreamOpFlagTestHelper.allStreamFlags().stream().map(StreamOpFlag::set).collect(toList());
+        sourceFlagsList.add(0, 0);
+
+        for (int sourceFlags : sourceFlagsList) {
+            for (StreamOpFlag f1 : StreamOpFlagTestHelper.allStreamFlags()) {
+                for (StreamOpFlag f2 : StreamOpFlagTestHelper.allStreamFlags()) {
+                    int opsFlags;
+
+                    opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+                    opsFlags = combineOpFlags(f1.set(), opsFlags);
+                    opsFlags = combineOpFlags(f2.set(), opsFlags);
+                    assertEquals(sourceFlags | f1.set() | f2.set(), toStreamFlags(opsFlags));
+                }
+            }
+        }
+    }
+
+    public void testPairSetAndClear() {
+        List<Integer> sourceFlagsList
+                = StreamOpFlagTestHelper.allStreamFlags().stream().map(StreamOpFlag::set).collect(toList());
+        sourceFlagsList.add(0, 0);
+
+        for (int sourceFlags : sourceFlagsList) {
+            for (StreamOpFlag f1 : StreamOpFlagTestHelper.allStreamFlags())  {
+                for (StreamOpFlag f2 : StreamOpFlagTestHelper.allStreamFlags()) {
+                    int opsFlags;
+
+                    opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+                    opsFlags = combineOpFlags(f1.set(), opsFlags);
+                    opsFlags = combineOpFlags(f2.clear(), opsFlags);
+                    if (f1 == f2)
+                        assertEquals((f2.set() == sourceFlags) ? 0 : sourceFlags, toStreamFlags(opsFlags));
+                    else
+                        assertEquals((f2.set() == sourceFlags) ? f1.set() : sourceFlags | f1.set(), toStreamFlags(opsFlags));
+                }
+            }
+        }
+    }
+
+    public void testShortCircuit() {
+        int opsFlags = combineOpFlags(0, StreamOpFlag.INITIAL_OPS_VALUE);
+        assertFalse(StreamOpFlag.SHORT_CIRCUIT.isKnown(opsFlags));
+
+        opsFlags = combineOpFlags(StreamOpFlag.IS_SHORT_CIRCUIT, opsFlags);
+        assertTrue(StreamOpFlag.SHORT_CIRCUIT.isKnown(opsFlags));
+
+        opsFlags = combineOpFlags(0, opsFlags);
+        assertTrue(StreamOpFlag.SHORT_CIRCUIT.isKnown(opsFlags));
+    }
+
+    public void testApplySourceFlags() {
+        int sourceFlags = StreamOpFlag.IS_SIZED | StreamOpFlag.IS_DISTINCT;
+
+        List<Integer> ops = Arrays.asList(StreamOpFlag.NOT_SIZED, StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SORTED);
+
+        int opsFlags = StreamOpFlag.combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+        for (int opFlags : ops) {
+            opsFlags = combineOpFlags(opFlags, opsFlags);
+        }
+        assertFalse(StreamOpFlag.SIZED.isKnown(opsFlags));
+        assertTrue(StreamOpFlag.SIZED.isCleared(opsFlags));
+        assertFalse(StreamOpFlag.SIZED.isPreserved(opsFlags));
+        assertTrue(StreamOpFlag.DISTINCT.isKnown(opsFlags));
+        assertFalse(StreamOpFlag.DISTINCT.isCleared(opsFlags));
+        assertFalse(StreamOpFlag.DISTINCT.isPreserved(opsFlags));
+        assertTrue(StreamOpFlag.SORTED.isKnown(opsFlags));
+        assertFalse(StreamOpFlag.SORTED.isCleared(opsFlags));
+        assertFalse(StreamOpFlag.SORTED.isPreserved(opsFlags));
+        assertTrue(StreamOpFlag.ORDERED.isKnown(opsFlags));
+        assertFalse(StreamOpFlag.ORDERED.isCleared(opsFlags));
+        assertFalse(StreamOpFlag.ORDERED.isPreserved(opsFlags));
+
+        int streamFlags = toStreamFlags(opsFlags);
+        assertFalse(StreamOpFlag.SIZED.isKnown(streamFlags));
+        assertTrue(StreamOpFlag.DISTINCT.isKnown(streamFlags));
+        assertTrue(StreamOpFlag.SORTED.isKnown(streamFlags));
+        assertTrue(StreamOpFlag.ORDERED.isKnown(streamFlags));
+    }
+
+    public void testSpliteratorMask() {
+        assertSpliteratorMask(StreamOpFlag.DISTINCT.set(), StreamOpFlag.IS_DISTINCT);
+        assertSpliteratorMask(StreamOpFlag.DISTINCT.clear(), 0);
+
+        assertSpliteratorMask(StreamOpFlag.SORTED.set(), StreamOpFlag.IS_SORTED);
+        assertSpliteratorMask(StreamOpFlag.SORTED.clear(), 0);
+
+        assertSpliteratorMask(StreamOpFlag.ORDERED.set(), StreamOpFlag.IS_ORDERED);
+        assertSpliteratorMask(StreamOpFlag.ORDERED.clear(), 0);
+
+        assertSpliteratorMask(StreamOpFlag.SIZED.set(), StreamOpFlag.IS_SIZED);
+        assertSpliteratorMask(StreamOpFlag.SIZED.clear(), 0);
+
+        assertSpliteratorMask(StreamOpFlag.SHORT_CIRCUIT.set(), 0);
+        assertSpliteratorMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
+    }
+
+    private void assertSpliteratorMask(int actual, int expected) {
+        assertEquals(actual & StreamOpFlag.SPLITERATOR_CHARACTERISTICS_MASK, expected);
+    }
+
+    public void testStreamMask() {
+        assertStreamMask(StreamOpFlag.DISTINCT.set(), StreamOpFlag.IS_DISTINCT);
+        assertStreamMask(StreamOpFlag.DISTINCT.clear(), 0);
+
+        assertStreamMask(StreamOpFlag.SORTED.set(), StreamOpFlag.IS_SORTED);
+        assertStreamMask(StreamOpFlag.SORTED.clear(), 0);
+
+        assertStreamMask(StreamOpFlag.ORDERED.set(), StreamOpFlag.IS_ORDERED);
+        assertStreamMask(StreamOpFlag.ORDERED.clear(), 0);
+
+        assertStreamMask(StreamOpFlag.SIZED.set(), StreamOpFlag.IS_SIZED);
+        assertStreamMask(StreamOpFlag.SIZED.clear(), 0);
+
+        assertStreamMask(StreamOpFlag.SHORT_CIRCUIT.set(), 0);
+        assertStreamMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
+    }
+
+    private void assertStreamMask(int actual, int expected) {
+        assertEquals(actual & StreamOpFlag.STREAM_MASK, expected);
+    }
+
+    public void testOpMask() {
+        assertOpMask(StreamOpFlag.DISTINCT.set(), StreamOpFlag.IS_DISTINCT);
+        assertOpMask(StreamOpFlag.DISTINCT.clear(), StreamOpFlag.NOT_DISTINCT);
+
+        assertOpMask(StreamOpFlag.SORTED.set(), StreamOpFlag.IS_SORTED);
+        assertOpMask(StreamOpFlag.SORTED.clear(), StreamOpFlag.NOT_SORTED);
+
+        assertOpMask(StreamOpFlag.ORDERED.set(), StreamOpFlag.IS_ORDERED);
+        assertOpMask(StreamOpFlag.ORDERED.clear(), StreamOpFlag.NOT_ORDERED);
+
+        assertOpMask(StreamOpFlag.SIZED.set(), 0);
+        assertOpMask(StreamOpFlag.SIZED.clear(), StreamOpFlag.NOT_SIZED);
+
+        assertOpMask(StreamOpFlag.SHORT_CIRCUIT.set(), StreamOpFlag.IS_SHORT_CIRCUIT);
+        assertOpMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
+    }
+
+    private void assertOpMask(int actual, int expected) {
+        assertEquals(actual & StreamOpFlag.OP_MASK, expected);
+    }
+
+    public void testTerminalOpMask() {
+        assertTerminalOpMask(StreamOpFlag.DISTINCT.set(), 0);
+        assertTerminalOpMask(StreamOpFlag.DISTINCT.clear(), 0);
+
+        assertTerminalOpMask(StreamOpFlag.SORTED.set(), 0);
+        assertTerminalOpMask(StreamOpFlag.SORTED.clear(), 0);
+
+        assertTerminalOpMask(StreamOpFlag.ORDERED.set(), 0);
+        assertTerminalOpMask(StreamOpFlag.ORDERED.clear(), StreamOpFlag.NOT_ORDERED);
+
+        assertTerminalOpMask(StreamOpFlag.SIZED.set(), 0);
+        assertTerminalOpMask(StreamOpFlag.SIZED.clear(), 0);
+
+        assertTerminalOpMask(StreamOpFlag.SHORT_CIRCUIT.set(), StreamOpFlag.IS_SHORT_CIRCUIT);
+        assertTerminalOpMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
+    }
+
+    private void assertTerminalOpMask(int actual, int expected) {
+        assertEquals(actual & StreamOpFlag.TERMINAL_OP_MASK, expected);
+    }
+
+    public void testUpstreamTerminalOpMask() {
+        assertUpstreamTerminalOpMask(StreamOpFlag.DISTINCT.set(), 0);
+        assertUpstreamTerminalOpMask(StreamOpFlag.DISTINCT.clear(), 0);
+
+        assertUpstreamTerminalOpMask(StreamOpFlag.SORTED.set(), 0);
+        assertUpstreamTerminalOpMask(StreamOpFlag.SORTED.clear(), 0);
+
+        assertUpstreamTerminalOpMask(StreamOpFlag.ORDERED.set(), 0);
+        assertUpstreamTerminalOpMask(StreamOpFlag.ORDERED.clear(), StreamOpFlag.NOT_ORDERED);
+
+        assertUpstreamTerminalOpMask(StreamOpFlag.SIZED.set(), 0);
+        assertUpstreamTerminalOpMask(StreamOpFlag.SIZED.clear(), 0);
+
+        assertUpstreamTerminalOpMask(StreamOpFlag.SHORT_CIRCUIT.set(), 0);
+        assertUpstreamTerminalOpMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
+    }
+
+    private void assertUpstreamTerminalOpMask(int actual, int expected) {
+        assertEquals(actual & StreamOpFlag.UPSTREAM_TERMINAL_OP_MASK, expected);
+    }
+
+    public void testSpliteratorCharacteristics() {
+        assertEquals(Spliterator.DISTINCT, StreamOpFlag.IS_DISTINCT);
+        assertEquals(Spliterator.SORTED, StreamOpFlag.IS_SORTED);
+        assertEquals(Spliterator.ORDERED, StreamOpFlag.IS_ORDERED);
+        assertEquals(Spliterator.SIZED, StreamOpFlag.IS_SIZED);
+
+        List<Integer> others = Arrays.asList(Spliterator.NONNULL, Spliterator.IMMUTABLE,
+                                             Spliterator.CONCURRENT, Spliterator.SUBSIZED);
+        for (int c : others) {
+            assertNotEquals(c, StreamOpFlag.IS_SHORT_CIRCUIT);
+        }
+    }
+
+    public void testSpliteratorCharacteristicsMask() {
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.DISTINCT.set(), StreamOpFlag.IS_DISTINCT);
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.DISTINCT.clear(), 0);
+
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.SORTED.set(), StreamOpFlag.IS_SORTED);
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.SORTED.clear(), 0);
+
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.ORDERED.set(), StreamOpFlag.IS_ORDERED);
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.ORDERED.clear(), 0);
+
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.SIZED.set(), StreamOpFlag.IS_SIZED);
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.SIZED.clear(), 0);
+
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.SHORT_CIRCUIT.set(), 0);
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
+    }
+
+    private void assertSpliteratorCharacteristicsMask(int actual, int expected) {
+        assertEquals(StreamOpFlag.fromCharacteristics(actual), expected);
+    }
+
+    public void testSpliteratorSorted() {
+        class SortedEmptySpliterator implements Spliterator<Object> {
+            final Comparator<Object> c;
+
+            SortedEmptySpliterator(Comparator<Object> c) {
+                this.c = c;
+            }
+
+            @Override
+            public Spliterator<Object> trySplit() {
+                return null;
+            }
+
+            @Override
+            public boolean tryAdvance(Consumer<? super Object> action) {
+                return false;
+            }
+
+            @Override
+            public long estimateSize() {
+                return Long.MAX_VALUE;
+            }
+
+            @Override
+            public int characteristics() {
+                return Spliterator.SORTED;
+            }
+
+            @Override
+            public Comparator<? super Object> getComparator() {
+                return c;
+            }
+        };
+
+        {
+            int flags = StreamOpFlag.fromCharacteristics(new SortedEmptySpliterator(null));
+            assertEquals(flags, StreamOpFlag.IS_SORTED);
+        }
+
+        {
+            int flags = StreamOpFlag.fromCharacteristics(new SortedEmptySpliterator((a, b) -> 0));
+            assertEquals(flags, 0);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/boottest/java/util/stream/StreamReuseTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package java.util.stream;
+
+import org.testng.annotations.Test;
+
+import java.util.function.Function;
+
+import static org.testng.Assert.fail;
+
+/**
+ * StreamReuseTest
+ *
+ * @author Brian Goetz
+ */
+@Test
+public class StreamReuseTest {
+
+    private <T, U, E, S extends BaseStream<E, S>, D extends TestData<E, S>> void assertSecondFails(
+            D data,
+            Function<S, T> first,
+            Function<S, U> second,
+            Class<? extends Throwable> exception,
+            String text) {
+        S stream = data.stream();
+        T fr = first.apply(stream);
+        try {
+            U sr = second.apply(stream);
+            fail(text + " (seq)");
+        }
+        catch (Throwable e) {
+            if (exception.isAssignableFrom(e.getClass())) {
+                // Expected
+            }
+            else if (e instanceof Error)
+                throw (Error) e;
+            else if (e instanceof RuntimeException)
+                throw (RuntimeException) e;
+            else
+                throw new AssertionError("Unexpected exception " + e.getClass(), e);
+        }
+
+        stream = data.parallelStream();
+        fr = first.apply(stream);
+        try {
+            U sr = second.apply(stream);
+            fail(text + " (par)");
+        }
+        catch (Throwable e) {
+            if (exception.isAssignableFrom(e.getClass())) {
+                // Expected
+            }
+            else if (e instanceof Error)
+                throw (Error) e;
+            else if (e instanceof RuntimeException)
+                throw (RuntimeException) e;
+            else
+                throw new AssertionError("Unexpected exception " + e.getClass(), e);
+        }
+    }
+
+    // Stream
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testTwoStreams(String name, TestData<Integer, Stream<Integer>> data) {
+        assertSecondFails(data,
+                          (Stream<Integer> s) -> s.map(i -> i), (Stream<Integer> s) -> s.map(i -> i),
+                          IllegalStateException.class,
+                          "Stream map / map succeeded erroneously");
+        assertSecondFails(data,
+                          Stream::distinct, (Stream<Integer> s) -> s.map(i -> i),
+                          IllegalStateException.class,
+                          "Stream distinct / map succeeded erroneously");
+        assertSecondFails(data,
+                          (Stream<Integer> s) -> s.map(i -> i), Stream::distinct,
+                          IllegalStateException.class,
+                          "Stream map / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          Stream::distinct, Stream::distinct,
+                          IllegalStateException.class,
+                          "Stream distinct / distinct succeeded erroneously");
+    }
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testTwoTerminals(String name, TestData<Integer, Stream<Integer>> data) {
+        assertSecondFails(data,
+                          Stream::findFirst, Stream::findFirst,
+                          IllegalStateException.class,
+                          "Stream findFirst / findFirst succeeded erroneously");
+    }
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testTerminalStream(String name, TestData<Integer, Stream<Integer>> data) {
+        assertSecondFails(data,
+                          Stream::findFirst, (Stream<Integer> s) -> s.map(i -> i),
+                          IllegalStateException.class,
+                          "Stream findFirst / map succeeded erroneously");
+        assertSecondFails(data,
+                          (Stream<Integer> s) -> s.map(i -> i), Stream::findFirst,
+                          IllegalStateException.class,
+                          "Stream map / findFirst succeeded erroneously");
+        assertSecondFails(data,
+                          Stream::findFirst, Stream::distinct,
+                          IllegalStateException.class,
+                          "Stream findFirst / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          Stream::distinct, Stream::findFirst,
+                          IllegalStateException.class,
+                          "Stream distinct / findFirst succeeded erroneously");
+    }
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testTwoIterators(String name, TestData<Integer, Stream<Integer>> data) {
+        assertSecondFails(data,
+                          Stream::iterator, Stream::iterator,
+                          IllegalStateException.class,
+                          "Stream iterator / iterator succeeded erroneously");
+    }
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testTerminalIterator(String name, TestData<Integer, Stream<Integer>> data) {
+        assertSecondFails(data,
+                          Stream::iterator, Stream::findFirst,
+                          IllegalStateException.class,
+                          "Stream iterator / findFirst succeeded erroneously");
+        assertSecondFails(data,
+                          Stream::findFirst, Stream::iterator,
+                          IllegalStateException.class,
+                          "Stream findFirst / iterator succeeded erroneously");
+    }
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testStreamIterator(String name, TestData<Integer, Stream<Integer>> data) {
+        assertSecondFails(data,
+                          Stream::iterator, (Stream<Integer> s) -> s.map(i -> i),
+                          IllegalStateException.class,
+                          "Stream iterator / map succeeded erroneously");
+        assertSecondFails(data,
+                          (Stream<Integer> s) -> s.map(i -> i), Stream::iterator,
+                          IllegalStateException.class,
+                          "Stream map / iterator succeeded erroneously");
+        assertSecondFails(data,
+                          Stream::iterator, Stream::distinct,
+                          IllegalStateException.class,
+                          "Stream iterator / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          Stream::distinct, Stream::iterator,
+                          IllegalStateException.class,
+                          "Stream distinct / iterator succeeded erroneously");
+    }
+
+    // IntStream
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testTwoStreams(String name, TestData.OfInt data) {
+        assertSecondFails(data,
+                          (IntStream s) -> s.mapToObj(i -> i), (IntStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "IntStream map / map succeeded erroneously");
+        assertSecondFails(data,
+                          IntStream::distinct, (IntStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "IntStream distinct / map succeeded erroneously");
+        assertSecondFails(data,
+                          (IntStream s) -> s.mapToObj(i -> i), IntStream::distinct,
+                          IllegalStateException.class,
+                          "IntStream map / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          IntStream::distinct, IntStream::distinct,
+                          IllegalStateException.class,
+                          "IntStream distinct / distinct succeeded erroneously");
+    }
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testTwoTerminals(String name, TestData.OfInt data) {
+        assertSecondFails(data,
+                          IntStream::sum, IntStream::sum,
+                          IllegalStateException.class,
+                          "IntStream sum / sum succeeded erroneously");
+    }
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testTerminalStream(String name, TestData.OfInt data) {
+        assertSecondFails(data,
+                          IntStream::sum, (IntStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "IntStream sum / map succeeded erroneously");
+        assertSecondFails(data,
+                          (IntStream s) -> s.mapToObj(i -> i), IntStream::sum,
+                          IllegalStateException.class,
+                          "IntStream map / sum succeeded erroneously");
+        assertSecondFails(data,
+                          IntStream::sum, IntStream::distinct,
+                          IllegalStateException.class,
+                          "IntStream sum / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          IntStream::distinct, IntStream::sum,
+                          IllegalStateException.class,
+                          "IntStream distinct / sum succeeded erroneously");
+    }
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testTwoIterators(String name, TestData.OfInt data) {
+        assertSecondFails(data,
+                          IntStream::iterator, IntStream::iterator,
+                          IllegalStateException.class,
+                          "IntStream iterator / iterator succeeded erroneously");
+    }
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testTerminalIterator(String name, TestData.OfInt data) {
+        assertSecondFails(data,
+                          IntStream::iterator, IntStream::sum,
+                          IllegalStateException.class,
+                          "IntStream iterator / sum succeeded erroneously");
+        assertSecondFails(data,
+                          IntStream::sum, IntStream::iterator,
+                          IllegalStateException.class,
+                          "Stream sum / iterator succeeded erroneously");
+    }
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testStreamIterator(String name, TestData.OfInt data) {
+        assertSecondFails(data,
+                          IntStream::iterator, (IntStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "IntStream iterator / map succeeded erroneously");
+        assertSecondFails(data,
+                          (IntStream s) -> s.mapToObj(i -> i), IntStream::iterator,
+                          IllegalStateException.class,
+                          "IntStream map / iterator succeeded erroneously");
+        assertSecondFails(data,
+                          IntStream::iterator, IntStream::distinct,
+                          IllegalStateException.class,
+                          "IntStream iterator / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          IntStream::distinct, IntStream::iterator,
+                          IllegalStateException.class,
+                          "IntStream distinct / iterator succeeded erroneously");
+    }
+
+    // LongStream
+
+    @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+    public void testTwoStreams(String name, TestData.OfLong data) {
+        assertSecondFails(data,
+                          (LongStream s) -> s.mapToObj(i -> i), (LongStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "LongStream map / map succeeded erroneously");
+        assertSecondFails(data,
+                          LongStream::distinct, (LongStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "LongStream distinct / map succeeded erroneously");
+        assertSecondFails(data,
+                          (LongStream s) -> s.mapToObj(i -> i), LongStream::distinct,
+                          IllegalStateException.class,
+                          "LongStream map / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          LongStream::distinct, LongStream::distinct,
+                          IllegalStateException.class,
+                          "LongStream distinct / distinct succeeded erroneously");
+    }
+
+    @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+    public void testTwoTerminals(String name, TestData.OfLong data) {
+        assertSecondFails(data,
+                          LongStream::sum, LongStream::sum,
+                          IllegalStateException.class,
+                          "LongStream sum / sum succeeded erroneously");
+    }
+
+    @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+    public void testTerminalStream(String name, TestData.OfLong data) {
+        assertSecondFails(data,
+                          LongStream::sum, (LongStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "LongStream sum / map succeeded erroneously");
+        assertSecondFails(data,
+                          (LongStream s) -> s.mapToObj(i -> i), LongStream::sum,
+                          IllegalStateException.class,
+                          "LongStream map / sum succeeded erroneously");
+        assertSecondFails(data,
+                          LongStream::sum, LongStream::distinct,
+                          IllegalStateException.class,
+                          "LongStream sum / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          LongStream::distinct, LongStream::sum,
+                          IllegalStateException.class,
+                          "LongStream distinct / sum succeeded erroneously");
+    }
+
+    @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+    public void testTwoIterators(String name, TestData.OfLong data) {
+        assertSecondFails(data,
+                          LongStream::iterator, LongStream::iterator,
+                          IllegalStateException.class,
+                          "LongStream iterator / iterator succeeded erroneously");
+    }
+
+    @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+    public void testTerminalIterator(String name, TestData.OfLong data) {
+        assertSecondFails(data,
+                          LongStream::iterator, LongStream::sum,
+                          IllegalStateException.class,
+                          "LongStream iterator / sum succeeded erroneously");
+        assertSecondFails(data,
+                          LongStream::sum, LongStream::iterator,
+                          IllegalStateException.class,
+                          "Stream sum / iterator succeeded erroneously");
+    }
+
+    @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+    public void testStreamIterator(String name, TestData.OfLong data) {
+        assertSecondFails(data,
+                          LongStream::iterator, (LongStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "LongStream iterator / map succeeded erroneously");
+        assertSecondFails(data,
+                          (LongStream s) -> s.mapToObj(i -> i), LongStream::iterator,
+                          IllegalStateException.class,
+                          "LongStream map / iterator succeeded erroneously");
+        assertSecondFails(data,
+                          LongStream::iterator, LongStream::distinct,
+                          IllegalStateException.class,
+                          "LongStream iterator / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          LongStream::distinct, LongStream::iterator,
+                          IllegalStateException.class,
+                          "LongStream distinct / iterator succeeded erroneously");
+    }
+
+    // DoubleStream
+
+    @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+    public void testTwoStreams(String name, TestData.OfDouble data) {
+        assertSecondFails(data,
+                          (DoubleStream s) -> s.mapToObj(i -> i), (DoubleStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "DoubleStream map / map succeeded erroneously");
+        assertSecondFails(data,
+                          DoubleStream::distinct, (DoubleStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "DoubleStream distinct / map succeeded erroneously");
+        assertSecondFails(data,
+                          (DoubleStream s) -> s.mapToObj(i -> i), DoubleStream::distinct,
+                          IllegalStateException.class,
+                          "DoubleStream map / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          DoubleStream::distinct, DoubleStream::distinct,
+                          IllegalStateException.class,
+                          "DoubleStream distinct / distinct succeeded erroneously");
+    }
+
+    @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+    public void testTwoTerminals(String name, TestData.OfDouble data) {
+        assertSecondFails(data,
+                          DoubleStream::sum, DoubleStream::sum,
+                          IllegalStateException.class,
+                          "DoubleStream sum / sum succeeded erroneously");
+    }
+
+    @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+    public void testTerminalStream(String name, TestData.OfDouble data) {
+        assertSecondFails(data,
+                          DoubleStream::sum, (DoubleStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "DoubleStream sum / map succeeded erroneously");
+        assertSecondFails(data,
+                          (DoubleStream s) -> s.mapToObj(i -> i), DoubleStream::sum,
+                          IllegalStateException.class,
+                          "DoubleStream map / sum succeeded erroneously");
+        assertSecondFails(data,
+                          DoubleStream::sum, DoubleStream::distinct,
+                          IllegalStateException.class,
+                          "DoubleStream sum / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          DoubleStream::distinct, DoubleStream::sum,
+                          IllegalStateException.class,
+                          "DoubleStream distinct / sum succeeded erroneously");
+    }
+
+    @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+    public void testTwoIterators(String name, TestData.OfDouble data) {
+        assertSecondFails(data,
+                          DoubleStream::iterator, DoubleStream::iterator,
+                          IllegalStateException.class,
+                          "DoubleStream iterator / iterator succeeded erroneously");
+    }
+
+    @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+    public void testTerminalIterator(String name, TestData.OfDouble data) {
+        assertSecondFails(data,
+                          DoubleStream::iterator, DoubleStream::sum,
+                          IllegalStateException.class,
+                          "DoubleStream iterator / sum succeeded erroneously");
+        assertSecondFails(data,
+                          DoubleStream::sum, DoubleStream::iterator,
+                          IllegalStateException.class,
+                          "Stream sum / iterator succeeded erroneously");
+    }
+
+    @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+    public void testStreamIterator(String name, TestData.OfDouble data) {
+        assertSecondFails(data,
+                          DoubleStream::iterator, (DoubleStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "DoubleStream iterator / map succeeded erroneously");
+        assertSecondFails(data,
+                          (DoubleStream s) -> s.mapToObj(i -> i), DoubleStream::iterator,
+                          IllegalStateException.class,
+                          "DoubleStream map / iterator succeeded erroneously");
+        assertSecondFails(data,
+                          DoubleStream::iterator, DoubleStream::distinct,
+                          IllegalStateException.class,
+                          "DoubleStream iterator / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          DoubleStream::distinct, DoubleStream::iterator,
+                          IllegalStateException.class,
+                          "DoubleStream distinct / iterator succeeded erroneously");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/boottest/java/util/stream/UnorderedTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+package java.util.stream;
+
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+import java.util.function.UnaryOperator;
+
+@Test
+public class UnorderedTest extends OpTestCase {
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testTerminalOps(String name, TestData<Integer, Stream<Integer>> data) {
+        testTerminal(data, s -> { s.forEach(x -> { }); return 0; });
+
+        testTerminal(data, s -> s.findAny(), (a, b) -> assertEquals(a.isPresent(), b.isPresent()));
+
+        testTerminal(data, s -> s.anyMatch(e -> true));
+    }
+
+
+    private <T, R> void testTerminal(TestData<T, Stream<T>> data, Function<Stream<T>, R> terminalF) {
+        testTerminal(data, terminalF, LambdaTestHelpers::assertContentsEqual);
+    }
+
+    static class WrappingUnaryOperator<S> implements UnaryOperator<S> {
+
+        final boolean isLimit;
+        final UnaryOperator<S> uo;
+
+        WrappingUnaryOperator(UnaryOperator<S> uo) {
+            this(uo, false);
+        }
+
+        WrappingUnaryOperator(UnaryOperator<S> uo, boolean isLimit) {
+            this.uo = uo;
+            this.isLimit = isLimit;
+        }
+
+        @Override
+        public S apply(S s) {
+            return uo.apply(s);
+        }
+    }
+
+    static <S> WrappingUnaryOperator<S> wrap(UnaryOperator<S> uo) {
+        return new WrappingUnaryOperator<>(uo);
+    }
+
+    static <S> WrappingUnaryOperator<S> wrap(UnaryOperator<S> uo, boolean isLimit) {
+        return new WrappingUnaryOperator<>(uo, isLimit);
+    }
+
+    @SuppressWarnings("rawtypes")
+    private List permutationOfFunctions =
+            LambdaTestHelpers.perm(Arrays.<WrappingUnaryOperator<Stream<Object>>>asList(
+                    wrap(s -> s.sorted()),
+                    wrap(s -> s.distinct()),
+                    wrap(s -> s.limit(5), true)
+            ));
+
+    @SuppressWarnings("unchecked")
+    private <T, R> void testTerminal(TestData<T, Stream<T>> data,
+                                     Function<Stream<T>, R> terminalF,
+                                     BiConsumer<R, R> equalityAsserter) {
+        testTerminal(data, terminalF, equalityAsserter, permutationOfFunctions, StreamShape.REFERENCE);
+    }
+
+    //
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testIntTerminalOps(String name, TestData.OfInt data) {
+        testIntTerminal(data, s -> { s.forEach(x -> { }); return 0; });
+        testIntTerminal(data, s -> s.findAny(), (a, b) -> assertEquals(a.isPresent(), b.isPresent()));
+        testIntTerminal(data, s -> s.anyMatch(e -> true));
+    }
+
+
+    private <T, R> void testIntTerminal(TestData.OfInt data, Function<IntStream, R> terminalF) {
+        testIntTerminal(data, terminalF, LambdaTestHelpers::assertContentsEqual);
+    }
+
+    private List<List<WrappingUnaryOperator<IntStream>>> intPermutationOfFunctions =
+            LambdaTestHelpers.perm(Arrays.asList(
+                    wrap(s -> s.sorted()),
+                    wrap(s -> s.distinct()),
+                    wrap(s -> s.limit(5), true)
+            ));
+
+    private <R> void testIntTerminal(TestData.OfInt data,
+                                     Function<IntStream, R> terminalF,
+                                     BiConsumer<R, R> equalityAsserter) {
+        testTerminal(data, terminalF, equalityAsserter, intPermutationOfFunctions, StreamShape.INT_VALUE);
+    }
+
+    //
+
+    @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+    public void testLongTerminalOps(String name, TestData.OfLong data) {
+        testLongTerminal(data, s -> { s.forEach(x -> { }); return 0; });
+        testLongTerminal(data, s -> s.findAny(), (a, b) -> assertEquals(a.isPresent(), b.isPresent()));
+        testLongTerminal(data, s -> s.anyMatch(e -> true));
+    }
+
+
+    private <T, R> void testLongTerminal(TestData.OfLong data, Function<LongStream, R> terminalF) {
+        testLongTerminal(data, terminalF, LambdaTestHelpers::assertContentsEqual);
+    }
+
+    private List<List<WrappingUnaryOperator<LongStream>>> longPermutationOfFunctions =
+            LambdaTestHelpers.perm(Arrays.asList(
+                    wrap(s -> s.sorted()),
+                    wrap(s -> s.distinct()),
+                    wrap(s -> s.limit(5), true)
+            ));
+
+    private <R> void testLongTerminal(TestData.OfLong data,
+                                      Function<LongStream, R> terminalF,
+                                      BiConsumer<R, R> equalityAsserter) {
+        testTerminal(data, terminalF, equalityAsserter, longPermutationOfFunctions, StreamShape.LONG_VALUE);
+    }
+
+    //
+
+    @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+    public void testDoubleTerminalOps(String name, TestData.OfDouble data) {
+        testDoubleTerminal(data, s -> { s.forEach(x -> { }); return 0; });
+        testDoubleTerminal(data, s -> s.findAny(), (a, b) -> assertEquals(a.isPresent(), b.isPresent()));
+        testDoubleTerminal(data, s -> s.anyMatch(e -> true));
+    }
+
+
+    private <T, R> void testDoubleTerminal(TestData.OfDouble data, Function<DoubleStream, R> terminalF) {
+        testDoubleTerminal(data, terminalF, LambdaTestHelpers::assertContentsEqual);
+    }
+
+    private List<List<WrappingUnaryOperator<DoubleStream>>> doublePermutationOfFunctions =
+            LambdaTestHelpers.perm(Arrays.asList(
+                    wrap(s -> s.sorted()),
+                    wrap(s -> s.distinct()),
+                    wrap(s -> s.limit(5), true)
+            ));
+
+    private <R> void testDoubleTerminal(TestData.OfDouble data,
+                                        Function<DoubleStream, R> terminalF,
+                                        BiConsumer<R, R> equalityAsserter) {
+        testTerminal(data, terminalF, equalityAsserter, doublePermutationOfFunctions, StreamShape.DOUBLE_VALUE);
+    }
+
+    //
+
+    private <T, S extends BaseStream<T, S>, R> void testTerminal(TestData<T, S> data,
+                                                                 Function<S, R> terminalF,
+                                                                 BiConsumer<R, R> equalityAsserter,
+                                                                 List<List<WrappingUnaryOperator<S>>> pFunctions,
+                                                                 StreamShape shape) {
+        CheckClearOrderedOp<T> checkClearOrderedOp = new CheckClearOrderedOp<>(shape);
+        for (List<WrappingUnaryOperator<S>> f : pFunctions) {
+            @SuppressWarnings("unchecked")
+            UnaryOperator<S> fi = interpose(f, (S s) -> (S) chain(s, checkClearOrderedOp));
+            withData(data).
+                    terminal(fi, terminalF).
+                    without(TerminalTestScenario.ALL_PARALLEL_SEQUENTIAL).
+                    equalator(equalityAsserter).
+                    exercise();
+        }
+
+        CheckSetOrderedOp<T> checkSetOrderedOp = new CheckSetOrderedOp<>(shape);
+        for (List<WrappingUnaryOperator<S>> f : pFunctions) {
+            @SuppressWarnings("unchecked")
+            UnaryOperator<S> fi = interpose(f, (S s) -> (S) chain(s, checkSetOrderedOp));
+            withData(data).
+                    terminal(fi, s -> terminalF.apply(s.sequential())).
+                    without(TerminalTestScenario.ALL_PARALLEL_SEQUENTIAL).
+                    equalator(equalityAsserter).
+                    exercise();
+        }
+    }
+
+    static class CheckClearOrderedOp<T> implements StatelessTestOp<T, T> {
+        private final StreamShape shape;
+
+        CheckClearOrderedOp(StreamShape shape) {
+            this.shape = shape;
+        }
+
+        @Override
+        public StreamShape outputShape() {
+            return shape;
+        }
+
+        @Override
+        public StreamShape inputShape() {
+            return shape;
+        }
+
+        @Override
+        public Sink<T> opWrapSink(int flags, boolean parallel, Sink<T> sink) {
+            if (parallel) {
+                assertTrue(StreamOpFlag.ORDERED.isCleared(flags));
+            }
+
+            return sink;
+        }
+    }
+
+    static class CheckSetOrderedOp<T> extends CheckClearOrderedOp<T> {
+
+        CheckSetOrderedOp(StreamShape shape) {
+            super(shape);
+        }
+
+        @Override
+        public Sink<T> opWrapSink(int flags, boolean parallel, Sink<T> sink) {
+            assertTrue(StreamOpFlag.ORDERED.isKnown(flags) || StreamOpFlag.ORDERED.isPreserved(flags));
+
+            return sink;
+        }
+    }
+
+    private <T, S extends BaseStream<T, S>>
+    UnaryOperator<S> interpose(List<WrappingUnaryOperator<S>> fs, UnaryOperator<S> fi) {
+        int l = -1;
+        for (int i = 0; i < fs.size(); i++) {
+            if (fs.get(i).isLimit) {
+                l = i;
+            }
+        }
+
+        final int lastLimitIndex = l;
+        return s -> {
+            if (lastLimitIndex == -1)
+                s = fi.apply(s);
+            for (int i = 0; i < fs.size(); i++) {
+                s = fs.get(i).apply(s);
+                if (i >= lastLimitIndex) {
+                    s = fi.apply(s);
+                }
+            }
+            return s;
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/test/TEST.properties	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,8 @@
+# This file identifies root(s) of the test-ng hierarchy.
+
+TestNG.dirs = .
+
+lib.dirs = /java/util/stream/bootlib
+
+# Tests that must run in othervm mode
+othervm.dirs= /java/util/stream
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/test/org/openjdk/tests/java/lang/invoke/DeserializeMethodTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ *
+ * 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.lang.invoke;
+
+import org.testng.annotations.Test;
+
+import java.io.Serializable;
+import java.lang.invoke.SerializedLambda;
+import java.lang.reflect.Method;
+
+import static org.testng.Assert.fail;
+
+/**
+ * Ensure that the $deserializeLambda$ method is present when it should be, and absent otherwise
+ */
+
+@Test(groups = { "serialization-hostile" })
+public class DeserializeMethodTest {
+    private void assertDeserializeMethod(Class<?> clazz, boolean expectedPresent) {
+        try {
+            Method m = clazz.getDeclaredMethod("$deserializeLambda$", SerializedLambda.class);
+            if (!expectedPresent)
+                fail("Unexpected $deserializeLambda$ in " + clazz);
+        }
+        catch (NoSuchMethodException e) {
+            if (expectedPresent)
+                fail("Expected to find $deserializeLambda$ in " + clazz);
+        }
+    }
+
+    static class Empty {}
+
+    public void testEmptyClass() {
+        assertDeserializeMethod(Empty.class, false);
+    }
+
+    static class Cap1 {
+        void foo() {
+            Runnable r = (Runnable & Serializable) () -> { };
+        }
+    }
+
+    public void testCapturingSerLambda() {
+        assertDeserializeMethod(Cap1.class, true);
+    }
+
+    static class Cap2 {
+        void foo() {
+            Runnable r = () -> { };
+        }
+    }
+
+    public void testCapturingNonSerLambda() {
+        assertDeserializeMethod(Cap2.class, false);
+    }
+
+    interface Marker { }
+    static class Cap3 {
+        void foo() {
+            Runnable r = (Runnable & Marker) () -> { };
+        }
+    }
+
+    public void testCapturingNonserIntersectionLambda() {
+        assertDeserializeMethod(Cap3.class, false);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/test/org/openjdk/tests/java/lang/invoke/MHProxiesTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ *
+ * 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.lang.invoke;
+
+import org.testng.annotations.Test;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandleProxies;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+
+import static org.testng.Assert.assertEquals;
+
+/**
+ * MHProxiesTest -- regression test for MH library bug
+ */
+@Test
+public class MHProxiesTest {
+    public interface Sam { double m(int arg); }
+
+    public static Byte m(int arg) { return (byte) arg; }
+
+    public void testProxy() throws NoSuchMethodException, IllegalAccessException {
+        MethodHandle m = MethodHandles.lookup().findStatic(MHProxiesTest.class, "m",
+                                                           MethodType.methodType(Byte.class, int.class));
+        Sam s = MethodHandleProxies.asInterfaceInstance(Sam.class, m);
+        assertEquals(66d, s.m(66));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/test/org/openjdk/tests/java/lang/invoke/SerializedLambdaTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,280 @@
+/*
+ * 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.
+ *
+ * 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.lang.invoke;
+
+import org.testng.annotations.Test;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.BiPredicate;
+import java.util.function.Consumer;
+import java.util.function.LongConsumer;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+/**
+ * SerializedLambdaTest
+ *
+ * @author Brian Goetz
+ */
+@Test
+public class SerializedLambdaTest {
+    @SuppressWarnings("unchecked")
+    private<T> void assertSerial(T p, Consumer<T> asserter) throws IOException, ClassNotFoundException {
+        asserter.accept(p);
+
+        byte[] bytes = serialize(p);
+        assertTrue(bytes.length > 0);
+
+        asserter.accept((T) deserialize(bytes));
+    }
+
+    private void assertNotSerial(Predicate<String> p, Consumer<Predicate<String>> asserter)
+            throws IOException, ClassNotFoundException {
+        asserter.accept(p);
+        try {
+            byte[] bytes = serialize(p);
+            fail("Expected serialization failure");
+        }
+        catch (NotSerializableException e) {
+            // success
+        }
+    }
+
+    private byte[] serialize(Object o) throws IOException {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(bos);
+        oos.writeObject(o);
+        oos.close();
+        return bos.toByteArray();
+    }
+
+    private Object deserialize(byte[] bytes) throws IOException, ClassNotFoundException {
+        try(ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes))) {
+            return ois.readObject();
+        }
+    }
+
+    // Test instantiating against intersection type
+    public void testSimpleSerializedInstantiation() throws IOException, ClassNotFoundException {
+        @SuppressWarnings("unchecked")
+        Predicate<String> pred = (Predicate<String> & Serializable) s -> true;
+        assertSerial(pred,
+                     p -> {
+                         assertTrue(p instanceof Predicate);
+                         assertTrue(p instanceof Serializable);
+                         assertTrue(p.test(""));
+                     });
+    }
+
+    interface SerPredicate<T> extends Predicate<T>, Serializable { }
+
+    // Test instantiating against derived type
+    public void testSimpleSerializedInstantiation2() throws IOException, ClassNotFoundException {
+        SerPredicate<String> serPred = (SerPredicate<String>) s -> true;
+        assertSerial(serPred,
+                     p -> {
+                         assertTrue(p instanceof Predicate);
+                         assertTrue(p instanceof Serializable);
+                         assertTrue(p instanceof SerPredicate);
+                         assertTrue(p.test(""));
+                     });
+    }
+
+    // Negative test: non-serializable lambdas are in fact not serializable
+    public void testNonserializableInstantiation() throws IOException, ClassNotFoundException {
+        @SuppressWarnings("unchecked")
+        Predicate<String> pred = (Predicate<String>) s -> true;
+        assertNotSerial(pred,
+                        p -> {
+                            assertTrue(p instanceof Predicate);
+                            assertFalse(p instanceof Serializable);
+                            assertTrue(p.test(""));
+                        });
+    }
+
+    // Test lambda capturing int
+    public void testSerializeCapturingInt() throws IOException, ClassNotFoundException {
+        class Moo {
+            @SuppressWarnings("unchecked")
+            Predicate<String> foo(int x) {
+                return (Predicate<String> & Serializable) s -> s.length() >= x;
+            }
+        }
+        Predicate<String> pred = new Moo().foo(3);
+        assertSerial(pred, p -> {
+            assertTrue(p.test("yada"));
+            assertFalse(p.test("no"));
+        });
+    }
+
+    // Test lambda capturing String
+    public void testSerializeCapturingString() throws IOException, ClassNotFoundException {
+        class Moo {
+            @SuppressWarnings("unchecked")
+            Predicate<String> foo(String t) {
+                return (Predicate<String> & Serializable) s -> s.equals(t);
+            }
+        }
+        Predicate<String> pred = new Moo().foo("goo");
+        assertSerial(pred, p -> {
+            assertTrue(p.test("goo"));
+            assertFalse(p.test("foo"));
+        });
+    }
+
+    // Negative test: lambdas that capture a non-serializable var
+    public void testSerializeCapturingNonSerializable() throws IOException, ClassNotFoundException {
+        class Box {
+            String s;
+
+            Box(String s) { this.s = s; }
+        }
+        class Moo {
+            @SuppressWarnings("unchecked")
+            Predicate<String> foo(Box b) {
+                return (Predicate<String> & Serializable) s -> s.equals(b.s);
+            }
+        }
+        Predicate<String> pred = new Moo().foo(new Box("goo"));
+        assertNotSerial(pred, p -> {
+            assertTrue(p.test("goo"));
+            assertFalse(p.test("foo"));
+        });
+    }
+
+    static boolean startsWithA(String s) {
+        return s.startsWith("a");
+    }
+
+    // Test static method ref
+    public void testStaticMR() throws IOException, ClassNotFoundException {
+        @SuppressWarnings("unchecked")
+        Predicate<String> mh1 = (Predicate<String> & Serializable) SerializedLambdaTest::startsWithA;
+        @SuppressWarnings("unchecked")
+        Predicate<String> mh2 = (SerPredicate<String>) SerializedLambdaTest::startsWithA;
+        Consumer<Predicate<String>> b = p -> {
+            assertTrue(p instanceof Serializable);
+            assertTrue(p.test("arf"));
+            assertFalse(p.test("barf"));
+        };
+        assertSerial(mh1, b);
+        assertSerial(mh2, b);
+    }
+
+    // Test unbound method ref of nonserializable class -- should still succeed
+    public void testUnboundMR() throws IOException, ClassNotFoundException {
+        class Moo {
+            public boolean startsWithB(String s) {
+                return s.startsWith("b");
+            }
+        }
+        @SuppressWarnings("unchecked")
+        BiPredicate<Moo, String> mh1 = (BiPredicate<Moo, String> & Serializable) Moo::startsWithB;
+        Consumer<BiPredicate<Moo, String>> b = p -> {
+            assertTrue(p instanceof Serializable);
+            assertTrue(p.test(new Moo(), "barf"));
+            assertFalse(p.test(new Moo(), "arf"));
+        };
+        assertSerial(mh1, b);
+    }
+
+    // Negative test: test bound MR of nonserializable class
+    public void testBoundMRNotSerReceiver() throws IOException, ClassNotFoundException {
+        class Moo {
+            public boolean startsWithB(String s) {
+                return s.startsWith("b");
+            }
+        }
+        Moo moo = new Moo();
+        @SuppressWarnings("unchecked")
+        Predicate<String> mh1 = (Predicate<String> & Serializable) moo::startsWithB;
+        @SuppressWarnings("unchecked")
+        Predicate<String> mh2 = (SerPredicate<String>) moo::startsWithB;
+        Consumer<Predicate<String>> b = p -> {
+            assertTrue(p instanceof Serializable);
+            assertTrue(p.test("barf"));
+            assertFalse(p.test("arf"));
+        };
+        assertNotSerial(mh1, b);
+        assertNotSerial(mh2, b);
+    }
+
+    // Test bound MR of serializable class
+    @SuppressWarnings("serial")
+    static class ForBoundMRef implements Serializable {
+        public boolean startsWithB(String s) {
+            return s.startsWith("b");
+        }
+    }
+
+    public void testBoundMR() throws IOException, ClassNotFoundException {
+        ForBoundMRef moo = new ForBoundMRef();
+        @SuppressWarnings("unchecked")
+        Predicate<String> mh1 = (Predicate<String> & Serializable) moo::startsWithB;
+        @SuppressWarnings("unchecked")
+        Predicate<String> mh2 = (SerPredicate<String>) moo::startsWithB;
+        Consumer<Predicate<String>> b = p -> {
+            assertTrue(p instanceof Serializable);
+            assertTrue(p.test("barf"));
+            assertFalse(p.test("arf"));
+        };
+        assertSerial(mh1, b);
+        assertSerial(mh2, b);
+    }
+
+    static class ForCtorRef {
+        public boolean startsWithB(String s) {
+            return s.startsWith("b");
+        }
+    }
+    // Test ctor ref of nonserializable class
+    public void testCtorRef() throws IOException, ClassNotFoundException {
+        @SuppressWarnings("unchecked")
+        Supplier<ForCtorRef> ctor = (Supplier<ForCtorRef> & Serializable) ForCtorRef::new;
+        Consumer<Supplier<ForCtorRef>> b = s -> {
+            assertTrue(s instanceof Serializable);
+            ForCtorRef m = s.get();
+            assertTrue(m.startsWithB("barf"));
+            assertFalse(m.startsWithB("arf"));
+        };
+        assertSerial(ctor, b);
+    }
+
+    //Test throwing away return type
+    public void testDiscardReturnBound() throws IOException, ClassNotFoundException {
+        List<String> list = new ArrayList<>();
+        Consumer<String> c = (Consumer<String> & Serializable) list::add;
+        assertSerial(c, cc -> { assertTrue(cc instanceof Consumer); });
+
+        AtomicLong a = new AtomicLong();
+        LongConsumer lc = (LongConsumer & Serializable) a::addAndGet;
+        assertSerial(lc, plc -> { plc.accept(3); });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/test/org/openjdk/tests/java/util/FillableStringTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ *
+ * 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;
+
+import java.util.Arrays;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.*;
+
+@Test(groups = "lib")
+public class FillableStringTest {
+    public Stream<String> generate() {
+        return Arrays.asList("one", "two", "three", "four", "five", "six").stream()
+                .filter(s->s.length() > 3)
+                .map(String::toUpperCase);
+    }
+
+    public void testStringBuilder() {
+        String s = generate().collect(Collectors.toStringBuilder()).toString();
+        assertEquals(s, "THREEFOURFIVE");
+    }
+
+    public void testStringBuffer() {
+        String s = generate().collect(Collectors.toStringBuilder()).toString();
+        assertEquals(s, "THREEFOURFIVE");
+    }
+
+    public void testStringJoiner() {
+        String s = generate().collect(Collectors.toStringJoiner("-")).toString();
+        assertEquals(s, "THREE-FOUR-FIVE");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/test/org/openjdk/tests/java/util/MapTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ *
+ * 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;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.LambdaTestHelpers;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+/**
+ * Unit tests for extension methods on Map
+ */
+public class MapTest {
+
+    private static final Map<Integer, String> EXPECTED = new HashMap<>();
+
+    private Map<Integer, String> map;
+
+    @BeforeClass
+    public void setUpClass() {
+        EXPECTED.put(0, "zero");
+        EXPECTED.put(1, "one");
+        EXPECTED.put(2, "two");
+        EXPECTED.put(3, "three");
+        EXPECTED.put(4, "four");
+        EXPECTED.put(5, "five");
+        EXPECTED.put(6, "six");
+        EXPECTED.put(7, "seven");
+        EXPECTED.put(8, "eight");
+        EXPECTED.put(9, "nine");
+    }
+
+    @AfterClass
+    public void tearDownClass() {
+        EXPECTED.clear();
+    }
+
+    @BeforeMethod
+    public void setUp() {
+        map = new HashMap<>(EXPECTED);
+    }
+
+    @AfterMethod
+    public void tearDown() {
+        map.clear();
+        map = null;
+    }
+
+    @Test(groups = { "serialization-hostile" })
+    public void testForEach() {
+        final Set<String> values = new HashSet<>(EXPECTED.size());
+        map.forEach((k, v) -> {values.add(v);});
+        LambdaTestHelpers.assertContentsUnordered(values, EXPECTED.values());
+    }
+
+    @Test
+    public void testReplaceAll() {
+        map.replaceAll((k, v) -> {return v.toUpperCase();});
+        for (final Map.Entry<Integer, String> entry : map.entrySet()) {
+            assertEquals(entry.getValue(), EXPECTED.get(entry.getKey()).toUpperCase());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/test/org/openjdk/tests/java/util/NullArgsTestCase.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 1997, 2010, 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.
+ */
+package org.openjdk.tests.java.util;
+
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.function.Consumer;
+
+import static org.testng.Assert.fail;
+
+/**
+ * NullArgsTestCase -- Given a Consumer&ltObject[]&gt, and an Object[] array of args, call the block with the args,
+ * assert success, and then call the consumer N times, each time setting one of the args to null, and assert that
+ * all these throw NPE.
+ *
+ * Typically this would be combined with a DataProvider that serves up combinations of things to be tested, as in
+ * IteratorsNullTest.
+ */
+public abstract class NullArgsTestCase {
+    public final String name;
+    public final Consumer<Object[]> sink;
+    public final Object[] args;
+
+    protected NullArgsTestCase(String name, Consumer<Object[]> sink, Object[] args) {
+        this.name = name;
+        this.sink = sink;
+        this.args = args;
+    }
+
+    @Test
+    public void goodNonNull() {
+        sink.accept(args);
+    }
+
+    @Test
+    public void throwWithNull() {
+        for (int i=0; i<args.length; i++) {
+            Object[] temp = Arrays.copyOf(args, args.length);
+            temp[i] = null;
+            try {
+                sink.accept(temp);
+                fail(String.format("Expected NullPointerException for argument %d of test case %s", i, name));
+            }
+            catch (NullPointerException e) {
+                // Success
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectionAndMapModifyStreamTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package org.openjdk.tests.java.util.stream;
+
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.LinkedTransferQueue;
+import java.util.concurrent.PriorityBlockingQueue;
+import java.util.function.Supplier;
+import java.util.stream.LambdaTestHelpers;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.*;
+import java.util.stream.Stream;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Tests laziness of stream operations -- mutations to the source after the stream() but prior to terminal operations
+ * are reflected in the stream contents.
+ */
+@Test
+public class CollectionAndMapModifyStreamTest {
+
+    @DataProvider(name = "collections")
+    public Object[][] createCollections() {
+        List<Integer> content = LambdaTestHelpers.countTo(10);
+
+        List<Collection<Integer>> collections = new ArrayList<>();
+        collections.add(new ArrayList<>(content));
+        collections.add(new LinkedList<>(content));
+        collections.add(new Vector<>(content));
+
+        collections.add(new HashSet<>(content));
+        collections.add(new LinkedHashSet<>(content));
+        collections.add(new TreeSet<>(content));
+
+        Stack<Integer> stack = new Stack<>();
+        stack.addAll(content);
+        collections.add(stack);
+        collections.add(new PriorityQueue<>(content));
+        collections.add(new ArrayDeque<>(content));
+
+        // Concurrent collections
+
+        collections.add(new ConcurrentSkipListSet<>(content));
+
+        ArrayBlockingQueue<Integer> arrayBlockingQueue = new ArrayBlockingQueue<>(content.size());
+        for (Integer i : content)
+            arrayBlockingQueue.add(i);
+        collections.add(arrayBlockingQueue);
+        collections.add(new PriorityBlockingQueue<>(content));
+        collections.add(new LinkedBlockingQueue<>(content));
+        collections.add(new LinkedTransferQueue<>(content));
+        collections.add(new ConcurrentLinkedQueue<>(content));
+        collections.add(new LinkedBlockingDeque<>(content));
+        collections.add(new ConcurrentLinkedDeque<>(content));
+
+        Object[][] params = new Object[collections.size()][];
+        for (int i = 0; i < collections.size(); i++) {
+            params[i] = new Object[]{collections.get(i).getClass().getName(), collections.get(i)};
+        }
+
+        return params;
+    }
+
+    @Test(dataProvider = "collections")
+    public void testCollectionSizeRemove(String name, Collection<Integer> c) {
+        assertTrue(c.remove(1));
+        Stream<Integer> s = c.stream();
+        assertTrue(c.remove(2));
+        Object[] result = s.toArray();
+        assertEquals(result.length, c.size());
+    }
+
+    @DataProvider(name = "maps")
+    public Object[][] createMaps() {
+        Map<Integer, Integer> content = new HashMap<>();
+        for (int i = 0; i < 10; i++) {
+            content.put(i, i);
+        }
+
+        Map<String, Supplier<Map<Integer, Integer>>> maps = new HashMap<>();
+
+        maps.put(HashMap.class.getName(), () -> new HashMap<>(content));
+        maps.put(HashMap.class.getName(), () -> new LinkedHashMap<>(content));
+        maps.put(IdentityHashMap.class.getName(), () -> new IdentityHashMap<>(content));
+        maps.put(WeakHashMap.class.getName(), () -> new WeakHashMap<>(content));
+
+        maps.put(TreeMap.class.getName(), () -> new TreeMap<>(content));
+        maps.put(TreeMap.class.getName() + ".descendingMap()", () -> new TreeMap<>(content).descendingMap());
+
+        // The following are not lazy
+//        maps.put(TreeMap.class.getName() + ".descendingMap().descendingMap()", () -> new TreeMap<>(content).descendingMap().descendingMap());
+//        maps.put(TreeMap.class.getName() + ".headMap()", () -> new TreeMap<>(content).headMap(content.size() - 1));
+//        maps.put(TreeMap.class.getName() + ".descendingMap().headMap()", () -> new TreeMap<>(content).descendingMap().tailMap(content.size() - 1, false));
+
+        // Concurrent collections
+
+        maps.put(ConcurrentHashMap.class.getName(), () -> new ConcurrentHashMap<>(content));
+        maps.put(ConcurrentSkipListMap.class.getName(), () -> new ConcurrentSkipListMap<>(content));
+
+        Object[][] params = new Object[maps.size()][];
+        int i = 0;
+        for (Map.Entry<String, Supplier<Map<Integer, Integer>>> e : maps.entrySet()) {
+            params[i++] = new Object[]{e.getKey(), e.getValue()};
+
+        }
+
+        return params;
+    }
+
+    @Test(dataProvider = "maps", groups = { "serialization-hostile" })
+    public void testMapKeysSizeRemove(String name, Supplier<Map<Integer, Integer>> c) {
+        testCollectionSizeRemove(name + " key set", c.get().keySet());
+    }
+
+    @Test(dataProvider = "maps", groups = { "serialization-hostile" })
+    public void testMapValuesSizeRemove(String name, Supplier<Map<Integer, Integer>> c) {
+        testCollectionSizeRemove(name + " value set", c.get().values());
+    }
+
+    @Test(dataProvider = "maps")
+    public void testMapEntriesSizeRemove(String name, Supplier<Map<Integer, Integer>> c) {
+        testEntrySetSizeRemove(name + " entry set", c.get().entrySet());
+    }
+
+    private void testEntrySetSizeRemove(String name, Set<Map.Entry<Integer, Integer>> c) {
+        Map.Entry<Integer, Integer> first = c.iterator().next();
+        assertTrue(c.remove(first));
+        Stream<Map.Entry<Integer, Integer>> s = c.stream();
+        Map.Entry<Integer, Integer> second = c.iterator().next();
+        assertTrue(c.remove(second));
+        Object[] result = s.toArray();
+        assertEquals(result.length, c.size());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/test/org/openjdk/tests/java/util/stream/DistinctOpTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package org.openjdk.tests.java.util.stream;
+
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.stream.*;
+
+import static java.util.stream.LambdaTestHelpers.*;
+
+/**
+ * DistinctOpTest
+ */
+@Test
+public class DistinctOpTest extends OpTestCase {
+
+    public void testUniqOp() {
+        assertCountSum(repeat(0, 10).stream().distinct(), 1, 0);
+        assertCountSum(repeat(1, 10).stream().distinct(), 1, 1);
+        assertCountSum(countTo(0).stream().distinct(), 0, 0);
+        assertCountSum(countTo(10).stream().distinct(), 10, 55);
+        assertCountSum(countTo(10).stream().distinct(), 10, 55);
+    }
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testOp(String name, TestData.OfRef<Integer> data) {
+        Collection<Integer> result = exerciseOpsInt(data, Stream::distinct, IntStream::distinct, LongStream::distinct, DoubleStream::distinct);
+
+        assertUnique(result);
+        assertTrue((data.size() > 0) ? result.size() > 0 : result.size() == 0);
+        assertTrue(result.size() <= data.size());
+    }
+
+    @Test(dataProvider = "withNull:StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testOpWithNull(String name, TestData.OfRef<Integer> data) {
+        Collection<Integer> node = exerciseOps(data, Stream::distinct);
+        assertUnique(node);
+
+        node = withData(data).
+                stream(s -> s.unordered().distinct()).
+                parallelEqualityAsserter(LambdaTestHelpers::assertContentsUnordered).
+                exercise();
+        assertUnique(node);
+
+        node = exerciseOps(data, s -> s.distinct().distinct());
+        assertUnique(node);
+    }
+
+    @Test(dataProvider = "withNull:StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testOpWithNullSorted(String name, TestData.OfRef<Integer> data) {
+        List<Integer> l = new ArrayList<>();
+        data.into(l).sort(cNullInteger);
+        // Need to inject SORTED into the sorted list source since
+        // sorted() with a comparator ironically clears SORTED
+        Collection<Integer> node = exerciseOps(new SortedTestData<>(l), Stream::distinct);
+        assertUnique(node);
+        assertSorted(node, cNullInteger);
+    }
+
+    @SuppressWarnings("serial")
+    static class SortedTestData<T> extends TestData.AbstractTestData.RefTestData<T, List<T>> {
+        SortedTestData(List<T> coll) {
+            super("SortedTestData", coll,
+                  c -> StreamSupport.stream(Spliterators.spliterator(c.toArray(), Spliterator.ORDERED | Spliterator.SORTED)),
+                  c -> StreamSupport.parallelStream(Spliterators.spliterator(c.toArray(), Spliterator.ORDERED | Spliterator.SORTED)),
+                  c -> Spliterators.spliterator(c.toArray(), Spliterator.ORDERED | Spliterator.SORTED),
+                  List::size);
+        }
+    }
+
+    public static final Comparator<Integer> cNullInteger = (a, b) -> {
+        if (a == null && b == null) {
+            return 0;
+        }
+        else if (a == null) {
+            return -1;
+        }
+        else if (b == null) {
+            return 1;
+        }
+        else {
+            return Integer.compare(a, b);
+        }
+    };
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testDistinctDistinct(String name, TestData.OfRef<Integer> data) {
+        Collection<Integer> result = withData(data)
+                .stream(s -> s.distinct().distinct(), new CollectorOps.TestParallelSizedOp<>())
+                .exercise();
+        assertUnique(result);
+    }
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testDistinctSorted(String name, TestData.OfRef<Integer> data) {
+        Collection<Integer> result = withData(data)
+                .stream(s -> s.distinct().sorted(),
+                        new CollectorOps.TestParallelSizedOp<>())
+                .exercise();
+        assertUnique(result);
+        assertSorted(result);
+    }
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testSortedDistinct(String name, TestData.OfRef<Integer> data) {
+        Collection<Integer> result = withData(data)
+                .stream(s -> s.sorted().distinct(),
+                        new CollectorOps.TestParallelSizedOp<>())
+                .exercise();
+        assertUnique(result);
+        assertSorted(result);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/test/org/openjdk/tests/java/util/stream/DoublePrimitiveOpsTests.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+package org.openjdk.tests.java.util.stream;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.Random;
+import java.util.stream.DoubleStream;
+import java.util.stream.LongStream;
+
+import static org.testng.Assert.assertEquals;
+
+@Test
+public class DoublePrimitiveOpsTests {
+
+    // @@@ tests for double are fragile if relying on equality when accumulating and multiplying values
+
+    public void testUnBox() {
+        double sum = Arrays.asList(1.0, 2.0, 3.0, 4.0, 5.0).stream().mapToDouble(i -> i).reduce(0.0, Double::sum);
+        assertEquals(sum, 1.0 + 2.0 + 3.0 + 4.0 + 5.0);
+    }
+
+    public void testToArray() {
+        {
+            double[] array =  LongStream.range(1, 10).doubles().map(i -> i * 2).toArray();
+            assertEquals(array, new double[]{2, 4, 6, 8, 10, 12, 14, 16, 18});
+        }
+
+        {
+            double[] array =  LongStream.range(1, 10).parallel().doubles().map(i -> i * 2).toArray();
+            assertEquals(array, new double[]{2, 4, 6, 8, 10, 12, 14, 16, 18});
+        }
+    }
+
+    public void testSort() {
+        Random r = new Random();
+
+        double[] content = DoubleStream.generate(() -> r.nextDouble()).limit(10).toArray();
+        double[] sortedContent = content.clone();
+        Arrays.sort(sortedContent);
+
+        {
+            double[] array =  Arrays.stream(content).sorted().toArray();
+            assertEquals(array, sortedContent);
+        }
+
+        {
+            double[] array =  Arrays.stream(content).parallel().sorted().toArray();
+            assertEquals(array, sortedContent);
+        }
+    }
+
+    public void testSortSort() {
+        Random r = new Random();
+
+        double[] content = DoubleStream.generate(() -> r.nextDouble()).limit(10).toArray();
+        double[] sortedContent = content.clone();
+        Arrays.sort(sortedContent);
+
+        {
+            double[] array =  Arrays.stream(content).sorted().sorted().toArray();
+            assertEquals(array, sortedContent);
+        }
+
+        {
+            double[] array =  Arrays.stream(content).parallel().sorted().sorted().toArray();
+            assertEquals(array, sortedContent);
+        }
+    }
+
+    public void testLimit() {
+        double[] expected = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+        {
+            double[] actual = DoubleStream.iterate(1.0, i -> i + 1.0).limit(9).toArray();
+            Assert.assertTrue(Arrays.equals(expected, actual));
+        }
+
+        {
+            double[] actual = LongStream.range(1, 100).parallel().doubles().limit(9).toArray();
+            Assert.assertTrue(Arrays.equals(expected, actual));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ExplodeOpTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package org.openjdk.tests.java.util.stream;
+
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.function.Function;
+import java.util.stream.*;
+
+import static java.util.stream.LambdaTestHelpers.*;
+
+/**
+ * ExplodeOpTest
+ *
+ * @author Brian Goetz
+ */
+@Test
+public class ExplodeOpTest extends OpTestCase {
+
+    static final Function<Integer, Stream<Integer>> integerRangeMapper
+            = e -> IntStream.range(0, e).boxed();
+
+    public void testFlatMap() {
+        String[] stringsArray = {"hello", "there", "", "yada"};
+        Stream<String> strings = Arrays.asList(stringsArray).stream();
+        assertConcat(strings.flatMap(flattenChars).iterator(), "hellothereyada");
+
+        assertCountSum(countTo(10).stream().flatMap(mfId), 10, 55);
+        assertCountSum(countTo(10).stream().flatMap(mfNull), 0, 0);
+        assertCountSum(countTo(3).stream().flatMap(mfLt), 6, 4);
+
+        exerciseOps(TestData.Factory.ofArray("stringsArray", stringsArray), s -> s.flatMap(flattenChars));
+        exerciseOps(TestData.Factory.ofArray("LONG_STRING", new String[] {LONG_STRING}), s -> s.flatMap(flattenChars));
+    }
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testOps(String name, TestData.OfRef<Integer> data) {
+        Collection<Integer> result = exerciseOps(data, s -> s.flatMap(mfId));
+        assertEquals(data.size(), result.size());
+
+        result = exerciseOps(data, s -> s.flatMap(mfNull));
+        assertEquals(0, result.size());
+
+        exerciseOps(data, s -> s.flatMap(mfLt));
+        exerciseOps(data, s -> s.flatMap(integerRangeMapper));
+        exerciseOps(data, s -> s.flatMap((Integer e) -> IntStream.range(0, e).boxed().limit(10)));
+    }
+
+    //
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testIntOps(String name, TestData.OfInt data) {
+        Collection<Integer> result = exerciseOps(data, s -> s.flatMap(i -> Collections.singleton(i).stream().mapToInt(j -> j)));
+        assertEquals(data.size(), result.size());
+        assertContents(data, result);
+
+        result = exerciseOps(data, s -> s.flatMap(i -> IntStream.empty()));
+        assertEquals(0, result.size());
+
+        exerciseOps(data, s -> s.flatMap(e -> IntStream.range(0, e)));
+        exerciseOps(data, s -> s.flatMap(e -> IntStream.range(0, e).limit(10)));
+    }
+
+    //
+
+    @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+    public void testLongOps(String name, TestData.OfLong data) {
+        Collection<Long> result = exerciseOps(data, s -> s.flatMap(i -> Collections.singleton(i).stream().mapToLong(j -> j)));
+        assertEquals(data.size(), result.size());
+        assertContents(data, result);
+
+        result = exerciseOps(data, s -> LongStream.empty());
+        assertEquals(0, result.size());
+
+        exerciseOps(data, s -> s.flatMap(e -> LongStream.range(0, e)));
+        exerciseOps(data, s -> s.flatMap(e -> LongStream.range(0, e).limit(10)));
+    }
+
+    //
+
+    @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+    public void testDoubleOps(String name, TestData.OfDouble data) {
+        Collection<Double> result = exerciseOps(data, s -> s.flatMap(i -> Collections.singleton(i).stream().mapToDouble(j -> j)));
+        assertEquals(data.size(), result.size());
+        assertContents(data, result);
+
+        result = exerciseOps(data, s -> DoubleStream.empty());
+        assertEquals(0, result.size());
+
+        exerciseOps(data, s -> s.flatMap(e -> DoubleStream.range(0, e)));
+        exerciseOps(data, s -> s.flatMap(e -> DoubleStream.range(0, e).limit(10)));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/test/org/openjdk/tests/java/util/stream/FilterOpTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package org.openjdk.tests.java.util.stream;
+
+import java.util.Collection;
+import java.util.stream.*;
+
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+
+import static java.util.stream.LambdaTestHelpers.*;
+
+/**
+ * FilterOpTest
+ *
+ * @author Brian Goetz
+ */
+@Test
+public class FilterOpTest extends OpTestCase {
+    public void testFilter() {
+        assertCountSum(countTo(0).stream().filter(pTrue), 0, 0);
+        assertCountSum(countTo(10).stream().filter(pFalse), 0, 0);
+        assertCountSum(countTo(10).stream().filter(pEven), 5, 30);
+        assertCountSum(countTo(10).stream().filter(pOdd), 5, 25);
+        assertCountSum(countTo(10).stream().filter(pTrue), 10, 55);
+        assertCountSum(countTo(10).stream().filter(pEven).filter(pOdd), 0, 0);
+
+        exerciseOps(countTo(1000), s -> s.filter(pTrue), countTo(1000));
+        exerciseOps(countTo(1000), s -> s.filter(pFalse), countTo(0));
+        exerciseOps(countTo(1000), s -> s.filter(e -> e > 100), range(101, 1000));
+        exerciseOps(countTo(1000), s -> s.filter(e -> e < 100), countTo(99));
+        exerciseOps(countTo(1000), s -> s.filter(e -> e == 100), Arrays.asList(100));
+    }
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testOps(String name, TestData.OfRef<Integer> data) {
+        Collection<Integer> result = exerciseOps(data, s -> s.filter(pTrue));
+        assertEquals(result.size(), data.size());
+
+        result = exerciseOps(data, s -> s.filter(pFalse));
+        assertEquals(result.size(), 0);
+
+        exerciseOps(data, s -> s.filter(pEven));
+        exerciseOps(data, s -> s.filter(pOdd));
+
+        result = exerciseOps(data, s -> s.filter(pOdd.and(pEven)));
+        assertEquals(result.size(), 0);
+
+        result = exerciseOps(data, s -> s.filter(pOdd.or(pEven)));
+        assertEquals(result.size(), data.size());
+    }
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testOps(String name, TestData.OfInt data) {
+        Collection<Integer> result = exerciseOps(data, s -> s.filter(i -> true));
+        assertEquals(result.size(), data.size());
+
+        result = exerciseOps(data, s -> s.filter(i -> false));
+        assertEquals(result.size(), 0);
+
+        exerciseOps(data, s -> s.filter(i -> 0 == i % 2));
+        exerciseOps(data, s -> s.filter(i -> 1 == i % 2));
+    }
+
+    @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+    public void testOps(String name, TestData.OfLong data) {
+        Collection<Long> result = exerciseOps(data, s -> s.filter(i -> true));
+        assertEquals(result.size(), data.size());
+
+        result = exerciseOps(data, s -> s.filter(i -> false));
+        assertEquals(result.size(), 0);
+
+        exerciseOps(data, s -> s.filter(i -> 0 == i % 2));
+        exerciseOps(data, s -> s.filter(i -> 1 == i % 2));
+    }
+
+    @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+    public void testOps(String name, TestData.OfDouble data) {
+        Collection<Double> result = exerciseOps(data, s -> s.filter(i -> true));
+        assertEquals(result.size(), data.size());
+
+        result = exerciseOps(data, s -> s.filter(i -> false));
+        assertEquals(result.size(), 0);
+
+        exerciseOps(data, s -> s.filter(i -> 0 == ((long) i) % 2));
+        exerciseOps(data, s -> s.filter(i -> 1 == ((long) i) % 2));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/test/org/openjdk/tests/java/util/stream/FindAnyOpTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package org.openjdk.tests.java.util.stream;
+
+import java.util.*;
+import java.util.function.BiConsumer;
+import java.util.stream.*;
+
+import org.testng.annotations.Test;
+
+import java.util.function.Function;
+
+import static java.util.stream.LambdaTestHelpers.*;
+
+
+/**
+ * FindAnyOpTest
+ */
+@Test
+public class FindAnyOpTest extends OpTestCase {
+
+    public void testFindAny() {
+        assertFalse(Collections.emptySet().stream().findAny().isPresent(), "no result");
+        assertFalse(countTo(10).stream().filter(x -> x > 10).findAny().isPresent(), "no result");
+        assertTrue(countTo(10).stream().filter(pEven).findAny().isPresent(), "with result");
+    }
+
+    public void testFindAnyParallel() {
+        assertFalse(Collections.emptySet().parallelStream().findAny().isPresent(), "no result");
+        assertFalse(countTo(1000).parallelStream().filter(x -> x > 1000).findAny().isPresent(), "no result");
+        assertTrue(countTo(1000).parallelStream().filter(pEven).findAny().isPresent(), "with result");
+    }
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testStream(String name, TestData.OfRef<Integer> data) {
+        exerciseStream(data, s -> s);
+        exerciseStream(data, s -> s.filter(pTrue));
+        exerciseStream(data, s -> s.filter(pFalse));
+        exerciseStream(data, s -> s.filter(pEven));
+    }
+
+    void exerciseStream(TestData.OfRef<Integer> data, Function<Stream<Integer>, Stream<Integer>> fs) {
+        Optional<Integer> or = withData(data).terminal(fs, s -> s.findAny()).equalator(VALID_ANSWER).exercise();
+        if (or.isPresent()) {
+            Integer r = or.get();
+            Iterator<Integer> it = fs.apply(data.stream()).iterator();
+            boolean contained = false;
+            while (!contained && it.hasNext()) {
+                contained = Objects.equals(r, it.next());
+            }
+            assertTrue(contained);
+        }
+        else {
+            assertFalse(fs.apply(data.stream()).iterator().hasNext());
+        }
+    }
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testIntStream(String name, TestData.OfInt data) {
+        exerciseIntStream(data, s -> s);
+        exerciseIntStream(data, s -> s.filter(ipTrue));
+        exerciseIntStream(data, s -> s.filter(ipFalse));
+        exerciseIntStream(data, s -> s.filter(ipEven));
+    }
+
+    void exerciseIntStream(TestData.OfInt data, Function<IntStream, IntStream> fs) {
+        OptionalInt or = withData(data).terminal(fs, s -> s.findAny()).equalator(INT_VALID_ANSWER).exercise();
+        if (or.isPresent()) {
+            int r = or.getAsInt();
+            PrimitiveIterator.OfInt it = fs.apply(data.stream()).iterator();
+            boolean contained = false;
+            while (!contained && it.hasNext()) {
+                contained = r == it.nextInt();
+            }
+            assertTrue(contained);
+        }
+        else {
+            assertFalse(fs.apply(data.stream()).iterator().hasNext());
+        }
+    }
+
+    @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+    public void testLongStream(String name, TestData.OfLong data) {
+        exerciseLongStream(data, s -> s);
+        exerciseLongStream(data, s -> s.filter(lpTrue));
+        exerciseLongStream(data, s -> s.filter(lpFalse));
+        exerciseLongStream(data, s -> s.filter(lpEven));
+    }
+
+    void exerciseLongStream(TestData.OfLong data, Function<LongStream, LongStream> fs) {
+        OptionalLong or = withData(data).terminal(fs, s -> s.findAny()).equalator(LONG_VALID_ANSWER).exercise();
+        if (or.isPresent()) {
+            long r = or.getAsLong();
+            PrimitiveIterator.OfLong it = fs.apply(data.stream()).iterator();
+            boolean contained = false;
+            while (!contained && it.hasNext()) {
+                contained = r == it.nextLong();
+            }
+            assertTrue(contained);
+        }
+        else {
+            assertFalse(fs.apply(data.stream()).iterator().hasNext());
+        }
+    }
+
+    @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+    public void testDoubleStream(String name, TestData.OfDouble data) {
+        exerciseDoubleStream(data, s -> s);
+        exerciseDoubleStream(data, s -> s.filter(dpTrue));
+        exerciseDoubleStream(data, s -> s.filter(dpEven));
+        exerciseDoubleStream(data, s -> s.filter(dpFalse));
+    }
+
+    void exerciseDoubleStream(TestData.OfDouble data, Function<DoubleStream, DoubleStream> fs) {
+        OptionalDouble or = withData(data).terminal(fs, s -> s.findAny()).equalator(DOUBLE_VALID_ANSWER).exercise();
+        if (or.isPresent()) {
+            double r = or.getAsDouble();
+            PrimitiveIterator.OfDouble it = fs.apply(data.stream()).iterator();
+            boolean contained = false;
+            while (!contained && it.hasNext()) {
+                contained = r == it.nextDouble();
+            }
+            assertTrue(contained);
+        }
+        else {
+            assertFalse(fs.apply(data.stream()).iterator().hasNext());
+        }
+    }
+
+    static final BiConsumer<Optional<Integer>, Optional<Integer>> VALID_ANSWER = (a, b) -> assertEquals(a.isPresent(), b.isPresent());
+
+    static final BiConsumer<OptionalInt, OptionalInt> INT_VALID_ANSWER = (a, b) -> assertEquals(a.isPresent(), b.isPresent());
+
+    static final BiConsumer<OptionalLong, OptionalLong> LONG_VALID_ANSWER = (a, b) -> assertEquals(a.isPresent(), b.isPresent());
+
+    static final BiConsumer<OptionalDouble, OptionalDouble> DOUBLE_VALID_ANSWER = (a, b) -> assertEquals(a.isPresent(), b.isPresent());
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/test/org/openjdk/tests/java/util/stream/FindFirstOpTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package org.openjdk.tests.java.util.stream;
+
+import java.util.*;
+import java.util.stream.*;
+
+import org.testng.annotations.Test;
+
+import java.util.function.Function;
+
+import static java.util.stream.LambdaTestHelpers.*;
+
+
+/**
+ * FindFirstOpTest
+ */
+@Test
+public class FindFirstOpTest extends OpTestCase {
+
+    public void testFindFirst() {
+        assertFalse(Collections.emptySet().stream().findFirst().isPresent(), "no result");
+        assertFalse(countTo(10).stream().filter(x -> x > 10).findFirst().isPresent(), "no result");
+
+        exerciseOps(countTo(1000), s -> Arrays.asList(new Integer[]{s.filter(pEven).findFirst().get()}).stream(), Arrays.asList(2));
+        exerciseOps(countTo(1000), s -> Arrays.asList(new Integer[]{s.findFirst().get()}).stream(), Arrays.asList(1));
+        exerciseOps(countTo(1000), s -> Arrays.asList(new Integer[]{s.filter(e -> e == 499).findFirst().get()}).stream(), Arrays.asList(499));
+        exerciseOps(countTo(1000), s -> Arrays.asList(new Integer[]{s.filter(e -> e == 999).findFirst().get()}).stream(), Arrays.asList(999));
+        exerciseOps(countTo(0), s -> Arrays.asList(new Integer[]{s.findFirst().orElse(-1)}).stream(), Arrays.asList(-1));
+        exerciseOps(countTo(1000), s -> Arrays.asList(new Integer[]{s.filter(e -> e == 1499).findFirst().orElse(-1)}).stream(), Arrays.asList(-1));
+    }
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testStream(String name, TestData.OfRef<Integer> data) {
+        exerciseStream(data, s -> s);
+        exerciseStream(data, s -> s.filter(pTrue));
+        exerciseStream(data, s -> s.filter(pFalse));
+        exerciseStream(data, s -> s.filter(pEven));
+    }
+
+    void exerciseStream(TestData.OfRef<Integer> data, Function<Stream<Integer>, Stream<Integer>> fs) {
+        Optional<Integer> r = exerciseTerminalOps(data, fs, s -> s.findFirst());
+        if (r.isPresent()) {
+            Iterator<Integer> i = fs.apply(data.stream()).iterator();
+            assertTrue(i.hasNext());
+            assertEquals(i.next(), r.get());
+        }
+        else {
+            assertFalse(fs.apply(data.stream()).iterator().hasNext());
+        }
+    }
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testIntStream(String name, TestData.OfInt data) {
+        exerciseIntStream(data, s -> s);
+        exerciseIntStream(data, s -> s.filter(ipTrue));
+        exerciseIntStream(data, s -> s.filter(ipFalse));
+        exerciseIntStream(data, s -> s.filter(ipEven));
+    }
+
+    void exerciseIntStream(TestData.OfInt data, Function<IntStream, IntStream> fs) {
+        OptionalInt r = exerciseTerminalOps(data, fs, s -> s.findFirst());
+        if (r.isPresent()) {
+            PrimitiveIterator.OfInt i = fs.apply(data.stream()).iterator();
+            assertTrue(i.hasNext());
+            assertEquals(i.nextInt(), r.getAsInt());
+        }
+        else {
+            assertFalse(fs.apply(data.stream()).iterator().hasNext());
+        }
+    }
+
+    @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+    public void testLongStream(String name, TestData.OfLong data) {
+        exerciseLongStream(data, s -> s);
+        exerciseLongStream(data, s -> s.filter(lpTrue));
+        exerciseLongStream(data, s -> s.filter(lpFalse));
+        exerciseLongStream(data, s -> s.filter(lpEven));
+    }
+
+    void exerciseLongStream(TestData.OfLong data, Function<LongStream, LongStream> fs) {
+        OptionalLong r = exerciseTerminalOps(data, fs, s -> s.findFirst());
+        if (r.isPresent()) {
+            PrimitiveIterator.OfLong i = fs.apply(data.stream()).iterator();
+            assertTrue(i.hasNext());
+            assertEquals(i.nextLong(), r.getAsLong());
+        }
+        else {
+            assertFalse(fs.apply(data.stream()).iterator().hasNext());
+        }
+    }
+
+    @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+    public void testDoubleStream(String name, TestData.OfDouble data) {
+        exerciseDoubleStream(data, s -> s);
+        exerciseDoubleStream(data, s -> s.filter(dpTrue));
+        exerciseDoubleStream(data, s -> s.filter(dpFalse));
+        exerciseDoubleStream(data, s -> s.filter(dpEven));
+    }
+
+    void exerciseDoubleStream(TestData.OfDouble data, Function<DoubleStream, DoubleStream> fs) {
+        OptionalDouble r = exerciseTerminalOps(data, fs, s -> s.findFirst());
+        if (r.isPresent()) {
+            PrimitiveIterator.OfDouble i = fs.apply(data.stream()).iterator();
+            assertTrue(i.hasNext());
+            assertEquals(i.nextDouble(), r.getAsDouble());
+        }
+        else {
+            assertFalse(fs.apply(data.stream()).iterator().hasNext());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ForEachOpTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package org.openjdk.tests.java.util.stream;
+
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Function;
+import java.util.stream.*;
+
+import static java.util.stream.LambdaTestHelpers.countTo;
+
+/**
+ * ForEachOpTest
+ */
+@Test
+public class ForEachOpTest extends OpTestCase {
+
+    @Test(groups = { "serialization-hostile" })
+    public void testForEach() {
+        exerciseTerminalOps(countTo(10),
+                            s -> {
+                                AtomicInteger count = new AtomicInteger(0);
+                                s.forEach(e -> count.incrementAndGet());
+                                return count.get();
+                            },
+                            10);
+
+        exerciseTerminalOps(countTo(10),
+                            s -> {
+                                AtomicInteger sum = new AtomicInteger(0);
+                                s.forEach(sum::addAndGet);
+                                return sum.get();
+                            },
+                            55);
+    }
+
+    @Test
+    public void testForEachOrdered() {
+        List<Integer> input = countTo(10000);
+        TestData.OfRef<Integer> data = TestData.Factory.ofCollection("[1, 10000]", input);
+
+        Function<Stream<Integer>, List<Integer>> terminalFunc = s -> {
+            List<Integer> l = new ArrayList<>();
+            s.forEachOrdered(l::add);
+            return l;
+        };
+
+        // Test head
+        withData(data).
+                terminal(terminalFunc).
+                expectedResult(input).
+                exercise();
+
+        // Test multiple stages
+        withData(data).
+                terminal(s -> s.map(LambdaTestHelpers.identity()), terminalFunc).
+                expectedResult(input).
+                exercise();
+    }
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testForEach(String name, TestData.OfRef<Integer> data) {
+        Function<Stream<Integer>, List<Integer>> terminalFunc = s -> {
+            List<Integer> l = Collections.synchronizedList(new ArrayList<>());
+            s.forEach(l::add);
+            return l;
+        };
+
+        // Test head
+        withData(data).
+                terminal(terminalFunc).
+                parallelEqualityAsserter(LambdaTestHelpers::assertContentsUnordered).
+                exercise();
+
+        // Test multiple stages
+        withData(data).
+                terminal(s -> s.map(LambdaTestHelpers.identity()), terminalFunc).
+                parallelEqualityAsserter(LambdaTestHelpers::assertContentsUnordered).
+                exercise();
+    }
+
+    //
+
+    @Test
+    public void testIntForEachOrdered() {
+        List<Integer> input = countTo(10000);
+        TestData.OfInt data = TestData.Factory.ofIntSupplier("[1, 10000]",
+                                                             () -> IntStream.range(1, 10001));
+
+        Function<IntStream, List<Integer>> terminalFunc = s -> {
+            List<Integer> l = new ArrayList<>();
+            s.forEachOrdered(l::add);
+            return l;
+        };
+
+        // Test head
+        withData(data).
+                terminal(terminalFunc).
+                expectedResult(input).
+                exercise();
+
+        // Test multiple stages
+        withData(data).
+                terminal(s -> s.map(i -> i), terminalFunc).
+                expectedResult(input).
+                exercise();
+    }
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testIntForEach(String name, TestData.OfInt data) {
+        Function<IntStream, List<Integer>> terminalFunc = s -> {
+            List<Integer> l = Collections.synchronizedList(new ArrayList<Integer>());
+            s.forEach(l::add);
+            return l;
+        };
+
+        // Test head
+        withData(data).
+                terminal(terminalFunc).
+                parallelEqualityAsserter(LambdaTestHelpers::assertContentsUnordered).
+                exercise();
+
+        // Test multiple stages
+        withData(data).
+                terminal(s -> s.map(i -> i), terminalFunc).
+                parallelEqualityAsserter(LambdaTestHelpers::assertContentsUnordered).
+                exercise();
+    }
+
+    //
+
+    @Test
+    public void testLongForEachOrdered() {
+        List<Integer> input = countTo(10000);
+        TestData.OfLong data = TestData.Factory.ofLongSupplier("[1, 10000]",
+                                                               () -> LongStream.range(1, 10001));
+
+        Function<LongStream, List<Integer>> terminalFunc = s -> {
+            List<Integer> l = new ArrayList<>();
+            s.forEachOrdered(e -> l.add((int) e));
+            return l;
+        };
+
+        // Test head
+        withData(data).
+                terminal(terminalFunc).
+                expectedResult(input).
+                exercise();
+
+        // Test multiple stages
+        withData(data).
+                terminal(s -> s.map(i -> i), terminalFunc).
+                expectedResult(input).
+                exercise();
+    }
+
+    @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+    public void testLongOps(String name, TestData.OfLong data) {
+        Function<LongStream, List<Long>> terminalFunc = s -> {
+            List<Long> l = Collections.synchronizedList(new ArrayList<Long>());
+            s.forEach(l::add);
+            return l;
+        };
+
+        // Test head
+        withData(data).
+                terminal(terminalFunc).
+                parallelEqualityAsserter(LambdaTestHelpers::assertContentsUnordered).
+                exercise();
+
+        // Test multiple stages
+        withData(data).
+                terminal(s -> s.map(i -> i), terminalFunc).
+                parallelEqualityAsserter(LambdaTestHelpers::assertContentsUnordered).
+                exercise();
+    }
+
+    //
+
+    @Test
+    public void testDoubleForEachOrdered() {
+        List<Integer> input = countTo(10000);
+        TestData.OfDouble data = TestData.Factory.ofDoubleSupplier("[1, 10000]",
+                                                                   () -> DoubleStream.range(1, 10001));
+
+        Function<DoubleStream, List<Integer>> terminalFunc = s -> {
+            List<Integer> l = new ArrayList<>();
+            s.forEachOrdered(e -> l.add((int) e));
+            return l;
+        };
+
+        // Test head
+        withData(data).
+                terminal(terminalFunc).
+                expectedResult(input).
+                exercise();
+
+        // Test multiple stages
+        withData(data).
+                terminal(s -> s.map(i -> i), terminalFunc).
+                expectedResult(input).
+                exercise();
+    }
+
+    @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+    public void testDoubleOps(String name, TestData.OfDouble data) {
+        Function<DoubleStream, List<Double>> terminalFunc = s -> {
+            List<Double> l = Collections.synchronizedList(new ArrayList<Double>());
+            s.forEach(l::add);
+            return l;
+        };
+
+        // Test head
+        withData(data).
+                terminal(terminalFunc).
+                parallelEqualityAsserter(LambdaTestHelpers::assertContentsUnordered).
+                exercise();
+
+        // Test multiple stages
+        withData(data).
+                terminal(s -> s.map(i -> i), terminalFunc).
+                parallelEqualityAsserter(LambdaTestHelpers::assertContentsUnordered).
+                exercise();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/test/org/openjdk/tests/java/util/stream/GroupByOpTest.java	Mon May 06 11:43:51 2013 -0400
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2012, 2013, 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.
+ */
+package org.openjdk.tests.java.util.stream;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;