ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/Collection8Test.java
Revision: 1.47
Committed: Mon Aug 21 20:12:36 2017 UTC (6 years, 8 months ago) by jsr166
Branch: MAIN
Changes since 1.46: +3 -3 lines
Log Message:
whitespace

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 jsr166 1.47 public boolean equals(Object x) { throw new AssertionError(); }
63     public int hashCode() { throw new AssertionError(); }
64     };
65 jsr166 1.10 }
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 jsr166 1.46 assertNull(q.poll(randomExpiredTimeout(), randomTimeUnit()));
144 jsr166 1.14 }
145     if (c instanceof BlockingDeque) {
146     BlockingDeque q = (BlockingDeque) c;
147 jsr166 1.46 assertNull(q.pollFirst(randomExpiredTimeout(), randomTimeUnit()));
148     assertNull(q.pollLast(randomExpiredTimeout(), randomTimeUnit()));
149 jsr166 1.14 }
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     }
545     try {
546     it2.forEachRemaining(iteratedForEachRemaining::add);
547     r2 = iteratedForEachRemaining;
548     } catch (ConcurrentModificationException ex) {
549     r2 = ConcurrentModificationException.class;
550 jsr166 1.44 assertFalse(impl.isConcurrent());
551 jsr166 1.42 }
552     assertEquals(r1, r2);
553     }
554    
555     /**
556 jsr166 1.5 * Calling Iterator#remove() after Iterator#forEachRemaining
557 jsr166 1.21 * should (maybe) remove last element
558 jsr166 1.5 */
559     public void testRemoveAfterForEachRemaining() {
560     Collection c = impl.emptyCollection();
561     ThreadLocalRandom rnd = ThreadLocalRandom.current();
562 jsr166 1.25 testCollection: {
563 jsr166 1.5 int n = 3 + rnd.nextInt(2);
564     for (int i = 0; i < n; i++) c.add(impl.makeElement(i));
565     Iterator it = c.iterator();
566     assertTrue(it.hasNext());
567     assertEquals(impl.makeElement(0), it.next());
568     assertTrue(it.hasNext());
569     assertEquals(impl.makeElement(1), it.next());
570 jsr166 1.21 it.forEachRemaining(e -> assertTrue(c.contains(e)));
571     if (testImplementationDetails) {
572     if (c instanceof java.util.concurrent.ArrayBlockingQueue) {
573     assertIteratorExhausted(it);
574     } else {
575 jsr166 1.25 try { it.remove(); }
576     catch (UnsupportedOperationException ok) {
577     break testCollection;
578     }
579 jsr166 1.21 assertEquals(n - 1, c.size());
580     for (int i = 0; i < n - 1; i++)
581     assertTrue(c.contains(impl.makeElement(i)));
582     assertFalse(c.contains(impl.makeElement(n - 1)));
583     }
584     }
585 jsr166 1.5 }
586     if (c instanceof Deque) {
587     Deque d = (Deque) impl.emptyCollection();
588     int n = 3 + rnd.nextInt(2);
589     for (int i = 0; i < n; i++) d.add(impl.makeElement(i));
590     Iterator it = d.descendingIterator();
591     assertTrue(it.hasNext());
592     assertEquals(impl.makeElement(n - 1), it.next());
593     assertTrue(it.hasNext());
594     assertEquals(impl.makeElement(n - 2), it.next());
595 jsr166 1.21 it.forEachRemaining(e -> assertTrue(c.contains(e)));
596     if (testImplementationDetails) {
597     it.remove();
598     assertEquals(n - 1, d.size());
599     for (int i = 1; i < n; i++)
600     assertTrue(d.contains(impl.makeElement(i)));
601     assertFalse(d.contains(impl.makeElement(0)));
602     }
603 jsr166 1.5 }
604     }
605    
606 jsr166 1.1 /**
607     * stream().forEach returns elements in the collection
608     */
609 jsr166 1.3 public void testStreamForEach() throws Throwable {
610 jsr166 1.1 final Collection c = impl.emptyCollection();
611     final AtomicLong count = new AtomicLong(0L);
612     final Object x = impl.makeElement(1);
613     final Object y = impl.makeElement(2);
614     final ArrayList found = new ArrayList();
615 jsr166 1.20 Consumer<Object> spy = o -> found.add(o);
616 jsr166 1.1 c.stream().forEach(spy);
617     assertTrue(found.isEmpty());
618    
619     assertTrue(c.add(x));
620     c.stream().forEach(spy);
621     assertEquals(Collections.singletonList(x), found);
622     found.clear();
623    
624     assertTrue(c.add(y));
625     c.stream().forEach(spy);
626     assertEquals(2, found.size());
627     assertTrue(found.contains(x));
628     assertTrue(found.contains(y));
629     found.clear();
630    
631     c.clear();
632     c.stream().forEach(spy);
633     assertTrue(found.isEmpty());
634     }
635    
636 jsr166 1.3 public void testStreamForEachConcurrentStressTest() throws Throwable {
637     if (!impl.isConcurrent()) return;
638     final Collection c = impl.emptyCollection();
639     final long testDurationMillis = timeoutMillis();
640     final AtomicBoolean done = new AtomicBoolean(false);
641     final Object elt = impl.makeElement(1);
642     final Future<?> f1, f2;
643     final ExecutorService pool = Executors.newCachedThreadPool();
644     try (PoolCleaner cleaner = cleaner(pool, done)) {
645     final CountDownLatch threadsStarted = new CountDownLatch(2);
646     Runnable checkElt = () -> {
647     threadsStarted.countDown();
648     while (!done.get())
649 jsr166 1.20 c.stream().forEach(x -> assertSame(x, elt)); };
650 jsr166 1.3 Runnable addRemove = () -> {
651     threadsStarted.countDown();
652     while (!done.get()) {
653     assertTrue(c.add(elt));
654     assertTrue(c.remove(elt));
655     }};
656     f1 = pool.submit(checkElt);
657     f2 = pool.submit(addRemove);
658     Thread.sleep(testDurationMillis);
659     }
660     assertNull(f1.get(0L, MILLISECONDS));
661     assertNull(f2.get(0L, MILLISECONDS));
662     }
663    
664     /**
665     * collection.forEach returns elements in the collection
666     */
667     public void testForEach() throws Throwable {
668     final Collection c = impl.emptyCollection();
669     final AtomicLong count = new AtomicLong(0L);
670     final Object x = impl.makeElement(1);
671     final Object y = impl.makeElement(2);
672     final ArrayList found = new ArrayList();
673 jsr166 1.20 Consumer<Object> spy = o -> found.add(o);
674 jsr166 1.3 c.forEach(spy);
675     assertTrue(found.isEmpty());
676    
677     assertTrue(c.add(x));
678     c.forEach(spy);
679     assertEquals(Collections.singletonList(x), found);
680     found.clear();
681    
682     assertTrue(c.add(y));
683     c.forEach(spy);
684     assertEquals(2, found.size());
685     assertTrue(found.contains(x));
686     assertTrue(found.contains(y));
687     found.clear();
688    
689     c.clear();
690     c.forEach(spy);
691     assertTrue(found.isEmpty());
692     }
693    
694 jsr166 1.38 /** TODO: promote to a common utility */
695     static <T> T chooseOne(T ... ts) {
696     return ts[ThreadLocalRandom.current().nextInt(ts.length)];
697     }
698    
699     /** TODO: more random adders and removers */
700     static <E> Runnable adderRemover(Collection<E> c, E e) {
701     return chooseOne(
702     () -> {
703     assertTrue(c.add(e));
704     assertTrue(c.contains(e));
705     assertTrue(c.remove(e));
706     assertFalse(c.contains(e));
707     },
708     () -> {
709     assertTrue(c.add(e));
710     assertTrue(c.contains(e));
711     assertTrue(c.removeIf(x -> x == e));
712     assertFalse(c.contains(e));
713     },
714     () -> {
715     assertTrue(c.add(e));
716     assertTrue(c.contains(e));
717     for (Iterator it = c.iterator();; )
718     if (it.next() == e) {
719     try { it.remove(); }
720     catch (UnsupportedOperationException ok) {
721     c.remove(e);
722     }
723     break;
724     }
725     assertFalse(c.contains(e));
726     });
727     }
728    
729 jsr166 1.26 /**
730 jsr166 1.45 * Concurrent Spliterators, once exhausted, stay exhausted.
731     */
732     public void testStickySpliteratorExhaustion() throws Throwable {
733     if (!impl.isConcurrent()) return;
734     if (!testImplementationDetails) return;
735     final ThreadLocalRandom rnd = ThreadLocalRandom.current();
736     final Consumer alwaysThrows = e -> { throw new AssertionError(); };
737     final Collection c = impl.emptyCollection();
738     final Spliterator s = c.spliterator();
739     if (rnd.nextBoolean()) {
740     assertFalse(s.tryAdvance(alwaysThrows));
741     } else {
742     s.forEachRemaining(alwaysThrows);
743     }
744     final Object one = impl.makeElement(1);
745     // Spliterator should not notice added element
746     c.add(one);
747     if (rnd.nextBoolean()) {
748     assertFalse(s.tryAdvance(alwaysThrows));
749     } else {
750     s.forEachRemaining(alwaysThrows);
751     }
752     }
753    
754     /**
755 jsr166 1.26 * Motley crew of threads concurrently randomly hammer the collection.
756     */
757     public void testDetectRaces() throws Throwable {
758 jsr166 1.1 if (!impl.isConcurrent()) return;
759 jsr166 1.26 final ThreadLocalRandom rnd = ThreadLocalRandom.current();
760 jsr166 1.1 final Collection c = impl.emptyCollection();
761 jsr166 1.34 final long testDurationMillis
762     = expensiveTests ? LONG_DELAY_MS : timeoutMillis();
763 jsr166 1.1 final AtomicBoolean done = new AtomicBoolean(false);
764 jsr166 1.26 final Object one = impl.makeElement(1);
765     final Object two = impl.makeElement(2);
766 jsr166 1.35 final Consumer checkSanity = x -> assertTrue(x == one || x == two);
767 jsr166 1.36 final Consumer<Object[]> checkArraySanity = array -> {
768 jsr166 1.37 // assertTrue(array.length <= 2); // duplicates are permitted
769 jsr166 1.36 for (Object x : array) assertTrue(x == one || x == two);
770     };
771 jsr166 1.29 final Object[] emptyArray =
772     (Object[]) java.lang.reflect.Array.newInstance(one.getClass(), 0);
773 jsr166 1.26 final List<Future<?>> futures;
774     final Phaser threadsStarted = new Phaser(1); // register this thread
775 jsr166 1.27 final Runnable[] frobbers = {
776 jsr166 1.32 () -> c.forEach(checkSanity),
777     () -> c.stream().forEach(checkSanity),
778     () -> c.parallelStream().forEach(checkSanity),
779 jsr166 1.26 () -> c.spliterator().trySplit(),
780     () -> {
781     Spliterator s = c.spliterator();
782 jsr166 1.32 s.tryAdvance(checkSanity);
783 jsr166 1.26 s.trySplit();
784     },
785     () -> {
786     Spliterator s = c.spliterator();
787 jsr166 1.32 do {} while (s.tryAdvance(checkSanity));
788 jsr166 1.29 },
789 jsr166 1.32 () -> { for (Object x : c) checkSanity.accept(x); },
790 jsr166 1.36 () -> checkArraySanity.accept(c.toArray()),
791     () -> checkArraySanity.accept(c.toArray(emptyArray)),
792 jsr166 1.29 () -> {
793 jsr166 1.38 Object[] a = new Object[5];
794     Object three = impl.makeElement(3);
795     Arrays.fill(a, 0, a.length, three);
796     Object[] x = c.toArray(a);
797     if (x == a)
798     for (int i = 0; i < a.length && a[i] != null; i++)
799     checkSanity.accept(a[i]);
800     // A careful reading of the spec does not support:
801     // for (i++; i < a.length; i++) assertSame(three, a[i]);
802     else
803     checkArraySanity.accept(x);
804     },
805     adderRemover(c, one),
806     adderRemover(c, two),
807 jsr166 1.27 };
808     final List<Runnable> tasks =
809     Arrays.stream(frobbers)
810 jsr166 1.26 .filter(task -> rnd.nextBoolean()) // random subset
811     .map(task -> (Runnable) () -> {
812     threadsStarted.arriveAndAwaitAdvance();
813     while (!done.get())
814     task.run();
815     })
816     .collect(Collectors.toList());
817 jsr166 1.2 final ExecutorService pool = Executors.newCachedThreadPool();
818     try (PoolCleaner cleaner = cleaner(pool, done)) {
819 jsr166 1.26 threadsStarted.bulkRegister(tasks.size());
820     futures = tasks.stream()
821 jsr166 1.28 .map(pool::submit)
822 jsr166 1.26 .collect(Collectors.toList());
823     threadsStarted.arriveAndDeregister();
824 jsr166 1.2 Thread.sleep(testDurationMillis);
825     }
826 jsr166 1.26 for (Future future : futures)
827     assertNull(future.get(0L, MILLISECONDS));
828 jsr166 1.1 }
829    
830 jsr166 1.30 /**
831     * Spliterators are either IMMUTABLE or truly late-binding or, if
832     * concurrent, use the same "late-binding style" of returning
833     * elements added between creation and first use.
834     */
835     public void testLateBindingStyle() {
836     if (!testImplementationDetails) return;
837 jsr166 1.31 if (impl.klazz() == ArrayList.class) return; // for jdk8
838 jsr166 1.30 // Immutable (snapshot) spliterators are exempt
839     if (impl.emptyCollection().spliterator()
840     .hasCharacteristics(Spliterator.IMMUTABLE))
841     return;
842     final Object one = impl.makeElement(1);
843     {
844     final Collection c = impl.emptyCollection();
845     final Spliterator split = c.spliterator();
846     c.add(one);
847     assertTrue(split.tryAdvance(e -> { assertSame(e, one); }));
848     assertFalse(split.tryAdvance(e -> { throw new AssertionError(); }));
849     assertTrue(c.contains(one));
850     }
851     {
852     final AtomicLong count = new AtomicLong(0);
853     final Collection c = impl.emptyCollection();
854     final Spliterator split = c.spliterator();
855     c.add(one);
856     split.forEachRemaining(
857     e -> { assertSame(e, one); count.getAndIncrement(); });
858     assertEquals(1L, count.get());
859     assertFalse(split.tryAdvance(e -> { throw new AssertionError(); }));
860     assertTrue(c.contains(one));
861     }
862     }
863    
864 jsr166 1.40 /**
865     * Spliterator.getComparator throws IllegalStateException iff the
866     * spliterator does not report SORTED.
867     */
868     public void testGetComparator_IllegalStateException() {
869     Collection c = impl.emptyCollection();
870     Spliterator s = c.spliterator();
871     boolean reportsSorted = s.hasCharacteristics(Spliterator.SORTED);
872     try {
873     s.getComparator();
874     assertTrue(reportsSorted);
875     } catch (IllegalStateException ex) {
876     assertFalse(reportsSorted);
877     }
878     }
879    
880 jsr166 1.4 // public void testCollection8DebugFail() {
881     // fail(impl.klazz().getSimpleName());
882     // }
883 jsr166 1.1 }