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