ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/Collection8Test.java
Revision: 1.8
Committed: Thu Nov 3 15:31:25 2016 UTC (7 years, 6 months ago) by jsr166
Branch: MAIN
Changes since 1.7: +2 -1 lines
Log Message:
improve testRemoveIf

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 assertFalse(survivors.contains(null));
186 try {
187 boolean modified = c.removeIf(randomPredicate);
188 if (!modified) {
189 assertNull(threwAt.get());
190 assertEquals(n, rejects.size());
191 assertEquals(0, accepts.size());
192 }
193 } catch (ArithmeticException ok) {}
194 survivors.removeAll(accepts);
195 assertEquals(n - accepts.size(), c.size());
196 assertTrue(c.containsAll(survivors));
197 assertTrue(survivors.containsAll(rejects));
198 for (Object x : accepts) assertFalse(c.contains(x));
199 if (threwAt.get() == null)
200 assertEquals(accepts.size() + rejects.size(), n);
201 } catch (Throwable ex) {
202 System.err.println(impl.klazz());
203 System.err.printf("c=%s%n", c);
204 System.err.printf("n=%d%n", n);
205 System.err.printf("accepts=%s%n", accepts);
206 System.err.printf("rejects=%s%n", rejects);
207 System.err.printf("survivors=%s%n", survivors);
208 System.err.printf("threw=%s%n", threwAt.get());
209 throw ex;
210 }
211 }
212
213 /**
214 * Various ways of traversing a collection yield same elements
215 */
216 public void testIteratorEquivalence() {
217 Collection c = impl.emptyCollection();
218 ThreadLocalRandom rnd = ThreadLocalRandom.current();
219 int n = rnd.nextInt(6);
220 for (int i = 0; i < n; i++) c.add(impl.makeElement(i));
221 ArrayList iterated = new ArrayList();
222 ArrayList iteratedForEachRemaining = new ArrayList();
223 ArrayList spliterated = new ArrayList();
224 ArrayList foreached = new ArrayList();
225 for (Object x : c) iterated.add(x);
226 c.iterator().forEachRemaining(e -> iteratedForEachRemaining.add(e));
227 c.spliterator().forEachRemaining(e -> spliterated.add(e));
228 c.forEach(e -> foreached.add(e));
229 boolean ordered =
230 c.spliterator().hasCharacteristics(Spliterator.ORDERED);
231 if (c instanceof List || c instanceof Deque)
232 assertTrue(ordered);
233 if (ordered) {
234 assertEquals(iterated, iteratedForEachRemaining);
235 assertEquals(iterated, spliterated);
236 assertEquals(iterated, foreached);
237 } else {
238 HashSet cset = new HashSet(c);
239 assertEquals(cset, new HashSet(iterated));
240 assertEquals(cset, new HashSet(iteratedForEachRemaining));
241 assertEquals(cset, new HashSet(spliterated));
242 assertEquals(cset, new HashSet(foreached));
243 }
244 if (c instanceof Deque) {
245 Deque d = (Deque) c;
246 ArrayList descending = new ArrayList();
247 ArrayList descendingForEachRemaining = new ArrayList();
248 for (Iterator it = d.descendingIterator(); it.hasNext(); )
249 descending.add(it.next());
250 d.descendingIterator().forEachRemaining(
251 e -> descendingForEachRemaining.add(e));
252 Collections.reverse(descending);
253 Collections.reverse(descendingForEachRemaining);
254 assertEquals(iterated, descending);
255 assertEquals(iterated, descendingForEachRemaining);
256 }
257 }
258
259 /**
260 * Calling Iterator#remove() after Iterator#forEachRemaining
261 * should remove last element
262 */
263 public void testRemoveAfterForEachRemaining() {
264 Collection c = impl.emptyCollection();
265 ThreadLocalRandom rnd = ThreadLocalRandom.current();
266 {
267 int n = 3 + rnd.nextInt(2);
268 for (int i = 0; i < n; i++) c.add(impl.makeElement(i));
269 Iterator it = c.iterator();
270 assertTrue(it.hasNext());
271 assertEquals(impl.makeElement(0), it.next());
272 assertTrue(it.hasNext());
273 assertEquals(impl.makeElement(1), it.next());
274 it.forEachRemaining((e) -> {});
275 it.remove();
276 assertEquals(n - 1, c.size());
277 for (int i = 0; i < n - 1; i++)
278 assertTrue(c.contains(impl.makeElement(i)));
279 assertFalse(c.contains(impl.makeElement(n - 1)));
280 }
281 if (c instanceof Deque) {
282 Deque d = (Deque) impl.emptyCollection();
283 int n = 3 + rnd.nextInt(2);
284 for (int i = 0; i < n; i++) d.add(impl.makeElement(i));
285 Iterator it = d.descendingIterator();
286 assertTrue(it.hasNext());
287 assertEquals(impl.makeElement(n - 1), it.next());
288 assertTrue(it.hasNext());
289 assertEquals(impl.makeElement(n - 2), it.next());
290 it.forEachRemaining((e) -> {});
291 it.remove();
292 assertEquals(n - 1, d.size());
293 for (int i = 1; i < n; i++)
294 assertTrue(d.contains(impl.makeElement(i)));
295 assertFalse(d.contains(impl.makeElement(0)));
296 }
297 }
298
299 /**
300 * stream().forEach returns elements in the collection
301 */
302 public void testStreamForEach() throws Throwable {
303 final Collection c = impl.emptyCollection();
304 final AtomicLong count = new AtomicLong(0L);
305 final Object x = impl.makeElement(1);
306 final Object y = impl.makeElement(2);
307 final ArrayList found = new ArrayList();
308 Consumer<Object> spy = (o) -> { found.add(o); };
309 c.stream().forEach(spy);
310 assertTrue(found.isEmpty());
311
312 assertTrue(c.add(x));
313 c.stream().forEach(spy);
314 assertEquals(Collections.singletonList(x), found);
315 found.clear();
316
317 assertTrue(c.add(y));
318 c.stream().forEach(spy);
319 assertEquals(2, found.size());
320 assertTrue(found.contains(x));
321 assertTrue(found.contains(y));
322 found.clear();
323
324 c.clear();
325 c.stream().forEach(spy);
326 assertTrue(found.isEmpty());
327 }
328
329 public void testStreamForEachConcurrentStressTest() throws Throwable {
330 if (!impl.isConcurrent()) return;
331 final Collection c = impl.emptyCollection();
332 final long testDurationMillis = timeoutMillis();
333 final AtomicBoolean done = new AtomicBoolean(false);
334 final Object elt = impl.makeElement(1);
335 final Future<?> f1, f2;
336 final ExecutorService pool = Executors.newCachedThreadPool();
337 try (PoolCleaner cleaner = cleaner(pool, done)) {
338 final CountDownLatch threadsStarted = new CountDownLatch(2);
339 Runnable checkElt = () -> {
340 threadsStarted.countDown();
341 while (!done.get())
342 c.stream().forEach((x) -> { assertSame(x, elt); }); };
343 Runnable addRemove = () -> {
344 threadsStarted.countDown();
345 while (!done.get()) {
346 assertTrue(c.add(elt));
347 assertTrue(c.remove(elt));
348 }};
349 f1 = pool.submit(checkElt);
350 f2 = pool.submit(addRemove);
351 Thread.sleep(testDurationMillis);
352 }
353 assertNull(f1.get(0L, MILLISECONDS));
354 assertNull(f2.get(0L, MILLISECONDS));
355 }
356
357 /**
358 * collection.forEach returns elements in the collection
359 */
360 public void testForEach() throws Throwable {
361 final Collection c = impl.emptyCollection();
362 final AtomicLong count = new AtomicLong(0L);
363 final Object x = impl.makeElement(1);
364 final Object y = impl.makeElement(2);
365 final ArrayList found = new ArrayList();
366 Consumer<Object> spy = (o) -> { found.add(o); };
367 c.forEach(spy);
368 assertTrue(found.isEmpty());
369
370 assertTrue(c.add(x));
371 c.forEach(spy);
372 assertEquals(Collections.singletonList(x), found);
373 found.clear();
374
375 assertTrue(c.add(y));
376 c.forEach(spy);
377 assertEquals(2, found.size());
378 assertTrue(found.contains(x));
379 assertTrue(found.contains(y));
380 found.clear();
381
382 c.clear();
383 c.forEach(spy);
384 assertTrue(found.isEmpty());
385 }
386
387 public void testForEachConcurrentStressTest() throws Throwable {
388 if (!impl.isConcurrent()) return;
389 final Collection c = impl.emptyCollection();
390 final long testDurationMillis = timeoutMillis();
391 final AtomicBoolean done = new AtomicBoolean(false);
392 final Object elt = impl.makeElement(1);
393 final Future<?> f1, f2;
394 final ExecutorService pool = Executors.newCachedThreadPool();
395 try (PoolCleaner cleaner = cleaner(pool, done)) {
396 final CountDownLatch threadsStarted = new CountDownLatch(2);
397 Runnable checkElt = () -> {
398 threadsStarted.countDown();
399 while (!done.get())
400 c.forEach((x) -> { assertSame(x, elt); }); };
401 Runnable addRemove = () -> {
402 threadsStarted.countDown();
403 while (!done.get()) {
404 assertTrue(c.add(elt));
405 assertTrue(c.remove(elt));
406 }};
407 f1 = pool.submit(checkElt);
408 f2 = pool.submit(addRemove);
409 Thread.sleep(testDurationMillis);
410 }
411 assertNull(f1.get(0L, MILLISECONDS));
412 assertNull(f2.get(0L, MILLISECONDS));
413 }
414
415 // public void testCollection8DebugFail() {
416 // fail(impl.klazz().getSimpleName());
417 // }
418 }