1 /*
2  * Copyright (c) 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 package test.java.util.Collections;
25 
26 /**
27  * @test
28  * @bug 8048209
29  * @summary Check that Collections.synchronizedNavigableSet().tailSet() is using
30  * the same lock object as it's source.
31  * @modules java.base/java.util:open
32  * @run testng SyncSubMutexes
33  */
34 import java.lang.reflect.Field;
35 import java.util.*;
36 import java.util.Set;
37 import java.util.Arrays;
38 
39 import org.testng.annotations.Test;
40 import org.testng.annotations.DataProvider;
41 import static org.testng.Assert.assertSame;
42 
43 public class SyncSubMutexes {
44 
45     @Test(dataProvider = "Collections")
testCollections(Collection<String> instance)46     public void testCollections(Collection<String> instance) {
47         // nothing to test, no subset methods
48     }
49 
50     @Test(dataProvider = "Lists")
testLists(List<String> instance)51     public void testLists(List<String> instance) {
52          assertSame(getSyncCollectionMutex(instance.subList(0, 1)), getSyncCollectionMutex(instance));
53     }
54 
55     @Test(dataProvider = "Sets")
testSets(Set<String> instance)56     public void testSets(Set<String> instance) {
57         // nothing to test, no subset methods
58 
59     }
60 
61     @Test(dataProvider = "SortedSets")
testSortedSets(SortedSet<String> instance)62     public void testSortedSets(SortedSet<String> instance) {
63          assertSame(getSyncCollectionMutex(instance.headSet("Echo")), getSyncCollectionMutex(instance));
64          assertSame(getSyncCollectionMutex(instance.tailSet("Charlie")), getSyncCollectionMutex(instance));
65          assertSame(getSyncCollectionMutex(instance.subSet("Charlie", "Echo")), getSyncCollectionMutex(instance));
66 
67     }
68 
69     @Test(dataProvider = "NavigableSets")
testNavigableSets(NavigableSet<String> instance)70     public void testNavigableSets(NavigableSet<String> instance) {
71          assertSame(getSyncCollectionMutex(instance.descendingSet()), getSyncCollectionMutex(instance));
72          assertSame(getSyncCollectionMutex(instance.headSet("Echo")), getSyncCollectionMutex(instance));
73          assertSame(getSyncCollectionMutex(instance.headSet("Echo", true)), getSyncCollectionMutex(instance));
74          assertSame(getSyncCollectionMutex(instance.tailSet("Charlie")), getSyncCollectionMutex(instance));
75          assertSame(getSyncCollectionMutex(instance.tailSet("Charlie", true)), getSyncCollectionMutex(instance));
76          assertSame(getSyncCollectionMutex(instance.subSet("Charlie", "Echo")), getSyncCollectionMutex(instance));
77          assertSame(getSyncCollectionMutex(instance.subSet("Charlie", true, "Echo", true)), getSyncCollectionMutex(instance));
78     }
79 
80     @Test(dataProvider = "Maps")
testMaps(Map<String, String> instance)81     public void testMaps(Map<String, String> instance) {
82          assertSame(getSyncCollectionMutex(instance.entrySet()), getSyncMapMutex(instance));
83          assertSame(getSyncCollectionMutex(instance.keySet()), getSyncMapMutex(instance));
84          assertSame(getSyncCollectionMutex(instance.values()), getSyncMapMutex(instance));
85     }
86 
87     @Test(dataProvider = "SortedMaps")
testSortedMaps(SortedMap<String, String> instance)88     public void testSortedMaps(SortedMap<String, String> instance) {
89          assertSame(getSyncCollectionMutex(instance.entrySet()), getSyncMapMutex(instance));
90          assertSame(getSyncCollectionMutex(instance.keySet()), getSyncMapMutex(instance));
91          assertSame(getSyncCollectionMutex(instance.values()), getSyncMapMutex(instance));
92          assertSame(getSyncMapMutex(instance.headMap("Echo")), getSyncMapMutex(instance));
93          assertSame(getSyncMapMutex(instance.tailMap("Charlie")), getSyncMapMutex(instance));
94          assertSame(getSyncMapMutex(instance.subMap("Charlie", "Echo")), getSyncMapMutex(instance));
95     }
96 
97     @Test(dataProvider = "NavigableMaps")
testNavigableMaps(NavigableMap<String, String> instance)98     public void testNavigableMaps(NavigableMap<String, String> instance) {
99          assertSame(getSyncMapMutex(instance.descendingMap()), getSyncMapMutex(instance));
100          assertSame(getSyncCollectionMutex(instance.entrySet()), getSyncMapMutex(instance));
101          assertSame(getSyncCollectionMutex(instance.keySet()), getSyncMapMutex(instance));
102          assertSame(getSyncCollectionMutex(instance.descendingKeySet()), getSyncMapMutex(instance));
103          assertSame(getSyncCollectionMutex(instance.values()), getSyncMapMutex(instance));
104          assertSame(getSyncMapMutex(instance.headMap("Echo")), getSyncMapMutex(instance));
105          assertSame(getSyncMapMutex(instance.headMap("Echo", true)), getSyncMapMutex(instance));
106          assertSame(getSyncMapMutex(instance.tailMap("Charlie")), getSyncMapMutex(instance));
107          assertSame(getSyncMapMutex(instance.tailMap("Charlie", true)), getSyncMapMutex(instance));
108          assertSame(getSyncMapMutex(instance.subMap("Charlie", true, "Echo", true)), getSyncMapMutex(instance));
109          assertSame(getSyncMapMutex(instance.subMap("Charlie", true, "Echo", true)), getSyncMapMutex(instance));
110     }
111 
112     @DataProvider(name = "Collections", parallel = true)
collectionProvider()113     public static Iterator<Object[]> collectionProvider() {
114         return makeCollections().iterator();
115     }
116 
117     @DataProvider(name = "Lists", parallel = true)
listProvider()118     public static Iterator<Object[]> listProvider() {
119         return makeLists().iterator();
120     }
121 
122     @DataProvider(name = "Sets", parallel = true)
setProvider()123     public static Iterator<Object[]> setProvider() {
124         return makeSets().iterator();
125     }
126 
127     @DataProvider(name = "SortedSets", parallel = true)
sortedsetProvider()128     public static Iterator<Object[]> sortedsetProvider() {
129         return makeSortedSets().iterator();
130     }
131 
132     @DataProvider(name = "NavigableSets", parallel = true)
navigablesetProvider()133     public static Iterator<Object[]> navigablesetProvider() {
134         return makeNavigableSets().iterator();
135     }
136 
137     @DataProvider(name = "Maps", parallel = true)
mapProvider()138     public static Iterator<Object[]> mapProvider() {
139         return makeMaps().iterator();
140     }
141 
142     @DataProvider(name = "SortedMaps", parallel = true)
sortedmapProvider()143     public static Iterator<Object[]> sortedmapProvider() {
144         return makeSortedMaps().iterator();
145     }
146 
147     @DataProvider(name = "NavigableMaps", parallel = true)
navigablemapProvider()148     public static Iterator<Object[]> navigablemapProvider() {
149         return makeNavigableMaps().iterator();
150     }
151 
152     private static final Collection<String> BASE_COLLECTION = Collections.unmodifiableCollection(
153             Arrays.asList("Alpha", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot", "Golf")
154     );
155     private static final Map<String, String> BASE_MAP;
156 
157     static {
158         Map<String, String> map = new HashMap<>();
159         for(String each : BASE_COLLECTION) {
map.put(each, "*" + each + "*")160             map.put(each, "*" + each + "*");
161         }
162         BASE_MAP = Collections.unmodifiableMap(map);
163     }
164 
makeCollections()165     public static Collection<Object[]> makeCollections() {
166         Collection<Object[]> instances = new ArrayList<>();
167         instances.add(new Object[] {Collections.synchronizedCollection(new ArrayList<>(BASE_COLLECTION))});
168         instances.addAll(makeLists());
169 
170         return instances;
171     }
172 
makeLists()173     public static Collection<Object[]> makeLists() {
174         Collection<Object[]> instances = new ArrayList<>();
175         instances.add(new Object[] {Collections.synchronizedList(new ArrayList<>(BASE_COLLECTION))});
176         instances.add(new Object[] {Collections.synchronizedList(new ArrayList<>(BASE_COLLECTION)).subList(1, 2)});
177 
178         return instances;
179     }
180 
makeSets()181      public static Collection<Object[]> makeSets() {
182         Collection<Object[]> instances = new ArrayList<>();
183 
184         instances.add(new Object[] {Collections.synchronizedSet(new TreeSet<>(BASE_COLLECTION))});
185         instances.addAll(makeSortedSets());
186         return instances;
187      }
188 
makeSortedSets()189     public static Collection<Object[]> makeSortedSets() {
190         Collection<Object[]> instances = new ArrayList<>();
191         instances.add(new Object[] {Collections.synchronizedSortedSet(new TreeSet<>(BASE_COLLECTION))});
192         instances.add(new Object[] {Collections.synchronizedSortedSet(new TreeSet<>(BASE_COLLECTION)).headSet("Foxtrot")});
193         instances.add(new Object[] {Collections.synchronizedSortedSet(new TreeSet<>(BASE_COLLECTION)).tailSet("Bravo")});
194         instances.add(new Object[] {Collections.synchronizedSortedSet(new TreeSet<>(BASE_COLLECTION)).subSet("Bravo", "Foxtrot")});
195         instances.addAll(makeNavigableSets());
196 
197         return instances;
198      }
199 
makeNavigableSets()200     public static Collection<Object[]> makeNavigableSets() {
201         Collection<Object[]> instances = new ArrayList<>();
202 
203         instances.add(new Object[] {Collections.synchronizedNavigableSet(new TreeSet<>(BASE_COLLECTION))});
204         instances.add(new Object[] {Collections.synchronizedNavigableSet(new TreeSet<>(BASE_COLLECTION)).descendingSet().descendingSet()});
205         instances.add(new Object[] {Collections.synchronizedNavigableSet(new TreeSet<>(BASE_COLLECTION)).headSet("Foxtrot")});
206         instances.add(new Object[] {Collections.synchronizedNavigableSet(new TreeSet<>(BASE_COLLECTION)).headSet("Foxtrot", true)});
207         instances.add(new Object[] {Collections.synchronizedNavigableSet(new TreeSet<>(BASE_COLLECTION)).tailSet("Bravo")});
208         instances.add(new Object[] {Collections.synchronizedNavigableSet(new TreeSet<>(BASE_COLLECTION)).tailSet("Bravo", true)});
209         instances.add(new Object[] {Collections.synchronizedNavigableSet(new TreeSet<>(BASE_COLLECTION)).subSet("Bravo", "Foxtrot")});
210         instances.add(new Object[] {Collections.synchronizedNavigableSet(new TreeSet<>(BASE_COLLECTION)).subSet("Bravo", true, "Foxtrot", true)});
211 
212         return instances;
213     }
214 
makeMaps()215     public static Collection<Object[]> makeMaps() {
216         Collection<Object[]> instances = new ArrayList<>();
217 
218         instances.add(new Object[] {Collections.synchronizedMap(new HashMap<>(BASE_MAP))});
219         instances.addAll(makeSortedMaps());
220 
221         return instances;
222     }
223 
makeSortedMaps()224     public static Collection<Object[]> makeSortedMaps() {
225         Collection<Object[]> instances = new ArrayList<>();
226 
227         instances.add(new Object[] {Collections.synchronizedSortedMap(new TreeMap<>(BASE_MAP))});
228         instances.add(new Object[] {Collections.synchronizedSortedMap(new TreeMap<>(BASE_MAP)).headMap("Foxtrot")});
229         instances.add(new Object[] {Collections.synchronizedSortedMap(new TreeMap<>(BASE_MAP)).tailMap("Bravo")});
230         instances.add(new Object[] {Collections.synchronizedSortedMap(new TreeMap<>(BASE_MAP)).subMap("Bravo", "Foxtrot")});
231         instances.addAll(makeNavigableMaps());
232 
233         return instances;
234     }
235 
makeNavigableMaps()236     public static Collection<Object[]> makeNavigableMaps() {
237         Collection<Object[]> instances = new ArrayList<>();
238 
239         instances.add(new Object[] {Collections.synchronizedNavigableMap(new TreeMap<>(BASE_MAP))});
240         instances.add(new Object[] {Collections.synchronizedNavigableMap(new TreeMap<>(BASE_MAP).descendingMap().descendingMap())});
241         instances.add(new Object[] {Collections.synchronizedNavigableMap(new TreeMap<>(BASE_MAP)).headMap("Foxtrot")});
242         instances.add(new Object[] {Collections.synchronizedNavigableMap(new TreeMap<>(BASE_MAP)).headMap("Foxtrot", true)});
243         instances.add(new Object[] {Collections.synchronizedNavigableMap(new TreeMap<>(BASE_MAP)).tailMap("Bravo")});
244         instances.add(new Object[] {Collections.synchronizedNavigableMap(new TreeMap<>(BASE_MAP)).tailMap("Bravo", true)});
245         instances.add(new Object[] {Collections.synchronizedNavigableMap(new TreeMap<>(BASE_MAP)).subMap("Bravo", "Foxtrot")});
246         instances.add(new Object[] {Collections.synchronizedNavigableMap(new TreeMap<>(BASE_MAP)).subMap("Bravo", true, "Foxtrot", true)});
247 
248         return instances;
249     }
250 
getSyncCollectionMutex(Collection<?> from)251     private static Object getSyncCollectionMutex(Collection<?> from) {
252         try {
253             Class<?> synchronizedCollectionClazz = Class.forName("java.util.Collections$SynchronizedCollection");
254             Field f = synchronizedCollectionClazz.getDeclaredField("mutex");
255             f.setAccessible(true);
256             return f.get(from);
257         } catch ( ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
258             throw new RuntimeException("Unable to get mutex field.", e);
259         }
260     }
261 
getSyncMapMutex(Map<?,?> from)262     private static Object getSyncMapMutex(Map<?,?> from) {
263         try {
264             Class<?> synchronizedMapClazz = Class.forName("java.util.Collections$SynchronizedMap");
265             Field f = synchronizedMapClazz.getDeclaredField("mutex");
266             f.setAccessible(true);
267             return f.get(from);
268         } catch ( ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
269             throw new RuntimeException("Unable to get mutex field.", e);
270         }
271     }
272 
273 }
274