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.DataProvider;
26 import org.testng.annotations.Factory;
27 import org.testng.annotations.Test;
28 
29 import java.util.Arrays;
30 import java.util.Collection;
31 import java.util.Collections;
32 import java.util.LinkedHashSet;
33 import java.util.LinkedList;
34 import java.util.List;
35 import java.util.Spliterator;
36 import java.util.TreeSet;
37 import java.util.stream.DoubleStream;
38 import java.util.stream.IntStream;
39 import java.util.stream.LongStream;
40 import java.util.stream.Stream;
41 
42 import static java.util.stream.LambdaTestHelpers.*;
43 import static org.testng.Assert.*;
44 
45 @Test
46 public class ConcatTest {
47     private static Object[][] cases;
48 
49     static {
50         List<Integer> part1 = Arrays.asList(5, 3, 4, 1, 2, 6, 2, 4);
51         List<Integer> part2 = Arrays.asList(8, 8, 6, 6, 9, 7, 10, 9);
52         List<Integer> p1p2 = Arrays.asList(5, 3, 4, 1, 2, 6, 2, 4, 8, 8, 6, 6, 9, 7, 10, 9);
53         List<Integer> p2p1 = Arrays.asList(8, 8, 6, 6, 9, 7, 10, 9, 5, 3, 4, 1, 2, 6, 2, 4);
54         List<Integer> empty = new LinkedList<>(); // To be ordered
empty.isEmpty()55         assertTrue(empty.isEmpty());
56         LinkedHashSet<Integer> distinctP1 = new LinkedHashSet<>(part1);
57         LinkedHashSet<Integer> distinctP2 = new LinkedHashSet<>(part2);
58         TreeSet<Integer> sortedP1 = new TreeSet<>(part1);
59         TreeSet<Integer> sortedP2 = new TreeSet<>(part2);
60 
61         cases = new Object[][] {
62             { "regular", part1, part2, p1p2 },
63             { "reverse regular", part2, part1, p2p1 },
64             { "front distinct", distinctP1, part2, Arrays.asList(5, 3, 4, 1, 2, 6, 8, 8, 6, 6, 9, 7, 10, 9) },
65             { "back distinct", part1, distinctP2, Arrays.asList(5, 3, 4, 1, 2, 6, 2, 4, 8, 6, 9, 7, 10) },
66             { "both distinct", distinctP1, distinctP2, Arrays.asList(5, 3, 4, 1, 2, 6, 8, 6, 9, 7, 10) },
67             { "front sorted", sortedP1, part2, Arrays.asList(1, 2, 3, 4, 5, 6, 8, 8, 6, 6, 9, 7, 10, 9) },
68             { "back sorted", part1, sortedP2, Arrays.asList(5, 3, 4, 1, 2, 6, 2, 4, 6, 7, 8, 9, 10) },
69             { "both sorted", sortedP1, sortedP2, Arrays.asList(1, 2, 3, 4, 5, 6, 6, 7, 8, 9, 10) },
70             { "reverse both sorted", sortedP2, sortedP1, Arrays.asList(6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6) },
71             { "empty something", empty, part1, part1 },
72             { "something empty", part1, empty, part1 },
73             { "empty empty", empty, empty, empty }
74         };
75     }
76 
77     @DataProvider(name = "cases")
getCases()78     private static Object[][] getCases() {
79         return cases;
80     }
81 
82     @Factory(dataProvider = "cases")
createTests(String scenario, Collection<Integer> c1, Collection<Integer> c2, Collection<Integer> expected)83     public static Object[] createTests(String scenario, Collection<Integer> c1, Collection<Integer> c2, Collection<Integer> expected) {
84         return new Object[] {
85             new ConcatTest(scenario, c1, c2, expected)
86         };
87     }
88 
89     protected final String scenario;
90     protected final Collection<Integer> c1;
91     protected final Collection<Integer> c2;
92     protected final Collection<Integer> expected;
93 
ConcatTest(String scenario, Collection<Integer> c1, Collection<Integer> c2, Collection<Integer> expected)94     public ConcatTest(String scenario, Collection<Integer> c1, Collection<Integer> c2, Collection<Integer> expected) {
95         this.scenario = scenario;
96         this.c1 = c1;
97         this.c2 = c2;
98         this.expected = expected;
99 
100         // verify prerequisite
101         Stream<Integer> s1s = c1.stream();
102         Stream<Integer> s2s = c2.stream();
103         Stream<Integer> s1p = c1.parallelStream();
104         Stream<Integer> s2p = c2.parallelStream();
105         assertTrue(s1p.isParallel());
106         assertTrue(s2p.isParallel());
107         assertFalse(s1s.isParallel());
108         assertFalse(s2s.isParallel());
109 
110         assertTrue(s1s.spliterator().hasCharacteristics(Spliterator.ORDERED));
111         assertTrue(s1p.spliterator().hasCharacteristics(Spliterator.ORDERED));
112         assertTrue(s2s.spliterator().hasCharacteristics(Spliterator.ORDERED));
113         assertTrue(s2p.spliterator().hasCharacteristics(Spliterator.ORDERED));
114     }
115 
assertConcatContent(Spliterator<T> sp, boolean ordered, Spliterator<T> expected)116     private <T> void assertConcatContent(Spliterator<T> sp, boolean ordered, Spliterator<T> expected) {
117         // concat stream cannot guarantee uniqueness
118         assertFalse(sp.hasCharacteristics(Spliterator.DISTINCT), scenario);
119         // concat stream cannot guarantee sorted
120         assertFalse(sp.hasCharacteristics(Spliterator.SORTED), scenario);
121         // concat stream is ordered if both are ordered
122         assertEquals(sp.hasCharacteristics(Spliterator.ORDERED), ordered, scenario);
123 
124         // Verify elements
125         if (ordered) {
126             assertEquals(toBoxedList(sp),
127                          toBoxedList(expected),
128                          scenario);
129         } else {
130             assertEquals(toBoxedMultiset(sp),
131                          toBoxedMultiset(expected),
132                          scenario);
133         }
134     }
135 
assertRefConcat(Stream<Integer> s1, Stream<Integer> s2, boolean parallel, boolean ordered)136     private void assertRefConcat(Stream<Integer> s1, Stream<Integer> s2, boolean parallel, boolean ordered) {
137         Stream<Integer> result = Stream.concat(s1, s2);
138         assertEquals(result.isParallel(), parallel);
139         assertConcatContent(result.spliterator(), ordered, expected.spliterator());
140     }
141 
assertIntConcat(Stream<Integer> s1, Stream<Integer> s2, boolean parallel, boolean ordered)142     private void assertIntConcat(Stream<Integer> s1, Stream<Integer> s2, boolean parallel, boolean ordered) {
143         IntStream result = IntStream.concat(s1.mapToInt(Integer::intValue),
144                                             s2.mapToInt(Integer::intValue));
145         assertEquals(result.isParallel(), parallel);
146         assertConcatContent(result.spliterator(), ordered,
147                             expected.stream().mapToInt(Integer::intValue).spliterator());
148     }
149 
assertLongConcat(Stream<Integer> s1, Stream<Integer> s2, boolean parallel, boolean ordered)150     private void assertLongConcat(Stream<Integer> s1, Stream<Integer> s2, boolean parallel, boolean ordered) {
151         LongStream result = LongStream.concat(s1.mapToLong(Integer::longValue),
152                                               s2.mapToLong(Integer::longValue));
153         assertEquals(result.isParallel(), parallel);
154         assertConcatContent(result.spliterator(), ordered,
155                             expected.stream().mapToLong(Integer::longValue).spliterator());
156     }
157 
assertDoubleConcat(Stream<Integer> s1, Stream<Integer> s2, boolean parallel, boolean ordered)158     private void assertDoubleConcat(Stream<Integer> s1, Stream<Integer> s2, boolean parallel, boolean ordered) {
159         DoubleStream result = DoubleStream.concat(s1.mapToDouble(Integer::doubleValue),
160                                                   s2.mapToDouble(Integer::doubleValue));
161         assertEquals(result.isParallel(), parallel);
162         assertConcatContent(result.spliterator(), ordered,
163                             expected.stream().mapToDouble(Integer::doubleValue).spliterator());
164     }
165 
testRefConcat()166     public void testRefConcat() {
167         // sequential + sequential -> sequential
168         assertRefConcat(c1.stream(), c2.stream(), false, true);
169         // parallel + parallel -> parallel
170         assertRefConcat(c1.parallelStream(), c2.parallelStream(), true, true);
171         // sequential + parallel -> parallel
172         assertRefConcat(c1.stream(), c2.parallelStream(), true, true);
173         // parallel + sequential -> parallel
174         assertRefConcat(c1.parallelStream(), c2.stream(), true, true);
175 
176         // not ordered
177         assertRefConcat(c1.stream().unordered(), c2.stream(), false, false);
178         assertRefConcat(c1.stream(), c2.stream().unordered(), false, false);
179         assertRefConcat(c1.parallelStream().unordered(), c2.stream().unordered(), true, false);
180     }
181 
testIntConcat()182     public void testIntConcat() {
183         // sequential + sequential -> sequential
184         assertIntConcat(c1.stream(), c2.stream(), false, true);
185         // parallel + parallel -> parallel
186         assertIntConcat(c1.parallelStream(), c2.parallelStream(), true, true);
187         // sequential + parallel -> parallel
188         assertIntConcat(c1.stream(), c2.parallelStream(), true, true);
189         // parallel + sequential -> parallel
190         assertIntConcat(c1.parallelStream(), c2.stream(), true, true);
191 
192         // not ordered
193         assertIntConcat(c1.stream().unordered(), c2.stream(), false, false);
194         assertIntConcat(c1.stream(), c2.stream().unordered(), false, false);
195         assertIntConcat(c1.parallelStream().unordered(), c2.stream().unordered(), true, false);
196     }
197 
testLongConcat()198     public void testLongConcat() {
199         // sequential + sequential -> sequential
200         assertLongConcat(c1.stream(), c2.stream(), false, true);
201         // parallel + parallel -> parallel
202         assertLongConcat(c1.parallelStream(), c2.parallelStream(), true, true);
203         // sequential + parallel -> parallel
204         assertLongConcat(c1.stream(), c2.parallelStream(), true, true);
205         // parallel + sequential -> parallel
206         assertLongConcat(c1.parallelStream(), c2.stream(), true, true);
207 
208         // not ordered
209         assertLongConcat(c1.stream().unordered(), c2.stream(), false, false);
210         assertLongConcat(c1.stream(), c2.stream().unordered(), false, false);
211         assertLongConcat(c1.parallelStream().unordered(), c2.stream().unordered(), true, false);
212     }
213 
testDoubleConcat()214     public void testDoubleConcat() {
215         // sequential + sequential -> sequential
216         assertDoubleConcat(c1.stream(), c2.stream(), false, true);
217         // parallel + parallel -> parallel
218         assertDoubleConcat(c1.parallelStream(), c2.parallelStream(), true, true);
219         // sequential + parallel -> parallel
220         assertDoubleConcat(c1.stream(), c2.parallelStream(), true, true);
221         // parallel + sequential -> parallel
222         assertDoubleConcat(c1.parallelStream(), c2.stream(), true, true);
223 
224         // not ordered
225         assertDoubleConcat(c1.stream().unordered(), c2.stream(), false, false);
226         assertDoubleConcat(c1.stream(), c2.stream().unordered(), false, false);
227         assertDoubleConcat(c1.parallelStream().unordered(), c2.stream().unordered(), true, false);
228     }
229 }
230