ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/Collection8Test.java
Revision: 1.60
Committed: Mon Dec 16 21:22:33 2019 UTC (4 years, 4 months ago) by jsr166
Branch: MAIN
Changes since 1.59: +0 -3 lines
Log Message:
removed unused locals

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