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 */
23package org.openjdk.tests.java.util.stream;
24
25import org.testng.annotations.DataProvider;
26import org.testng.annotations.Factory;
27import org.testng.annotations.Test;
28
29import java.util.Arrays;
30import java.util.Collection;
31import java.util.Collections;
32import java.util.LinkedHashSet;
33import java.util.LinkedList;
34import java.util.List;
35import java.util.Spliterator;
36import java.util.TreeSet;
37import java.util.stream.DoubleStream;
38import java.util.stream.IntStream;
39import java.util.stream.LongStream;
40import java.util.stream.Stream;
41
42import static java.util.stream.LambdaTestHelpers.*;
43import static org.testng.Assert.*;
44
45@Test
46public 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
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")
78    private static Object[][] getCases() {
79        return cases;
80    }
81
82    @Factory(dataProvider = "cases")
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
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
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
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
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
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
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
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
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
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
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