ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/Collection8Test.java
Revision: 1.50
Committed: Wed Apr 4 03:35:13 2018 UTC (6 years, 1 month ago) by jsr166
Branch: MAIN
Changes since 1.49: +20 -0 lines
Log Message:
add testObjectMethods

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