ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/Collection8Test.java
Revision: 1.48
Committed: Sat Mar 24 14:46:18 2018 UTC (6 years, 1 month ago) by jsr166
Branch: MAIN
Changes since 1.47: +27 -2 lines
Log Message:
add assertions for List

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