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