Collection8Test.java revision 16158:a15610e000ba
1/*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This code is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11 * version 2 for more details (a copy is included in the LICENSE file that
12 * accompanied this code).
13 *
14 * You should have received a copy of the GNU General Public License version
15 * 2 along with this work; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
19 * or visit www.oracle.com if you need additional information or have any
20 * questions.
21 */
22
23/*
24 * This file is available under and governed by the GNU General Public
25 * License version 2 only, as published by the Free Software Foundation.
26 * However, the following notice accompanied the original version of this
27 * file:
28 *
29 * Written by Doug Lea and Martin Buchholz with assistance from
30 * members of JCP JSR-166 Expert Group and released to the public
31 * domain, as explained at
32 * http://creativecommons.org/publicdomain/zero/1.0/
33 */
34
35import static java.util.concurrent.TimeUnit.HOURS;
36import static java.util.concurrent.TimeUnit.MILLISECONDS;
37
38import java.util.ArrayList;
39import java.util.Arrays;
40import java.util.Collection;
41import java.util.Collections;
42import java.util.Deque;
43import java.util.HashSet;
44import java.util.Iterator;
45import java.util.List;
46import java.util.NoSuchElementException;
47import java.util.Queue;
48import java.util.Spliterator;
49import java.util.concurrent.BlockingDeque;
50import java.util.concurrent.BlockingQueue;
51import java.util.concurrent.ConcurrentLinkedQueue;
52import java.util.concurrent.CountDownLatch;
53import java.util.concurrent.Executors;
54import java.util.concurrent.ExecutorService;
55import java.util.concurrent.Future;
56import java.util.concurrent.Phaser;
57import java.util.concurrent.ThreadLocalRandom;
58import java.util.concurrent.atomic.AtomicBoolean;
59import java.util.concurrent.atomic.AtomicLong;
60import java.util.concurrent.atomic.AtomicReference;
61import java.util.function.Consumer;
62import java.util.function.Predicate;
63import java.util.stream.Collectors;
64
65import junit.framework.Test;
66
67/**
68 * Contains tests applicable to all jdk8+ Collection implementations.
69 * An extension of CollectionTest.
70 */
71public class Collection8Test extends JSR166TestCase {
72    final CollectionImplementation impl;
73
74    /** Tests are parameterized by a Collection implementation. */
75    Collection8Test(CollectionImplementation impl, String methodName) {
76        super(methodName);
77        this.impl = impl;
78    }
79
80    public static Test testSuite(CollectionImplementation impl) {
81        return parameterizedTestSuite(Collection8Test.class,
82                                      CollectionImplementation.class,
83                                      impl);
84    }
85
86    Object bomb() {
87        return new Object() {
88                public boolean equals(Object x) { throw new AssertionError(); }
89                public int hashCode() { throw new AssertionError(); }
90            };
91    }
92
93    /** Checks properties of empty collections. */
94    public void testEmptyMeansEmpty() throws Throwable {
95        Collection c = impl.emptyCollection();
96        emptyMeansEmpty(c);
97
98        if (c instanceof java.io.Serializable) {
99            try {
100                emptyMeansEmpty(serialClonePossiblyFailing(c));
101            } catch (java.io.NotSerializableException ex) {
102                // excusable when we have a serializable wrapper around
103                // a non-serializable collection, as can happen with:
104                // Vector.subList() => wrapped AbstractList$RandomAccessSubList
105                if (testImplementationDetails
106                    && (! c.getClass().getName().matches(
107                                "java.util.Collections.*")))
108                    throw ex;
109            }
110        }
111
112        Collection clone = cloneableClone(c);
113        if (clone != null)
114            emptyMeansEmpty(clone);
115    }
116
117    void emptyMeansEmpty(Collection c) throws InterruptedException {
118        assertTrue(c.isEmpty());
119        assertEquals(0, c.size());
120        assertEquals("[]", c.toString());
121        {
122            Object[] a = c.toArray();
123            assertEquals(0, a.length);
124            assertSame(Object[].class, a.getClass());
125        }
126        {
127            Object[] a = new Object[0];
128            assertSame(a, c.toArray(a));
129        }
130        {
131            Integer[] a = new Integer[0];
132            assertSame(a, c.toArray(a));
133        }
134        {
135            Integer[] a = { 1, 2, 3};
136            assertSame(a, c.toArray(a));
137            assertNull(a[0]);
138            assertSame(2, a[1]);
139            assertSame(3, a[2]);
140        }
141        assertIteratorExhausted(c.iterator());
142        Consumer alwaysThrows = e -> { throw new AssertionError(); };
143        c.forEach(alwaysThrows);
144        c.iterator().forEachRemaining(alwaysThrows);
145        c.spliterator().forEachRemaining(alwaysThrows);
146        assertFalse(c.spliterator().tryAdvance(alwaysThrows));
147        if (c.spliterator().hasCharacteristics(Spliterator.SIZED))
148            assertEquals(0, c.spliterator().estimateSize());
149        assertFalse(c.contains(bomb()));
150        assertFalse(c.remove(bomb()));
151        if (c instanceof Queue) {
152            Queue q = (Queue) c;
153            assertNull(q.peek());
154            assertNull(q.poll());
155        }
156        if (c instanceof Deque) {
157            Deque d = (Deque) c;
158            assertNull(d.peekFirst());
159            assertNull(d.peekLast());
160            assertNull(d.pollFirst());
161            assertNull(d.pollLast());
162            assertIteratorExhausted(d.descendingIterator());
163            d.descendingIterator().forEachRemaining(alwaysThrows);
164            assertFalse(d.removeFirstOccurrence(bomb()));
165            assertFalse(d.removeLastOccurrence(bomb()));
166        }
167        if (c instanceof BlockingQueue) {
168            BlockingQueue q = (BlockingQueue) c;
169            assertNull(q.poll(0L, MILLISECONDS));
170        }
171        if (c instanceof BlockingDeque) {
172            BlockingDeque q = (BlockingDeque) c;
173            assertNull(q.pollFirst(0L, MILLISECONDS));
174            assertNull(q.pollLast(0L, MILLISECONDS));
175        }
176    }
177
178    public void testNullPointerExceptions() throws InterruptedException {
179        Collection c = impl.emptyCollection();
180        assertThrows(
181            NullPointerException.class,
182            () -> c.addAll(null),
183            () -> c.containsAll(null),
184            () -> c.retainAll(null),
185            () -> c.removeAll(null),
186            () -> c.removeIf(null),
187            () -> c.forEach(null),
188            () -> c.iterator().forEachRemaining(null),
189            () -> c.spliterator().forEachRemaining(null),
190            () -> c.spliterator().tryAdvance(null),
191            () -> c.toArray(null));
192
193        if (!impl.permitsNulls()) {
194            assertThrows(
195                NullPointerException.class,
196                () -> c.add(null));
197        }
198        if (!impl.permitsNulls() && c instanceof Queue) {
199            Queue q = (Queue) c;
200            assertThrows(
201                NullPointerException.class,
202                () -> q.offer(null));
203        }
204        if (!impl.permitsNulls() && c instanceof Deque) {
205            Deque d = (Deque) c;
206            assertThrows(
207                NullPointerException.class,
208                () -> d.addFirst(null),
209                () -> d.addLast(null),
210                () -> d.offerFirst(null),
211                () -> d.offerLast(null),
212                () -> d.push(null),
213                () -> d.descendingIterator().forEachRemaining(null));
214        }
215        if (c instanceof BlockingQueue) {
216            BlockingQueue q = (BlockingQueue) c;
217            assertThrows(
218                NullPointerException.class,
219                () -> {
220                    try { q.offer(null, 1L, HOURS); }
221                    catch (InterruptedException ex) {
222                        throw new AssertionError(ex);
223                    }},
224                () -> {
225                    try { q.put(null); }
226                    catch (InterruptedException ex) {
227                        throw new AssertionError(ex);
228                    }});
229        }
230        if (c instanceof BlockingDeque) {
231            BlockingDeque q = (BlockingDeque) c;
232            assertThrows(
233                NullPointerException.class,
234                () -> {
235                    try { q.offerFirst(null, 1L, HOURS); }
236                    catch (InterruptedException ex) {
237                        throw new AssertionError(ex);
238                    }},
239                () -> {
240                    try { q.offerLast(null, 1L, HOURS); }
241                    catch (InterruptedException ex) {
242                        throw new AssertionError(ex);
243                    }},
244                () -> {
245                    try { q.putFirst(null); }
246                    catch (InterruptedException ex) {
247                        throw new AssertionError(ex);
248                    }},
249                () -> {
250                    try { q.putLast(null); }
251                    catch (InterruptedException ex) {
252                        throw new AssertionError(ex);
253                    }});
254        }
255    }
256
257    public void testNoSuchElementExceptions() {
258        Collection c = impl.emptyCollection();
259        assertThrows(
260            NoSuchElementException.class,
261            () -> c.iterator().next());
262
263        if (c instanceof Queue) {
264            Queue q = (Queue) c;
265            assertThrows(
266                NoSuchElementException.class,
267                () -> q.element(),
268                () -> q.remove());
269        }
270        if (c instanceof Deque) {
271            Deque d = (Deque) c;
272            assertThrows(
273                NoSuchElementException.class,
274                () -> d.getFirst(),
275                () -> d.getLast(),
276                () -> d.removeFirst(),
277                () -> d.removeLast(),
278                () -> d.pop(),
279                () -> d.descendingIterator().next());
280        }
281    }
282
283    public void testRemoveIf() {
284        Collection c = impl.emptyCollection();
285        boolean ordered =
286            c.spliterator().hasCharacteristics(Spliterator.ORDERED);
287        ThreadLocalRandom rnd = ThreadLocalRandom.current();
288        int n = rnd.nextInt(6);
289        for (int i = 0; i < n; i++) c.add(impl.makeElement(i));
290        AtomicReference threwAt = new AtomicReference(null);
291        List orig = rnd.nextBoolean()
292            ? new ArrayList(c)
293            : Arrays.asList(c.toArray());
294
295        // Merely creating an iterator can change ArrayBlockingQueue behavior
296        Iterator it = rnd.nextBoolean() ? c.iterator() : null;
297
298        ArrayList survivors = new ArrayList();
299        ArrayList accepts = new ArrayList();
300        ArrayList rejects = new ArrayList();
301
302        Predicate randomPredicate = e -> {
303            assertNull(threwAt.get());
304            switch (rnd.nextInt(3)) {
305            case 0: accepts.add(e); return true;
306            case 1: rejects.add(e); return false;
307            case 2: threwAt.set(e); throw new ArithmeticException();
308            default: throw new AssertionError();
309            }
310        };
311        try {
312            try {
313                boolean modified = c.removeIf(randomPredicate);
314                assertNull(threwAt.get());
315                assertEquals(modified, accepts.size() > 0);
316                assertEquals(modified, rejects.size() != n);
317                assertEquals(accepts.size() + rejects.size(), n);
318                if (ordered) {
319                    assertEquals(rejects,
320                                 Arrays.asList(c.toArray()));
321                } else {
322                    assertEquals(new HashSet(rejects),
323                                 new HashSet(Arrays.asList(c.toArray())));
324                }
325            } catch (ArithmeticException ok) {
326                assertNotNull(threwAt.get());
327                assertTrue(c.contains(threwAt.get()));
328            }
329            if (it != null && impl.isConcurrent())
330                // check for weakly consistent iterator
331                while (it.hasNext()) assertTrue(orig.contains(it.next()));
332            switch (rnd.nextInt(4)) {
333            case 0: survivors.addAll(c); break;
334            case 1: survivors.addAll(Arrays.asList(c.toArray())); break;
335            case 2: c.forEach(survivors::add); break;
336            case 3: for (Object e : c) survivors.add(e); break;
337            }
338            assertTrue(orig.containsAll(accepts));
339            assertTrue(orig.containsAll(rejects));
340            assertTrue(orig.containsAll(survivors));
341            assertTrue(orig.containsAll(c));
342            assertTrue(c.containsAll(rejects));
343            assertTrue(c.containsAll(survivors));
344            assertTrue(survivors.containsAll(rejects));
345            if (threwAt.get() == null) {
346                assertEquals(n - accepts.size(), c.size());
347                for (Object x : accepts) assertFalse(c.contains(x));
348            } else {
349                // Two acceptable behaviors: entire removeIf call is one
350                // transaction, or each element processed is one transaction.
351                assertTrue(n == c.size() || n == c.size() + accepts.size());
352                int k = 0;
353                for (Object x : accepts) if (c.contains(x)) k++;
354                assertTrue(k == accepts.size() || k == 0);
355            }
356        } catch (Throwable ex) {
357            System.err.println(impl.klazz());
358            // c is at risk of corruption if we got here, so be lenient
359            try { System.err.printf("c=%s%n", c); }
360            catch (Throwable t) { t.printStackTrace(); }
361            System.err.printf("n=%d%n", n);
362            System.err.printf("orig=%s%n", orig);
363            System.err.printf("accepts=%s%n", accepts);
364            System.err.printf("rejects=%s%n", rejects);
365            System.err.printf("survivors=%s%n", survivors);
366            System.err.printf("threwAt=%s%n", threwAt.get());
367            throw ex;
368        }
369    }
370
371    /**
372     * Various ways of traversing a collection yield same elements
373     */
374    public void testIteratorEquivalence() {
375        Collection c = impl.emptyCollection();
376        ThreadLocalRandom rnd = ThreadLocalRandom.current();
377        int n = rnd.nextInt(6);
378        for (int i = 0; i < n; i++) c.add(impl.makeElement(i));
379        ArrayList iterated = new ArrayList();
380        ArrayList iteratedForEachRemaining = new ArrayList();
381        ArrayList tryAdvanced = new ArrayList();
382        ArrayList spliterated = new ArrayList();
383        ArrayList splitonced = new ArrayList();
384        ArrayList forEached = new ArrayList();
385        ArrayList streamForEached = new ArrayList();
386        ConcurrentLinkedQueue parallelStreamForEached = new ConcurrentLinkedQueue();
387        ArrayList removeIfed = new ArrayList();
388        for (Object x : c) iterated.add(x);
389        c.iterator().forEachRemaining(iteratedForEachRemaining::add);
390        for (Spliterator s = c.spliterator();
391             s.tryAdvance(tryAdvanced::add); ) {}
392        c.spliterator().forEachRemaining(spliterated::add);
393        {                       // trySplit returns "strict prefix"
394            Spliterator s1 = c.spliterator(), s2 = s1.trySplit();
395            if (s2 != null) s2.forEachRemaining(splitonced::add);
396            s1.forEachRemaining(splitonced::add);
397        }
398        c.forEach(forEached::add);
399        c.stream().forEach(streamForEached::add);
400        c.parallelStream().forEach(parallelStreamForEached::add);
401        c.removeIf(e -> { removeIfed.add(e); return false; });
402        boolean ordered =
403            c.spliterator().hasCharacteristics(Spliterator.ORDERED);
404        if (c instanceof List || c instanceof Deque)
405            assertTrue(ordered);
406        HashSet cset = new HashSet(c);
407        assertEquals(cset, new HashSet(parallelStreamForEached));
408        if (ordered) {
409            assertEquals(iterated, iteratedForEachRemaining);
410            assertEquals(iterated, tryAdvanced);
411            assertEquals(iterated, spliterated);
412            assertEquals(iterated, splitonced);
413            assertEquals(iterated, forEached);
414            assertEquals(iterated, streamForEached);
415            assertEquals(iterated, removeIfed);
416        } else {
417            assertEquals(cset, new HashSet(iterated));
418            assertEquals(cset, new HashSet(iteratedForEachRemaining));
419            assertEquals(cset, new HashSet(tryAdvanced));
420            assertEquals(cset, new HashSet(spliterated));
421            assertEquals(cset, new HashSet(splitonced));
422            assertEquals(cset, new HashSet(forEached));
423            assertEquals(cset, new HashSet(streamForEached));
424            assertEquals(cset, new HashSet(removeIfed));
425        }
426        if (c instanceof Deque) {
427            Deque d = (Deque) c;
428            ArrayList descending = new ArrayList();
429            ArrayList descendingForEachRemaining = new ArrayList();
430            for (Iterator it = d.descendingIterator(); it.hasNext(); )
431                descending.add(it.next());
432            d.descendingIterator().forEachRemaining(
433                e -> descendingForEachRemaining.add(e));
434            Collections.reverse(descending);
435            Collections.reverse(descendingForEachRemaining);
436            assertEquals(iterated, descending);
437            assertEquals(iterated, descendingForEachRemaining);
438        }
439    }
440
441    /**
442     * Calling Iterator#remove() after Iterator#forEachRemaining
443     * should (maybe) remove last element
444     */
445    public void testRemoveAfterForEachRemaining() {
446        Collection c = impl.emptyCollection();
447        ThreadLocalRandom rnd = ThreadLocalRandom.current();
448        testCollection: {
449            int n = 3 + rnd.nextInt(2);
450            for (int i = 0; i < n; i++) c.add(impl.makeElement(i));
451            Iterator it = c.iterator();
452            assertTrue(it.hasNext());
453            assertEquals(impl.makeElement(0), it.next());
454            assertTrue(it.hasNext());
455            assertEquals(impl.makeElement(1), it.next());
456            it.forEachRemaining(e -> assertTrue(c.contains(e)));
457            if (testImplementationDetails) {
458                if (c instanceof java.util.concurrent.ArrayBlockingQueue) {
459                    assertIteratorExhausted(it);
460                } else {
461                    try { it.remove(); }
462                    catch (UnsupportedOperationException ok) {
463                        break testCollection;
464                    }
465                    assertEquals(n - 1, c.size());
466                    for (int i = 0; i < n - 1; i++)
467                        assertTrue(c.contains(impl.makeElement(i)));
468                    assertFalse(c.contains(impl.makeElement(n - 1)));
469                }
470            }
471        }
472        if (c instanceof Deque) {
473            Deque d = (Deque) impl.emptyCollection();
474            int n = 3 + rnd.nextInt(2);
475            for (int i = 0; i < n; i++) d.add(impl.makeElement(i));
476            Iterator it = d.descendingIterator();
477            assertTrue(it.hasNext());
478            assertEquals(impl.makeElement(n - 1), it.next());
479            assertTrue(it.hasNext());
480            assertEquals(impl.makeElement(n - 2), it.next());
481            it.forEachRemaining(e -> assertTrue(c.contains(e)));
482            if (testImplementationDetails) {
483                it.remove();
484                assertEquals(n - 1, d.size());
485                for (int i = 1; i < n; i++)
486                    assertTrue(d.contains(impl.makeElement(i)));
487                assertFalse(d.contains(impl.makeElement(0)));
488            }
489        }
490    }
491
492    /**
493     * stream().forEach returns elements in the collection
494     */
495    public void testStreamForEach() throws Throwable {
496        final Collection c = impl.emptyCollection();
497        final AtomicLong count = new AtomicLong(0L);
498        final Object x = impl.makeElement(1);
499        final Object y = impl.makeElement(2);
500        final ArrayList found = new ArrayList();
501        Consumer<Object> spy = o -> found.add(o);
502        c.stream().forEach(spy);
503        assertTrue(found.isEmpty());
504
505        assertTrue(c.add(x));
506        c.stream().forEach(spy);
507        assertEquals(Collections.singletonList(x), found);
508        found.clear();
509
510        assertTrue(c.add(y));
511        c.stream().forEach(spy);
512        assertEquals(2, found.size());
513        assertTrue(found.contains(x));
514        assertTrue(found.contains(y));
515        found.clear();
516
517        c.clear();
518        c.stream().forEach(spy);
519        assertTrue(found.isEmpty());
520    }
521
522    public void testStreamForEachConcurrentStressTest() throws Throwable {
523        if (!impl.isConcurrent()) return;
524        final Collection c = impl.emptyCollection();
525        final long testDurationMillis = timeoutMillis();
526        final AtomicBoolean done = new AtomicBoolean(false);
527        final Object elt = impl.makeElement(1);
528        final Future<?> f1, f2;
529        final ExecutorService pool = Executors.newCachedThreadPool();
530        try (PoolCleaner cleaner = cleaner(pool, done)) {
531            final CountDownLatch threadsStarted = new CountDownLatch(2);
532            Runnable checkElt = () -> {
533                threadsStarted.countDown();
534                while (!done.get())
535                    c.stream().forEach(x -> assertSame(x, elt)); };
536            Runnable addRemove = () -> {
537                threadsStarted.countDown();
538                while (!done.get()) {
539                    assertTrue(c.add(elt));
540                    assertTrue(c.remove(elt));
541                }};
542            f1 = pool.submit(checkElt);
543            f2 = pool.submit(addRemove);
544            Thread.sleep(testDurationMillis);
545        }
546        assertNull(f1.get(0L, MILLISECONDS));
547        assertNull(f2.get(0L, MILLISECONDS));
548    }
549
550    /**
551     * collection.forEach returns elements in the collection
552     */
553    public void testForEach() throws Throwable {
554        final Collection c = impl.emptyCollection();
555        final AtomicLong count = new AtomicLong(0L);
556        final Object x = impl.makeElement(1);
557        final Object y = impl.makeElement(2);
558        final ArrayList found = new ArrayList();
559        Consumer<Object> spy = o -> found.add(o);
560        c.forEach(spy);
561        assertTrue(found.isEmpty());
562
563        assertTrue(c.add(x));
564        c.forEach(spy);
565        assertEquals(Collections.singletonList(x), found);
566        found.clear();
567
568        assertTrue(c.add(y));
569        c.forEach(spy);
570        assertEquals(2, found.size());
571        assertTrue(found.contains(x));
572        assertTrue(found.contains(y));
573        found.clear();
574
575        c.clear();
576        c.forEach(spy);
577        assertTrue(found.isEmpty());
578    }
579
580    /**
581     * Motley crew of threads concurrently randomly hammer the collection.
582     */
583    public void testDetectRaces() throws Throwable {
584        if (!impl.isConcurrent()) return;
585        final ThreadLocalRandom rnd = ThreadLocalRandom.current();
586        final Collection c = impl.emptyCollection();
587        final long testDurationMillis
588            = expensiveTests ? LONG_DELAY_MS : timeoutMillis();
589        final AtomicBoolean done = new AtomicBoolean(false);
590        final Object one = impl.makeElement(1);
591        final Object two = impl.makeElement(2);
592        final Consumer checkSanity = x -> assertTrue(x == one || x == two);
593        final Consumer<Object[]> checkArraySanity = array -> {
594            // assertTrue(array.length <= 2); // duplicates are permitted
595            for (Object x : array) assertTrue(x == one || x == two);
596        };
597        final Object[] emptyArray =
598            (Object[]) java.lang.reflect.Array.newInstance(one.getClass(), 0);
599        final List<Future<?>> futures;
600        final Phaser threadsStarted = new Phaser(1); // register this thread
601        final Runnable[] frobbers = {
602            () -> c.forEach(checkSanity),
603            () -> c.stream().forEach(checkSanity),
604            () -> c.parallelStream().forEach(checkSanity),
605            () -> c.spliterator().trySplit(),
606            () -> {
607                Spliterator s = c.spliterator();
608                s.tryAdvance(checkSanity);
609                s.trySplit();
610            },
611            () -> {
612                Spliterator s = c.spliterator();
613                do {} while (s.tryAdvance(checkSanity));
614            },
615            () -> { for (Object x : c) checkSanity.accept(x); },
616            () -> checkArraySanity.accept(c.toArray()),
617            () -> checkArraySanity.accept(c.toArray(emptyArray)),
618            () -> {
619                assertTrue(c.add(one));
620                assertTrue(c.contains(one));
621                assertTrue(c.remove(one));
622                assertFalse(c.contains(one));
623            },
624            () -> {
625                assertTrue(c.add(two));
626                assertTrue(c.contains(two));
627                assertTrue(c.remove(two));
628                assertFalse(c.contains(two));
629            },
630        };
631        final List<Runnable> tasks =
632            Arrays.stream(frobbers)
633            .filter(task -> rnd.nextBoolean()) // random subset
634            .map(task -> (Runnable) () -> {
635                     threadsStarted.arriveAndAwaitAdvance();
636                     while (!done.get())
637                         task.run();
638                 })
639            .collect(Collectors.toList());
640        final ExecutorService pool = Executors.newCachedThreadPool();
641        try (PoolCleaner cleaner = cleaner(pool, done)) {
642            threadsStarted.bulkRegister(tasks.size());
643            futures = tasks.stream()
644                .map(pool::submit)
645                .collect(Collectors.toList());
646            threadsStarted.arriveAndDeregister();
647            Thread.sleep(testDurationMillis);
648        }
649        for (Future future : futures)
650            assertNull(future.get(0L, MILLISECONDS));
651    }
652
653    /**
654     * Spliterators are either IMMUTABLE or truly late-binding or, if
655     * concurrent, use the same "late-binding style" of returning
656     * elements added between creation and first use.
657     */
658    public void testLateBindingStyle() {
659        if (!testImplementationDetails) return;
660        if (impl.klazz() == ArrayList.class) return; // for jdk8
661        // Immutable (snapshot) spliterators are exempt
662        if (impl.emptyCollection().spliterator()
663            .hasCharacteristics(Spliterator.IMMUTABLE))
664            return;
665        final Object one = impl.makeElement(1);
666        {
667            final Collection c = impl.emptyCollection();
668            final Spliterator split = c.spliterator();
669            c.add(one);
670            assertTrue(split.tryAdvance(e -> { assertSame(e, one); }));
671            assertFalse(split.tryAdvance(e -> { throw new AssertionError(); }));
672            assertTrue(c.contains(one));
673        }
674        {
675            final AtomicLong count = new AtomicLong(0);
676            final Collection c = impl.emptyCollection();
677            final Spliterator split = c.spliterator();
678            c.add(one);
679            split.forEachRemaining(
680                e -> { assertSame(e, one); count.getAndIncrement(); });
681            assertEquals(1L, count.get());
682            assertFalse(split.tryAdvance(e -> { throw new AssertionError(); }));
683            assertTrue(c.contains(one));
684        }
685    }
686
687//     public void testCollection8DebugFail() {
688//         fail(impl.klazz().getSimpleName());
689//     }
690}
691