ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/Collection8Test.java
Revision: 1.61
Committed: Tue Jan 26 13:33:05 2021 UTC (3 years, 2 months ago) by dl
Branch: MAIN
CVS Tags: HEAD
Changes since 1.60: +60 -59 lines
Log Message:
Replace Integer with Item class

File Contents

# Content
1 /*
2 * Written by Doug Lea and Martin Buchholz with assistance from
3 * members of JCP JSR-166 Expert Group and released to the public
4 * domain, as explained at
5 * http://creativecommons.org/publicdomain/zero/1.0/
6 */
7
8 import static java.util.concurrent.TimeUnit.HOURS;
9 import static java.util.concurrent.TimeUnit.MILLISECONDS;
10
11 import java.util.ArrayDeque;
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.Collection;
15 import java.util.Collections;
16 import java.util.ConcurrentModificationException;
17 import java.util.Deque;
18 import java.util.HashSet;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.NoSuchElementException;
22 import java.util.Queue;
23 import java.util.Set;
24 import java.util.Spliterator;
25 import java.util.concurrent.BlockingDeque;
26 import java.util.concurrent.BlockingQueue;
27 import java.util.concurrent.ConcurrentLinkedQueue;
28 import java.util.concurrent.CountDownLatch;
29 import java.util.concurrent.Executors;
30 import java.util.concurrent.ExecutorService;
31 import java.util.concurrent.Future;
32 import java.util.concurrent.Phaser;
33 import java.util.concurrent.ThreadLocalRandom;
34 import java.util.concurrent.atomic.AtomicBoolean;
35 import java.util.concurrent.atomic.AtomicLong;
36 import java.util.concurrent.atomic.AtomicReference;
37 import java.util.function.Consumer;
38 import java.util.function.Predicate;
39 import java.util.stream.Collectors;
40
41 import junit.framework.Test;
42
43 /**
44 * Contains tests applicable to all jdk8+ Collection implementations.
45 * An extension of CollectionTest.
46 */
47 public class Collection8Test extends JSR166TestCase {
48 final CollectionImplementation impl;
49
50 /** Tests are parameterized by a Collection implementation. */
51 Collection8Test(CollectionImplementation impl, String methodName) {
52 super(methodName);
53 this.impl = impl;
54 }
55
56 public static Test testSuite(CollectionImplementation impl) {
57 return parameterizedTestSuite(Collection8Test.class,
58 CollectionImplementation.class,
59 impl);
60 }
61
62 Object bomb() {
63 return new Object() {
64 @Override public boolean equals(Object x) { throw new AssertionError(); }
65 @Override public int hashCode() { throw new AssertionError(); }
66 @Override public String toString() { throw new AssertionError(); }
67 };
68 }
69
70 /** Checks properties of empty collections. */
71 public void testEmptyMeansEmpty() throws Throwable {
72 Collection c = impl.emptyCollection();
73 emptyMeansEmpty(c);
74
75 if (c instanceof java.io.Serializable) {
76 try {
77 emptyMeansEmpty(serialClonePossiblyFailing(c));
78 } catch (java.io.NotSerializableException ex) {
79 // excusable when we have a serializable wrapper around
80 // a non-serializable collection, as can happen with:
81 // Vector.subList() => wrapped AbstractList$RandomAccessSubList
82 if (testImplementationDetails
83 && (! c.getClass().getName().matches(
84 "java.util.Collections.*")))
85 throw ex;
86 }
87 }
88
89 Collection clone = cloneableClone(c);
90 if (clone != null)
91 emptyMeansEmpty(clone);
92 }
93
94 void emptyMeansEmpty(Collection c) throws InterruptedException {
95 assertTrue(c.isEmpty());
96 mustEqual(0, c.size());
97 mustEqual("[]", c.toString());
98 if (c instanceof List<?>) {
99 List x = (List) c;
100 mustEqual(1, x.hashCode());
101 mustEqual(x, Collections.emptyList());
102 mustEqual(Collections.emptyList(), x);
103 mustEqual(-1, x.indexOf(impl.makeElement(86)));
104 mustEqual(-1, x.lastIndexOf(impl.makeElement(99)));
105 assertThrows(
106 IndexOutOfBoundsException.class,
107 () -> x.get(0),
108 () -> x.set(0, impl.makeElement(42)));
109 }
110 else if (c instanceof Set<?>) {
111 mustEqual(0, c.hashCode());
112 mustEqual(c, Collections.emptySet());
113 mustEqual(Collections.emptySet(), c);
114 }
115 {
116 Object[] a = c.toArray();
117 mustEqual(0, a.length);
118 assertSame(Object[].class, a.getClass());
119 }
120 {
121 Object[] a = new Object[0];
122 assertSame(a, c.toArray(a));
123 }
124 {
125 Item[] a = new Item[0];
126 assertSame(a, c.toArray(a));
127 }
128 {
129 Item[] a = { one, two, three};
130 assertSame(a, c.toArray(a));
131 assertNull(a[0]);
132 mustEqual(2, a[1]);
133 mustEqual(3, a[2]);
134 }
135 assertIteratorExhausted(c.iterator());
136 Consumer alwaysThrows = e -> { throw new AssertionError(); };
137 c.forEach(alwaysThrows);
138 c.iterator().forEachRemaining(alwaysThrows);
139 c.spliterator().forEachRemaining(alwaysThrows);
140 assertFalse(c.spliterator().tryAdvance(alwaysThrows));
141 if (c.spliterator().hasCharacteristics(Spliterator.SIZED))
142 mustEqual(0, c.spliterator().estimateSize());
143 assertFalse(c.contains(bomb()));
144 assertFalse(c.remove(bomb()));
145 if (c instanceof Queue) {
146 Queue q = (Queue) c;
147 assertNull(q.peek());
148 assertNull(q.poll());
149 }
150 if (c instanceof Deque) {
151 Deque d = (Deque) c;
152 assertNull(d.peekFirst());
153 assertNull(d.peekLast());
154 assertNull(d.pollFirst());
155 assertNull(d.pollLast());
156 assertIteratorExhausted(d.descendingIterator());
157 d.descendingIterator().forEachRemaining(alwaysThrows);
158 assertFalse(d.removeFirstOccurrence(bomb()));
159 assertFalse(d.removeLastOccurrence(bomb()));
160 }
161 if (c instanceof BlockingQueue) {
162 BlockingQueue q = (BlockingQueue) c;
163 assertNull(q.poll(randomExpiredTimeout(), randomTimeUnit()));
164 }
165 if (c instanceof BlockingDeque) {
166 BlockingDeque q = (BlockingDeque) c;
167 assertNull(q.pollFirst(randomExpiredTimeout(), randomTimeUnit()));
168 assertNull(q.pollLast(randomExpiredTimeout(), randomTimeUnit()));
169 }
170 }
171
172 public void testNullPointerExceptions() throws InterruptedException {
173 Collection c = impl.emptyCollection();
174 Collection nullCollection = null;
175 assertThrows(
176 NullPointerException.class,
177 () -> c.addAll(nullCollection),
178 () -> c.containsAll(nullCollection),
179 () -> c.retainAll(nullCollection),
180 () -> c.removeAll(nullCollection),
181 () -> c.removeIf(null),
182 () -> c.forEach(null),
183 () -> c.iterator().forEachRemaining(null),
184 () -> c.spliterator().forEachRemaining(null),
185 () -> c.spliterator().tryAdvance(null),
186 () -> c.toArray((Object[])null));
187
188 if (!impl.permitsNulls()) {
189 assertThrows(
190 NullPointerException.class,
191 () -> c.add(null));
192 }
193 if (!impl.permitsNulls() && c instanceof Queue) {
194 Queue q = (Queue) c;
195 assertThrows(
196 NullPointerException.class,
197 () -> q.offer(null));
198 }
199 if (!impl.permitsNulls() && c instanceof Deque) {
200 Deque d = (Deque) c;
201 assertThrows(
202 NullPointerException.class,
203 () -> d.addFirst(null),
204 () -> d.addLast(null),
205 () -> d.offerFirst(null),
206 () -> d.offerLast(null),
207 () -> d.push(null),
208 () -> d.descendingIterator().forEachRemaining(null));
209 }
210 if (c instanceof BlockingQueue) {
211 BlockingQueue q = (BlockingQueue) c;
212 assertThrows(
213 NullPointerException.class,
214 () -> q.offer(null, 1L, HOURS),
215 () -> q.put(null));
216 }
217 if (c instanceof BlockingDeque) {
218 BlockingDeque q = (BlockingDeque) c;
219 assertThrows(
220 NullPointerException.class,
221 () -> q.offerFirst(null, 1L, HOURS),
222 () -> q.offerLast(null, 1L, HOURS),
223 () -> q.putFirst(null),
224 () -> q.putLast(null));
225 }
226 }
227
228 public void testNoSuchElementExceptions() {
229 Collection c = impl.emptyCollection();
230 assertThrows(
231 NoSuchElementException.class,
232 () -> c.iterator().next());
233
234 if (c instanceof Queue) {
235 Queue q = (Queue) c;
236 assertThrows(
237 NoSuchElementException.class,
238 () -> q.element(),
239 () -> q.remove());
240 }
241 if (c instanceof Deque) {
242 Deque d = (Deque) c;
243 assertThrows(
244 NoSuchElementException.class,
245 () -> d.getFirst(),
246 () -> d.getLast(),
247 () -> d.removeFirst(),
248 () -> d.removeLast(),
249 () -> d.pop(),
250 () -> d.descendingIterator().next());
251 }
252 if (c instanceof List) {
253 List x = (List) c;
254 assertThrows(
255 NoSuchElementException.class,
256 () -> x.iterator().next(),
257 () -> x.listIterator().next(),
258 () -> x.listIterator(0).next(),
259 () -> x.listIterator().previous(),
260 () -> x.listIterator(0).previous());
261 }
262 }
263
264 public void testRemoveIf() {
265 Collection c = impl.emptyCollection();
266 boolean ordered =
267 c.spliterator().hasCharacteristics(Spliterator.ORDERED);
268 ThreadLocalRandom rnd = ThreadLocalRandom.current();
269 int n = rnd.nextInt(6);
270 for (int i = 0; i < n; i++) c.add(impl.makeElement(i));
271 AtomicReference threwAt = new AtomicReference(null);
272 List orig = rnd.nextBoolean()
273 ? new ArrayList(c)
274 : Arrays.asList(c.toArray());
275
276 // Merely creating an iterator can change ArrayBlockingQueue behavior
277 Iterator it = rnd.nextBoolean() ? c.iterator() : null;
278
279 ArrayList survivors = new ArrayList();
280 ArrayList accepts = new ArrayList();
281 ArrayList rejects = new ArrayList();
282
283 Predicate randomPredicate = e -> {
284 assertNull(threwAt.get());
285 switch (rnd.nextInt(3)) {
286 case 0: accepts.add(e); return true;
287 case 1: rejects.add(e); return false;
288 case 2: threwAt.set(e); throw new ArithmeticException();
289 default: throw new AssertionError();
290 }
291 };
292 try {
293 try {
294 boolean modified = c.removeIf(randomPredicate);
295 assertNull(threwAt.get());
296 mustEqual(modified, accepts.size() > 0);
297 mustEqual(modified, rejects.size() != n);
298 mustEqual(accepts.size() + rejects.size(), n);
299 if (ordered) {
300 mustEqual(rejects,
301 Arrays.asList(c.toArray()));
302 } else {
303 mustEqual(new HashSet(rejects),
304 new HashSet(Arrays.asList(c.toArray())));
305 }
306 } catch (ArithmeticException ok) {
307 assertNotNull(threwAt.get());
308 assertTrue(c.contains(threwAt.get()));
309 }
310 if (it != null && impl.isConcurrent())
311 // check for weakly consistent iterator
312 while (it.hasNext()) assertTrue(orig.contains(it.next()));
313 switch (rnd.nextInt(4)) {
314 case 0: survivors.addAll(c); break;
315 case 1: survivors.addAll(Arrays.asList(c.toArray())); break;
316 case 2: c.forEach(survivors::add); break;
317 case 3: for (Object e : c) survivors.add(e); break;
318 }
319 assertTrue(orig.containsAll(accepts));
320 assertTrue(orig.containsAll(rejects));
321 assertTrue(orig.containsAll(survivors));
322 assertTrue(orig.containsAll(c));
323 assertTrue(c.containsAll(rejects));
324 assertTrue(c.containsAll(survivors));
325 assertTrue(survivors.containsAll(rejects));
326 if (threwAt.get() == null) {
327 mustEqual(n - accepts.size(), c.size());
328 for (Object x : accepts) assertFalse(c.contains(x));
329 } else {
330 // Two acceptable behaviors: entire removeIf call is one
331 // transaction, or each element processed is one transaction.
332 assertTrue(n == c.size() || n == c.size() + accepts.size());
333 int k = 0;
334 for (Object x : accepts) if (c.contains(x)) k++;
335 assertTrue(k == accepts.size() || k == 0);
336 }
337 } catch (Throwable ex) {
338 System.err.println(impl.klazz());
339 // c is at risk of corruption if we got here, so be lenient
340 try { System.err.printf("c=%s%n", c); }
341 catch (Throwable t) { t.printStackTrace(); }
342 System.err.printf("n=%d%n", n);
343 System.err.printf("orig=%s%n", orig);
344 System.err.printf("accepts=%s%n", accepts);
345 System.err.printf("rejects=%s%n", rejects);
346 System.err.printf("survivors=%s%n", survivors);
347 System.err.printf("threwAt=%s%n", threwAt.get());
348 throw ex;
349 }
350 }
351
352 /**
353 * All elements removed in the middle of CONCURRENT traversal.
354 */
355 public void testElementRemovalDuringTraversal() {
356 Collection c = impl.emptyCollection();
357 ThreadLocalRandom rnd = ThreadLocalRandom.current();
358 int n = rnd.nextInt(6);
359 ArrayList copy = new ArrayList();
360 for (int i = 0; i < n; i++) {
361 Object x = impl.makeElement(i);
362 copy.add(x);
363 c.add(x);
364 }
365 ArrayList iterated = new ArrayList();
366 ArrayList spliterated = new ArrayList();
367 Spliterator s = c.spliterator();
368 Iterator it = c.iterator();
369 for (int i = rnd.nextInt(n + 1); --i >= 0; ) {
370 assertTrue(s.tryAdvance(spliterated::add));
371 if (rnd.nextBoolean()) assertTrue(it.hasNext());
372 iterated.add(it.next());
373 }
374 Consumer alwaysThrows = e -> { throw new AssertionError(); };
375 if (s.hasCharacteristics(Spliterator.CONCURRENT)) {
376 c.clear(); // TODO: many more removal methods
377 if (testImplementationDetails
378 && !(c instanceof java.util.concurrent.ArrayBlockingQueue)) {
379 if (rnd.nextBoolean())
380 assertFalse(s.tryAdvance(alwaysThrows));
381 else
382 s.forEachRemaining(alwaysThrows);
383 }
384 if (it.hasNext()) iterated.add(it.next());
385 if (rnd.nextBoolean()) assertIteratorExhausted(it);
386 }
387 assertTrue(copy.containsAll(iterated));
388 assertTrue(copy.containsAll(spliterated));
389 }
390
391 /**
392 * Some elements randomly disappear in the middle of traversal.
393 */
394 public void testRandomElementRemovalDuringTraversal() {
395 Collection c = impl.emptyCollection();
396 ThreadLocalRandom rnd = ThreadLocalRandom.current();
397 int n = rnd.nextInt(6);
398 ArrayList copy = new ArrayList();
399 for (int i = 0; i < n; i++) {
400 Object x = impl.makeElement(i);
401 copy.add(x);
402 c.add(x);
403 }
404 ArrayList iterated = new ArrayList();
405 ArrayList spliterated = new ArrayList();
406 ArrayList removed = new ArrayList();
407 Spliterator s = c.spliterator();
408 Iterator it = c.iterator();
409 if (! (s.hasCharacteristics(Spliterator.CONCURRENT) ||
410 s.hasCharacteristics(Spliterator.IMMUTABLE)))
411 return;
412 for (int i = rnd.nextInt(n + 1); --i >= 0; ) {
413 assertTrue(s.tryAdvance(e -> {}));
414 if (rnd.nextBoolean()) assertTrue(it.hasNext());
415 it.next();
416 }
417 // TODO: many more removal methods
418 if (rnd.nextBoolean()) {
419 for (Iterator z = c.iterator(); z.hasNext(); ) {
420 Object e = z.next();
421 if (rnd.nextBoolean()) {
422 try {
423 z.remove();
424 } catch (UnsupportedOperationException ok) { return; }
425 removed.add(e);
426 }
427 }
428 } else {
429 Predicate randomlyRemove = e -> {
430 if (rnd.nextBoolean()) { removed.add(e); return true; }
431 else return false;
432 };
433 c.removeIf(randomlyRemove);
434 }
435 s.forEachRemaining(spliterated::add);
436 while (it.hasNext())
437 iterated.add(it.next());
438 assertTrue(copy.containsAll(iterated));
439 assertTrue(copy.containsAll(spliterated));
440 assertTrue(copy.containsAll(removed));
441 if (s.hasCharacteristics(Spliterator.CONCURRENT)) {
442 ArrayList iteratedAndRemoved = new ArrayList(iterated);
443 ArrayList spliteratedAndRemoved = new ArrayList(spliterated);
444 iteratedAndRemoved.retainAll(removed);
445 spliteratedAndRemoved.retainAll(removed);
446 assertTrue(iteratedAndRemoved.size() <= 1);
447 assertTrue(spliteratedAndRemoved.size() <= 1);
448 if (testImplementationDetails
449 && !(c instanceof java.util.concurrent.ArrayBlockingQueue))
450 assertTrue(spliteratedAndRemoved.isEmpty());
451 }
452 }
453
454 /**
455 * Various ways of traversing a collection yield same elements
456 */
457 public void testTraversalEquivalence() {
458 Collection c = impl.emptyCollection();
459 ThreadLocalRandom rnd = ThreadLocalRandom.current();
460 int n = rnd.nextInt(6);
461 for (int i = 0; i < n; i++) c.add(impl.makeElement(i));
462 ArrayList iterated = new ArrayList();
463 ArrayList iteratedForEachRemaining = new ArrayList();
464 ArrayList tryAdvanced = new ArrayList();
465 ArrayList spliterated = new ArrayList();
466 ArrayList splitonced = new ArrayList();
467 ArrayList forEached = new ArrayList();
468 ArrayList streamForEached = new ArrayList();
469 ConcurrentLinkedQueue parallelStreamForEached = new ConcurrentLinkedQueue();
470 ArrayList removeIfed = new ArrayList();
471 for (Object x : c) iterated.add(x);
472 c.iterator().forEachRemaining(iteratedForEachRemaining::add);
473 for (Spliterator s = c.spliterator();
474 s.tryAdvance(tryAdvanced::add); ) {}
475 c.spliterator().forEachRemaining(spliterated::add);
476 { // trySplit returns "strict prefix"
477 Spliterator s1 = c.spliterator(), s2 = s1.trySplit();
478 if (s2 != null) s2.forEachRemaining(splitonced::add);
479 s1.forEachRemaining(splitonced::add);
480 }
481 c.forEach(forEached::add);
482 c.stream().forEach(streamForEached::add);
483 c.parallelStream().forEach(parallelStreamForEached::add);
484 c.removeIf(e -> { removeIfed.add(e); return false; });
485 boolean ordered =
486 c.spliterator().hasCharacteristics(Spliterator.ORDERED);
487 if (c instanceof List || c instanceof Deque)
488 assertTrue(ordered);
489 HashSet cset = new HashSet(c);
490 mustEqual(cset, new HashSet(parallelStreamForEached));
491 if (ordered) {
492 mustEqual(iterated, iteratedForEachRemaining);
493 mustEqual(iterated, tryAdvanced);
494 mustEqual(iterated, spliterated);
495 mustEqual(iterated, splitonced);
496 mustEqual(iterated, forEached);
497 mustEqual(iterated, streamForEached);
498 mustEqual(iterated, removeIfed);
499 } else {
500 mustEqual(cset, new HashSet(iterated));
501 mustEqual(cset, new HashSet(iteratedForEachRemaining));
502 mustEqual(cset, new HashSet(tryAdvanced));
503 mustEqual(cset, new HashSet(spliterated));
504 mustEqual(cset, new HashSet(splitonced));
505 mustEqual(cset, new HashSet(forEached));
506 mustEqual(cset, new HashSet(streamForEached));
507 mustEqual(cset, new HashSet(removeIfed));
508 }
509 if (c instanceof Deque) {
510 Deque d = (Deque) c;
511 ArrayList descending = new ArrayList();
512 ArrayList descendingForEachRemaining = new ArrayList();
513 for (Iterator it = d.descendingIterator(); it.hasNext(); )
514 descending.add(it.next());
515 d.descendingIterator().forEachRemaining(
516 e -> descendingForEachRemaining.add(e));
517 Collections.reverse(descending);
518 Collections.reverse(descendingForEachRemaining);
519 mustEqual(iterated, descending);
520 mustEqual(iterated, descendingForEachRemaining);
521 }
522 }
523
524 /**
525 * Iterator.forEachRemaining has same behavior as Iterator's
526 * default implementation.
527 */
528 public void testForEachRemainingConsistentWithDefaultImplementation() {
529 Collection c = impl.emptyCollection();
530 if (!testImplementationDetails
531 || c.getClass() == java.util.LinkedList.class)
532 return;
533 ThreadLocalRandom rnd = ThreadLocalRandom.current();
534 int n = 1 + rnd.nextInt(3);
535 for (int i = 0; i < n; i++) c.add(impl.makeElement(i));
536 ArrayList iterated = new ArrayList();
537 ArrayList iteratedForEachRemaining = new ArrayList();
538 Iterator it1 = c.iterator();
539 Iterator it2 = c.iterator();
540 assertTrue(it1.hasNext());
541 assertTrue(it2.hasNext());
542 c.clear();
543 Object r1, r2;
544 try {
545 while (it1.hasNext()) iterated.add(it1.next());
546 r1 = iterated;
547 } catch (ConcurrentModificationException ex) {
548 r1 = ConcurrentModificationException.class;
549 assertFalse(impl.isConcurrent());
550 }
551 try {
552 it2.forEachRemaining(iteratedForEachRemaining::add);
553 r2 = iteratedForEachRemaining;
554 } catch (ConcurrentModificationException ex) {
555 r2 = ConcurrentModificationException.class;
556 assertFalse(impl.isConcurrent());
557 }
558 mustEqual(r1, r2);
559 }
560
561 /**
562 * Calling Iterator#remove() after Iterator#forEachRemaining
563 * should (maybe) remove last element
564 */
565 public void testRemoveAfterForEachRemaining() {
566 Collection c = impl.emptyCollection();
567 ThreadLocalRandom rnd = ThreadLocalRandom.current();
568 ArrayList copy = new ArrayList();
569 boolean ordered = c.spliterator().hasCharacteristics(Spliterator.ORDERED);
570 testCollection: {
571 int n = 3 + rnd.nextInt(2);
572 for (int i = 0; i < n; i++) {
573 Object x = impl.makeElement(i);
574 c.add(x);
575 copy.add(x);
576 }
577 Iterator it = c.iterator();
578 if (ordered) {
579 if (rnd.nextBoolean()) assertTrue(it.hasNext());
580 mustEqual(impl.makeElement(0), it.next());
581 if (rnd.nextBoolean()) assertTrue(it.hasNext());
582 mustEqual(impl.makeElement(1), it.next());
583 } else {
584 if (rnd.nextBoolean()) assertTrue(it.hasNext());
585 assertTrue(copy.contains(it.next()));
586 if (rnd.nextBoolean()) assertTrue(it.hasNext());
587 assertTrue(copy.contains(it.next()));
588 }
589 if (rnd.nextBoolean()) assertTrue(it.hasNext());
590 it.forEachRemaining(
591 e -> {
592 assertTrue(c.contains(e));
593 assertTrue(copy.contains(e));});
594 if (testImplementationDetails) {
595 if (c instanceof java.util.concurrent.ArrayBlockingQueue) {
596 assertIteratorExhausted(it);
597 } else {
598 try { it.remove(); }
599 catch (UnsupportedOperationException ok) {
600 break testCollection;
601 }
602 mustEqual(n - 1, c.size());
603 if (ordered) {
604 for (int i = 0; i < n - 1; i++)
605 assertTrue(c.contains(impl.makeElement(i)));
606 assertFalse(c.contains(impl.makeElement(n - 1)));
607 }
608 }
609 }
610 }
611 if (c instanceof Deque) {
612 Deque d = (Deque) impl.emptyCollection();
613 assertTrue(ordered);
614 int n = 3 + rnd.nextInt(2);
615 for (int i = 0; i < n; i++) d.add(impl.makeElement(i));
616 Iterator it = d.descendingIterator();
617 assertTrue(it.hasNext());
618 mustEqual(impl.makeElement(n - 1), it.next());
619 assertTrue(it.hasNext());
620 mustEqual(impl.makeElement(n - 2), it.next());
621 it.forEachRemaining(e -> assertTrue(c.contains(e)));
622 if (testImplementationDetails) {
623 it.remove();
624 mustEqual(n - 1, d.size());
625 for (int i = 1; i < n; i++)
626 assertTrue(d.contains(impl.makeElement(i)));
627 assertFalse(d.contains(impl.makeElement(0)));
628 }
629 }
630 }
631
632 /**
633 * stream().forEach returns elements in the collection
634 */
635 public void testStreamForEach() throws Throwable {
636 final Collection c = impl.emptyCollection();
637 final Object x = impl.makeElement(1);
638 final Object y = impl.makeElement(2);
639 final ArrayList found = new ArrayList();
640 Consumer<Object> spy = o -> found.add(o);
641 c.stream().forEach(spy);
642 assertTrue(found.isEmpty());
643
644 assertTrue(c.add(x));
645 c.stream().forEach(spy);
646 mustEqual(Collections.singletonList(x), found);
647 found.clear();
648
649 assertTrue(c.add(y));
650 c.stream().forEach(spy);
651 mustEqual(2, found.size());
652 assertTrue(found.contains(x));
653 assertTrue(found.contains(y));
654 found.clear();
655
656 c.clear();
657 c.stream().forEach(spy);
658 assertTrue(found.isEmpty());
659 }
660
661 public void testStreamForEachConcurrentStressTest() throws Throwable {
662 if (!impl.isConcurrent()) return;
663 final Collection c = impl.emptyCollection();
664 final long testDurationMillis = timeoutMillis();
665 final AtomicBoolean done = new AtomicBoolean(false);
666 final Object elt = impl.makeElement(1);
667 final Future<?> f1, f2;
668 final ExecutorService pool = Executors.newCachedThreadPool();
669 try (PoolCleaner cleaner = cleaner(pool, done)) {
670 final CountDownLatch threadsStarted = new CountDownLatch(2);
671 Runnable checkElt = () -> {
672 threadsStarted.countDown();
673 while (!done.get())
674 c.stream().forEach(x -> assertSame(x, elt)); };
675 Runnable addRemove = () -> {
676 threadsStarted.countDown();
677 while (!done.get()) {
678 assertTrue(c.add(elt));
679 assertTrue(c.remove(elt));
680 }};
681 f1 = pool.submit(checkElt);
682 f2 = pool.submit(addRemove);
683 Thread.sleep(testDurationMillis);
684 }
685 assertNull(f1.get(0L, MILLISECONDS));
686 assertNull(f2.get(0L, MILLISECONDS));
687 }
688
689 /**
690 * collection.forEach returns elements in the collection
691 */
692 public void testForEach() throws Throwable {
693 final Collection c = impl.emptyCollection();
694 final Object x = impl.makeElement(1);
695 final Object y = impl.makeElement(2);
696 final ArrayList found = new ArrayList();
697 Consumer<Object> spy = o -> found.add(o);
698 c.forEach(spy);
699 assertTrue(found.isEmpty());
700
701 assertTrue(c.add(x));
702 c.forEach(spy);
703 mustEqual(Collections.singletonList(x), found);
704 found.clear();
705
706 assertTrue(c.add(y));
707 c.forEach(spy);
708 mustEqual(2, found.size());
709 assertTrue(found.contains(x));
710 assertTrue(found.contains(y));
711 found.clear();
712
713 c.clear();
714 c.forEach(spy);
715 assertTrue(found.isEmpty());
716 }
717
718 /** TODO: promote to a common utility */
719 static <T> T chooseOne(T ... ts) {
720 return ts[ThreadLocalRandom.current().nextInt(ts.length)];
721 }
722
723 /** TODO: more random adders and removers */
724 static <E> Runnable adderRemover(Collection<E> c, E e) {
725 return chooseOne(
726 () -> {
727 assertTrue(c.add(e));
728 assertTrue(c.contains(e));
729 assertTrue(c.remove(e));
730 assertFalse(c.contains(e));
731 },
732 () -> {
733 assertTrue(c.add(e));
734 assertTrue(c.contains(e));
735 assertTrue(c.removeIf(x -> x == e));
736 assertFalse(c.contains(e));
737 },
738 () -> {
739 assertTrue(c.add(e));
740 assertTrue(c.contains(e));
741 for (Iterator it = c.iterator();; )
742 if (it.next() == e) {
743 try { it.remove(); }
744 catch (UnsupportedOperationException ok) {
745 c.remove(e);
746 }
747 break;
748 }
749 assertFalse(c.contains(e));
750 });
751 }
752
753 /**
754 * Concurrent Spliterators, once exhausted, stay exhausted.
755 */
756 public void testStickySpliteratorExhaustion() throws Throwable {
757 if (!impl.isConcurrent()) return;
758 if (!testImplementationDetails) return;
759 final ThreadLocalRandom rnd = ThreadLocalRandom.current();
760 final Consumer alwaysThrows = e -> { throw new AssertionError(); };
761 final Collection c = impl.emptyCollection();
762 final Spliterator s = c.spliterator();
763 if (rnd.nextBoolean()) {
764 assertFalse(s.tryAdvance(alwaysThrows));
765 } else {
766 s.forEachRemaining(alwaysThrows);
767 }
768 final Object one = impl.makeElement(1);
769 // Spliterator should not notice added element
770 c.add(one);
771 if (rnd.nextBoolean()) {
772 assertFalse(s.tryAdvance(alwaysThrows));
773 } else {
774 s.forEachRemaining(alwaysThrows);
775 }
776 }
777
778 /**
779 * Motley crew of threads concurrently randomly hammer the collection.
780 */
781 public void testDetectRaces() throws Throwable {
782 if (!impl.isConcurrent()) return;
783 final ThreadLocalRandom rnd = ThreadLocalRandom.current();
784 final Collection c = impl.emptyCollection();
785 final long testDurationMillis
786 = expensiveTests ? LONG_DELAY_MS : timeoutMillis();
787 final AtomicBoolean done = new AtomicBoolean(false);
788 final Object one = impl.makeElement(1);
789 final Object two = impl.makeElement(2);
790 final Consumer checkSanity = x -> assertTrue(x == one || x == two);
791 final Consumer<Object[]> checkArraySanity = array -> {
792 // assertTrue(array.length <= 2); // duplicates are permitted
793 for (Object x : array) assertTrue(x == one || x == two);
794 };
795 final Object[] emptyArray =
796 (Object[]) java.lang.reflect.Array.newInstance(one.getClass(), 0);
797 final List<Future<?>> futures;
798 final Phaser threadsStarted = new Phaser(1); // register this thread
799 final Runnable[] frobbers = {
800 () -> c.forEach(checkSanity),
801 () -> c.stream().forEach(checkSanity),
802 () -> c.parallelStream().forEach(checkSanity),
803 () -> c.spliterator().trySplit(),
804 () -> {
805 Spliterator s = c.spliterator();
806 s.tryAdvance(checkSanity);
807 s.trySplit();
808 },
809 () -> {
810 Spliterator s = c.spliterator();
811 do {} while (s.tryAdvance(checkSanity));
812 },
813 () -> { for (Object x : c) checkSanity.accept(x); },
814 () -> checkArraySanity.accept(c.toArray()),
815 () -> checkArraySanity.accept(c.toArray(emptyArray)),
816 () -> {
817 Object[] a = new Object[5];
818 Object three = impl.makeElement(3);
819 Arrays.fill(a, 0, a.length, three);
820 Object[] x = c.toArray(a);
821 if (x == a)
822 for (int i = 0; i < a.length && a[i] != null; i++)
823 checkSanity.accept(a[i]);
824 // A careful reading of the spec does not support:
825 // for (i++; i < a.length; i++) assertSame(three, a[i]);
826 else
827 checkArraySanity.accept(x);
828 },
829 adderRemover(c, one),
830 adderRemover(c, two),
831 };
832 final List<Runnable> tasks =
833 Arrays.stream(frobbers)
834 .filter(task -> rnd.nextBoolean()) // random subset
835 .map(task -> (Runnable) () -> {
836 threadsStarted.arriveAndAwaitAdvance();
837 while (!done.get())
838 task.run();
839 })
840 .collect(Collectors.toList());
841 final ExecutorService pool = Executors.newCachedThreadPool();
842 try (PoolCleaner cleaner = cleaner(pool, done)) {
843 threadsStarted.bulkRegister(tasks.size());
844 futures = tasks.stream()
845 .map(pool::submit)
846 .collect(Collectors.toList());
847 threadsStarted.arriveAndDeregister();
848 Thread.sleep(testDurationMillis);
849 }
850 for (Future future : futures)
851 assertNull(future.get(0L, MILLISECONDS));
852 }
853
854 /**
855 * Spliterators are either IMMUTABLE or truly late-binding or, if
856 * concurrent, use the same "late-binding style" of returning
857 * elements added between creation and first use.
858 */
859 public void testLateBindingStyle() {
860 if (!testImplementationDetails) return;
861 if (impl.klazz() == ArrayList.class) return; // for jdk8
862 // Immutable (snapshot) spliterators are exempt
863 if (impl.emptyCollection().spliterator()
864 .hasCharacteristics(Spliterator.IMMUTABLE))
865 return;
866 final Object one = impl.makeElement(1);
867 {
868 final Collection c = impl.emptyCollection();
869 final Spliterator split = c.spliterator();
870 c.add(one);
871 assertTrue(split.tryAdvance(e -> { assertSame(e, one); }));
872 assertFalse(split.tryAdvance(e -> { throw new AssertionError(); }));
873 assertTrue(c.contains(one));
874 }
875 {
876 final AtomicLong count = new AtomicLong(0);
877 final Collection c = impl.emptyCollection();
878 final Spliterator split = c.spliterator();
879 c.add(one);
880 split.forEachRemaining(
881 e -> { assertSame(e, one); count.getAndIncrement(); });
882 mustEqual(1L, count.get());
883 assertFalse(split.tryAdvance(e -> { throw new AssertionError(); }));
884 assertTrue(c.contains(one));
885 }
886 }
887
888 /**
889 * Spliterator.getComparator throws IllegalStateException iff the
890 * spliterator does not report SORTED.
891 */
892 public void testGetComparator_IllegalStateException() {
893 Collection c = impl.emptyCollection();
894 Spliterator s = c.spliterator();
895 boolean reportsSorted = s.hasCharacteristics(Spliterator.SORTED);
896 try {
897 s.getComparator();
898 assertTrue(reportsSorted);
899 } catch (IllegalStateException ex) {
900 assertFalse(reportsSorted);
901 }
902 }
903
904 public void testCollectionCopies() throws Exception {
905 ThreadLocalRandom rnd = ThreadLocalRandom.current();
906 Collection c = impl.emptyCollection();
907 for (int n = rnd.nextInt(4); n--> 0; )
908 c.add(impl.makeElement(rnd.nextInt()));
909 mustEqual(c, c);
910 if (c instanceof List)
911 assertCollectionsEquals(c, new ArrayList(c));
912 else if (c instanceof Set)
913 assertCollectionsEquals(c, new HashSet(c));
914 else if (c instanceof Deque)
915 assertCollectionsEquivalent(c, new ArrayDeque(c));
916
917 Collection clone = cloneableClone(c);
918 if (clone != null) {
919 assertSame(c.getClass(), clone.getClass());
920 assertCollectionsEquivalent(c, clone);
921 }
922 try {
923 Collection serialClone = serialClonePossiblyFailing(c);
924 assertSame(c.getClass(), serialClone.getClass());
925 assertCollectionsEquivalent(c, serialClone);
926 } catch (java.io.NotSerializableException acceptable) {}
927 }
928
929 /**
930 * TODO: move out of limbo
931 * 8203662: remove increment of modCount from ArrayList and Vector replaceAll()
932 */
933 public void DISABLED_testReplaceAllIsNotStructuralModification() {
934 Collection c = impl.emptyCollection();
935 if (!(c instanceof List))
936 return;
937 List list = (List) c;
938 ThreadLocalRandom rnd = ThreadLocalRandom.current();
939 for (int n = rnd.nextInt(2, 10); n--> 0; )
940 list.add(impl.makeElement(rnd.nextInt()));
941 ArrayList copy = new ArrayList(list);
942 int size = list.size(), half = size / 2;
943 Iterator it = list.iterator();
944 for (int i = 0; i < half; i++)
945 mustEqual(it.next(), copy.get(i));
946 list.replaceAll(n -> n);
947 // ConcurrentModificationException must not be thrown here.
948 for (int i = half; i < size; i++)
949 mustEqual(it.next(), copy.get(i));
950 }
951
952 // public void testCollection8DebugFail() {
953 // fail(impl.klazz().getSimpleName());
954 // }
955 }