1 /* 2 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.openjdk.tests.java.util.stream; 24 25 import org.testng.annotations.Test; 26 27 import java.util.*; 28 import java.util.Spliterators; 29 import java.util.concurrent.atomic.AtomicInteger; 30 import java.util.function.BiFunction; 31 import java.util.function.Consumer; 32 import java.util.function.Function; 33 import java.util.function.Supplier; 34 import java.util.stream.*; 35 36 import static java.util.stream.LambdaTestHelpers.*; 37 38 /** 39 * SortedOpTest 40 * 41 * @author Brian Goetz 42 */ 43 @Test 44 public class SortedOpTest extends OpTestCase { 45 testRefStreamTooLarge()46 public void testRefStreamTooLarge() { 47 Function<LongStream, Stream<Long>> f = s -> 48 // Clear the SORTED flag 49 s.mapToObj(i -> i) 50 .sorted(); 51 52 testStreamTooLarge(f, Stream::findFirst); 53 } 54 testIntStreamTooLarge()55 public void testIntStreamTooLarge() { 56 Function<LongStream, IntStream> f = s -> 57 // Clear the SORTED flag 58 s.mapToInt(i -> (int) i) 59 .sorted(); 60 61 testStreamTooLarge(f, IntStream::findFirst); 62 } 63 testLongStreamTooLarge()64 public void testLongStreamTooLarge() { 65 Function<LongStream, LongStream> f = s -> 66 // Clear the SORTED flag 67 s.map(i -> i) 68 .sorted(); 69 70 testStreamTooLarge(f, LongStream::findFirst); 71 } 72 testDoubleStreamTooLarge()73 public void testDoubleStreamTooLarge() { 74 Function<LongStream, DoubleStream> f = s -> 75 // Clear the SORTED flag 76 s.mapToDouble(i -> (double) i) 77 .sorted(); 78 79 testStreamTooLarge(f, DoubleStream::findFirst); 80 } 81 testStreamTooLarge(Function<LongStream, S> s, Function<S, ?> terminal)82 <T, S extends BaseStream<T, S>> void testStreamTooLarge(Function<LongStream, S> s, 83 Function<S, ?> terminal) { 84 // Set up conditions for a large input > maximum array size 85 Supplier<LongStream> input = () -> LongStream.range(0, 1L + Integer.MAX_VALUE); 86 87 // Transformation functions 88 List<Function<LongStream, LongStream>> transforms = Arrays.asList( 89 ls -> ls, 90 ls -> ls.parallel(), 91 // Clear the SIZED flag 92 ls -> ls.limit(Long.MAX_VALUE), 93 ls -> ls.limit(Long.MAX_VALUE).parallel()); 94 95 for (Function<LongStream, LongStream> transform : transforms) { 96 RuntimeException caught = null; 97 try { 98 terminal.apply(s.apply(transform.apply(input.get()))); 99 } catch (RuntimeException e) { 100 caught = e; 101 } 102 assertNotNull(caught, "Expected an instance of exception IllegalArgumentException but no exception thrown"); 103 assertTrue(caught instanceof IllegalArgumentException, 104 String.format("Expected an instance of exception IllegalArgumentException but got %s", caught)); 105 } 106 } 107 testSorted()108 public void testSorted() { 109 assertCountSum(countTo(0).stream().sorted(), 0, 0); 110 assertCountSum(countTo(10).stream().sorted(), 10, 55); 111 assertCountSum(countTo(10).stream().sorted(cInteger.reversed()), 10, 55); 112 113 List<Integer> to10 = countTo(10); 114 assertSorted(to10.stream().sorted(cInteger.reversed()).iterator(), cInteger.reversed()); 115 116 Collections.reverse(to10); 117 assertSorted(to10.stream().sorted().iterator()); 118 119 Spliterator<Integer> s = to10.stream().sorted().spliterator(); 120 assertTrue(s.hasCharacteristics(Spliterator.SORTED)); 121 122 s = to10.stream().sorted(cInteger.reversed()).spliterator(); 123 assertFalse(s.hasCharacteristics(Spliterator.SORTED)); 124 } 125 126 @Test(groups = { "serialization-hostile" }) testSequentialShortCircuitTerminal()127 public void testSequentialShortCircuitTerminal() { 128 // The sorted op for sequential evaluation will buffer all elements when 129 // accepting then at the end sort those elements and push those elements 130 // downstream 131 // A peek operation is added in-between the sorted() and terminal 132 // operation that counts the number of calls to its consumer and 133 // asserts that the number of calls is at most the required quantity 134 135 List<Integer> l = Arrays.asList(5, 4, 3, 2, 1); 136 137 Function<Integer, Stream<Integer>> knownSize = i -> assertNCallsOnly( 138 l.stream().sorted(), Stream::peek, i); 139 Function<Integer, Stream<Integer>> unknownSize = i -> assertNCallsOnly 140 (unknownSizeStream(l).sorted(), Stream::peek, i); 141 142 // Find 143 assertEquals(knownSize.apply(1).findFirst(), Optional.of(1)); 144 assertEquals(knownSize.apply(1).findAny(), Optional.of(1)); 145 assertEquals(unknownSize.apply(1).findFirst(), Optional.of(1)); 146 assertEquals(unknownSize.apply(1).findAny(), Optional.of(1)); 147 148 // Match 149 assertEquals(knownSize.apply(2).anyMatch(i -> i == 2), true); 150 assertEquals(knownSize.apply(2).noneMatch(i -> i == 2), false); 151 assertEquals(knownSize.apply(2).allMatch(i -> i == 2), false); 152 assertEquals(unknownSize.apply(2).anyMatch(i -> i == 2), true); 153 assertEquals(unknownSize.apply(2).noneMatch(i -> i == 2), false); 154 assertEquals(unknownSize.apply(2).allMatch(i -> i == 2), false); 155 } 156 unknownSizeStream(List<T> l)157 private <T> Stream<T> unknownSizeStream(List<T> l) { 158 return StreamSupport.stream(Spliterators.spliteratorUnknownSize(l.iterator(), 0), false); 159 } 160 161 @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class) testOps(String name, TestData.OfRef<Integer> data)162 public void testOps(String name, TestData.OfRef<Integer> data) { 163 Collection<Integer> result = exerciseOpsInt(data, Stream::sorted, IntStream::sorted, LongStream::sorted, DoubleStream::sorted); 164 assertSorted(result.iterator()); 165 assertContentsUnordered(data, result); 166 167 result = exerciseOps(data, s -> s.sorted(cInteger.reversed())); 168 assertSorted(result.iterator(), cInteger.reversed()); 169 assertContentsUnordered(data, result); 170 } 171 172 @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class) testSortSort(String name, TestData.OfRef<Integer> data)173 public void testSortSort(String name, TestData.OfRef<Integer> data) { 174 // For parallel cases ensure the size is known 175 Collection<Integer> result = withData(data) 176 .stream(s -> s.sorted().sorted(), 177 new CollectorOps.TestParallelSizedOp<Integer>()) 178 .exercise(); 179 180 assertSorted(result); 181 assertContentsUnordered(data, result); 182 183 result = withData(data) 184 .stream(s -> s.sorted(cInteger.reversed()).sorted(cInteger.reversed()), 185 new CollectorOps.TestParallelSizedOp<Integer>()) 186 .exercise(); 187 188 assertSorted(result, cInteger.reversed()); 189 assertContentsUnordered(data, result); 190 191 result = withData(data) 192 .stream(s -> s.sorted().sorted(cInteger.reversed()), 193 new CollectorOps.TestParallelSizedOp<Integer>()) 194 .exercise(); 195 196 assertSorted(result, cInteger.reversed()); 197 assertContentsUnordered(data, result); 198 199 result = withData(data) 200 .stream(s -> s.sorted(cInteger.reversed()).sorted(), 201 new CollectorOps.TestParallelSizedOp<Integer>()) 202 .exercise(); 203 204 assertSorted(result); 205 assertContentsUnordered(data, result); 206 } 207 208 // 209 210 @Test(groups = { "serialization-hostile" }) testIntSequentialShortCircuitTerminal()211 public void testIntSequentialShortCircuitTerminal() { 212 int[] a = new int[]{5, 4, 3, 2, 1}; 213 214 Function<Integer, IntStream> knownSize = i -> assertNCallsOnly( 215 Arrays.stream(a).sorted(), (s, c) -> s.peek(c::accept), i); 216 Function<Integer, IntStream> unknownSize = i -> assertNCallsOnly 217 (unknownSizeIntStream(a).sorted(), (s, c) -> s.peek(c::accept), i); 218 219 // Find 220 assertEquals(knownSize.apply(1).findFirst(), OptionalInt.of(1)); 221 assertEquals(knownSize.apply(1).findAny(), OptionalInt.of(1)); 222 assertEquals(unknownSize.apply(1).findFirst(), OptionalInt.of(1)); 223 assertEquals(unknownSize.apply(1).findAny(), OptionalInt.of(1)); 224 225 // Match 226 assertEquals(knownSize.apply(2).anyMatch(i -> i == 2), true); 227 assertEquals(knownSize.apply(2).noneMatch(i -> i == 2), false); 228 assertEquals(knownSize.apply(2).allMatch(i -> i == 2), false); 229 assertEquals(unknownSize.apply(2).anyMatch(i -> i == 2), true); 230 assertEquals(unknownSize.apply(2).noneMatch(i -> i == 2), false); 231 assertEquals(unknownSize.apply(2).allMatch(i -> i == 2), false); 232 } 233 unknownSizeIntStream(int[] a)234 private IntStream unknownSizeIntStream(int[] a) { 235 return StreamSupport.intStream(Spliterators.spliteratorUnknownSize(Spliterators.iterator(Arrays.spliterator(a)), 0), false); 236 } 237 238 @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class) testIntOps(String name, TestData.OfInt data)239 public void testIntOps(String name, TestData.OfInt data) { 240 Collection<Integer> result = exerciseOps(data, s -> s.sorted()); 241 assertSorted(result); 242 assertContentsUnordered(data, result); 243 } 244 245 @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class) testIntSortSort(String name, TestData.OfInt data)246 public void testIntSortSort(String name, TestData.OfInt data) { 247 // For parallel cases ensure the size is known 248 Collection<Integer> result = withData(data) 249 .stream(s -> s.sorted().sorted(), new CollectorOps.TestParallelSizedOp.OfInt()) 250 .exercise(); 251 252 assertSorted(result); 253 assertContentsUnordered(data, result); 254 } 255 256 // 257 258 @Test(groups = { "serialization-hostile" }) testLongSequentialShortCircuitTerminal()259 public void testLongSequentialShortCircuitTerminal() { 260 long[] a = new long[]{5, 4, 3, 2, 1}; 261 262 Function<Integer, LongStream> knownSize = i -> assertNCallsOnly( 263 Arrays.stream(a).sorted(), (s, c) -> s.peek(c::accept), i); 264 Function<Integer, LongStream> unknownSize = i -> assertNCallsOnly 265 (unknownSizeLongStream(a).sorted(), (s, c) -> s.peek(c::accept), i); 266 267 // Find 268 assertEquals(knownSize.apply(1).findFirst(), OptionalLong.of(1)); 269 assertEquals(knownSize.apply(1).findAny(), OptionalLong.of(1)); 270 assertEquals(unknownSize.apply(1).findFirst(), OptionalLong.of(1)); 271 assertEquals(unknownSize.apply(1).findAny(), OptionalLong.of(1)); 272 273 // Match 274 assertEquals(knownSize.apply(2).anyMatch(i -> i == 2), true); 275 assertEquals(knownSize.apply(2).noneMatch(i -> i == 2), false); 276 assertEquals(knownSize.apply(2).allMatch(i -> i == 2), false); 277 assertEquals(unknownSize.apply(2).anyMatch(i -> i == 2), true); 278 assertEquals(unknownSize.apply(2).noneMatch(i -> i == 2), false); 279 assertEquals(unknownSize.apply(2).allMatch(i -> i == 2), false); 280 } 281 unknownSizeLongStream(long[] a)282 private LongStream unknownSizeLongStream(long[] a) { 283 return StreamSupport.longStream(Spliterators.spliteratorUnknownSize(Spliterators.iterator(Arrays.spliterator(a)), 0), false); 284 } 285 286 @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class) testLongOps(String name, TestData.OfLong data)287 public void testLongOps(String name, TestData.OfLong data) { 288 Collection<Long> result = exerciseOps(data, s -> s.sorted()); 289 assertSorted(result); 290 assertContentsUnordered(data, result); 291 } 292 293 @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class) testLongSortSort(String name, TestData.OfLong data)294 public void testLongSortSort(String name, TestData.OfLong data) { 295 // For parallel cases ensure the size is known 296 Collection<Long> result = withData(data) 297 .stream(s -> s.sorted().sorted(), new CollectorOps.TestParallelSizedOp.OfLong()) 298 .exercise(); 299 300 assertSorted(result); 301 assertContentsUnordered(data, result); 302 } 303 304 // 305 306 @Test(groups = { "serialization-hostile" }) testDoubleSequentialShortCircuitTerminal()307 public void testDoubleSequentialShortCircuitTerminal() { 308 double[] a = new double[]{5.0, 4.0, 3.0, 2.0, 1.0}; 309 310 Function<Integer, DoubleStream> knownSize = i -> assertNCallsOnly( 311 Arrays.stream(a).sorted(), (s, c) -> s.peek(c::accept), i); 312 Function<Integer, DoubleStream> unknownSize = i -> assertNCallsOnly 313 (unknownSizeDoubleStream(a).sorted(), (s, c) -> s.peek(c::accept), i); 314 315 // Find 316 assertEquals(knownSize.apply(1).findFirst(), OptionalDouble.of(1)); 317 assertEquals(knownSize.apply(1).findAny(), OptionalDouble.of(1)); 318 assertEquals(unknownSize.apply(1).findFirst(), OptionalDouble.of(1)); 319 assertEquals(unknownSize.apply(1).findAny(), OptionalDouble.of(1)); 320 321 // Match 322 assertEquals(knownSize.apply(2).anyMatch(i -> i == 2.0), true); 323 assertEquals(knownSize.apply(2).noneMatch(i -> i == 2.0), false); 324 assertEquals(knownSize.apply(2).allMatch(i -> i == 2.0), false); 325 assertEquals(unknownSize.apply(2).anyMatch(i -> i == 2.0), true); 326 assertEquals(unknownSize.apply(2).noneMatch(i -> i == 2.0), false); 327 assertEquals(unknownSize.apply(2).allMatch(i -> i == 2.0), false); 328 } 329 unknownSizeDoubleStream(double[] a)330 private DoubleStream unknownSizeDoubleStream(double[] a) { 331 return StreamSupport.doubleStream(Spliterators.spliteratorUnknownSize(Spliterators.iterator(Arrays.spliterator(a)), 0), false); 332 } 333 334 @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class) testDoubleOps(String name, TestData.OfDouble data)335 public void testDoubleOps(String name, TestData.OfDouble data) { 336 Collection<Double> result = exerciseOps(data, s -> s.sorted()); 337 assertSorted(result); 338 assertContentsUnordered(data, result); 339 } 340 341 @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class) testDoubleSortSort(String name, TestData.OfDouble data)342 public void testDoubleSortSort(String name, TestData.OfDouble data) { 343 // For parallel cases ensure the size is known 344 Collection<Double> result = withData(data) 345 .stream(s -> s.sorted().sorted(), new CollectorOps.TestParallelSizedOp.OfDouble()) 346 .exercise(); 347 348 assertSorted(result); 349 assertContentsUnordered(data, result); 350 } 351 352 /** 353 * Interpose a consumer that asserts it is called at most N times. 354 */ assertNCallsOnly(S s, BiFunction<S, Consumer<T>, S> pf, int n)355 <T, S extends BaseStream<T, S>, R> S assertNCallsOnly(S s, BiFunction<S, Consumer<T>, S> pf, int n) { 356 AtomicInteger boxedInt = new AtomicInteger(); 357 return pf.apply(s, i -> { 358 assertFalse(boxedInt.incrementAndGet() > n, "Intermediate op called more than " + n + " time(s)"); 359 }); 360 } 361 } 362