• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2015, 2017, 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.openjdk.testlib.java.util.stream.DefaultMethodStreams;
26 import org.openjdk.testlib.java.util.stream.LambdaTestHelpers;
27 import org.openjdk.testlib.java.util.stream.OpTestCase;
28 import org.openjdk.testlib.java.util.stream.StreamTestDataProvider;
29 import org.openjdk.testlib.java.util.stream.TestData;
30 import org.testng.annotations.Test;
31 
32 import java.util.ArrayList;
33 import java.util.Collection;
34 import java.util.HashMap;
35 import java.util.LinkedHashSet;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Set;
39 import java.util.concurrent.atomic.AtomicBoolean;
40 import java.util.function.Function;
41 import java.util.function.Predicate;
42 import java.util.stream.DoubleStream;
43 import java.util.stream.IntStream;
44 import java.util.stream.LongStream;
45 import java.util.stream.Stream;
46 
47 /*
48  * @test
49  * @bug 8071597 8193856
50  * @run main/timeout=240
51  */
52 @Test
53 // Android-changed: this test checks while/drop ops on reference and primitive streams.
54 // But in Android U only reference streams have those APIs, hence primitive streams part
55 // are commented out.
56 public class WhileOpTest extends OpTestCase {
57 
58     @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class,
59           groups = { "serialization-hostile" })
testTakeWhileOps(String name, TestData.OfRef<Integer> data)60     public void testTakeWhileOps(String name, TestData.OfRef<Integer> data) {
61         for (int size : sizes(data.size())) {
62             setContext("takeWhile", size);
63 
64             testWhileMulti(data,
65                            whileResultAsserter(data, WhileOp.Take, e -> e < size),
66                            s -> s.takeWhile(e -> e < size));
67             // BEGIN Android-removed: Drop primitive stream test.
68             /*
69                            s -> s.takeWhile(e -> e < size),
70                            s -> s.takeWhile(e -> e < size),
71                            s -> s.takeWhile(e -> e < size));
72              */
73             // END Android-removed: Drop primitive stream test.
74 
75 
76             testWhileMulti(data,
77                            whileResultAsserter(data, WhileOp.Take, e -> e < size / 2),
78                            s -> s.takeWhile(e -> e < size).takeWhile(e -> e < size / 2));
79             // BEGIN Android-removed: Drop primitive stream test.
80             /*
81                            s -> s.takeWhile(e -> e < size).takeWhile(e -> e < size / 2),
82                            s -> s.takeWhile(e -> e < size).takeWhile(e -> e < size / 2),
83                            s -> s.takeWhile(e -> e < size).takeWhile(e -> e < size / 2));
84             */
85             // END Android-removed: Drop primitive stream test.
86         }
87     }
88 
89     @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class,
90           groups = { "serialization-hostile" })
testDropWhileOps(String name, TestData.OfRef<Integer> data)91     public void testDropWhileOps(String name, TestData.OfRef<Integer> data) {
92         for (int size : sizes(data.size())) {
93             setContext("dropWhile", size);
94 
95             testWhileMulti(data,
96                            whileResultAsserter(data, WhileOp.Drop, e -> e < size),
97                            s -> s.dropWhile(e -> e < size));
98             // BEGIN Android-removed: Drop primitive stream test.
99             /*
100                            s -> s.dropWhile(e -> e < size),
101                            s -> s.dropWhile(e -> e < size),
102                            s -> s.dropWhile(e -> e < size));
103              */
104             // END Android-removed: Drop primitive stream test.
105 
106             testWhileMulti(data,
107                            whileResultAsserter(data, WhileOp.Drop, e -> e < size),
108                            s -> s.dropWhile(e -> e < size / 2).dropWhile(e -> e < size));
109             // BEGIN Android-removed: Drop primitive stream test.
110             /*
111                            s -> s.dropWhile(e -> e < size / 2).dropWhile(e -> e < size),
112                            s -> s.dropWhile(e -> e < size / 2).dropWhile(e -> e < size),
113                            s -> s.dropWhile(e -> e < size / 2).dropWhile(e -> e < size));
114             */
115             // END Android-removed: Drop primitive stream test.
116         }
117     }
118 
119     @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class,
120           groups = { "serialization-hostile" })
testDropTakeWhileOps(String name, TestData.OfRef<Integer> data)121     public void testDropTakeWhileOps(String name, TestData.OfRef<Integer> data) {
122         for (int size : sizes(data.size())) {
123             setContext("dropWhile", size);
124 
125             testWhileMulti(data,
126                            whileResultAsserter(data, WhileOp.Undefined, null),
127                            s -> s.dropWhile(e -> e < size / 2).takeWhile(e -> e < size));
128             // BEGIN Android-removed: Drop primitive stream test.
129             /*
130                            s -> s.dropWhile(e -> e < size / 2).takeWhile(e -> e < size),
131                            s -> s.dropWhile(e -> e < size / 2).takeWhile(e -> e < size),
132                            s -> s.dropWhile(e -> e < size / 2).takeWhile(e -> e < size));
133             */
134             // END Android-removed: Drop primitive stream test.
135         }
136     }
137 
138     /**
139      * While operation type to be asserted on
140      */
141     enum WhileOp {
142         /**
143          * The takeWhile operation
144          */
145         Take,
146         /**
147          * The dropWhile operation
148          */
149         Drop,
150         /**
151          * The operation(s) are undefined
152          */
153         Undefined
154     }
155 
156     /**
157      * Create a result asserter for takeWhile or dropWhile operations.
158      * <p>
159      * If the stream pipeline consists of the takeWhile operation
160      * ({@link WhileOp#Take}) or the dropWhile operation ({@link WhileOp#Drop})
161      * then specific assertions can be made on the actual result based on the
162      * input elements, {@code inputData}, and whether those elements match the
163      * predicate, {@code p}, of the operation.
164      * <p>
165      * If the input elements have an encounter order then the actual result
166      * is asserted against the result of operating sequentially on input
167      * elements given the predicate and in accordance with the operation
168      * semantics. (The actual result whether produced sequentially or in
169      * parallel should the same.)
170      * <p>
171      * If the input elements have no encounter order then an actual result
172      * is, for practical purposes, considered non-deterministic.
173      * Consider an input list of lists that contains all possible permutations
174      * of the input elements, and a output list of lists that is the result of
175      * applying the pipeline with the operation sequentially to each input
176      * list.
177      * Any list in the output lists is a valid result. It's not practical to
178      * test in such a manner.
179      * For a takeWhile operation the following assertions can be made if
180      * only some of the input elements match the predicate (i.e. taking will
181      * short-circuit the pipeline):
182      * <ol>
183      * <li>The set of output elements is a subset of the set of matching
184      * input elements</li>
185      * <li>The set of output elements and the set of non-matching input
186      * element are disjoint</li>
187      * </ol>
188      * For a dropWhile operation the following assertions can be made:
189      * <ol>
190      * <li>The set of non-matching input elements is a subset of the set of
191      * output elements</li>
192      * <li>The set of matching output elements is a subset of the set of
193      * matching input elements</li>
194      * </ol>
195      *
196      * @param inputData the elements input into the stream pipeline
197      * @param op the operation of the stream pipeline, one of takeWhile,
198      * dropWhile, or an undefined set of operations (possibly including
199      * two or more takeWhile and/or dropWhile operations, or because
200      * the predicate is not stateless).
201      * @param p the stateless predicate applied to the operation, ignored if
202      * the
203      * operation is {@link WhileOp#Undefined}.
204      * @param <T> the type of elements
205      * @return a result asserter
206      */
whileResultAsserter(Iterable<T> inputData, WhileOp op, Predicate<? super T> p)207     private <T> ResultAsserter<Iterable<T>> whileResultAsserter(Iterable<T> inputData,
208                                                                 WhileOp op,
209                                                                 Predicate<? super T> p) {
210         return (act, exp, ord, par) -> {
211             if (par & !ord) {
212                 List<T> input = new ArrayList<>();
213                 inputData.forEach(input::add);
214 
215                 List<T> output = new ArrayList<>();
216                 act.forEach(output::add);
217 
218                 if (op == WhileOp.Take) {
219                     List<T> matchingInput = new ArrayList<>();
220                     List<T> nonMatchingInput = new ArrayList<>();
221                     input.forEach(t -> {
222                         if (p.test(t))
223                             matchingInput.add(t);
224                         else
225                             nonMatchingInput.add(t);
226                     });
227 
228                     // If some, not all, elements are taken
229                     if (matchingInput.size() < input.size()) {
230                         assertTrue(output.size() <= matchingInput.size(),
231                                    "Output is larger than the matching input");
232 
233                         // The output must be a subset of the matching input
234                         assertTrue(matchingInput.containsAll(output),
235                                    "Output is not a subset of the matching input");
236 
237                         // The output must not contain any non matching elements
238                         for (T nonMatching : nonMatchingInput) {
239                             assertFalse(output.contains(nonMatching),
240                                         "Output and non-matching input are not disjoint");
241                         }
242                     }
243                 }
244                 else if (op == WhileOp.Drop) {
245                     List<T> matchingInput = new ArrayList<>();
246                     List<T> nonMatchingInput = new ArrayList<>();
247                     input.forEach(t -> {
248                         if (p.test(t))
249                             matchingInput.add(t);
250                         else
251                             nonMatchingInput.add(t);
252                     });
253 
254                     // The non matching input must be a subset of output
255                     assertTrue(output.containsAll(nonMatchingInput),
256                                "Non-matching input is not a subset of the output");
257 
258                     // The matching output must be a subset of the matching input
259                     List<T> matchingOutput = new ArrayList<>();
260                     output.forEach(i -> {
261                         if (p.test(i))
262                             matchingOutput.add(i);
263                     });
264                     assertTrue(matchingInput.containsAll(matchingOutput),
265                                "Matching output is not a subset of matching input");
266                 }
267 
268                 // Note: if there is a combination of takeWhile and dropWhile then specific
269                 // assertions cannot be performed.
270                 // All that can be reliably asserted is the output is a subset of the input
271 
272                 assertTrue(input.containsAll(output));
273             }
274             else {
275                 // For specific operations derive expected result from the input
276                 if (op == WhileOp.Take) {
277                     List<T> takeInput = new ArrayList<>();
278                     for (T t : inputData) {
279                         if (p.test(t))
280                             takeInput.add(t);
281                         else
282                             break;
283                     }
284 
285                     LambdaTestHelpers.assertContents(act, takeInput);
286                 }
287                 else if (op == WhileOp.Drop) {
288                     List<T> dropInput = new ArrayList<>();
289                     for (T t : inputData) {
290                         if (dropInput.size() > 0 || !p.test(t))
291                             dropInput.add(t);
292                     }
293 
294                     LambdaTestHelpers.assertContents(act, dropInput);
295                 }
296 
297                 LambdaTestHelpers.assertContents(act, exp);
298             }
299         };
300     }
301 
302     private Collection<Integer> sizes(int s) {
303         Set<Integer> sizes = new LinkedHashSet<>();
304 
305         sizes.add(0);
306         sizes.add(1);
307         sizes.add(s / 4);
308         sizes.add(s / 2);
309         sizes.add(3 * s / 4);
310         sizes.add(Math.max(0, s - 1));
311         sizes.add(s);
312         sizes.add(Integer.MAX_VALUE);
313 
314         return sizes;
315     }
316 
317     private void testWhileMulti(TestData.OfRef<Integer> data,
318                                 ResultAsserter<Iterable<Integer>> ra,
319                                 Function<Stream<Integer>, Stream<Integer>> mRef) {
320         // BEGIN Android-removed: Drop primitive stream test.
321         /*
322                                 Function<IntStream, IntStream> mInt,
323                                 Function<LongStream, LongStream> mLong,
324                                 Function<DoubleStream, DoubleStream> mDouble) {
325         */
326         // BEGIN Android-removed: Drop primitive stream test.
327         Map<String, Function<Stream<Integer>, Stream<Integer>>> ms = new HashMap<>();
328         ms.put("Ref", mRef);
329         // Android-removed: Drop primitive stream test.
330         // ms.put("Int", s -> mInt.apply(s.mapToInt(e -> e)).mapToObj(e -> e));
331         // ms.put("Long", s -> mLong.apply(s.mapToLong(e -> e)).mapToObj(e -> (int) e));
332         // ms.put("Double", s -> mDouble.apply(s.mapToDouble(e -> e)).mapToObj(e -> (int) e));
333         ms.put("Ref using defaults", s -> mRef.apply(DefaultMethodStreams.delegateTo(s)));
334         // Android-removed: Drop primitive stream test.
335         // ms.put("Int using defaults", s -> mInt.apply(DefaultMethodStreams.delegateTo(s.mapToInt(e -> e))).mapToObj(e -> e));
336         // ms.put("Long using defaults", s -> mLong.apply(DefaultMethodStreams.delegateTo(s.mapToLong(e -> e))).mapToObj(e -> (int) e));
337         // ms.put("Double using defaults", s -> mDouble.apply(DefaultMethodStreams.delegateTo(s.mapToDouble(e -> e))).mapToObj(e -> (int) e));
338 
339         testWhileMulti(data, ra, ms);
340     }
341 
342     private final void testWhileMulti(TestData.OfRef<Integer> data,
343                                       ResultAsserter<Iterable<Integer>> ra,
344                                       Map<String, Function<Stream<Integer>, Stream<Integer>>> ms) {
345         for (Map.Entry<String, Function<Stream<Integer>, Stream<Integer>>> e : ms.entrySet()) {
346             setContext("shape", e.getKey());
347 
348             withData(data)
349                     .stream(e.getValue())
350                     .resultAsserter(ra)
351                     .exercise();
352         }
353     }
354 
355     @Test(groups = { "serialization-hostile" })
356     public void testRefDefaultClose() {
357         AtomicBoolean isClosed = new AtomicBoolean();
358         Stream<Integer> s = Stream.of(1, 2, 3).onClose(() -> isClosed.set(true));
359         try (Stream<Integer> ds = DefaultMethodStreams.delegateTo(s).takeWhile(e -> e < 3)) {
360             ds.count();
361         }
362         assertTrue(isClosed.get());
363     }
364 
365     // BEGIN Android-removed: Drop primitive stream test.
366     /*
367     @Test(groups = { "serialization-hostile" })
368     public void testIntDefaultClose() {
369         AtomicBoolean isClosed = new AtomicBoolean();
370         IntStream s = IntStream.of(1, 2, 3).onClose(() -> isClosed.set(true));
371         try (IntStream ds = DefaultMethodStreams.delegateTo(s).takeWhile(e -> e < 3)) {
372             ds.count();
373         }
374         assertTrue(isClosed.get());
375     }
376 
377     @Test(groups = { "serialization-hostile" })
378     public void testLongDefaultClose() {
379         AtomicBoolean isClosed = new AtomicBoolean();
380         LongStream s = LongStream.of(1, 2, 3).onClose(() -> isClosed.set(true));
381         try (LongStream ds = DefaultMethodStreams.delegateTo(s).takeWhile(e -> e < 3)) {
382             ds.count();
383         }
384         assertTrue(isClosed.get());
385     }
386 
387     @Test(groups = { "serialization-hostile" })
388     public void testDoubleDefaultClose() {
389         AtomicBoolean isClosed = new AtomicBoolean();
390         DoubleStream s = DoubleStream.of(1, 2, 3).onClose(() -> isClosed.set(true));
391         try (DoubleStream ds = DefaultMethodStreams.delegateTo(s).takeWhile(e -> e < 3)) {
392             ds.count();
393         }
394         assertTrue(isClosed.get());
395     }
396     */
397     // END Android-removed: Drop primitive stream test.
398 
399     @Test(groups = { "serialization-hostile" })
400     public void testFlatMapThenTake() {
401         TestData.OfRef<Integer> range = TestData.Factory.ofSupplier(
402                 "range", () -> IntStream.range(0, 100).boxed());
403 
404         exerciseOpsMulti(range,
405                          // Reference result
406                          s -> s.takeWhile(e -> e != 50),
407                          // For other results collect into array,
408                          // stream the single array (not the elements),
409                          // then flat map to stream the array elements
410                          s -> Stream.<Integer[]>of(s.toArray(Integer[]::new)).
411                                  flatMap(Stream::of).
412                                  takeWhile(e -> e != 50)
413                         );
414         // BEGIN Android-removed: Drop primitive stream test.
415         /*
416                          s -> Stream.of(s.mapToInt(e -> e).toArray()).
417                                  flatMapToInt(IntStream::of).
418                                  takeWhile(e -> e != 50).
419                                  mapToObj(e -> e),
420                          s -> Stream.of(s.mapToLong(e -> e).toArray()).
421                                  flatMapToLong(LongStream::of).
422                                  takeWhile(e -> e != 50L).
423                                  mapToObj(e -> (int) e),
424                          s -> Stream.of(s.mapToDouble(e -> e).toArray()).
425                                  flatMapToDouble(DoubleStream::of).
426                                  takeWhile(e -> e != 50.0).
427                                  mapToObj(e -> (int) e)
428                          );
429         */
430         // END Android-removed: Drop primitive stream test.
431     }
432 }
433