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