1 /*
2  * Copyright (c) 2006, 2014, 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 
24 /*
25  * @test
26  * @bug 6415641 6377302
27  * @summary Concurrent collections are permitted to lie about their size
28  * @author Martin Buchholz
29  */
30 package test.java.util.Collection;
31 
32 import java.util.Arrays;
33 import java.util.Collection;
34 import java.util.Map;
35 import java.util.NavigableMap;
36 import java.util.NavigableSet;
37 import java.util.Objects;
38 import java.util.Random;
39 import java.util.Set;
40 import java.util.TreeSet;
41 import java.util.concurrent.ArrayBlockingQueue;
42 import java.util.concurrent.ConcurrentHashMap;
43 import java.util.concurrent.ConcurrentLinkedDeque;
44 import java.util.concurrent.ConcurrentLinkedQueue;
45 import java.util.concurrent.ConcurrentSkipListMap;
46 import java.util.concurrent.ConcurrentSkipListSet;
47 import java.util.concurrent.CopyOnWriteArrayList;
48 import java.util.concurrent.CopyOnWriteArraySet;
49 import java.util.concurrent.LinkedBlockingDeque;
50 import java.util.concurrent.LinkedBlockingQueue;
51 import java.util.concurrent.LinkedTransferQueue;
52 import java.util.concurrent.PriorityBlockingQueue;
53 import org.testng.Assert;
54 import org.testng.annotations.Test;
55 
56 @SuppressWarnings("unchecked")
57 public class BiggernYours {
58 
59     static final Random rnd = new Random(18675309);
60 
compareCollections(Collection c1, Collection c2)61     static void compareCollections(Collection c1, Collection c2) {
62         Object[] c1Array = c1.toArray();
63         Object[] c2Array = c2.toArray();
64 
65         Assert.assertEquals(c1Array.length, c2Array.length);
66         for (Object aC1 : c1Array) {
67             boolean found = false;
68             for (Object aC2 : c2Array) {
69                 if (Objects.equals(aC1, aC2)) {
70                     found = true;
71                     break;
72                 }
73             }
74 
75             if (!found) {
76                 Assert.fail(aC1 + " not found in " + Arrays.toString(c2Array));
77             }
78         }
79     }
80 
compareMaps(Map m1, Map m2)81     static void compareMaps(Map m1, Map m2) {
82         compareCollections(m1.keySet(),
83                 m2.keySet());
84         compareCollections(m1.values(),
85                 m2.values());
86         compareCollections(m1.entrySet(),
87                 m2.entrySet());
88     }
89 
compareNavigableMaps(NavigableMap m1, NavigableMap m2)90     static void compareNavigableMaps(NavigableMap m1, NavigableMap m2) {
91         compareMaps(m1, m2);
92         compareMaps(m1.descendingMap(),
93                 m2.descendingMap());
94         compareMaps(m1.tailMap(Integer.MIN_VALUE),
95                 m2.tailMap(Integer.MIN_VALUE));
96         compareMaps(m1.headMap(Integer.MAX_VALUE),
97                 m2.headMap(Integer.MAX_VALUE));
98     }
99 
compareNavigableSets(NavigableSet s1, NavigableSet s2)100     static void compareNavigableSets(NavigableSet s1, NavigableSet s2) {
101         compareCollections(s1, s2);
102         compareCollections(s1.descendingSet(),
103                 s2.descendingSet());
104         compareCollections(s1.tailSet(Integer.MIN_VALUE),
105                 s2.tailSet(Integer.MIN_VALUE));
106     }
107 
108     abstract static class MapFrobber {
109 
frob(Map m)110         abstract void frob(Map m);
111     }
112 
113     abstract static class ColFrobber {
114 
frob(Collection c)115         abstract void frob(Collection c);
116     }
117 
adder(final int i)118     static ColFrobber adder(final int i) {
119         return new ColFrobber() {
120             void frob(Collection c) {
121                 c.add(i);
122             }
123         };
124     }
125 
126     static final ColFrobber[] adders =
127             {adder(1), adder(3), adder(2)};
128 
129     static MapFrobber putter(final int k, final int v) {
130         return new MapFrobber() {
131             void frob(Map m) {
132                 m.put(k, v);
133             }
134         };
135     }
136 
137     static final MapFrobber[] putters =
138             {putter(1, -2), putter(3, -6), putter(2, -4)};
139 
140     static void testCollections(Collection c1, Collection c2) {
141         try {
142             compareCollections(c1, c2);
143             for (ColFrobber adder : adders) {
144                 for (Collection c : new Collection[]{c1, c2}) {
145                     adder.frob(c);
146                 }
147                 compareCollections(c1, c2);
148             }
149         } catch (Throwable t) {
150             Assert.fail("Unexpected exception: " + t.getMessage());
151         }
152     }
153 
154     static void testNavigableSets(NavigableSet s1, NavigableSet s2) {
155         try {
156             compareNavigableSets(s1, s2);
157             for (ColFrobber adder : adders) {
158                 for (Set s : new Set[]{s1, s2}) {
159                     adder.frob(s);
160                 }
161                 compareNavigableSets(s1, s2);
162             }
163         } catch (Throwable t) {
164             Assert.fail("Unexpected exception: " + t.getMessage());
165         }
166     }
167 
168     static void testMaps(Map m1, Map m2) {
169         try {
170             compareMaps(m1, m2);
171             for (MapFrobber putter : putters) {
172                 for (Map m : new Map[]{m1, m2}) {
173                     putter.frob(m);
174                 }
175                 compareMaps(m1, m2);
176             }
177         } catch (Throwable t) {
178             Assert.fail("Unexpected exception: " + t.getMessage());
179         }
180     }
181 
182     static void testNavigableMaps(NavigableMap m1, NavigableMap m2) {
183         try {
184             compareNavigableMaps(m1, m2);
185             for (MapFrobber putter : putters) {
186                 for (Map m : new Map[]{m1, m2}) {
187                     putter.frob(m);
188                 }
189                 compareNavigableMaps(m1, m2);
190             }
191         } catch (Throwable t) {
192             Assert.fail("Unexpected exception: " + t.getMessage());
193         }
194     }
195 
196     static int randomize(int size) {
197         return rnd.nextInt(size + 2);
198     }
199 
200     @Test
201     public void testConcurrentSkipListMap() {
202         testNavigableMaps(
203                 new ConcurrentSkipListMap(),
204                 new ConcurrentSkipListMap() {
205                     public int size() {
206                         return randomize(super.size());
207                     }
208                 });
209     }
210 
211     @Test
212     public void testConcurrentSkipListSet() {
213         testNavigableSets(
214                 new ConcurrentSkipListSet(),
215                 new ConcurrentSkipListSet() {
216                     public int size() {
217                         return randomize(super.size());
218                     }
219                 });
220     }
221 
222     @Test
223     public void testCopyOnWriteArraySet() {
224         testCollections(
225                 new CopyOnWriteArraySet(),
226                 new CopyOnWriteArraySet() {
227                     public int size() {
228                         return randomize(super.size());
229                     }
230                 });
231     }
232 
233     @Test
234     public void testCopyOnWriteArrayList() {
235         testCollections(
236                 new CopyOnWriteArrayList(),
237                 new CopyOnWriteArrayList() {
238                     public int size() {
239                         return randomize(super.size());
240                     }
241                 });
242     }
243 
244     @Test
245     public void testTreeSet() {
246         testCollections(
247                 new TreeSet(),
248                 new TreeSet() {
249                     public int size() {
250                         return randomize(super.size());
251                     }
252                 });
253     }
254 
255     @Test
256     public void testConcurrentHashMap() {
257         testMaps(
258                 new ConcurrentHashMap(),
259                 new ConcurrentHashMap() {
260                     public int size() {
261                         return randomize(super.size());
262                     }
263                 });
264     }
265 
266     @Test
267     public void testConcurrentLinkedDeque() {
268         testCollections(
269                 new ConcurrentLinkedDeque(),
270                 new ConcurrentLinkedDeque() {
271                     public int size() {
272                         return randomize(super.size());
273                     }
274                 });
275     }
276 
277     @Test
278     public void testConcurrentLinkedQueue() {
279         testCollections(
280                 new ConcurrentLinkedQueue(),
281                 new ConcurrentLinkedQueue() {
282                     public int size() {
283                         return randomize(super.size());
284                     }
285                 });
286     }
287 
288     @Test
289     public void testLinkedTransferQueue() {
290         testCollections(
291                 new LinkedTransferQueue(),
292                 new LinkedTransferQueue() {
293                     public int size() {
294                         return randomize(super.size());
295                     }
296                 });
297     }
298 
299     @Test
300     public void testLinkedBlockingQueue() {
301         testCollections(
302                 new LinkedBlockingQueue(),
303                 new LinkedBlockingQueue() {
304                     public int size() {
305                         return randomize(super.size());
306                     }
307                 });
308     }
309 
310     @Test
311     public void testLinkedBlockingDeque() {
312         testCollections(
313                 new LinkedBlockingDeque(),
314                 new LinkedBlockingDeque() {
315                     public int size() {
316                         return randomize(super.size());
317                     }
318                 });
319     }
320 
321     @Test
322     public void testArrayBlockingQueue() {
323         testCollections(
324                 new ArrayBlockingQueue(5),
325                 new ArrayBlockingQueue(5) {
326                     public int size() {
327                         return randomize(super.size());
328                     }
329                 });
330     }
331 
332     @Test
333     public void testPriorityBlockingQueue() {
334         testCollections(
335                 new PriorityBlockingQueue(5),
336                 new PriorityBlockingQueue(5) {
337                     public int size() {
338                         return randomize(super.size());
339                     }
340                 });
341     }
342 }
343