ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/Collection8Test.java
Revision: 1.54
Committed: Sun May 6 22:33:06 2018 UTC (6 years ago) by jsr166
Branch: MAIN
Changes since 1.53: +1 -0 lines
Log Message:
testRemoveAfterForEachRemaining: add an assertion

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