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