--- jsr166/src/test/tck/Collection8Test.java 2016/10/31 20:08:40 1.7 +++ jsr166/src/test/tck/Collection8Test.java 2016/11/13 02:10:10 1.22 @@ -5,9 +5,11 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ +import static java.util.concurrent.TimeUnit.HOURS; import static java.util.concurrent.TimeUnit.MILLISECONDS; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Deque; @@ -17,6 +19,8 @@ import java.util.List; import java.util.NoSuchElementException; import java.util.Queue; import java.util.Spliterator; +import java.util.concurrent.BlockingDeque; +import java.util.concurrent.BlockingQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; @@ -49,9 +53,27 @@ public class Collection8Test extends JSR impl); } + Object bomb() { + return new Object() { + public boolean equals(Object x) { throw new AssertionError(); } + public int hashCode() { throw new AssertionError(); } + }; + } + /** Checks properties of empty collections. */ - public void testEmptyMeansEmpty() { + public void testEmptyMeansEmpty() throws InterruptedException { Collection c = impl.emptyCollection(); + emptyMeansEmpty(c); + + if (c instanceof java.io.Serializable) + emptyMeansEmpty(serialClone(c)); + + Collection clone = cloneableClone(c); + if (clone != null) + emptyMeansEmpty(clone); + } + + void emptyMeansEmpty(Collection c) throws InterruptedException { assertTrue(c.isEmpty()); assertEquals(0, c.size()); assertEquals("[]", c.toString()); @@ -76,27 +98,43 @@ public class Collection8Test extends JSR assertSame(3, a[2]); } assertIteratorExhausted(c.iterator()); - Consumer alwaysThrows = (e) -> { throw new AssertionError(); }; + Consumer alwaysThrows = e -> { throw new AssertionError(); }; c.forEach(alwaysThrows); c.iterator().forEachRemaining(alwaysThrows); c.spliterator().forEachRemaining(alwaysThrows); assertFalse(c.spliterator().tryAdvance(alwaysThrows)); - if (Queue.class.isAssignableFrom(impl.klazz())) { + if (c.spliterator().hasCharacteristics(Spliterator.SIZED)) + assertEquals(0, c.spliterator().estimateSize()); + assertFalse(c.contains(bomb())); + assertFalse(c.remove(bomb())); + if (c instanceof Queue) { Queue q = (Queue) c; assertNull(q.peek()); assertNull(q.poll()); } - if (Deque.class.isAssignableFrom(impl.klazz())) { + if (c instanceof Deque) { Deque d = (Deque) c; assertNull(d.peekFirst()); assertNull(d.peekLast()); assertNull(d.pollFirst()); assertNull(d.pollLast()); assertIteratorExhausted(d.descendingIterator()); + d.descendingIterator().forEachRemaining(alwaysThrows); + assertFalse(d.removeFirstOccurrence(bomb())); + assertFalse(d.removeLastOccurrence(bomb())); + } + if (c instanceof BlockingQueue) { + BlockingQueue q = (BlockingQueue) c; + assertNull(q.poll(0L, MILLISECONDS)); + } + if (c instanceof BlockingDeque) { + BlockingDeque q = (BlockingDeque) c; + assertNull(q.pollFirst(0L, MILLISECONDS)); + assertNull(q.pollLast(0L, MILLISECONDS)); } } - public void testNullPointerExceptions() { + public void testNullPointerExceptions() throws InterruptedException { Collection c = impl.emptyCollection(); assertThrows( NullPointerException.class, @@ -116,15 +154,13 @@ public class Collection8Test extends JSR NullPointerException.class, () -> c.add(null)); } - if (!impl.permitsNulls() - && Queue.class.isAssignableFrom(impl.klazz())) { + if (!impl.permitsNulls() && c instanceof Queue) { Queue q = (Queue) c; assertThrows( NullPointerException.class, () -> q.offer(null)); } - if (!impl.permitsNulls() - && Deque.class.isAssignableFrom(impl.klazz())) { + if (!impl.permitsNulls() && c instanceof Deque) { Deque d = (Deque) c; assertThrows( NullPointerException.class, @@ -135,6 +171,46 @@ public class Collection8Test extends JSR () -> d.push(null), () -> d.descendingIterator().forEachRemaining(null)); } + if (c instanceof BlockingQueue) { + BlockingQueue q = (BlockingQueue) c; + assertThrows( + NullPointerException.class, + () -> { + try { q.offer(null, 1L, HOURS); } + catch (InterruptedException ex) { + throw new AssertionError(ex); + }}, + () -> { + try { q.put(null); } + catch (InterruptedException ex) { + throw new AssertionError(ex); + }}); + } + if (c instanceof BlockingDeque) { + BlockingDeque q = (BlockingDeque) c; + assertThrows( + NullPointerException.class, + () -> { + try { q.offerFirst(null, 1L, HOURS); } + catch (InterruptedException ex) { + throw new AssertionError(ex); + }}, + () -> { + try { q.offerLast(null, 1L, HOURS); } + catch (InterruptedException ex) { + throw new AssertionError(ex); + }}, + () -> { + try { q.putFirst(null); } + catch (InterruptedException ex) { + throw new AssertionError(ex); + }}, + () -> { + try { q.putLast(null); } + catch (InterruptedException ex) { + throw new AssertionError(ex); + }}); + } } public void testNoSuchElementExceptions() { @@ -143,14 +219,14 @@ public class Collection8Test extends JSR NoSuchElementException.class, () -> c.iterator().next()); - if (Queue.class.isAssignableFrom(impl.klazz())) { + if (c instanceof Queue) { Queue q = (Queue) c; assertThrows( NoSuchElementException.class, () -> q.element(), () -> q.remove()); } - if (Deque.class.isAssignableFrom(impl.klazz())) { + if (c instanceof Deque) { Deque d = (Deque) c; assertThrows( NoSuchElementException.class, @@ -165,14 +241,24 @@ public class Collection8Test extends JSR public void testRemoveIf() { Collection c = impl.emptyCollection(); + boolean ordered = + c.spliterator().hasCharacteristics(Spliterator.ORDERED); ThreadLocalRandom rnd = ThreadLocalRandom.current(); int n = rnd.nextInt(6); for (int i = 0; i < n; i++) c.add(impl.makeElement(i)); AtomicReference threwAt = new AtomicReference(null); - ArrayList survivors = new ArrayList(c); + List orig = rnd.nextBoolean() + ? new ArrayList(c) + : Arrays.asList(c.toArray()); + + // Merely creating an iterator can change ArrayBlockingQueue behavior + Iterator it = rnd.nextBoolean() ? c.iterator() : null; + + ArrayList survivors = new ArrayList(); ArrayList accepts = new ArrayList(); ArrayList rejects = new ArrayList(); - Predicate randomPredicate = (e) -> { + + Predicate randomPredicate = e -> { assertNull(threwAt.get()); switch (rnd.nextInt(3)) { case 0: accepts.add(e); return true; @@ -184,27 +270,57 @@ public class Collection8Test extends JSR try { try { boolean modified = c.removeIf(randomPredicate); - if (!modified) { - assertNull(threwAt.get()); - assertEquals(n, rejects.size()); - assertEquals(0, accepts.size()); + assertNull(threwAt.get()); + assertEquals(modified, accepts.size() > 0); + assertEquals(modified, rejects.size() != n); + assertEquals(accepts.size() + rejects.size(), n); + if (ordered) { + assertEquals(rejects, + Arrays.asList(c.toArray())); + } else { + assertEquals(new HashSet(rejects), + new HashSet(Arrays.asList(c.toArray()))); } - } catch (ArithmeticException ok) {} - survivors.removeAll(accepts); - assertEquals(n - accepts.size(), c.size()); + } catch (ArithmeticException ok) { + assertNotNull(threwAt.get()); + assertTrue(c.contains(threwAt.get())); + } + if (it != null && impl.isConcurrent()) + // check for weakly consistent iterator + while (it.hasNext()) assertTrue(orig.contains(it.next())); + switch (rnd.nextInt(4)) { + case 0: survivors.addAll(c); break; + case 1: survivors.addAll(Arrays.asList(c.toArray())); break; + case 2: c.forEach(e -> survivors.add(e)); break; + case 3: for (Object e : c) survivors.add(e); break; + } + assertTrue(orig.containsAll(accepts)); + assertTrue(orig.containsAll(rejects)); + assertTrue(orig.containsAll(survivors)); + assertTrue(orig.containsAll(c)); + assertTrue(c.containsAll(rejects)); assertTrue(c.containsAll(survivors)); assertTrue(survivors.containsAll(rejects)); - for (Object x : accepts) assertFalse(c.contains(x)); - if (threwAt.get() == null) - assertEquals(accepts.size() + rejects.size(), n); + if (threwAt.get() == null) { + assertEquals(n - accepts.size(), c.size()); + for (Object x : accepts) assertFalse(c.contains(x)); + } else { + // Two acceptable behaviors: entire removeIf call is one + // transaction, or each element processed is one transaction. + assertTrue(n == c.size() || n == c.size() + accepts.size()); + int k = 0; + for (Object x : accepts) if (c.contains(x)) k++; + assertTrue(k == accepts.size() || k == 0); + } } catch (Throwable ex) { System.err.println(impl.klazz()); System.err.printf("c=%s%n", c); System.err.printf("n=%d%n", n); + System.err.printf("orig=%s%n", orig); System.err.printf("accepts=%s%n", accepts); System.err.printf("rejects=%s%n", rejects); - System.err.println(survivors); - System.err.printf("threw=%s%n", threwAt.get()); + System.err.printf("survivors=%s%n", survivors); + System.err.printf("threwAt=%s%n", threwAt.get()); throw ex; } } @@ -219,26 +335,35 @@ public class Collection8Test extends JSR for (int i = 0; i < n; i++) c.add(impl.makeElement(i)); ArrayList iterated = new ArrayList(); ArrayList iteratedForEachRemaining = new ArrayList(); + ArrayList tryAdvanced = new ArrayList(); ArrayList spliterated = new ArrayList(); - ArrayList foreached = new ArrayList(); + ArrayList forEached = new ArrayList(); + ArrayList removeIfed = new ArrayList(); for (Object x : c) iterated.add(x); c.iterator().forEachRemaining(e -> iteratedForEachRemaining.add(e)); + for (Spliterator s = c.spliterator(); + s.tryAdvance(e -> tryAdvanced.add(e)); ) {} c.spliterator().forEachRemaining(e -> spliterated.add(e)); - c.forEach(e -> foreached.add(e)); + c.forEach(e -> forEached.add(e)); + c.removeIf(e -> { removeIfed.add(e); return false; }); boolean ordered = c.spliterator().hasCharacteristics(Spliterator.ORDERED); if (c instanceof List || c instanceof Deque) assertTrue(ordered); if (ordered) { assertEquals(iterated, iteratedForEachRemaining); + assertEquals(iterated, tryAdvanced); assertEquals(iterated, spliterated); - assertEquals(iterated, foreached); + assertEquals(iterated, forEached); + assertEquals(iterated, removeIfed); } else { HashSet cset = new HashSet(c); assertEquals(cset, new HashSet(iterated)); assertEquals(cset, new HashSet(iteratedForEachRemaining)); + assertEquals(cset, new HashSet(tryAdvanced)); assertEquals(cset, new HashSet(spliterated)); - assertEquals(cset, new HashSet(foreached)); + assertEquals(cset, new HashSet(forEached)); + assertEquals(cset, new HashSet(removeIfed)); } if (c instanceof Deque) { Deque d = (Deque) c; @@ -257,7 +382,7 @@ public class Collection8Test extends JSR /** * Calling Iterator#remove() after Iterator#forEachRemaining - * should remove last element + * should (maybe) remove last element */ public void testRemoveAfterForEachRemaining() { Collection c = impl.emptyCollection(); @@ -270,12 +395,18 @@ public class Collection8Test extends JSR assertEquals(impl.makeElement(0), it.next()); assertTrue(it.hasNext()); assertEquals(impl.makeElement(1), it.next()); - it.forEachRemaining((e) -> {}); - it.remove(); - assertEquals(n - 1, c.size()); - for (int i = 0; i < n - 1; i++) - assertTrue(c.contains(impl.makeElement(i))); - assertFalse(c.contains(impl.makeElement(n - 1))); + it.forEachRemaining(e -> assertTrue(c.contains(e))); + if (testImplementationDetails) { + if (c instanceof java.util.concurrent.ArrayBlockingQueue) { + assertIteratorExhausted(it); + } else { + it.remove(); + assertEquals(n - 1, c.size()); + for (int i = 0; i < n - 1; i++) + assertTrue(c.contains(impl.makeElement(i))); + assertFalse(c.contains(impl.makeElement(n - 1))); + } + } } if (c instanceof Deque) { Deque d = (Deque) impl.emptyCollection(); @@ -286,12 +417,14 @@ public class Collection8Test extends JSR assertEquals(impl.makeElement(n - 1), it.next()); assertTrue(it.hasNext()); assertEquals(impl.makeElement(n - 2), it.next()); - it.forEachRemaining((e) -> {}); - it.remove(); - assertEquals(n - 1, d.size()); - for (int i = 1; i < n; i++) - assertTrue(d.contains(impl.makeElement(i))); - assertFalse(d.contains(impl.makeElement(0))); + it.forEachRemaining(e -> assertTrue(c.contains(e))); + if (testImplementationDetails) { + it.remove(); + assertEquals(n - 1, d.size()); + for (int i = 1; i < n; i++) + assertTrue(d.contains(impl.makeElement(i))); + assertFalse(d.contains(impl.makeElement(0))); + } } } @@ -304,7 +437,7 @@ public class Collection8Test extends JSR final Object x = impl.makeElement(1); final Object y = impl.makeElement(2); final ArrayList found = new ArrayList(); - Consumer spy = (o) -> { found.add(o); }; + Consumer spy = o -> found.add(o); c.stream().forEach(spy); assertTrue(found.isEmpty()); @@ -338,7 +471,7 @@ public class Collection8Test extends JSR Runnable checkElt = () -> { threadsStarted.countDown(); while (!done.get()) - c.stream().forEach((x) -> { assertSame(x, elt); }); }; + c.stream().forEach(x -> assertSame(x, elt)); }; Runnable addRemove = () -> { threadsStarted.countDown(); while (!done.get()) { @@ -362,7 +495,7 @@ public class Collection8Test extends JSR final Object x = impl.makeElement(1); final Object y = impl.makeElement(2); final ArrayList found = new ArrayList(); - Consumer spy = (o) -> { found.add(o); }; + Consumer spy = o -> found.add(o); c.forEach(spy); assertTrue(found.isEmpty()); @@ -396,7 +529,7 @@ public class Collection8Test extends JSR Runnable checkElt = () -> { threadsStarted.countDown(); while (!done.get()) - c.forEach((x) -> { assertSame(x, elt); }); }; + c.forEach(x -> assertSame(x, elt)); }; Runnable addRemove = () -> { threadsStarted.countDown(); while (!done.get()) {