1 /*
2  * Copyright (c) 2011, 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 
24 /*
25  * @test
26  * @bug 4533691 7129185
27  * @summary Unit test for Collections.emptyNavigableMap
28  * @run testng EmptyNavigableMap
29  */
30 import java.math.BigInteger;
31 import java.util.Arrays;
32 import java.util.Collection;
33 import java.util.Collections;
34 import java.util.Comparator;
35 import java.util.Iterator;
36 import java.util.NoSuchElementException;
37 import java.util.NavigableMap;
38 import java.util.SortedMap;
39 import java.util.TreeMap;
40 import org.testng.annotations.Test;
41 import org.testng.annotations.DataProvider;
42 
43 import static org.testng.Assert.fail;
44 import static org.testng.Assert.assertEquals;
45 import static org.testng.Assert.assertTrue;
46 import static org.testng.Assert.assertFalse;
47 import static org.testng.Assert.assertSame;
48 
49 public class EmptyNavigableMap {
50 
assertInstance(T actual, Class<? extends T> expected)51     public static <T> void assertInstance(T actual, Class<? extends T> expected) {
52         assertInstance(expected.isInstance(actual), null);
53     }
54 
assertInstance(T actual, Class<? extends T> expected, String message)55     public static <T> void assertInstance(T actual, Class<? extends T> expected, String message) {
56         assertTrue(expected.isInstance(actual), ((null != message) ? message : "")
57             + " " + (actual == null ? "<null>" : actual.getClass().getSimpleName()) + " != " + expected.getSimpleName() + ". ");
58     }
59 
assertEmptyNavigableMap(Object obj)60     public static <T extends Throwable> void assertEmptyNavigableMap(Object obj) {
61         assertInstance(obj, NavigableMap.class);
62         assertTrue(((NavigableMap)obj).isEmpty() && (((NavigableMap)obj).size() == 0));
63     }
64 
assertEmptyNavigableMap(Object obj, String message)65     public static <T extends Throwable> void assertEmptyNavigableMap(Object obj, String message) {
66         assertInstance(obj, NavigableMap.class, message);
67         assertTrue(((NavigableMap)obj).isEmpty() && (((NavigableMap)obj).size() == 0),
68             ((null != message) ? message : "") + " Not empty. ");
69     }
70 
71     public interface Thrower<T extends Throwable> {
72 
run()73         public void run() throws T;
74     }
75 
assertThrows(Thrower<T> thrower, Class<T> throwable)76     public static <T extends Throwable> void assertThrows(Thrower<T> thrower, Class<T> throwable) {
77         assertThrows(thrower, throwable, null);
78     }
79 
assertThrows(Thrower<T> thrower, Class<T> throwable, String message)80     public static <T extends Throwable> void assertThrows(Thrower<T> thrower, Class<T> throwable, String message) {
81         Throwable result;
82         try {
83             thrower.run();
84             fail(((null != message) ? message : "") + "Failed to throw " + throwable.getCanonicalName() + ". ");
85             return;
86         } catch (Throwable caught) {
87             result = caught;
88         }
89 
90         assertInstance(result, throwable, ((null != message) ? message : "") + "Failed to throw " + throwable.getCanonicalName() + ". ");
91     }
92 
isDescending(SortedMap<?,?> set)93     public static final boolean isDescending(SortedMap<?,?> set) {
94         if (null == set.comparator()) {
95             // natural order
96             return false;
97         }
98 
99         if (Collections.reverseOrder() == set.comparator()) {
100             // reverse natural order.
101             return true;
102         }
103 
104         if (set.comparator().equals(Collections.reverseOrder(Collections.reverseOrder(set.comparator())))) {
105             // it's a Collections.reverseOrder(Comparator).
106             return true;
107         }
108 
109         throw new IllegalStateException("can't determine ordering for " + set);
110     }
111 
112     /**
113      * Tests that the comparator is {@code null}.
114      */
115     @Test(dataProvider = "NavigableMap<?,?>", dataProviderClass = EmptyNavigableMap.class)
testComparatorIsNull(String description, NavigableMap<?,?> navigableMap)116     public void testComparatorIsNull(String description, NavigableMap<?,?> navigableMap) {
117         Comparator comparator = navigableMap.comparator();
118 
119         assertTrue(comparator == null || comparator == Collections.reverseOrder(), description + ": Comparator (" + comparator + ") is not null.");
120     }
121 
122     /**
123      * Tests that contains requires Comparable
124      */
125     @Test(dataProvider = "NavigableMap<?,?>", dataProviderClass = EmptyNavigableMap.class)
testContainsRequiresComparable(String description, NavigableMap<?,?> navigableMap)126     public void testContainsRequiresComparable(String description, NavigableMap<?,?> navigableMap) {
127         assertThrows(() -> {
128             navigableMap.containsKey(new Object());
129         },
130             ClassCastException.class,
131             description + ": Compareable should be required");
132     }
133 
134     /**
135      * Tests that the contains method returns {@code false}.
136      */
137     @Test(dataProvider = "NavigableMap<?,?>", dataProviderClass = EmptyNavigableMap.class)
testContains(String description, NavigableMap<?,?> navigableMap)138     public void testContains(String description, NavigableMap<?,?> navigableMap) {
139         assertFalse(navigableMap.containsKey(new Integer(1)),
140             description + ": Should not contain any elements.");
141         assertFalse(navigableMap.containsValue(new Integer(1)),
142             description + ": Should not contain any elements.");
143     }
144 
145     /**
146      * Tests that the containsAll method returns {@code false}.
147      */
148     @Test(dataProvider = "NavigableMap<?,?>", dataProviderClass = EmptyNavigableMap.class)
testContainsAll(String description, NavigableMap<?,?> navigableMap)149     public void testContainsAll(String description, NavigableMap<?,?> navigableMap) {
150         TreeMap treeMap = new TreeMap();
151         treeMap.put("1", 1);
152         treeMap.put("2", 2);
153         treeMap.put("3", 3);
154 
155         assertFalse(navigableMap.equals(treeMap), "Should not contain any elements.");
156     }
157 
158     /**
159      * Tests that the iterator is empty.
160      */
161     @Test(dataProvider = "NavigableMap<?,?>", dataProviderClass = EmptyNavigableMap.class)
testEmptyIterator(String description, NavigableMap<?,?> navigableMap)162     public void testEmptyIterator(String description, NavigableMap<?,?> navigableMap) {
163         assertFalse(navigableMap.keySet().iterator().hasNext(), "The iterator is not empty.");
164         assertFalse(navigableMap.values().iterator().hasNext(), "The iterator is not empty.");
165         assertFalse(navigableMap.entrySet().iterator().hasNext(), "The iterator is not empty.");
166     }
167 
168     /**
169      * Tests that the set is empty.
170      */
171     @Test(dataProvider = "NavigableMap<?,?>", dataProviderClass = EmptyNavigableMap.class)
testIsEmpty(String description, NavigableMap<?,?> navigableMap)172     public void testIsEmpty(String description, NavigableMap<?,?> navigableMap) {
173         assertTrue(navigableMap.isEmpty(), "The set is not empty.");
174     }
175 
176     /**
177      * Tests the headMap() method.
178      */
179     @Test(dataProvider = "NavigableMap<?,?>", dataProviderClass = EmptyNavigableMap.class)
testHeadMap(String description, NavigableMap navigableMap)180     public void testHeadMap(String description, NavigableMap navigableMap) {
181         assertThrows(
182             () -> { NavigableMap ss = navigableMap.headMap(null, false); },
183             NullPointerException.class,
184             description + ": Must throw NullPointerException for null element");
185 
186         assertThrows(
187             () -> { NavigableMap ss = navigableMap.headMap(new Object(), true); },
188             ClassCastException.class,
189             description + ": Must throw ClassCastException for non-Comparable element");
190 
191         NavigableMap ss = navigableMap.headMap("1", false);
192 
193         assertEmptyNavigableMap(ss, description + ": Returned value is not empty navigable set.");
194     }
195 
196     /**
197      * Tests that the size is 0.
198      */
199     @Test(dataProvider = "NavigableMap<?,?>", dataProviderClass = EmptyNavigableMap.class)
testSizeIsZero(String description, NavigableMap<?,?> navigableMap)200     public void testSizeIsZero(String description, NavigableMap<?,?> navigableMap) {
201         assertTrue(0 == navigableMap.size(), "The size of the set is not 0.");
202     }
203 
204     /**
205      * Tests the subMap() method.
206      */
207     @Test(dataProvider = "NavigableMap<?,?>", dataProviderClass = EmptyNavigableMap.class)
testSubMap(String description, NavigableMap navigableMap)208     public void testSubMap(String description, NavigableMap navigableMap) {
209         assertThrows(
210             () -> {
211                 SortedMap ss = navigableMap.subMap(null, BigInteger.TEN);
212             },
213             NullPointerException.class,
214             description + ": Must throw NullPointerException for null element");
215 
216         assertThrows(
217             () -> {
218                 SortedMap ss = navigableMap.subMap(BigInteger.ZERO, null);
219             },
220             NullPointerException.class,
221             description + ": Must throw NullPointerException for null element");
222 
223         assertThrows(
224             () -> {
225                 SortedMap ss = navigableMap.subMap(null, null);
226             },
227             NullPointerException.class,
228             description + ": Must throw NullPointerException for null element");
229 
230         Object obj1 = new Object();
231         Object obj2 = new Object();
232 
233         assertThrows(
234             () -> {
235                 SortedMap ss = navigableMap.subMap(obj1, BigInteger.TEN);
236             },
237             ClassCastException.class, description
238             + ": Must throw ClassCastException for parameter which is not Comparable.");
239 
240         assertThrows(
241             () -> {
242                 SortedMap ss = navigableMap.subMap(BigInteger.ZERO, obj2);
243             },
244             ClassCastException.class, description
245             + ": Must throw ClassCastException for parameter which is not Comparable.");
246 
247         assertThrows(
248             () -> {
249                 SortedMap ss = navigableMap.subMap(obj1, obj2);
250             },
251             ClassCastException.class, description
252             + ": Must throw ClassCastException for parameter which is not Comparable.");
253 
254         // minimal range
255         navigableMap.subMap(BigInteger.ZERO, false, BigInteger.ZERO, false);
256         navigableMap.subMap(BigInteger.ZERO, false, BigInteger.ZERO, true);
257         navigableMap.subMap(BigInteger.ZERO, true, BigInteger.ZERO, false);
258         navigableMap.subMap(BigInteger.ZERO, true, BigInteger.ZERO, true);
259 
260         Object first = isDescending(navigableMap) ? BigInteger.TEN : BigInteger.ZERO;
261         Object last = (BigInteger.ZERO == first) ? BigInteger.TEN : BigInteger.ZERO;
262 
263             assertThrows(
264                 () -> {
265                     navigableMap.subMap(last, true, first, false);
266                 },
267                 IllegalArgumentException.class, description
268                 + ": Must throw IllegalArgumentException when fromElement is not less then then toElement.");
269 
270         navigableMap.subMap(first, true, last, false);
271     }
272 
273     @Test(dataProvider = "NavigableMap<?,?>", dataProviderClass = EmptyNavigableMap.class)
testSubMapRanges(String description, NavigableMap navigableMap)274     public void testSubMapRanges(String description, NavigableMap navigableMap) {
275         Object first = isDescending(navigableMap) ? BigInteger.TEN : BigInteger.ZERO;
276         Object last = (BigInteger.ZERO == first) ? BigInteger.TEN : BigInteger.ZERO;
277 
278         NavigableMap subMap = navigableMap.subMap(first, true, last, true);
279 
280         // same subset
281         subMap.subMap(first, true, last, true);
282 
283         // slightly smaller
284         NavigableMap ns = subMap.subMap(first, false, last, false);
285         // slight exapansion
286         assertThrows(() -> {
287             ns.subMap(first, true, last, true);
288         },
289             IllegalArgumentException.class,
290             description + ": Expansion should not be allowed");
291 
292         // much smaller
293         subMap.subMap(first, false, BigInteger.ONE, false);
294     }
295 
296     @Test(dataProvider = "NavigableMap<?,?>", dataProviderClass = EmptyNavigableMap.class)
testheadMapRanges(String description, NavigableMap navigableMap)297     public void testheadMapRanges(String description, NavigableMap navigableMap) {
298         NavigableMap subMap = navigableMap.headMap(BigInteger.ONE, true);
299 
300         // same subset
301         subMap.headMap(BigInteger.ONE, true);
302 
303         // slightly smaller
304         NavigableMap ns = subMap.headMap(BigInteger.ONE, false);
305 
306         // slight exapansion
307         assertThrows(() -> {
308             ns.headMap(BigInteger.ONE, true);
309         },
310             IllegalArgumentException.class,
311             description + ": Expansion should not be allowed");
312 
313         // much smaller
314         subMap.headMap(isDescending(subMap) ? BigInteger.TEN : BigInteger.ZERO, true);
315     }
316 
317     @Test(dataProvider = "NavigableMap<?,?>", dataProviderClass = EmptyNavigableMap.class)
testTailMapRanges(String description, NavigableMap navigableMap)318     public void testTailMapRanges(String description, NavigableMap navigableMap) {
319         NavigableMap subMap = navigableMap.tailMap(BigInteger.ONE, true);
320 
321         // same subset
322         subMap.tailMap(BigInteger.ONE, true);
323 
324         // slightly smaller
325         NavigableMap ns = subMap.tailMap(BigInteger.ONE, false);
326 
327         // slight exapansion
328         assertThrows(() -> {
329             ns.tailMap(BigInteger.ONE, true);
330         },
331             IllegalArgumentException.class,
332             description + ": Expansion should not be allowed");
333 
334         // much smaller
335         subMap.tailMap(isDescending(subMap) ? BigInteger.ZERO : BigInteger.TEN, false);
336     }
337 
338     /**
339      * Tests the tailMap() method.
340      */
341     @Test(dataProvider = "NavigableMap<?,?>", dataProviderClass = EmptyNavigableMap.class)
testTailMap(String description, NavigableMap navigableMap)342     public void testTailMap(String description, NavigableMap navigableMap) {
343         assertThrows(() -> {
344             navigableMap.tailMap(null);
345         },
346             NullPointerException.class,
347             description + ": Must throw NullPointerException for null element");
348 
349         assertThrows(() -> {
350             navigableMap.tailMap(new Object());
351         }, ClassCastException.class);
352 
353         NavigableMap ss = navigableMap.tailMap("1", true);
354 
355         assertEmptyNavigableMap(ss, description + ": Returned value is not empty navigable set.");
356     }
357 
358     @DataProvider(name = "NavigableMap<?,?>", parallel = true)
navigableMapsProvider()359     public static Iterator<Object[]> navigableMapsProvider() {
360         return makeNavigableMaps().iterator();
361     }
362 
makeNavigableMaps()363     public static Collection<Object[]> makeNavigableMaps() {
364         return Arrays.asList(
365             new Object[]{"UnmodifiableNavigableMap(TreeMap)", Collections.unmodifiableNavigableMap(new TreeMap())},
366             new Object[]{"UnmodifiableNavigableMap(TreeMap.descendingMap()", Collections.unmodifiableNavigableMap(new TreeMap().descendingMap())},
367             new Object[]{"UnmodifiableNavigableMap(TreeMap.descendingMap().descendingMap()", Collections.unmodifiableNavigableMap(new TreeMap().descendingMap().descendingMap())},
368             new Object[]{"emptyNavigableMap()", Collections.emptyNavigableMap()},
369             new Object[]{"emptyNavigableMap().descendingMap()", Collections.emptyNavigableMap().descendingMap()},
370             new Object[]{"emptyNavigableMap().descendingMap().descendingMap()", Collections.emptyNavigableMap().descendingMap().descendingMap()}
371         );
372     }
373 }
374