ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/Collection8Test.java
Revision: 1.7
Committed: Mon Oct 31 20:08:40 2016 UTC (7 years, 6 months ago) by jsr166
Branch: MAIN
Changes since 1.6: +22 -19 lines
Log Message:
testRemoveIf: better diagnostics on failure

File Contents

# Content
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 import static java.util.concurrent.TimeUnit.MILLISECONDS;
9
10 import java.util.ArrayList;
11 import java.util.Collection;
12 import java.util.Collections;
13 import java.util.Deque;
14 import java.util.HashSet;
15 import java.util.Iterator;
16 import java.util.List;
17 import java.util.NoSuchElementException;
18 import java.util.Queue;
19 import java.util.Spliterator;
20 import java.util.concurrent.CountDownLatch;
21 import java.util.concurrent.Executors;
22 import java.util.concurrent.ExecutorService;
23 import java.util.concurrent.Future;
24 import java.util.concurrent.ThreadLocalRandom;
25 import java.util.concurrent.atomic.AtomicBoolean;
26 import java.util.concurrent.atomic.AtomicLong;
27 import java.util.concurrent.atomic.AtomicReference;
28 import java.util.function.Consumer;
29 import java.util.function.Predicate;
30
31 import junit.framework.Test;
32
33 /**
34 * Contains tests applicable to all jdk8+ Collection implementations.
35 * An extension of CollectionTest.
36 */
37 public class Collection8Test extends JSR166TestCase {
38 final CollectionImplementation impl;
39
40 /** Tests are parameterized by a Collection implementation. */
41 Collection8Test(CollectionImplementation impl, String methodName) {
42 super(methodName);
43 this.impl = impl;
44 }
45
46 public static Test testSuite(CollectionImplementation impl) {
47 return parameterizedTestSuite(Collection8Test.class,
48 CollectionImplementation.class,
49 impl);
50 }
51
52 /** Checks properties of empty collections. */
53 public void testEmptyMeansEmpty() {
54 Collection c = impl.emptyCollection();
55 assertTrue(c.isEmpty());
56 assertEquals(0, c.size());
57 assertEquals("[]", c.toString());
58 {
59 Object[] a = c.toArray();
60 assertEquals(0, a.length);
61 assertSame(Object[].class, a.getClass());
62 }
63 {
64 Object[] a = new Object[0];
65 assertSame(a, c.toArray(a));
66 }
67 {
68 Integer[] a = new Integer[0];
69 assertSame(a, c.toArray(a));
70 }
71 {
72 Integer[] a = { 1, 2, 3};
73 assertSame(a, c.toArray(a));
74 assertNull(a[0]);
75 assertSame(2, a[1]);
76 assertSame(3, a[2]);
77 }
78 assertIteratorExhausted(c.iterator());
79 Consumer alwaysThrows = (e) -> { throw new AssertionError(); };
80 c.forEach(alwaysThrows);
81 c.iterator().forEachRemaining(alwaysThrows);
82 c.spliterator().forEachRemaining(alwaysThrows);
83 assertFalse(c.spliterator().tryAdvance(alwaysThrows));
84 if (Queue.class.isAssignableFrom(impl.klazz())) {
85 Queue q = (Queue) c;
86 assertNull(q.peek());
87 assertNull(q.poll());
88 }
89 if (Deque.class.isAssignableFrom(impl.klazz())) {
90 Deque d = (Deque) c;
91 assertNull(d.peekFirst());
92 assertNull(d.peekLast());
93 assertNull(d.pollFirst());
94 assertNull(d.pollLast());
95 assertIteratorExhausted(d.descendingIterator());
96 }
97 }
98
99 public void testNullPointerExceptions() {
100 Collection c = impl.emptyCollection();
101 assertThrows(
102 NullPointerException.class,
103 () -> c.addAll(null),
104 () -> c.containsAll(null),
105 () -> c.retainAll(null),
106 () -> c.removeAll(null),
107 () -> c.removeIf(null),
108 () -> c.forEach(null),
109 () -> c.iterator().forEachRemaining(null),
110 () -> c.spliterator().forEachRemaining(null),
111 () -> c.spliterator().tryAdvance(null),
112 () -> c.toArray(null));
113
114 if (!impl.permitsNulls()) {
115 assertThrows(
116 NullPointerException.class,
117 () -> c.add(null));
118 }
119 if (!impl.permitsNulls()
120 && Queue.class.isAssignableFrom(impl.klazz())) {
121 Queue q = (Queue) c;
122 assertThrows(
123 NullPointerException.class,
124 () -> q.offer(null));
125 }
126 if (!impl.permitsNulls()
127 && Deque.class.isAssignableFrom(impl.klazz())) {
128 Deque d = (Deque) c;
129 assertThrows(
130 NullPointerException.class,
131 () -> d.addFirst(null),
132 () -> d.addLast(null),
133 () -> d.offerFirst(null),
134 () -> d.offerLast(null),
135 () -> d.push(null),
136 () -> d.descendingIterator().forEachRemaining(null));
137 }
138 }
139
140 public void testNoSuchElementExceptions() {
141 Collection c = impl.emptyCollection();
142 assertThrows(
143 NoSuchElementException.class,
144 () -> c.iterator().next());
145
146 if (Queue.class.isAssignableFrom(impl.klazz())) {
147 Queue q = (Queue) c;
148 assertThrows(
149 NoSuchElementException.class,
150 () -> q.element(),
151 () -> q.remove());
152 }
153 if (Deque.class.isAssignableFrom(impl.klazz())) {
154 Deque d = (Deque) c;
155 assertThrows(
156 NoSuchElementException.class,
157 () -> d.getFirst(),
158 () -> d.getLast(),
159 () -> d.removeFirst(),
160 () -> d.removeLast(),
161 () -> d.pop(),
162 () -> d.descendingIterator().next());
163 }
164 }
165
166 public void testRemoveIf() {
167 Collection c = impl.emptyCollection();
168 ThreadLocalRandom rnd = ThreadLocalRandom.current();
169 int n = rnd.nextInt(6);
170 for (int i = 0; i < n; i++) c.add(impl.makeElement(i));
171 AtomicReference threwAt = new AtomicReference(null);
172 ArrayList survivors = new ArrayList(c);
173 ArrayList accepts = new ArrayList();
174 ArrayList rejects = new ArrayList();
175 Predicate randomPredicate = (e) -> {
176 assertNull(threwAt.get());
177 switch (rnd.nextInt(3)) {
178 case 0: accepts.add(e); return true;
179 case 1: rejects.add(e); return false;
180 case 2: threwAt.set(e); throw new ArithmeticException();
181 default: throw new AssertionError();
182 }
183 };
184 try {
185 try {
186 boolean modified = c.removeIf(randomPredicate);
187 if (!modified) {
188 assertNull(threwAt.get());
189 assertEquals(n, rejects.size());
190 assertEquals(0, accepts.size());
191 }
192 } catch (ArithmeticException ok) {}
193 survivors.removeAll(accepts);
194 assertEquals(n - accepts.size(), c.size());
195 assertTrue(c.containsAll(survivors));
196 assertTrue(survivors.containsAll(rejects));
197 for (Object x : accepts) assertFalse(c.contains(x));
198 if (threwAt.get() == null)
199 assertEquals(accepts.size() + rejects.size(), n);
200 } catch (Throwable ex) {
201 System.err.println(impl.klazz());
202 System.err.printf("c=%s%n", c);
203 System.err.printf("n=%d%n", n);
204 System.err.printf("accepts=%s%n", accepts);
205 System.err.printf("rejects=%s%n", rejects);
206 System.err.println(survivors);
207 System.err.printf("threw=%s%n", threwAt.get());
208 throw ex;
209 }
210 }
211
212 /**
213 * Various ways of traversing a collection yield same elements
214 */
215 public void testIteratorEquivalence() {
216 Collection c = impl.emptyCollection();
217 ThreadLocalRandom rnd = ThreadLocalRandom.current();
218 int n = rnd.nextInt(6);
219 for (int i = 0; i < n; i++) c.add(impl.makeElement(i));
220 ArrayList iterated = new ArrayList();
221 ArrayList iteratedForEachRemaining = new ArrayList();
222 ArrayList spliterated = new ArrayList();
223 ArrayList foreached = new ArrayList();
224 for (Object x : c) iterated.add(x);
225 c.iterator().forEachRemaining(e -> iteratedForEachRemaining.add(e));
226 c.spliterator().forEachRemaining(e -> spliterated.add(e));
227 c.forEach(e -> foreached.add(e));
228 boolean ordered =
229 c.spliterator().hasCharacteristics(Spliterator.ORDERED);
230 if (c instanceof List || c instanceof Deque)
231 assertTrue(ordered);
232 if (ordered) {
233 assertEquals(iterated, iteratedForEachRemaining);
234 assertEquals(iterated, spliterated);
235 assertEquals(iterated, foreached);
236 } else {
237 HashSet cset = new HashSet(c);
238 assertEquals(cset, new HashSet(iterated));
239 assertEquals(cset, new HashSet(iteratedForEachRemaining));
240 assertEquals(cset, new HashSet(spliterated));
241 assertEquals(cset, new HashSet(foreached));
242 }
243 if (c instanceof Deque) {
244 Deque d = (Deque) c;
245 ArrayList descending = new ArrayList();
246 ArrayList descendingForEachRemaining = new ArrayList();
247 for (Iterator it = d.descendingIterator(); it.hasNext(); )
248 descending.add(it.next());
249 d.descendingIterator().forEachRemaining(
250 e -> descendingForEachRemaining.add(e));
251 Collections.reverse(descending);
252 Collections.reverse(descendingForEachRemaining);
253 assertEquals(iterated, descending);
254 assertEquals(iterated, descendingForEachRemaining);
255 }
256 }
257
258 /**
259 * Calling Iterator#remove() after Iterator#forEachRemaining
260 * should remove last element
261 */
262 public void testRemoveAfterForEachRemaining() {
263 Collection c = impl.emptyCollection();
264 ThreadLocalRandom rnd = ThreadLocalRandom.current();
265 {
266 int n = 3 + rnd.nextInt(2);
267 for (int i = 0; i < n; i++) c.add(impl.makeElement(i));
268 Iterator it = c.iterator();
269 assertTrue(it.hasNext());
270 assertEquals(impl.makeElement(0), it.next());
271 assertTrue(it.hasNext());
272 assertEquals(impl.makeElement(1), it.next());
273 it.forEachRemaining((e) -> {});
274 it.remove();
275 assertEquals(n - 1, c.size());
276 for (int i = 0; i < n - 1; i++)
277 assertTrue(c.contains(impl.makeElement(i)));
278 assertFalse(c.contains(impl.makeElement(n - 1)));
279 }
280 if (c instanceof Deque) {
281 Deque d = (Deque) impl.emptyCollection();
282 int n = 3 + rnd.nextInt(2);
283 for (int i = 0; i < n; i++) d.add(impl.makeElement(i));
284 Iterator it = d.descendingIterator();
285 assertTrue(it.hasNext());
286 assertEquals(impl.makeElement(n - 1), it.next());
287 assertTrue(it.hasNext());
288 assertEquals(impl.makeElement(n - 2), it.next());
289 it.forEachRemaining((e) -> {});
290 it.remove();
291 assertEquals(n - 1, d.size());
292 for (int i = 1; i < n; i++)
293 assertTrue(d.contains(impl.makeElement(i)));
294 assertFalse(d.contains(impl.makeElement(0)));
295 }
296 }
297
298 /**
299 * stream().forEach returns elements in the collection
300 */
301 public void testStreamForEach() throws Throwable {
302 final Collection c = impl.emptyCollection();
303 final AtomicLong count = new AtomicLong(0L);
304 final Object x = impl.makeElement(1);
305 final Object y = impl.makeElement(2);
306 final ArrayList found = new ArrayList();
307 Consumer<Object> spy = (o) -> { found.add(o); };
308 c.stream().forEach(spy);
309 assertTrue(found.isEmpty());
310
311 assertTrue(c.add(x));
312 c.stream().forEach(spy);
313 assertEquals(Collections.singletonList(x), found);
314 found.clear();
315
316 assertTrue(c.add(y));
317 c.stream().forEach(spy);
318 assertEquals(2, found.size());
319 assertTrue(found.contains(x));
320 assertTrue(found.contains(y));
321 found.clear();
322
323 c.clear();
324 c.stream().forEach(spy);
325 assertTrue(found.isEmpty());
326 }
327
328 public void testStreamForEachConcurrentStressTest() throws Throwable {
329 if (!impl.isConcurrent()) return;
330 final Collection c = impl.emptyCollection();
331 final long testDurationMillis = timeoutMillis();
332 final AtomicBoolean done = new AtomicBoolean(false);
333 final Object elt = impl.makeElement(1);
334 final Future<?> f1, f2;
335 final ExecutorService pool = Executors.newCachedThreadPool();
336 try (PoolCleaner cleaner = cleaner(pool, done)) {
337 final CountDownLatch threadsStarted = new CountDownLatch(2);
338 Runnable checkElt = () -> {
339 threadsStarted.countDown();
340 while (!done.get())
341 c.stream().forEach((x) -> { assertSame(x, elt); }); };
342 Runnable addRemove = () -> {
343 threadsStarted.countDown();
344 while (!done.get()) {
345 assertTrue(c.add(elt));
346 assertTrue(c.remove(elt));
347 }};
348 f1 = pool.submit(checkElt);
349 f2 = pool.submit(addRemove);
350 Thread.sleep(testDurationMillis);
351 }
352 assertNull(f1.get(0L, MILLISECONDS));
353 assertNull(f2.get(0L, MILLISECONDS));
354 }
355
356 /**
357 * collection.forEach returns elements in the collection
358 */
359 public void testForEach() throws Throwable {
360 final Collection c = impl.emptyCollection();
361 final AtomicLong count = new AtomicLong(0L);
362 final Object x = impl.makeElement(1);
363 final Object y = impl.makeElement(2);
364 final ArrayList found = new ArrayList();
365 Consumer<Object> spy = (o) -> { found.add(o); };
366 c.forEach(spy);
367 assertTrue(found.isEmpty());
368
369 assertTrue(c.add(x));
370 c.forEach(spy);
371 assertEquals(Collections.singletonList(x), found);
372 found.clear();
373
374 assertTrue(c.add(y));
375 c.forEach(spy);
376 assertEquals(2, found.size());
377 assertTrue(found.contains(x));
378 assertTrue(found.contains(y));
379 found.clear();
380
381 c.clear();
382 c.forEach(spy);
383 assertTrue(found.isEmpty());
384 }
385
386 public void testForEachConcurrentStressTest() throws Throwable {
387 if (!impl.isConcurrent()) return;
388 final Collection c = impl.emptyCollection();
389 final long testDurationMillis = timeoutMillis();
390 final AtomicBoolean done = new AtomicBoolean(false);
391 final Object elt = impl.makeElement(1);
392 final Future<?> f1, f2;
393 final ExecutorService pool = Executors.newCachedThreadPool();
394 try (PoolCleaner cleaner = cleaner(pool, done)) {
395 final CountDownLatch threadsStarted = new CountDownLatch(2);
396 Runnable checkElt = () -> {
397 threadsStarted.countDown();
398 while (!done.get())
399 c.forEach((x) -> { assertSame(x, elt); }); };
400 Runnable addRemove = () -> {
401 threadsStarted.countDown();
402 while (!done.get()) {
403 assertTrue(c.add(elt));
404 assertTrue(c.remove(elt));
405 }};
406 f1 = pool.submit(checkElt);
407 f2 = pool.submit(addRemove);
408 Thread.sleep(testDurationMillis);
409 }
410 assertNull(f1.get(0L, MILLISECONDS));
411 assertNull(f2.get(0L, MILLISECONDS));
412 }
413
414 // public void testCollection8DebugFail() {
415 // fail(impl.klazz().getSimpleName());
416 // }
417 }