--- jsr166/src/test/tck/Collection8Test.java 2016/12/11 19:59:51 1.39 +++ jsr166/src/test/tck/Collection8Test.java 2016/12/26 19:54:46 1.45 @@ -12,6 +12,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.ConcurrentModificationException; import java.util.Deque; import java.util.HashSet; import java.util.Iterator; @@ -447,7 +448,7 @@ public class Collection8Test extends JSR /** * Various ways of traversing a collection yield same elements */ - public void testIteratorEquivalence() { + public void testTraversalEquivalence() { Collection c = impl.emptyCollection(); ThreadLocalRandom rnd = ThreadLocalRandom.current(); int n = rnd.nextInt(6); @@ -515,6 +516,43 @@ public class Collection8Test extends JSR } /** + * Iterator.forEachRemaining has same behavior as Iterator's + * default implementation. + */ + public void testForEachRemainingConsistentWithDefaultImplementation() { + Collection c = impl.emptyCollection(); + if (!testImplementationDetails + || c.getClass() == java.util.LinkedList.class) + return; + ThreadLocalRandom rnd = ThreadLocalRandom.current(); + int n = 1 + rnd.nextInt(3); + for (int i = 0; i < n; i++) c.add(impl.makeElement(i)); + ArrayList iterated = new ArrayList(); + ArrayList iteratedForEachRemaining = new ArrayList(); + Iterator it1 = c.iterator(); + Iterator it2 = c.iterator(); + assertTrue(it1.hasNext()); + assertTrue(it2.hasNext()); + c.clear(); + Object r1, r2; + try { + while (it1.hasNext()) iterated.add(it1.next()); + r1 = iterated; + } catch (ConcurrentModificationException ex) { + r1 = ConcurrentModificationException.class; + assertFalse(impl.isConcurrent()); + } + try { + it2.forEachRemaining(iteratedForEachRemaining::add); + r2 = iteratedForEachRemaining; + } catch (ConcurrentModificationException ex) { + r2 = ConcurrentModificationException.class; + assertFalse(impl.isConcurrent()); + } + assertEquals(r1, r2); + } + + /** * Calling Iterator#remove() after Iterator#forEachRemaining * should (maybe) remove last element */ @@ -689,6 +727,31 @@ public class Collection8Test extends JSR } /** + * Concurrent Spliterators, once exhausted, stay exhausted. + */ + public void testStickySpliteratorExhaustion() throws Throwable { + if (!impl.isConcurrent()) return; + if (!testImplementationDetails) return; + final ThreadLocalRandom rnd = ThreadLocalRandom.current(); + final Consumer alwaysThrows = e -> { throw new AssertionError(); }; + final Collection c = impl.emptyCollection(); + final Spliterator s = c.spliterator(); + if (rnd.nextBoolean()) { + assertFalse(s.tryAdvance(alwaysThrows)); + } else { + s.forEachRemaining(alwaysThrows); + } + final Object one = impl.makeElement(1); + // Spliterator should not notice added element + c.add(one); + if (rnd.nextBoolean()) { + assertFalse(s.tryAdvance(alwaysThrows)); + } else { + s.forEachRemaining(alwaysThrows); + } + } + + /** * Motley crew of threads concurrently randomly hammer the collection. */ public void testDetectRaces() throws Throwable { @@ -798,6 +861,22 @@ public class Collection8Test extends JSR } } + /** + * Spliterator.getComparator throws IllegalStateException iff the + * spliterator does not report SORTED. + */ + public void testGetComparator_IllegalStateException() { + Collection c = impl.emptyCollection(); + Spliterator s = c.spliterator(); + boolean reportsSorted = s.hasCharacteristics(Spliterator.SORTED); + try { + s.getComparator(); + assertTrue(reportsSorted); + } catch (IllegalStateException ex) { + assertFalse(reportsSorted); + } + } + // public void testCollection8DebugFail() { // fail(impl.klazz().getSimpleName()); // }