ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/Collection8Test.java
Revision: 1.49
Committed: Mon Mar 26 21:06:51 2018 UTC (6 years, 1 month ago) by jsr166
Branch: MAIN
Changes since 1.48: +4 -0 lines
Log Message:
emptyMeansEmpty: more List assertions

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