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.openjdk.testlib.java.util.stream.LambdaTestHelpers;
26
27import java.util.concurrent.ArrayBlockingQueue;
28import java.util.concurrent.ConcurrentHashMap;
29import java.util.concurrent.ConcurrentLinkedDeque;
30import java.util.concurrent.ConcurrentLinkedQueue;
31import java.util.concurrent.ConcurrentSkipListMap;
32import java.util.concurrent.ConcurrentSkipListSet;
33import java.util.concurrent.CopyOnWriteArrayList;
34import java.util.concurrent.CopyOnWriteArraySet;
35import java.util.concurrent.LinkedBlockingDeque;
36import java.util.concurrent.LinkedBlockingQueue;
37import java.util.concurrent.LinkedTransferQueue;
38import java.util.concurrent.PriorityBlockingQueue;
39import java.util.function.Supplier;
40import org.testng.annotations.DataProvider;
41import org.testng.annotations.Test;
42
43import java.util.*;
44import java.util.stream.Stream;
45
46import static org.testng.Assert.assertEquals;
47import static org.testng.Assert.assertTrue;
48
49/**
50 * Tests laziness of stream operations -- mutations to the source after the stream() but prior to terminal operations
51 * are reflected in the stream contents.
52 */
53@Test
54public class CollectionAndMapModifyStreamTest {
55
56    @DataProvider(name = "collections")
57    public Object[][] createCollections() {
58        List<Integer> content = LambdaTestHelpers.countTo(10);
59
60        List<Collection<Integer>> collections = new ArrayList<>();
61        collections.add(new ArrayList<>(content));
62        collections.add(new LinkedList<>(content));
63        collections.add(new Vector<>(content));
64
65        collections.add(new HashSet<>(content));
66        collections.add(new LinkedHashSet<>(content));
67        collections.add(new TreeSet<>(content));
68
69        Stack<Integer> stack = new Stack<>();
70        stack.addAll(content);
71        collections.add(stack);
72        collections.add(new PriorityQueue<>(content));
73        collections.add(new ArrayDeque<>(content));
74
75        // Concurrent collections
76
77        collections.add(new ConcurrentSkipListSet<>(content));
78
79        ArrayBlockingQueue<Integer> arrayBlockingQueue = new ArrayBlockingQueue<>(content.size());
80        for (Integer i : content)
81            arrayBlockingQueue.add(i);
82        collections.add(arrayBlockingQueue);
83        collections.add(new PriorityBlockingQueue<>(content));
84        collections.add(new LinkedBlockingQueue<>(content));
85        collections.add(new LinkedTransferQueue<>(content));
86        collections.add(new ConcurrentLinkedQueue<>(content));
87        collections.add(new LinkedBlockingDeque<>(content));
88        collections.add(new ConcurrentLinkedDeque<>(content));
89
90        Object[][] params = new Object[collections.size()][];
91        for (int i = 0; i < collections.size(); i++) {
92            params[i] = new Object[]{collections.get(i).getClass().getName(), collections.get(i)};
93        }
94
95        return params;
96    }
97
98    @Test(dataProvider = "collections")
99    public void testCollectionSizeRemove(String name, Collection<Integer> c) {
100        assertTrue(c.remove(1));
101        Stream<Integer> s = c.stream();
102        assertTrue(c.remove(2));
103        Object[] result = s.toArray();
104        assertEquals(result.length, c.size());
105    }
106
107    @DataProvider(name = "maps")
108    public Object[][] createMaps() {
109        Map<Integer, Integer> content = new HashMap<>();
110        for (int i = 0; i < 10; i++) {
111            content.put(i, i);
112        }
113
114        Map<String, Supplier<Map<Integer, Integer>>> maps = new HashMap<>();
115
116        maps.put(HashMap.class.getName(), () -> new HashMap<>(content));
117        maps.put(HashMap.class.getName(), () -> new LinkedHashMap<>(content));
118        maps.put(IdentityHashMap.class.getName(), () -> new IdentityHashMap<>(content));
119        maps.put(WeakHashMap.class.getName(), () -> new WeakHashMap<>(content));
120
121        maps.put(TreeMap.class.getName(), () -> new TreeMap<>(content));
122        maps.put(TreeMap.class.getName() + ".descendingMap()", () -> new TreeMap<>(content).descendingMap());
123
124        // The following are not lazy
125//        maps.put(TreeMap.class.getName() + ".descendingMap().descendingMap()", () -> new TreeMap<>(content).descendingMap().descendingMap());
126//        maps.put(TreeMap.class.getName() + ".headMap()", () -> new TreeMap<>(content).headMap(content.size() - 1));
127//        maps.put(TreeMap.class.getName() + ".descendingMap().headMap()", () -> new TreeMap<>(content).descendingMap().tailMap(content.size() - 1, false));
128
129        // Concurrent collections
130
131        maps.put(ConcurrentHashMap.class.getName(), () -> new ConcurrentHashMap<>(content));
132        maps.put(ConcurrentSkipListMap.class.getName(), () -> new ConcurrentSkipListMap<>(content));
133
134        Object[][] params = new Object[maps.size()][];
135        int i = 0;
136        for (Map.Entry<String, Supplier<Map<Integer, Integer>>> e : maps.entrySet()) {
137            params[i++] = new Object[]{e.getKey(), e.getValue()};
138
139        }
140
141        return params;
142    }
143
144    @Test(dataProvider = "maps", groups = { "serialization-hostile" })
145    public void testMapKeysSizeRemove(String name, Supplier<Map<Integer, Integer>> c) {
146        testCollectionSizeRemove(name + " key set", c.get().keySet());
147    }
148
149    @Test(dataProvider = "maps", groups = { "serialization-hostile" })
150    public void testMapValuesSizeRemove(String name, Supplier<Map<Integer, Integer>> c) {
151        testCollectionSizeRemove(name + " value set", c.get().values());
152    }
153
154    @Test(dataProvider = "maps")
155    public void testMapEntriesSizeRemove(String name, Supplier<Map<Integer, Integer>> c) {
156        testEntrySetSizeRemove(name + " entry set", c.get().entrySet());
157    }
158
159    private void testEntrySetSizeRemove(String name, Set<Map.Entry<Integer, Integer>> c) {
160        Map.Entry<Integer, Integer> first = c.iterator().next();
161        assertTrue(c.remove(first));
162        Stream<Map.Entry<Integer, Integer>> s = c.stream();
163        Map.Entry<Integer, Integer> second = c.iterator().next();
164        assertTrue(c.remove(second));
165        Object[] result = s.toArray();
166        assertEquals(result.length, c.size());
167    }
168}
169