ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/Collection8Test.java
Revision: 1.42
Committed: Mon Dec 12 20:49:34 2016 UTC (7 years, 4 months ago) by jsr166
Branch: MAIN
Changes since 1.41: +42 -0 lines
Log Message:
add testForEachRemainingConsistentWithDefaultImplementation

File Contents

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