1 /*
2  * Written by Doug Lea with assistance from members of JCP JSR-166
3  * Expert Group and released to the public domain, as explained at
4  * http://creativecommons.org/publicdomain/zero/1.0/
5  */
6 
7 package jsr166;
8 
9 import java.util.Arrays;
10 import java.util.BitSet;
11 import java.util.Collection;
12 import java.util.Comparator;
13 import java.util.Iterator;
14 import java.util.NavigableSet;
15 import java.util.NoSuchElementException;
16 import java.util.Random;
17 import java.util.Set;
18 import java.util.SortedSet;
19 import java.util.TreeSet;
20 
21 import junit.framework.Test;
22 import junit.framework.TestSuite;
23 
24 public class TreeSetTest extends JSR166TestCase {
25     // android-note: Removed because the CTS runner does a bad job of
26     // retrying tests that have suite() declarations.
27     //
28     // public static void main(String[] args) {
29     //     main(suite(), args);
30     // }
31     // public static Test suite() {
32     //     return new TestSuite(TreeSetTest.class);
33     // }
34 
35     static class MyReverseComparator implements Comparator {
compare(Object x, Object y)36         public int compare(Object x, Object y) {
37             return ((Comparable)y).compareTo(x);
38         }
39     }
40 
41     /**
42      * The number of elements to place in collections, arrays, etc.
43      */
44     static final int SIZE = 20;
45 
46     /**
47      * Returns a new set of given size containing consecutive
48      * Integers 0 ... n.
49      */
populatedSet(int n)50     private TreeSet<Integer> populatedSet(int n) {
51         TreeSet<Integer> q = new TreeSet<Integer>();
52         assertTrue(q.isEmpty());
53         for (int i = n - 1; i >= 0; i -= 2)
54             assertTrue(q.add(new Integer(i)));
55         for (int i = (n & 1); i < n; i += 2)
56             assertTrue(q.add(new Integer(i)));
57         assertFalse(q.isEmpty());
58         assertEquals(n, q.size());
59         return q;
60     }
61 
62     /**
63      * Returns a new set of first 5 ints.
64      */
set5()65     private TreeSet set5() {
66         TreeSet q = new TreeSet();
67         assertTrue(q.isEmpty());
68         q.add(one);
69         q.add(two);
70         q.add(three);
71         q.add(four);
72         q.add(five);
73         assertEquals(5, q.size());
74         return q;
75     }
76 
77     /**
78      * A new set has unbounded capacity
79      */
testConstructor1()80     public void testConstructor1() {
81         assertEquals(0, new TreeSet().size());
82     }
83 
84     /**
85      * Initializing from null Collection throws NPE
86      */
testConstructor3()87     public void testConstructor3() {
88         try {
89             new TreeSet((Collection)null);
90             shouldThrow();
91         } catch (NullPointerException success) {}
92     }
93 
94     /**
95      * Initializing from Collection of null elements throws NPE
96      */
testConstructor4()97     public void testConstructor4() {
98         try {
99             new TreeSet(Arrays.asList(new Integer[SIZE]));
100             shouldThrow();
101         } catch (NullPointerException success) {}
102     }
103 
104     /**
105      * Initializing from Collection with some null elements throws NPE
106      */
testConstructor5()107     public void testConstructor5() {
108         Integer[] ints = new Integer[SIZE];
109         for (int i = 0; i < SIZE - 1; ++i)
110             ints[i] = new Integer(i);
111         try {
112             new TreeSet(Arrays.asList(ints));
113             shouldThrow();
114         } catch (NullPointerException success) {}
115     }
116 
117     /**
118      * Set contains all elements of collection used to initialize
119      */
testConstructor6()120     public void testConstructor6() {
121         Integer[] ints = new Integer[SIZE];
122         for (int i = 0; i < SIZE; ++i)
123             ints[i] = new Integer(i);
124         TreeSet q = new TreeSet(Arrays.asList(ints));
125         for (int i = 0; i < SIZE; ++i)
126             assertEquals(ints[i], q.pollFirst());
127     }
128 
129     /**
130      * The comparator used in constructor is used
131      */
testConstructor7()132     public void testConstructor7() {
133         MyReverseComparator cmp = new MyReverseComparator();
134         TreeSet q = new TreeSet(cmp);
135         assertEquals(cmp, q.comparator());
136         Integer[] ints = new Integer[SIZE];
137         for (int i = 0; i < SIZE; ++i)
138             ints[i] = new Integer(i);
139         q.addAll(Arrays.asList(ints));
140         for (int i = SIZE - 1; i >= 0; --i)
141             assertEquals(ints[i], q.pollFirst());
142     }
143 
144     /**
145      * isEmpty is true before add, false after
146      */
testEmpty()147     public void testEmpty() {
148         TreeSet q = new TreeSet();
149         assertTrue(q.isEmpty());
150         q.add(new Integer(1));
151         assertFalse(q.isEmpty());
152         q.add(new Integer(2));
153         q.pollFirst();
154         q.pollFirst();
155         assertTrue(q.isEmpty());
156     }
157 
158     /**
159      * size changes when elements added and removed
160      */
testSize()161     public void testSize() {
162         TreeSet q = populatedSet(SIZE);
163         for (int i = 0; i < SIZE; ++i) {
164             assertEquals(SIZE - i, q.size());
165             q.pollFirst();
166         }
167         for (int i = 0; i < SIZE; ++i) {
168             assertEquals(i, q.size());
169             q.add(new Integer(i));
170         }
171     }
172 
173     /**
174      * add(null) throws NPE if nonempty
175      */
testAddNull()176     public void testAddNull() {
177         TreeSet q = populatedSet(SIZE);
178         try {
179             q.add(null);
180             shouldThrow();
181         } catch (NullPointerException success) {}
182     }
183 
184     /**
185      * Add of comparable element succeeds
186      */
testAdd()187     public void testAdd() {
188         TreeSet q = new TreeSet();
189         assertTrue(q.add(zero));
190         assertTrue(q.add(one));
191     }
192 
193     /**
194      * Add of duplicate element fails
195      */
testAddDup()196     public void testAddDup() {
197         TreeSet q = new TreeSet();
198         assertTrue(q.add(zero));
199         assertFalse(q.add(zero));
200     }
201 
202     /**
203      * Add of non-Comparable throws CCE
204      */
testAddNonComparable()205     public void testAddNonComparable() {
206         TreeSet q = new TreeSet();
207         try {
208             q.add(new Object());
209             q.add(new Object());
210             shouldThrow();
211         } catch (ClassCastException success) {}
212     }
213 
214     /**
215      * addAll(null) throws NPE
216      */
testAddAll1()217     public void testAddAll1() {
218         TreeSet q = new TreeSet();
219         try {
220             q.addAll(null);
221             shouldThrow();
222         } catch (NullPointerException success) {}
223     }
224 
225     /**
226      * addAll of a collection with null elements throws NPE
227      */
testAddAll2()228     public void testAddAll2() {
229         TreeSet q = new TreeSet();
230         Integer[] ints = new Integer[SIZE];
231         try {
232             q.addAll(Arrays.asList(ints));
233             shouldThrow();
234         } catch (NullPointerException success) {}
235     }
236 
237     /**
238      * addAll of a collection with any null elements throws NPE after
239      * possibly adding some elements
240      */
testAddAll3()241     public void testAddAll3() {
242         TreeSet q = new TreeSet();
243         Integer[] ints = new Integer[SIZE];
244         for (int i = 0; i < SIZE - 1; ++i)
245             ints[i] = new Integer(i);
246         try {
247             q.addAll(Arrays.asList(ints));
248             shouldThrow();
249         } catch (NullPointerException success) {}
250     }
251 
252     /**
253      * Set contains all elements of successful addAll
254      */
testAddAll5()255     public void testAddAll5() {
256         Integer[] empty = new Integer[0];
257         Integer[] ints = new Integer[SIZE];
258         for (int i = 0; i < SIZE; ++i)
259             ints[i] = new Integer(SIZE - 1 - i);
260         TreeSet q = new TreeSet();
261         assertFalse(q.addAll(Arrays.asList(empty)));
262         assertTrue(q.addAll(Arrays.asList(ints)));
263         for (int i = 0; i < SIZE; ++i)
264             assertEquals(new Integer(i), q.pollFirst());
265     }
266 
267     /**
268      * pollFirst succeeds unless empty
269      */
testPollFirst()270     public void testPollFirst() {
271         TreeSet q = populatedSet(SIZE);
272         for (int i = 0; i < SIZE; ++i) {
273             assertEquals(i, q.pollFirst());
274         }
275         assertNull(q.pollFirst());
276     }
277 
278     /**
279      * pollLast succeeds unless empty
280      */
testPollLast()281     public void testPollLast() {
282         TreeSet q = populatedSet(SIZE);
283         for (int i = SIZE - 1; i >= 0; --i) {
284             assertEquals(i, q.pollLast());
285         }
286         assertNull(q.pollFirst());
287     }
288 
289     /**
290      * remove(x) removes x and returns true if present
291      */
testRemoveElement()292     public void testRemoveElement() {
293         TreeSet q = populatedSet(SIZE);
294         for (int i = 1; i < SIZE; i += 2) {
295             assertTrue(q.contains(i));
296             assertTrue(q.remove(i));
297             assertFalse(q.contains(i));
298             assertTrue(q.contains(i - 1));
299         }
300         for (int i = 0; i < SIZE; i += 2) {
301             assertTrue(q.contains(i));
302             assertTrue(q.remove(i));
303             assertFalse(q.contains(i));
304             assertFalse(q.remove(i + 1));
305             assertFalse(q.contains(i + 1));
306         }
307         assertTrue(q.isEmpty());
308     }
309 
310     /**
311      * contains(x) reports true when elements added but not yet removed
312      */
testContains()313     public void testContains() {
314         TreeSet q = populatedSet(SIZE);
315         for (int i = 0; i < SIZE; ++i) {
316             assertTrue(q.contains(new Integer(i)));
317             q.pollFirst();
318             assertFalse(q.contains(new Integer(i)));
319         }
320     }
321 
322     /**
323      * clear removes all elements
324      */
testClear()325     public void testClear() {
326         TreeSet q = populatedSet(SIZE);
327         q.clear();
328         assertTrue(q.isEmpty());
329         assertEquals(0, q.size());
330         q.add(new Integer(1));
331         assertFalse(q.isEmpty());
332         q.clear();
333         assertTrue(q.isEmpty());
334     }
335 
336     /**
337      * containsAll(c) is true when c contains a subset of elements
338      */
testContainsAll()339     public void testContainsAll() {
340         TreeSet q = populatedSet(SIZE);
341         TreeSet p = new TreeSet();
342         for (int i = 0; i < SIZE; ++i) {
343             assertTrue(q.containsAll(p));
344             assertFalse(p.containsAll(q));
345             p.add(new Integer(i));
346         }
347         assertTrue(p.containsAll(q));
348     }
349 
350     /**
351      * retainAll(c) retains only those elements of c and reports true if changed
352      */
testRetainAll()353     public void testRetainAll() {
354         TreeSet q = populatedSet(SIZE);
355         TreeSet p = populatedSet(SIZE);
356         for (int i = 0; i < SIZE; ++i) {
357             boolean changed = q.retainAll(p);
358             if (i == 0)
359                 assertFalse(changed);
360             else
361                 assertTrue(changed);
362 
363             assertTrue(q.containsAll(p));
364             assertEquals(SIZE - i, q.size());
365             p.pollFirst();
366         }
367     }
368 
369     /**
370      * removeAll(c) removes only those elements of c and reports true if changed
371      */
testRemoveAll()372     public void testRemoveAll() {
373         for (int i = 1; i < SIZE; ++i) {
374             TreeSet q = populatedSet(SIZE);
375             TreeSet p = populatedSet(i);
376             assertTrue(q.removeAll(p));
377             assertEquals(SIZE - i, q.size());
378             for (int j = 0; j < i; ++j) {
379                 Integer x = (Integer)(p.pollFirst());
380                 assertFalse(q.contains(x));
381             }
382         }
383     }
384 
385     /**
386      * lower returns preceding element
387      */
testLower()388     public void testLower() {
389         TreeSet q = set5();
390         Object e1 = q.lower(three);
391         assertEquals(two, e1);
392 
393         Object e2 = q.lower(six);
394         assertEquals(five, e2);
395 
396         Object e3 = q.lower(one);
397         assertNull(e3);
398 
399         Object e4 = q.lower(zero);
400         assertNull(e4);
401     }
402 
403     /**
404      * higher returns next element
405      */
testHigher()406     public void testHigher() {
407         TreeSet q = set5();
408         Object e1 = q.higher(three);
409         assertEquals(four, e1);
410 
411         Object e2 = q.higher(zero);
412         assertEquals(one, e2);
413 
414         Object e3 = q.higher(five);
415         assertNull(e3);
416 
417         Object e4 = q.higher(six);
418         assertNull(e4);
419     }
420 
421     /**
422      * floor returns preceding element
423      */
testFloor()424     public void testFloor() {
425         TreeSet q = set5();
426         Object e1 = q.floor(three);
427         assertEquals(three, e1);
428 
429         Object e2 = q.floor(six);
430         assertEquals(five, e2);
431 
432         Object e3 = q.floor(one);
433         assertEquals(one, e3);
434 
435         Object e4 = q.floor(zero);
436         assertNull(e4);
437     }
438 
439     /**
440      * ceiling returns next element
441      */
testCeiling()442     public void testCeiling() {
443         TreeSet q = set5();
444         Object e1 = q.ceiling(three);
445         assertEquals(three, e1);
446 
447         Object e2 = q.ceiling(zero);
448         assertEquals(one, e2);
449 
450         Object e3 = q.ceiling(five);
451         assertEquals(five, e3);
452 
453         Object e4 = q.ceiling(six);
454         assertNull(e4);
455     }
456 
457     /**
458      * toArray contains all elements in sorted order
459      */
testToArray()460     public void testToArray() {
461         TreeSet q = populatedSet(SIZE);
462         Object[] o = q.toArray();
463         for (int i = 0; i < o.length; i++)
464             assertSame(o[i], q.pollFirst());
465     }
466 
467     /**
468      * toArray(a) contains all elements in sorted order
469      */
testToArray2()470     public void testToArray2() {
471         TreeSet<Integer> q = populatedSet(SIZE);
472         Integer[] ints = new Integer[SIZE];
473         Integer[] array = q.toArray(ints);
474         assertSame(ints, array);
475         for (int i = 0; i < ints.length; i++)
476             assertSame(ints[i], q.pollFirst());
477     }
478 
479     /**
480      * iterator iterates through all elements
481      */
testIterator()482     public void testIterator() {
483         TreeSet q = populatedSet(SIZE);
484         Iterator it = q.iterator();
485         int i;
486         for (i = 0; it.hasNext(); i++)
487             assertTrue(q.contains(it.next()));
488         assertEquals(i, SIZE);
489         assertIteratorExhausted(it);
490     }
491 
492     /**
493      * iterator of empty set has no elements
494      */
testEmptyIterator()495     public void testEmptyIterator() {
496         assertIteratorExhausted(new TreeSet().iterator());
497     }
498 
499     /**
500      * iterator.remove removes current element
501      */
testIteratorRemove()502     public void testIteratorRemove() {
503         final TreeSet q = new TreeSet();
504         q.add(new Integer(2));
505         q.add(new Integer(1));
506         q.add(new Integer(3));
507 
508         Iterator it = q.iterator();
509         it.next();
510         it.remove();
511 
512         it = q.iterator();
513         assertEquals(it.next(), new Integer(2));
514         assertEquals(it.next(), new Integer(3));
515         assertFalse(it.hasNext());
516     }
517 
518     /**
519      * toString contains toStrings of elements
520      */
testToString()521     public void testToString() {
522         TreeSet q = populatedSet(SIZE);
523         String s = q.toString();
524         for (int i = 0; i < SIZE; ++i) {
525             assertTrue(s.contains(String.valueOf(i)));
526         }
527     }
528 
529     /**
530      * A deserialized serialized set has same elements
531      */
testSerialization()532     public void testSerialization() throws Exception {
533         NavigableSet x = populatedSet(SIZE);
534         NavigableSet y = serialClone(x);
535 
536         assertNotSame(x, y);
537         assertEquals(x.size(), y.size());
538         assertEquals(x, y);
539         assertEquals(y, x);
540         while (!x.isEmpty()) {
541             assertFalse(y.isEmpty());
542             assertEquals(x.pollFirst(), y.pollFirst());
543         }
544         assertTrue(y.isEmpty());
545     }
546 
547     /**
548      * subSet returns set with keys in requested range
549      */
testSubSetContents()550     public void testSubSetContents() {
551         TreeSet set = set5();
552         SortedSet sm = set.subSet(two, four);
553         assertEquals(two, sm.first());
554         assertEquals(three, sm.last());
555         assertEquals(2, sm.size());
556         assertFalse(sm.contains(one));
557         assertTrue(sm.contains(two));
558         assertTrue(sm.contains(three));
559         assertFalse(sm.contains(four));
560         assertFalse(sm.contains(five));
561         Iterator i = sm.iterator();
562         Object k;
563         k = (Integer)(i.next());
564         assertEquals(two, k);
565         k = (Integer)(i.next());
566         assertEquals(three, k);
567         assertFalse(i.hasNext());
568         Iterator j = sm.iterator();
569         j.next();
570         j.remove();
571         assertFalse(set.contains(two));
572         assertEquals(4, set.size());
573         assertEquals(1, sm.size());
574         assertEquals(three, sm.first());
575         assertEquals(three, sm.last());
576         assertTrue(sm.remove(three));
577         assertTrue(sm.isEmpty());
578         assertEquals(3, set.size());
579     }
580 
testSubSetContents2()581     public void testSubSetContents2() {
582         TreeSet set = set5();
583         SortedSet sm = set.subSet(two, three);
584         assertEquals(1, sm.size());
585         assertEquals(two, sm.first());
586         assertEquals(two, sm.last());
587         assertFalse(sm.contains(one));
588         assertTrue(sm.contains(two));
589         assertFalse(sm.contains(three));
590         assertFalse(sm.contains(four));
591         assertFalse(sm.contains(five));
592         Iterator i = sm.iterator();
593         Object k;
594         k = (Integer)(i.next());
595         assertEquals(two, k);
596         assertFalse(i.hasNext());
597         Iterator j = sm.iterator();
598         j.next();
599         j.remove();
600         assertFalse(set.contains(two));
601         assertEquals(4, set.size());
602         assertEquals(0, sm.size());
603         assertTrue(sm.isEmpty());
604         assertFalse(sm.remove(three));
605         assertEquals(4, set.size());
606     }
607 
608     /**
609      * headSet returns set with keys in requested range
610      */
testHeadSetContents()611     public void testHeadSetContents() {
612         TreeSet set = set5();
613         SortedSet sm = set.headSet(four);
614         assertTrue(sm.contains(one));
615         assertTrue(sm.contains(two));
616         assertTrue(sm.contains(three));
617         assertFalse(sm.contains(four));
618         assertFalse(sm.contains(five));
619         Iterator i = sm.iterator();
620         Object k;
621         k = (Integer)(i.next());
622         assertEquals(one, k);
623         k = (Integer)(i.next());
624         assertEquals(two, k);
625         k = (Integer)(i.next());
626         assertEquals(three, k);
627         assertFalse(i.hasNext());
628         sm.clear();
629         assertTrue(sm.isEmpty());
630         assertEquals(2, set.size());
631         assertEquals(four, set.first());
632     }
633 
634     /**
635      * tailSet returns set with keys in requested range
636      */
testTailSetContents()637     public void testTailSetContents() {
638         TreeSet set = set5();
639         SortedSet sm = set.tailSet(two);
640         assertFalse(sm.contains(one));
641         assertTrue(sm.contains(two));
642         assertTrue(sm.contains(three));
643         assertTrue(sm.contains(four));
644         assertTrue(sm.contains(five));
645         Iterator i = sm.iterator();
646         Object k;
647         k = (Integer)(i.next());
648         assertEquals(two, k);
649         k = (Integer)(i.next());
650         assertEquals(three, k);
651         k = (Integer)(i.next());
652         assertEquals(four, k);
653         k = (Integer)(i.next());
654         assertEquals(five, k);
655         assertFalse(i.hasNext());
656 
657         SortedSet ssm = sm.tailSet(four);
658         assertEquals(four, ssm.first());
659         assertEquals(five, ssm.last());
660         assertTrue(ssm.remove(four));
661         assertEquals(1, ssm.size());
662         assertEquals(3, sm.size());
663         assertEquals(4, set.size());
664     }
665 
666     Random rnd = new Random(666);
667     BitSet bs;
668 
669     /**
670      * Subsets of subsets subdivide correctly
671      */
testRecursiveSubSets()672     public void testRecursiveSubSets() throws Exception {
673         int setSize = expensiveTests ? 1000 : 100;
674         Class cl = TreeSet.class;
675 
676         NavigableSet<Integer> set = newSet(cl);
677         bs = new BitSet(setSize);
678 
679         populate(set, setSize);
680         check(set,                 0, setSize - 1, true);
681         check(set.descendingSet(), 0, setSize - 1, false);
682 
683         mutateSet(set, 0, setSize - 1);
684         check(set,                 0, setSize - 1, true);
685         check(set.descendingSet(), 0, setSize - 1, false);
686 
687         bashSubSet(set.subSet(0, true, setSize, false),
688                    0, setSize - 1, true);
689     }
690 
691     /**
692      * addAll is idempotent
693      */
testAddAll_idempotent()694     public void testAddAll_idempotent() throws Exception {
695         Set x = populatedSet(SIZE);
696         Set y = new TreeSet(x);
697         y.addAll(x);
698         assertEquals(x, y);
699         assertEquals(y, x);
700     }
701 
newSet(Class cl)702     static NavigableSet<Integer> newSet(Class cl) throws Exception {
703         NavigableSet<Integer> result = (NavigableSet<Integer>) cl.newInstance();
704         assertEquals(0, result.size());
705         assertFalse(result.iterator().hasNext());
706         return result;
707     }
708 
populate(NavigableSet<Integer> set, int limit)709     void populate(NavigableSet<Integer> set, int limit) {
710         for (int i = 0, n = 2 * limit / 3; i < n; i++) {
711             int element = rnd.nextInt(limit);
712             put(set, element);
713         }
714     }
715 
mutateSet(NavigableSet<Integer> set, int min, int max)716     void mutateSet(NavigableSet<Integer> set, int min, int max) {
717         int size = set.size();
718         int rangeSize = max - min + 1;
719 
720         // Remove a bunch of entries directly
721         for (int i = 0, n = rangeSize / 2; i < n; i++) {
722             remove(set, min - 5 + rnd.nextInt(rangeSize + 10));
723         }
724 
725         // Remove a bunch of entries with iterator
726         for (Iterator<Integer> it = set.iterator(); it.hasNext(); ) {
727             if (rnd.nextBoolean()) {
728                 bs.clear(it.next());
729                 it.remove();
730             }
731         }
732 
733         // Add entries till we're back to original size
734         while (set.size() < size) {
735             int element = min + rnd.nextInt(rangeSize);
736             assertTrue(element >= min && element <= max);
737             put(set, element);
738         }
739     }
740 
mutateSubSet(NavigableSet<Integer> set, int min, int max)741     void mutateSubSet(NavigableSet<Integer> set, int min, int max) {
742         int size = set.size();
743         int rangeSize = max - min + 1;
744 
745         // Remove a bunch of entries directly
746         for (int i = 0, n = rangeSize / 2; i < n; i++) {
747             remove(set, min - 5 + rnd.nextInt(rangeSize + 10));
748         }
749 
750         // Remove a bunch of entries with iterator
751         for (Iterator<Integer> it = set.iterator(); it.hasNext(); ) {
752             if (rnd.nextBoolean()) {
753                 bs.clear(it.next());
754                 it.remove();
755             }
756         }
757 
758         // Add entries till we're back to original size
759         while (set.size() < size) {
760             int element = min - 5 + rnd.nextInt(rangeSize + 10);
761             if (element >= min && element <= max) {
762                 put(set, element);
763             } else {
764                 try {
765                     set.add(element);
766                     shouldThrow();
767                 } catch (IllegalArgumentException success) {}
768             }
769         }
770     }
771 
put(NavigableSet<Integer> set, int element)772     void put(NavigableSet<Integer> set, int element) {
773         if (set.add(element))
774             bs.set(element);
775     }
776 
remove(NavigableSet<Integer> set, int element)777     void remove(NavigableSet<Integer> set, int element) {
778         if (set.remove(element))
779             bs.clear(element);
780     }
781 
bashSubSet(NavigableSet<Integer> set, int min, int max, boolean ascending)782     void bashSubSet(NavigableSet<Integer> set,
783                     int min, int max, boolean ascending) {
784         check(set, min, max, ascending);
785         check(set.descendingSet(), min, max, !ascending);
786 
787         mutateSubSet(set, min, max);
788         check(set, min, max, ascending);
789         check(set.descendingSet(), min, max, !ascending);
790 
791         // Recurse
792         if (max - min < 2)
793             return;
794         int midPoint = (min + max) / 2;
795 
796         // headSet - pick direction and endpoint inclusion randomly
797         boolean incl = rnd.nextBoolean();
798         NavigableSet<Integer> hm = set.headSet(midPoint, incl);
799         if (ascending) {
800             if (rnd.nextBoolean())
801                 bashSubSet(hm, min, midPoint - (incl ? 0 : 1), true);
802             else
803                 bashSubSet(hm.descendingSet(), min, midPoint - (incl ? 0 : 1),
804                            false);
805         } else {
806             if (rnd.nextBoolean())
807                 bashSubSet(hm, midPoint + (incl ? 0 : 1), max, false);
808             else
809                 bashSubSet(hm.descendingSet(), midPoint + (incl ? 0 : 1), max,
810                            true);
811         }
812 
813         // tailSet - pick direction and endpoint inclusion randomly
814         incl = rnd.nextBoolean();
815         NavigableSet<Integer> tm = set.tailSet(midPoint,incl);
816         if (ascending) {
817             if (rnd.nextBoolean())
818                 bashSubSet(tm, midPoint + (incl ? 0 : 1), max, true);
819             else
820                 bashSubSet(tm.descendingSet(), midPoint + (incl ? 0 : 1), max,
821                            false);
822         } else {
823             if (rnd.nextBoolean()) {
824                 bashSubSet(tm, min, midPoint - (incl ? 0 : 1), false);
825             } else {
826                 bashSubSet(tm.descendingSet(), min, midPoint - (incl ? 0 : 1),
827                            true);
828             }
829         }
830 
831         // subSet - pick direction and endpoint inclusion randomly
832         int rangeSize = max - min + 1;
833         int[] endpoints = new int[2];
834         endpoints[0] = min + rnd.nextInt(rangeSize);
835         endpoints[1] = min + rnd.nextInt(rangeSize);
836         Arrays.sort(endpoints);
837         boolean lowIncl = rnd.nextBoolean();
838         boolean highIncl = rnd.nextBoolean();
839         if (ascending) {
840             NavigableSet<Integer> sm = set.subSet(
841                 endpoints[0], lowIncl, endpoints[1], highIncl);
842             if (rnd.nextBoolean())
843                 bashSubSet(sm, endpoints[0] + (lowIncl ? 0 : 1),
844                            endpoints[1] - (highIncl ? 0 : 1), true);
845             else
846                 bashSubSet(sm.descendingSet(), endpoints[0] + (lowIncl ? 0 : 1),
847                            endpoints[1] - (highIncl ? 0 : 1), false);
848         } else {
849             NavigableSet<Integer> sm = set.subSet(
850                 endpoints[1], highIncl, endpoints[0], lowIncl);
851             if (rnd.nextBoolean())
852                 bashSubSet(sm, endpoints[0] + (lowIncl ? 0 : 1),
853                            endpoints[1] - (highIncl ? 0 : 1), false);
854             else
855                 bashSubSet(sm.descendingSet(), endpoints[0] + (lowIncl ? 0 : 1),
856                            endpoints[1] - (highIncl ? 0 : 1), true);
857         }
858     }
859 
860     /**
861      * min and max are both inclusive.  If max < min, interval is empty.
862      */
check(NavigableSet<Integer> set, final int min, final int max, final boolean ascending)863     void check(NavigableSet<Integer> set,
864                       final int min, final int max, final boolean ascending) {
865         class ReferenceSet {
866             int lower(int element) {
867                 return ascending ?
868                     lowerAscending(element) : higherAscending(element);
869             }
870             int floor(int element) {
871                 return ascending ?
872                     floorAscending(element) : ceilingAscending(element);
873             }
874             int ceiling(int element) {
875                 return ascending ?
876                     ceilingAscending(element) : floorAscending(element);
877             }
878             int higher(int element) {
879                 return ascending ?
880                     higherAscending(element) : lowerAscending(element);
881             }
882             int first() {
883                 return ascending ? firstAscending() : lastAscending();
884             }
885             int last() {
886                 return ascending ? lastAscending() : firstAscending();
887             }
888             int lowerAscending(int element) {
889                 return floorAscending(element - 1);
890             }
891             int floorAscending(int element) {
892                 if (element < min)
893                     return -1;
894                 else if (element > max)
895                     element = max;
896 
897                 // BitSet should support this! Test would run much faster
898                 while (element >= min) {
899                     if (bs.get(element))
900                         return element;
901                     element--;
902                 }
903                 return -1;
904             }
905             int ceilingAscending(int element) {
906                 if (element < min)
907                     element = min;
908                 else if (element > max)
909                     return -1;
910                 int result = bs.nextSetBit(element);
911                 return (result > max) ? -1 : result;
912             }
913             int higherAscending(int element) {
914                 return ceilingAscending(element + 1);
915             }
916             private int firstAscending() {
917                 int result = ceilingAscending(min);
918                 return (result > max) ? -1 : result;
919             }
920             private int lastAscending() {
921                 int result = floorAscending(max);
922                 return (result < min) ? -1 : result;
923             }
924         }
925         ReferenceSet rs = new ReferenceSet();
926 
927         // Test contents using containsElement
928         int size = 0;
929         for (int i = min; i <= max; i++) {
930             boolean bsContainsI = bs.get(i);
931             assertEquals(bsContainsI, set.contains(i));
932             if (bsContainsI)
933                 size++;
934         }
935         assertEquals(size, set.size());
936 
937         // Test contents using contains elementSet iterator
938         int size2 = 0;
939         int previousElement = -1;
940         for (int element : set) {
941             assertTrue(bs.get(element));
942             size2++;
943             assertTrue(previousElement < 0 || (ascending ?
944                 element - previousElement > 0 : element - previousElement < 0));
945             previousElement = element;
946         }
947         assertEquals(size2, size);
948 
949         // Test navigation ops
950         for (int element = min - 1; element <= max + 1; element++) {
951             assertEq(set.lower(element), rs.lower(element));
952             assertEq(set.floor(element), rs.floor(element));
953             assertEq(set.higher(element), rs.higher(element));
954             assertEq(set.ceiling(element), rs.ceiling(element));
955         }
956 
957         // Test extrema
958         if (set.size() != 0) {
959             assertEq(set.first(), rs.first());
960             assertEq(set.last(), rs.last());
961         } else {
962             assertEq(rs.first(), -1);
963             assertEq(rs.last(),  -1);
964             try {
965                 set.first();
966                 shouldThrow();
967             } catch (NoSuchElementException success) {}
968             try {
969                 set.last();
970                 shouldThrow();
971             } catch (NoSuchElementException success) {}
972         }
973     }
974 
assertEq(Integer i, int j)975     static void assertEq(Integer i, int j) {
976         if (i == null)
977             assertEquals(j, -1);
978         else
979             assertEquals((int) i, j);
980     }
981 
eq(Integer i, int j)982     static boolean eq(Integer i, int j) {
983         return (i == null) ? j == -1 : i == j;
984     }
985 
986 }
987