ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/Collection8Test.java
Revision: 1.56
Committed: Wed May 23 05:24:05 2018 UTC (5 years, 11 months ago) by jsr166
Branch: MAIN
Changes since 1.55: +1 -1 lines
Log Message:
8203662: remove increment of modCount from ArrayList and Vector replaceAll()

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