summaryrefslogtreecommitdiffstats
path: root/jsr166-tests
diff options
context:
space:
mode:
authorCalin Juravle <calin@google.com>2013-08-01 17:26:00 +0100
committerCalin Juravle <calin@google.com>2013-08-14 19:15:59 +0100
commit8f0d92bba199d906c70a5e40d7f3516c1a424117 (patch)
tree3762e8e4275ac7535ce011915fb0e0f7a343deea /jsr166-tests
parent75a06e56a4cc4599946e21422513e4bafa759509 (diff)
downloadlibcore-8f0d92bba199d906c70a5e40d7f3516c1a424117.zip
libcore-8f0d92bba199d906c70a5e40d7f3516c1a424117.tar.gz
libcore-8f0d92bba199d906c70a5e40d7f3516c1a424117.tar.bz2
Added jsr166 tck tests as part of the libcore testsuite.
Change-Id: I6094d734f818fa043f2b277cf2b4ec7fec68e26e
Diffstat (limited to 'jsr166-tests')
-rw-r--r--jsr166-tests/src/test/java/jsr166/AbstractExecutorServiceTest.java604
-rw-r--r--jsr166-tests/src/test/java/jsr166/AbstractQueueTest.java172
-rw-r--r--jsr166-tests/src/test/java/jsr166/AbstractQueuedLongSynchronizerTest.java1209
-rw-r--r--jsr166-tests/src/test/java/jsr166/AbstractQueuedSynchronizerTest.java1212
-rw-r--r--jsr166-tests/src/test/java/jsr166/ArrayBlockingQueueTest.java891
-rw-r--r--jsr166-tests/src/test/java/jsr166/ArrayDequeTest.java888
-rw-r--r--jsr166-tests/src/test/java/jsr166/AtomicBooleanTest.java136
-rw-r--r--jsr166-tests/src/test/java/jsr166/AtomicIntegerArrayTest.java337
-rw-r--r--jsr166-tests/src/test/java/jsr166/AtomicIntegerFieldUpdaterTest.java232
-rw-r--r--jsr166-tests/src/test/java/jsr166/AtomicIntegerTest.java261
-rw-r--r--jsr166-tests/src/test/java/jsr166/AtomicLongArrayTest.java337
-rw-r--r--jsr166-tests/src/test/java/jsr166/AtomicLongFieldUpdaterTest.java232
-rw-r--r--jsr166-tests/src/test/java/jsr166/AtomicLongTest.java264
-rw-r--r--jsr166-tests/src/test/java/jsr166/AtomicMarkableReferenceTest.java147
-rw-r--r--jsr166-tests/src/test/java/jsr166/AtomicReferenceArrayTest.java213
-rw-r--r--jsr166-tests/src/test/java/jsr166/AtomicReferenceFieldUpdaterTest.java160
-rw-r--r--jsr166-tests/src/test/java/jsr166/AtomicReferenceTest.java137
-rw-r--r--jsr166-tests/src/test/java/jsr166/AtomicStampedReferenceTest.java147
-rw-r--r--jsr166-tests/src/test/java/jsr166/BlockingQueueTest.java366
-rw-r--r--jsr166-tests/src/test/java/jsr166/ConcurrentHashMapTest.java686
-rw-r--r--jsr166-tests/src/test/java/jsr166/ConcurrentLinkedDequeTest.java858
-rw-r--r--jsr166-tests/src/test/java/jsr166/ConcurrentLinkedQueueTest.java511
-rw-r--r--jsr166-tests/src/test/java/jsr166/ConcurrentSkipListMapTest.java1263
-rw-r--r--jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSetTest.java982
-rw-r--r--jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubMapTest.java1410
-rw-r--r--jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubSetTest.java1123
-rw-r--r--jsr166-tests/src/test/java/jsr166/CopyOnWriteArrayListTest.java705
-rw-r--r--jsr166-tests/src/test/java/jsr166/CopyOnWriteArraySetTest.java359
-rw-r--r--jsr166-tests/src/test/java/jsr166/CountDownLatchTest.java190
-rw-r--r--jsr166-tests/src/test/java/jsr166/CountedCompleterTest.java1821
-rw-r--r--jsr166-tests/src/test/java/jsr166/CyclicBarrierTest.java458
-rw-r--r--jsr166-tests/src/test/java/jsr166/DelayQueueTest.java767
-rw-r--r--jsr166-tests/src/test/java/jsr166/EntryTest.java123
-rw-r--r--jsr166-tests/src/test/java/jsr166/ExchangerTest.java146
-rw-r--r--jsr166-tests/src/test/java/jsr166/ExecutorCompletionServiceTest.java221
-rw-r--r--jsr166-tests/src/test/java/jsr166/ExecutorsTest.java585
-rw-r--r--jsr166-tests/src/test/java/jsr166/ForkJoinPoolTest.java996
-rw-r--r--jsr166-tests/src/test/java/jsr166/ForkJoinTaskTest.java1605
-rw-r--r--jsr166-tests/src/test/java/jsr166/FutureTaskTest.java799
-rw-r--r--jsr166-tests/src/test/java/jsr166/JSR166TestCase.java1140
-rw-r--r--jsr166-tests/src/test/java/jsr166/LinkedBlockingDequeTest.java1769
-rw-r--r--jsr166-tests/src/test/java/jsr166/LinkedBlockingQueueTest.java824
-rw-r--r--jsr166-tests/src/test/java/jsr166/LinkedListTest.java627
-rw-r--r--jsr166-tests/src/test/java/jsr166/LinkedTransferQueueTest.java1009
-rw-r--r--jsr166-tests/src/test/java/jsr166/LockSupportTest.java362
-rw-r--r--jsr166-tests/src/test/java/jsr166/PhaserTest.java786
-rw-r--r--jsr166-tests/src/test/java/jsr166/PriorityBlockingQueueTest.java711
-rw-r--r--jsr166-tests/src/test/java/jsr166/PriorityQueueTest.java492
-rw-r--r--jsr166-tests/src/test/java/jsr166/RecursiveActionTest.java1237
-rw-r--r--jsr166-tests/src/test/java/jsr166/RecursiveTaskTest.java1020
-rw-r--r--jsr166-tests/src/test/java/jsr166/ReentrantLockTest.java1133
-rw-r--r--jsr166-tests/src/test/java/jsr166/ReentrantReadWriteLockTest.java1670
-rw-r--r--jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java1213
-rw-r--r--jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java1164
-rw-r--r--jsr166-tests/src/test/java/jsr166/SemaphoreTest.java629
-rw-r--r--jsr166-tests/src/test/java/jsr166/SynchronousQueueTest.java601
-rw-r--r--jsr166-tests/src/test/java/jsr166/SystemTest.java63
-rw-r--r--jsr166-tests/src/test/java/jsr166/ThreadLocalRandomTest.java290
-rw-r--r--jsr166-tests/src/test/java/jsr166/ThreadLocalTest.java96
-rw-r--r--jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorSubclassTest.java1769
-rw-r--r--jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorTest.java2010
-rw-r--r--jsr166-tests/src/test/java/jsr166/ThreadTest.java65
-rw-r--r--jsr166-tests/src/test/java/jsr166/TimeUnitTest.java457
-rw-r--r--jsr166-tests/src/test/java/jsr166/TreeMapTest.java1068
-rw-r--r--jsr166-tests/src/test/java/jsr166/TreeSetTest.java985
-rw-r--r--jsr166-tests/src/test/java/jsr166/TreeSubMapTest.java1097
-rw-r--r--jsr166-tests/src/test/java/jsr166/TreeSubSetTest.java1116
67 files changed, 48956 insertions, 0 deletions
diff --git a/jsr166-tests/src/test/java/jsr166/AbstractExecutorServiceTest.java b/jsr166-tests/src/test/java/jsr166/AbstractExecutorServiceTest.java
new file mode 100644
index 0000000..ba4cc66
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/AbstractExecutorServiceTest.java
@@ -0,0 +1,604 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicBoolean;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import java.security.*;
+
+public class AbstractExecutorServiceTest extends JSR166TestCase {
+
+ /**
+ * A no-frills implementation of AbstractExecutorService, designed
+ * to test the submit methods only.
+ */
+ static class DirectExecutorService extends AbstractExecutorService {
+ public void execute(Runnable r) { r.run(); }
+ public void shutdown() { shutdown = true; }
+ public List<Runnable> shutdownNow() {
+ shutdown = true;
+ return Collections.EMPTY_LIST;
+ }
+ public boolean isShutdown() { return shutdown; }
+ public boolean isTerminated() { return isShutdown(); }
+ public boolean awaitTermination(long timeout, TimeUnit unit) {
+ return isShutdown();
+ }
+ private volatile boolean shutdown = false;
+ }
+
+ /**
+ * execute(runnable) runs it to completion
+ */
+ public void testExecuteRunnable() throws Exception {
+ ExecutorService e = new DirectExecutorService();
+ final AtomicBoolean done = new AtomicBoolean(false);
+ CheckedRunnable task = new CheckedRunnable() {
+ public void realRun() {
+ done.set(true);
+ }};
+ Future<?> future = e.submit(task);
+ assertNull(future.get());
+ assertNull(future.get(0, MILLISECONDS));
+ assertTrue(done.get());
+ assertTrue(future.isDone());
+ assertFalse(future.isCancelled());
+ }
+
+ /**
+ * Completed submit(callable) returns result
+ */
+ public void testSubmitCallable() throws Exception {
+ ExecutorService e = new DirectExecutorService();
+ Future<String> future = e.submit(new StringTask());
+ String result = future.get();
+ assertSame(TEST_STRING, result);
+ }
+
+ /**
+ * Completed submit(runnable) returns successfully
+ */
+ public void testSubmitRunnable() throws Exception {
+ ExecutorService e = new DirectExecutorService();
+ Future<?> future = e.submit(new NoOpRunnable());
+ future.get();
+ assertTrue(future.isDone());
+ }
+
+ /**
+ * Completed submit(runnable, result) returns result
+ */
+ public void testSubmitRunnable2() throws Exception {
+ ExecutorService e = new DirectExecutorService();
+ Future<String> future = e.submit(new NoOpRunnable(), TEST_STRING);
+ String result = future.get();
+ assertSame(TEST_STRING, result);
+ }
+
+ /**
+ * A submitted privileged action runs to completion
+ */
+ public void testSubmitPrivilegedAction() throws Exception {
+ Runnable r = new CheckedRunnable() {
+ public void realRun() throws Exception {
+ ExecutorService e = new DirectExecutorService();
+ Future future = e.submit(Executors.callable(new PrivilegedAction() {
+ public Object run() {
+ return TEST_STRING;
+ }}));
+
+ assertSame(TEST_STRING, future.get());
+ }};
+
+ runWithPermissions(r,
+ new RuntimePermission("getClassLoader"),
+ new RuntimePermission("setContextClassLoader"),
+ new RuntimePermission("modifyThread"));
+ }
+
+ /**
+ * A submitted privileged exception action runs to completion
+ */
+ public void testSubmitPrivilegedExceptionAction() throws Exception {
+ Runnable r = new CheckedRunnable() {
+ public void realRun() throws Exception {
+ ExecutorService e = new DirectExecutorService();
+ Future future = e.submit(Executors.callable(new PrivilegedExceptionAction() {
+ public Object run() {
+ return TEST_STRING;
+ }}));
+
+ assertSame(TEST_STRING, future.get());
+ }};
+
+ runWithPermissions(r);
+ }
+
+ /**
+ * A submitted failed privileged exception action reports exception
+ */
+ public void testSubmitFailedPrivilegedExceptionAction() throws Exception {
+ Runnable r = new CheckedRunnable() {
+ public void realRun() throws Exception {
+ ExecutorService e = new DirectExecutorService();
+ Future future = e.submit(Executors.callable(new PrivilegedExceptionAction() {
+ public Object run() throws Exception {
+ throw new IndexOutOfBoundsException();
+ }}));
+
+ try {
+ future.get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof IndexOutOfBoundsException);
+ }}};
+
+ runWithPermissions(r);
+ }
+
+ /**
+ * execute(null runnable) throws NPE
+ */
+ public void testExecuteNullRunnable() {
+ try {
+ ExecutorService e = new DirectExecutorService();
+ e.submit((Runnable) null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * submit(null callable) throws NPE
+ */
+ public void testSubmitNullCallable() {
+ try {
+ ExecutorService e = new DirectExecutorService();
+ e.submit((Callable) null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * submit(callable).get() throws InterruptedException if interrupted
+ */
+ public void testInterruptedSubmit() throws InterruptedException {
+ final CountDownLatch submitted = new CountDownLatch(1);
+ final CountDownLatch quittingTime = new CountDownLatch(1);
+ final ExecutorService p
+ = new ThreadPoolExecutor(1,1,60, TimeUnit.SECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ final Callable<Void> awaiter = new CheckedCallable<Void>() {
+ public Void realCall() throws InterruptedException {
+ quittingTime.await();
+ return null;
+ }};
+ try {
+ Thread t = new Thread(new CheckedInterruptedRunnable() {
+ public void realRun() throws Exception {
+ Future<Void> future = p.submit(awaiter);
+ submitted.countDown();
+ future.get();
+ }});
+ t.start();
+ submitted.await();
+ t.interrupt();
+ t.join();
+ } finally {
+ quittingTime.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * get of submit(callable) throws ExecutionException if callable
+ * throws exception
+ */
+ public void testSubmitEE() throws InterruptedException {
+ ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 1,
+ 60, TimeUnit.SECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+
+ Callable c = new Callable() {
+ public Object call() { throw new ArithmeticException(); }};
+
+ try {
+ p.submit(c).get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof ArithmeticException);
+ }
+ joinPool(p);
+ }
+
+ /**
+ * invokeAny(null) throws NPE
+ */
+ public void testInvokeAny1() throws Exception {
+ ExecutorService e = new DirectExecutorService();
+ try {
+ e.invokeAny(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(empty collection) throws IAE
+ */
+ public void testInvokeAny2() throws Exception {
+ ExecutorService e = new DirectExecutorService();
+ try {
+ e.invokeAny(new ArrayList<Callable<String>>());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(c) throws NPE if c has null elements
+ */
+ public void testInvokeAny3() throws Exception {
+ ExecutorService e = new DirectExecutorService();
+ List<Callable<Long>> l = new ArrayList<Callable<Long>>();
+ l.add(new Callable<Long>() {
+ public Long call() { throw new ArithmeticException(); }});
+ l.add(null);
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(c) throws ExecutionException if no task in c completes
+ */
+ public void testInvokeAny4() throws InterruptedException {
+ ExecutorService e = new DirectExecutorService();
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(c) returns result of some task in c if at least one completes
+ */
+ public void testInvokeAny5() throws Exception {
+ ExecutorService e = new DirectExecutorService();
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(new StringTask());
+ String result = e.invokeAny(l);
+ assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAll(null) throws NPE
+ */
+ public void testInvokeAll1() throws InterruptedException {
+ ExecutorService e = new DirectExecutorService();
+ try {
+ e.invokeAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAll(empty collection) returns empty collection
+ */
+ public void testInvokeAll2() throws InterruptedException {
+ ExecutorService e = new DirectExecutorService();
+ try {
+ List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>());
+ assertTrue(r.isEmpty());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAll(c) throws NPE if c has null elements
+ */
+ public void testInvokeAll3() throws InterruptedException {
+ ExecutorService e = new DirectExecutorService();
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(null);
+ try {
+ e.invokeAll(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * get of returned element of invokeAll(c) throws exception on failed task
+ */
+ public void testInvokeAll4() throws Exception {
+ ExecutorService e = new DirectExecutorService();
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ List<Future<String>> futures = e.invokeAll(l);
+ assertEquals(1, futures.size());
+ try {
+ futures.get(0).get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ }
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAll(c) returns results of all completed tasks in c
+ */
+ public void testInvokeAll5() throws Exception {
+ ExecutorService e = new DirectExecutorService();
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(new StringTask());
+ List<Future<String>> futures = e.invokeAll(l);
+ assertEquals(2, futures.size());
+ for (Future<String> future : futures)
+ assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(null) throws NPE
+ */
+ public void testTimedInvokeAny1() throws Exception {
+ ExecutorService e = new DirectExecutorService();
+ try {
+ e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(null time unit) throws NPE
+ */
+ public void testTimedInvokeAnyNullTimeUnit() throws Exception {
+ ExecutorService e = new DirectExecutorService();
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(empty collection) throws IAE
+ */
+ public void testTimedInvokeAny2() throws Exception {
+ ExecutorService e = new DirectExecutorService();
+ try {
+ e.invokeAny(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(c) throws NPE if c has null elements
+ */
+ public void testTimedInvokeAny3() throws Exception {
+ ExecutorService e = new DirectExecutorService();
+ List<Callable<Long>> l = new ArrayList<Callable<Long>>();
+ l.add(new Callable<Long>() {
+ public Long call() { throw new ArithmeticException(); }});
+ l.add(null);
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(c) throws ExecutionException if no task completes
+ */
+ public void testTimedInvokeAny4() throws Exception {
+ ExecutorService e = new DirectExecutorService();
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(c) returns result of some task in c
+ */
+ public void testTimedInvokeAny5() throws Exception {
+ ExecutorService e = new DirectExecutorService();
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(new StringTask());
+ String result = e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(null) throws NPE
+ */
+ public void testTimedInvokeAll1() throws InterruptedException {
+ ExecutorService e = new DirectExecutorService();
+ try {
+ e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(null time unit) throws NPE
+ */
+ public void testTimedInvokeAllNullTimeUnit() throws InterruptedException {
+ ExecutorService e = new DirectExecutorService();
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ try {
+ e.invokeAll(l, MEDIUM_DELAY_MS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(empty collection) returns empty collection
+ */
+ public void testTimedInvokeAll2() throws InterruptedException {
+ ExecutorService e = new DirectExecutorService();
+ try {
+ List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
+ assertTrue(r.isEmpty());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(c) throws NPE if c has null elements
+ */
+ public void testTimedInvokeAll3() throws InterruptedException {
+ ExecutorService e = new DirectExecutorService();
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(null);
+ try {
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * get of returned element of invokeAll(c) throws exception on failed task
+ */
+ public void testTimedInvokeAll4() throws Exception {
+ ExecutorService e = new DirectExecutorService();
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ List<Future<String>> futures =
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ assertEquals(1, futures.size());
+ try {
+ futures.get(0).get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ }
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(c) returns results of all completed tasks in c
+ */
+ public void testTimedInvokeAll5() throws Exception {
+ ExecutorService e = new DirectExecutorService();
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(new StringTask());
+ List<Future<String>> futures =
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ assertEquals(2, futures.size());
+ for (Future<String> future : futures)
+ assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll cancels tasks not completed by timeout
+ */
+ public void testTimedInvokeAll6() throws InterruptedException {
+ ExecutorService e = new DirectExecutorService();
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(Executors.callable(possiblyInterruptedRunnable(2 * SHORT_DELAY_MS), TEST_STRING));
+ l.add(new StringTask());
+ List<Future<String>> futures =
+ e.invokeAll(l, SHORT_DELAY_MS, MILLISECONDS);
+ assertEquals(l.size(), futures.size());
+ for (Future future : futures)
+ assertTrue(future.isDone());
+ assertFalse(futures.get(0).isCancelled());
+ assertFalse(futures.get(1).isCancelled());
+ assertTrue(futures.get(2).isCancelled());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/AbstractQueueTest.java b/jsr166-tests/src/test/java/jsr166/AbstractQueueTest.java
new file mode 100644
index 0000000..e74fc3c
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/AbstractQueueTest.java
@@ -0,0 +1,172 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.AbstractQueue;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+public class AbstractQueueTest extends JSR166TestCase {
+
+ static class Succeed extends AbstractQueue<Integer> {
+ public boolean offer(Integer x) {
+ if (x == null) throw new NullPointerException();
+ return true;
+ }
+ public Integer peek() { return one; }
+ public Integer poll() { return one; }
+ public int size() { return 0; }
+ public Iterator iterator() { return null; } // not needed
+ }
+
+ static class Fail extends AbstractQueue<Integer> {
+ public boolean offer(Integer x) {
+ if (x == null) throw new NullPointerException();
+ return false;
+ }
+ public Integer peek() { return null; }
+ public Integer poll() { return null; }
+ public int size() { return 0; }
+ public Iterator iterator() { return null; } // not needed
+ }
+
+ /**
+ * add returns true if offer succeeds
+ */
+ public void testAddS() {
+ Succeed q = new Succeed();
+ assertTrue(q.add(two));
+ }
+
+ /**
+ * add throws ISE true if offer fails
+ */
+ public void testAddF() {
+ Fail q = new Fail();
+ try {
+ q.add(one);
+ shouldThrow();
+ } catch (IllegalStateException success) {}
+ }
+
+ /**
+ * add throws NPE if offer does
+ */
+ public void testAddNPE() {
+ Succeed q = new Succeed();
+ try {
+ q.add(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * remove returns normally if poll succeeds
+ */
+ public void testRemoveS() {
+ Succeed q = new Succeed();
+ q.remove();
+ }
+
+ /**
+ * remove throws NSEE if poll returns null
+ */
+ public void testRemoveF() {
+ Fail q = new Fail();
+ try {
+ q.remove();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * element returns normally if peek succeeds
+ */
+ public void testElementS() {
+ Succeed q = new Succeed();
+ q.element();
+ }
+
+ /**
+ * element throws NSEE if peek returns null
+ */
+ public void testElementF() {
+ Fail q = new Fail();
+ try {
+ q.element();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * addAll(null) throws NPE
+ */
+ public void testAddAll1() {
+ try {
+ Succeed q = new Succeed();
+ q.addAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll(this) throws IAE
+ */
+ public void testAddAllSelf() {
+ try {
+ Succeed q = new Succeed();
+ q.addAll(q);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * addAll of a collection with null elements throws NPE
+ */
+ public void testAddAll2() {
+ try {
+ Succeed q = new Succeed();
+ Integer[] ints = new Integer[SIZE];
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll of a collection with any null elements throws NPE after
+ * possibly adding some elements
+ */
+ public void testAddAll3() {
+ try {
+ Succeed q = new Succeed();
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll throws ISE if an add fails
+ */
+ public void testAddAll4() {
+ try {
+ Fail q = new Fail();
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(i);
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (IllegalStateException success) {}
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/AbstractQueuedLongSynchronizerTest.java b/jsr166-tests/src/test/java/jsr166/AbstractQueuedLongSynchronizerTest.java
new file mode 100644
index 0000000..d957e61
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/AbstractQueuedLongSynchronizerTest.java
@@ -0,0 +1,1209 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.*;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import java.util.concurrent.locks.AbstractQueuedLongSynchronizer;
+import java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject;
+
+public class AbstractQueuedLongSynchronizerTest extends JSR166TestCase {
+
+ /**
+ * A simple mutex class, adapted from the class javadoc. Exclusive
+ * acquire tests exercise this as a sample user extension.
+ */
+ static class Mutex extends AbstractQueuedLongSynchronizer {
+ /** An eccentric value > 32 bits for locked synchronizer state. */
+ static final long LOCKED = (1L << 63) | (1L << 15);
+
+ static final long UNLOCKED = 0;
+
+ public boolean isHeldExclusively() {
+ long state = getState();
+ assertTrue(state == UNLOCKED || state == LOCKED);
+ return state == LOCKED;
+ }
+
+ public boolean tryAcquire(long acquires) {
+ assertEquals(LOCKED, acquires);
+ return compareAndSetState(UNLOCKED, LOCKED);
+ }
+
+ public boolean tryRelease(long releases) {
+ if (getState() != LOCKED) throw new IllegalMonitorStateException();
+ setState(UNLOCKED);
+ return true;
+ }
+
+ public boolean tryAcquireNanos(long nanos) throws InterruptedException {
+ return tryAcquireNanos(LOCKED, nanos);
+ }
+
+ public boolean tryAcquire() {
+ return tryAcquire(LOCKED);
+ }
+
+ public boolean tryRelease() {
+ return tryRelease(LOCKED);
+ }
+
+ public void acquire() {
+ acquire(LOCKED);
+ }
+
+ public void acquireInterruptibly() throws InterruptedException {
+ acquireInterruptibly(LOCKED);
+ }
+
+ public void release() {
+ release(LOCKED);
+ }
+
+ public ConditionObject newCondition() {
+ return new ConditionObject();
+ }
+ }
+
+ /**
+ * A simple latch class, to test shared mode.
+ */
+ static class BooleanLatch extends AbstractQueuedLongSynchronizer {
+ public boolean isSignalled() { return getState() != 0; }
+
+ public long tryAcquireShared(long ignore) {
+ return isSignalled() ? 1 : -1;
+ }
+
+ public boolean tryReleaseShared(long ignore) {
+ setState(1 << 62);
+ return true;
+ }
+ }
+
+ /**
+ * A runnable calling acquireInterruptibly that does not expect to
+ * be interrupted.
+ */
+ class InterruptibleSyncRunnable extends CheckedRunnable {
+ final Mutex sync;
+ InterruptibleSyncRunnable(Mutex sync) { this.sync = sync; }
+ public void realRun() throws InterruptedException {
+ sync.acquireInterruptibly();
+ }
+ }
+
+ /**
+ * A runnable calling acquireInterruptibly that expects to be
+ * interrupted.
+ */
+ class InterruptedSyncRunnable extends CheckedInterruptedRunnable {
+ final Mutex sync;
+ InterruptedSyncRunnable(Mutex sync) { this.sync = sync; }
+ public void realRun() throws InterruptedException {
+ sync.acquireInterruptibly();
+ }
+ }
+
+ /** A constant to clarify calls to checking methods below. */
+ static final Thread[] NO_THREADS = new Thread[0];
+
+ /**
+ * Spin-waits until sync.isQueued(t) becomes true.
+ */
+ void waitForQueuedThread(AbstractQueuedLongSynchronizer sync,
+ Thread t) {
+ long startTime = System.nanoTime();
+ while (!sync.isQueued(t)) {
+ if (millisElapsedSince(startTime) > LONG_DELAY_MS)
+ throw new AssertionFailedError("timed out");
+ Thread.yield();
+ }
+ assertTrue(t.isAlive());
+ }
+
+ /**
+ * Checks that sync has exactly the given queued threads.
+ */
+ void assertHasQueuedThreads(AbstractQueuedLongSynchronizer sync,
+ Thread... expected) {
+ Collection<Thread> actual = sync.getQueuedThreads();
+ assertEquals(expected.length > 0, sync.hasQueuedThreads());
+ assertEquals(expected.length, sync.getQueueLength());
+ assertEquals(expected.length, actual.size());
+ assertEquals(expected.length == 0, actual.isEmpty());
+ assertEquals(new HashSet<Thread>(actual),
+ new HashSet<Thread>(Arrays.asList(expected)));
+ }
+
+ /**
+ * Checks that sync has exactly the given (exclusive) queued threads.
+ */
+ void assertHasExclusiveQueuedThreads(AbstractQueuedLongSynchronizer sync,
+ Thread... expected) {
+ assertHasQueuedThreads(sync, expected);
+ assertEquals(new HashSet<Thread>(sync.getExclusiveQueuedThreads()),
+ new HashSet<Thread>(sync.getQueuedThreads()));
+ assertEquals(0, sync.getSharedQueuedThreads().size());
+ assertTrue(sync.getSharedQueuedThreads().isEmpty());
+ }
+
+ /**
+ * Checks that sync has exactly the given (shared) queued threads.
+ */
+ void assertHasSharedQueuedThreads(AbstractQueuedLongSynchronizer sync,
+ Thread... expected) {
+ assertHasQueuedThreads(sync, expected);
+ assertEquals(new HashSet<Thread>(sync.getSharedQueuedThreads()),
+ new HashSet<Thread>(sync.getQueuedThreads()));
+ assertEquals(0, sync.getExclusiveQueuedThreads().size());
+ assertTrue(sync.getExclusiveQueuedThreads().isEmpty());
+ }
+
+ /**
+ * Checks that condition c has exactly the given waiter threads,
+ * after acquiring mutex.
+ */
+ void assertHasWaitersUnlocked(Mutex sync, ConditionObject c,
+ Thread... threads) {
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, threads);
+ sync.release();
+ }
+
+ /**
+ * Checks that condition c has exactly the given waiter threads.
+ */
+ void assertHasWaitersLocked(Mutex sync, ConditionObject c,
+ Thread... threads) {
+ assertEquals(threads.length > 0, sync.hasWaiters(c));
+ assertEquals(threads.length, sync.getWaitQueueLength(c));
+ assertEquals(threads.length == 0, sync.getWaitingThreads(c).isEmpty());
+ assertEquals(threads.length, sync.getWaitingThreads(c).size());
+ assertEquals(new HashSet<Thread>(sync.getWaitingThreads(c)),
+ new HashSet<Thread>(Arrays.asList(threads)));
+ }
+
+ enum AwaitMethod { await, awaitTimed, awaitNanos, awaitUntil };
+
+ /**
+ * Awaits condition using the specified AwaitMethod.
+ */
+ void await(ConditionObject c, AwaitMethod awaitMethod)
+ throws InterruptedException {
+ long timeoutMillis = 2 * LONG_DELAY_MS;
+ switch (awaitMethod) {
+ case await:
+ c.await();
+ break;
+ case awaitTimed:
+ assertTrue(c.await(timeoutMillis, MILLISECONDS));
+ break;
+ case awaitNanos:
+ long nanosTimeout = MILLISECONDS.toNanos(timeoutMillis);
+ long nanosRemaining = c.awaitNanos(nanosTimeout);
+ assertTrue(nanosRemaining > 0);
+ break;
+ case awaitUntil:
+ assertTrue(c.awaitUntil(delayedDate(timeoutMillis)));
+ break;
+ }
+ }
+
+ /**
+ * Checks that awaiting the given condition times out (using the
+ * default timeout duration).
+ */
+ void assertAwaitTimesOut(ConditionObject c, AwaitMethod awaitMethod) {
+ long timeoutMillis = timeoutMillis();
+ long startTime = System.nanoTime();
+ try {
+ switch (awaitMethod) {
+ case awaitTimed:
+ assertFalse(c.await(timeoutMillis, MILLISECONDS));
+ break;
+ case awaitNanos:
+ long nanosTimeout = MILLISECONDS.toNanos(timeoutMillis);
+ long nanosRemaining = c.awaitNanos(nanosTimeout);
+ assertTrue(nanosRemaining <= 0);
+ break;
+ case awaitUntil:
+ assertFalse(c.awaitUntil(delayedDate(timeoutMillis)));
+ break;
+ default:
+ throw new UnsupportedOperationException();
+ }
+ } catch (InterruptedException ie) { threadUnexpectedException(ie); }
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
+ }
+
+ /**
+ * isHeldExclusively is false upon construction
+ */
+ public void testIsHeldExclusively() {
+ Mutex sync = new Mutex();
+ assertFalse(sync.isHeldExclusively());
+ }
+
+ /**
+ * acquiring released sync succeeds
+ */
+ public void testAcquire() {
+ Mutex sync = new Mutex();
+ sync.acquire();
+ assertTrue(sync.isHeldExclusively());
+ sync.release();
+ assertFalse(sync.isHeldExclusively());
+ }
+
+ /**
+ * tryAcquire on a released sync succeeds
+ */
+ public void testTryAcquire() {
+ Mutex sync = new Mutex();
+ assertTrue(sync.tryAcquire());
+ assertTrue(sync.isHeldExclusively());
+ sync.release();
+ assertFalse(sync.isHeldExclusively());
+ }
+
+ /**
+ * hasQueuedThreads reports whether there are waiting threads
+ */
+ public void testHasQueuedThreads() {
+ final Mutex sync = new Mutex();
+ assertFalse(sync.hasQueuedThreads());
+ sync.acquire();
+ Thread t1 = newStartedThread(new InterruptedSyncRunnable(sync));
+ waitForQueuedThread(sync, t1);
+ assertTrue(sync.hasQueuedThreads());
+ Thread t2 = newStartedThread(new InterruptibleSyncRunnable(sync));
+ waitForQueuedThread(sync, t2);
+ assertTrue(sync.hasQueuedThreads());
+ t1.interrupt();
+ awaitTermination(t1);
+ assertTrue(sync.hasQueuedThreads());
+ sync.release();
+ awaitTermination(t2);
+ assertFalse(sync.hasQueuedThreads());
+ }
+
+ /**
+ * isQueued(null) throws NullPointerException
+ */
+ public void testIsQueuedNPE() {
+ final Mutex sync = new Mutex();
+ try {
+ sync.isQueued(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * isQueued reports whether a thread is queued
+ */
+ public void testIsQueued() {
+ final Mutex sync = new Mutex();
+ Thread t1 = new Thread(new InterruptedSyncRunnable(sync));
+ Thread t2 = new Thread(new InterruptibleSyncRunnable(sync));
+ assertFalse(sync.isQueued(t1));
+ assertFalse(sync.isQueued(t2));
+ sync.acquire();
+ t1.start();
+ waitForQueuedThread(sync, t1);
+ assertTrue(sync.isQueued(t1));
+ assertFalse(sync.isQueued(t2));
+ t2.start();
+ waitForQueuedThread(sync, t2);
+ assertTrue(sync.isQueued(t1));
+ assertTrue(sync.isQueued(t2));
+ t1.interrupt();
+ awaitTermination(t1);
+ assertFalse(sync.isQueued(t1));
+ assertTrue(sync.isQueued(t2));
+ sync.release();
+ awaitTermination(t2);
+ assertFalse(sync.isQueued(t1));
+ assertFalse(sync.isQueued(t2));
+ }
+
+ /**
+ * getFirstQueuedThread returns first waiting thread or null if none
+ */
+ public void testGetFirstQueuedThread() {
+ final Mutex sync = new Mutex();
+ assertNull(sync.getFirstQueuedThread());
+ sync.acquire();
+ Thread t1 = newStartedThread(new InterruptedSyncRunnable(sync));
+ waitForQueuedThread(sync, t1);
+ assertEquals(t1, sync.getFirstQueuedThread());
+ Thread t2 = newStartedThread(new InterruptibleSyncRunnable(sync));
+ waitForQueuedThread(sync, t2);
+ assertEquals(t1, sync.getFirstQueuedThread());
+ t1.interrupt();
+ awaitTermination(t1);
+ assertEquals(t2, sync.getFirstQueuedThread());
+ sync.release();
+ awaitTermination(t2);
+ assertNull(sync.getFirstQueuedThread());
+ }
+
+ /**
+ * hasContended reports false if no thread has ever blocked, else true
+ */
+ public void testHasContended() {
+ final Mutex sync = new Mutex();
+ assertFalse(sync.hasContended());
+ sync.acquire();
+ assertFalse(sync.hasContended());
+ Thread t1 = newStartedThread(new InterruptedSyncRunnable(sync));
+ waitForQueuedThread(sync, t1);
+ assertTrue(sync.hasContended());
+ Thread t2 = newStartedThread(new InterruptibleSyncRunnable(sync));
+ waitForQueuedThread(sync, t2);
+ assertTrue(sync.hasContended());
+ t1.interrupt();
+ awaitTermination(t1);
+ assertTrue(sync.hasContended());
+ sync.release();
+ awaitTermination(t2);
+ assertTrue(sync.hasContended());
+ }
+
+ /**
+ * getQueuedThreads returns all waiting threads
+ */
+ public void testGetQueuedThreads() {
+ final Mutex sync = new Mutex();
+ Thread t1 = new Thread(new InterruptedSyncRunnable(sync));
+ Thread t2 = new Thread(new InterruptibleSyncRunnable(sync));
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ sync.acquire();
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ t1.start();
+ waitForQueuedThread(sync, t1);
+ assertHasExclusiveQueuedThreads(sync, t1);
+ assertTrue(sync.getQueuedThreads().contains(t1));
+ assertFalse(sync.getQueuedThreads().contains(t2));
+ t2.start();
+ waitForQueuedThread(sync, t2);
+ assertHasExclusiveQueuedThreads(sync, t1, t2);
+ assertTrue(sync.getQueuedThreads().contains(t1));
+ assertTrue(sync.getQueuedThreads().contains(t2));
+ t1.interrupt();
+ awaitTermination(t1);
+ assertHasExclusiveQueuedThreads(sync, t2);
+ sync.release();
+ awaitTermination(t2);
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ }
+
+ /**
+ * getExclusiveQueuedThreads returns all exclusive waiting threads
+ */
+ public void testGetExclusiveQueuedThreads() {
+ final Mutex sync = new Mutex();
+ Thread t1 = new Thread(new InterruptedSyncRunnable(sync));
+ Thread t2 = new Thread(new InterruptibleSyncRunnable(sync));
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ sync.acquire();
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ t1.start();
+ waitForQueuedThread(sync, t1);
+ assertHasExclusiveQueuedThreads(sync, t1);
+ assertTrue(sync.getExclusiveQueuedThreads().contains(t1));
+ assertFalse(sync.getExclusiveQueuedThreads().contains(t2));
+ t2.start();
+ waitForQueuedThread(sync, t2);
+ assertHasExclusiveQueuedThreads(sync, t1, t2);
+ assertTrue(sync.getExclusiveQueuedThreads().contains(t1));
+ assertTrue(sync.getExclusiveQueuedThreads().contains(t2));
+ t1.interrupt();
+ awaitTermination(t1);
+ assertHasExclusiveQueuedThreads(sync, t2);
+ sync.release();
+ awaitTermination(t2);
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ }
+
+ /**
+ * getSharedQueuedThreads does not include exclusively waiting threads
+ */
+ public void testGetSharedQueuedThreads_Exclusive() {
+ final Mutex sync = new Mutex();
+ assertTrue(sync.getSharedQueuedThreads().isEmpty());
+ sync.acquire();
+ assertTrue(sync.getSharedQueuedThreads().isEmpty());
+ Thread t1 = newStartedThread(new InterruptedSyncRunnable(sync));
+ waitForQueuedThread(sync, t1);
+ assertTrue(sync.getSharedQueuedThreads().isEmpty());
+ Thread t2 = newStartedThread(new InterruptibleSyncRunnable(sync));
+ waitForQueuedThread(sync, t2);
+ assertTrue(sync.getSharedQueuedThreads().isEmpty());
+ t1.interrupt();
+ awaitTermination(t1);
+ assertTrue(sync.getSharedQueuedThreads().isEmpty());
+ sync.release();
+ awaitTermination(t2);
+ assertTrue(sync.getSharedQueuedThreads().isEmpty());
+ }
+
+ /**
+ * getSharedQueuedThreads returns all shared waiting threads
+ */
+ public void testGetSharedQueuedThreads_Shared() {
+ final BooleanLatch l = new BooleanLatch();
+ assertHasSharedQueuedThreads(l, NO_THREADS);
+ Thread t1 = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ l.acquireSharedInterruptibly(0);
+ }});
+ waitForQueuedThread(l, t1);
+ assertHasSharedQueuedThreads(l, t1);
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ l.acquireSharedInterruptibly(0);
+ }});
+ waitForQueuedThread(l, t2);
+ assertHasSharedQueuedThreads(l, t1, t2);
+ t1.interrupt();
+ awaitTermination(t1);
+ assertHasSharedQueuedThreads(l, t2);
+ assertTrue(l.releaseShared(0));
+ awaitTermination(t2);
+ assertHasSharedQueuedThreads(l, NO_THREADS);
+ }
+
+ /**
+ * tryAcquireNanos is interruptible
+ */
+ public void testTryAcquireNanos_Interruptible() {
+ final Mutex sync = new Mutex();
+ sync.acquire();
+ Thread t = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ sync.tryAcquireNanos(MILLISECONDS.toNanos(2 * LONG_DELAY_MS));
+ }});
+
+ waitForQueuedThread(sync, t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * tryAcquire on exclusively held sync fails
+ */
+ public void testTryAcquireWhenSynced() {
+ final Mutex sync = new Mutex();
+ sync.acquire();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ assertFalse(sync.tryAcquire());
+ }});
+
+ awaitTermination(t);
+ sync.release();
+ }
+
+ /**
+ * tryAcquireNanos on an exclusively held sync times out
+ */
+ public void testAcquireNanos_Timeout() {
+ final Mutex sync = new Mutex();
+ sync.acquire();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ long startTime = System.nanoTime();
+ long nanos = MILLISECONDS.toNanos(timeoutMillis());
+ assertFalse(sync.tryAcquireNanos(nanos));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ }});
+
+ awaitTermination(t);
+ sync.release();
+ }
+
+ /**
+ * getState is true when acquired and false when not
+ */
+ public void testGetState() {
+ final Mutex sync = new Mutex();
+ sync.acquire();
+ assertTrue(sync.isHeldExclusively());
+ sync.release();
+ assertFalse(sync.isHeldExclusively());
+
+ final BooleanLatch acquired = new BooleanLatch();
+ final BooleanLatch done = new BooleanLatch();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ sync.acquire();
+ assertTrue(acquired.releaseShared(0));
+ done.acquireShared(0);
+ sync.release();
+ }});
+
+ acquired.acquireShared(0);
+ assertTrue(sync.isHeldExclusively());
+ assertTrue(done.releaseShared(0));
+ awaitTermination(t);
+ assertFalse(sync.isHeldExclusively());
+ }
+
+ /**
+ * acquireInterruptibly succeeds when released, else is interruptible
+ */
+ public void testAcquireInterruptibly() throws InterruptedException {
+ final Mutex sync = new Mutex();
+ final BooleanLatch threadStarted = new BooleanLatch();
+ sync.acquireInterruptibly();
+ Thread t = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertTrue(threadStarted.releaseShared(0));
+ sync.acquireInterruptibly();
+ }});
+
+ threadStarted.acquireShared(0);
+ waitForQueuedThread(sync, t);
+ t.interrupt();
+ awaitTermination(t);
+ assertTrue(sync.isHeldExclusively());
+ }
+
+ /**
+ * owns is true for a condition created by sync else false
+ */
+ public void testOwns() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ final Mutex sync2 = new Mutex();
+ assertTrue(sync.owns(c));
+ assertFalse(sync2.owns(c));
+ }
+
+ /**
+ * Calling await without holding sync throws IllegalMonitorStateException
+ */
+ public void testAwait_IMSE() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ for (AwaitMethod awaitMethod : AwaitMethod.values()) {
+ long startTime = System.nanoTime();
+ try {
+ await(c, awaitMethod);
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {
+ } catch (InterruptedException e) { threadUnexpectedException(e); }
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ }
+ }
+
+ /**
+ * Calling signal without holding sync throws IllegalMonitorStateException
+ */
+ public void testSignal_IMSE() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ try {
+ c.signal();
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {}
+ assertHasWaitersUnlocked(sync, c, NO_THREADS);
+ }
+
+ /**
+ * Calling signalAll without holding sync throws IllegalMonitorStateException
+ */
+ public void testSignalAll_IMSE() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ try {
+ c.signalAll();
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {}
+ }
+
+ /**
+ * await/awaitNanos/awaitUntil without a signal times out
+ */
+ public void testAwaitTimed_Timeout() { testAwait_Timeout(AwaitMethod.awaitTimed); }
+ public void testAwaitNanos_Timeout() { testAwait_Timeout(AwaitMethod.awaitNanos); }
+ public void testAwaitUntil_Timeout() { testAwait_Timeout(AwaitMethod.awaitUntil); }
+ public void testAwait_Timeout(AwaitMethod awaitMethod) {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ sync.acquire();
+ assertAwaitTimesOut(c, awaitMethod);
+ sync.release();
+ }
+
+ /**
+ * await/awaitNanos/awaitUntil returns when signalled
+ */
+ public void testSignal_await() { testSignal(AwaitMethod.await); }
+ public void testSignal_awaitTimed() { testSignal(AwaitMethod.awaitTimed); }
+ public void testSignal_awaitNanos() { testSignal(AwaitMethod.awaitNanos); }
+ public void testSignal_awaitUntil() { testSignal(AwaitMethod.awaitUntil); }
+ public void testSignal(final AwaitMethod awaitMethod) {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ final BooleanLatch acquired = new BooleanLatch();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ sync.acquire();
+ assertTrue(acquired.releaseShared(0));
+ await(c, awaitMethod);
+ sync.release();
+ }});
+
+ acquired.acquireShared(0);
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, t);
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ c.signal();
+ assertHasWaitersLocked(sync, c, NO_THREADS);
+ assertHasExclusiveQueuedThreads(sync, t);
+ sync.release();
+ awaitTermination(t);
+ }
+
+ /**
+ * hasWaiters(null) throws NullPointerException
+ */
+ public void testHasWaitersNPE() {
+ final Mutex sync = new Mutex();
+ try {
+ sync.hasWaiters(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * getWaitQueueLength(null) throws NullPointerException
+ */
+ public void testGetWaitQueueLengthNPE() {
+ final Mutex sync = new Mutex();
+ try {
+ sync.getWaitQueueLength(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * getWaitingThreads throws NPE if null
+ */
+ public void testGetWaitingThreadsNPE() {
+ final Mutex sync = new Mutex();
+ try {
+ sync.getWaitingThreads(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * hasWaiters throws IllegalArgumentException if not owned
+ */
+ public void testHasWaitersIAE() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ final Mutex sync2 = new Mutex();
+ try {
+ sync2.hasWaiters(c);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ assertHasWaitersUnlocked(sync, c, NO_THREADS);
+ }
+
+ /**
+ * hasWaiters throws IllegalMonitorStateException if not synced
+ */
+ public void testHasWaitersIMSE() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ try {
+ sync.hasWaiters(c);
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {}
+ assertHasWaitersUnlocked(sync, c, NO_THREADS);
+ }
+
+ /**
+ * getWaitQueueLength throws IllegalArgumentException if not owned
+ */
+ public void testGetWaitQueueLengthIAE() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ final Mutex sync2 = new Mutex();
+ try {
+ sync2.getWaitQueueLength(c);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ assertHasWaitersUnlocked(sync, c, NO_THREADS);
+ }
+
+ /**
+ * getWaitQueueLength throws IllegalMonitorStateException if not synced
+ */
+ public void testGetWaitQueueLengthIMSE() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ try {
+ sync.getWaitQueueLength(c);
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {}
+ assertHasWaitersUnlocked(sync, c, NO_THREADS);
+ }
+
+ /**
+ * getWaitingThreads throws IllegalArgumentException if not owned
+ */
+ public void testGetWaitingThreadsIAE() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ final Mutex sync2 = new Mutex();
+ try {
+ sync2.getWaitingThreads(c);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ assertHasWaitersUnlocked(sync, c, NO_THREADS);
+ }
+
+ /**
+ * getWaitingThreads throws IllegalMonitorStateException if not synced
+ */
+ public void testGetWaitingThreadsIMSE() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ try {
+ sync.getWaitingThreads(c);
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {}
+ assertHasWaitersUnlocked(sync, c, NO_THREADS);
+ }
+
+ /**
+ * hasWaiters returns true when a thread is waiting, else false
+ */
+ public void testHasWaiters() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ final BooleanLatch acquired = new BooleanLatch();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, NO_THREADS);
+ assertFalse(sync.hasWaiters(c));
+ assertTrue(acquired.releaseShared(0));
+ c.await();
+ sync.release();
+ }});
+
+ acquired.acquireShared(0);
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, t);
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ assertTrue(sync.hasWaiters(c));
+ c.signal();
+ assertHasWaitersLocked(sync, c, NO_THREADS);
+ assertHasExclusiveQueuedThreads(sync, t);
+ assertFalse(sync.hasWaiters(c));
+ sync.release();
+
+ awaitTermination(t);
+ assertHasWaitersUnlocked(sync, c, NO_THREADS);
+ }
+
+ /**
+ * getWaitQueueLength returns number of waiting threads
+ */
+ public void testGetWaitQueueLength() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ final BooleanLatch acquired1 = new BooleanLatch();
+ final BooleanLatch acquired2 = new BooleanLatch();
+ final Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, NO_THREADS);
+ assertEquals(0, sync.getWaitQueueLength(c));
+ assertTrue(acquired1.releaseShared(0));
+ c.await();
+ sync.release();
+ }});
+ acquired1.acquireShared(0);
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, t1);
+ assertEquals(1, sync.getWaitQueueLength(c));
+ sync.release();
+
+ final Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, t1);
+ assertEquals(1, sync.getWaitQueueLength(c));
+ assertTrue(acquired2.releaseShared(0));
+ c.await();
+ sync.release();
+ }});
+ acquired2.acquireShared(0);
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, t1, t2);
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ assertEquals(2, sync.getWaitQueueLength(c));
+ c.signalAll();
+ assertHasWaitersLocked(sync, c, NO_THREADS);
+ assertHasExclusiveQueuedThreads(sync, t1, t2);
+ assertEquals(0, sync.getWaitQueueLength(c));
+ sync.release();
+
+ awaitTermination(t1);
+ awaitTermination(t2);
+ assertHasWaitersUnlocked(sync, c, NO_THREADS);
+ }
+
+ /**
+ * getWaitingThreads returns only and all waiting threads
+ */
+ public void testGetWaitingThreads() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ final BooleanLatch acquired1 = new BooleanLatch();
+ final BooleanLatch acquired2 = new BooleanLatch();
+ final Thread t1 = new Thread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, NO_THREADS);
+ assertTrue(sync.getWaitingThreads(c).isEmpty());
+ assertTrue(acquired1.releaseShared(0));
+ c.await();
+ sync.release();
+ }});
+
+ final Thread t2 = new Thread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, t1);
+ assertTrue(sync.getWaitingThreads(c).contains(t1));
+ assertFalse(sync.getWaitingThreads(c).isEmpty());
+ assertEquals(1, sync.getWaitingThreads(c).size());
+ assertTrue(acquired2.releaseShared(0));
+ c.await();
+ sync.release();
+ }});
+
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, NO_THREADS);
+ assertFalse(sync.getWaitingThreads(c).contains(t1));
+ assertFalse(sync.getWaitingThreads(c).contains(t2));
+ assertTrue(sync.getWaitingThreads(c).isEmpty());
+ assertEquals(0, sync.getWaitingThreads(c).size());
+ sync.release();
+
+ t1.start();
+ acquired1.acquireShared(0);
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, t1);
+ assertTrue(sync.getWaitingThreads(c).contains(t1));
+ assertFalse(sync.getWaitingThreads(c).contains(t2));
+ assertFalse(sync.getWaitingThreads(c).isEmpty());
+ assertEquals(1, sync.getWaitingThreads(c).size());
+ sync.release();
+
+ t2.start();
+ acquired2.acquireShared(0);
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, t1, t2);
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ assertTrue(sync.getWaitingThreads(c).contains(t1));
+ assertTrue(sync.getWaitingThreads(c).contains(t2));
+ assertFalse(sync.getWaitingThreads(c).isEmpty());
+ assertEquals(2, sync.getWaitingThreads(c).size());
+ c.signalAll();
+ assertHasWaitersLocked(sync, c, NO_THREADS);
+ assertHasExclusiveQueuedThreads(sync, t1, t2);
+ assertFalse(sync.getWaitingThreads(c).contains(t1));
+ assertFalse(sync.getWaitingThreads(c).contains(t2));
+ assertTrue(sync.getWaitingThreads(c).isEmpty());
+ assertEquals(0, sync.getWaitingThreads(c).size());
+ sync.release();
+
+ awaitTermination(t1);
+ awaitTermination(t2);
+ assertHasWaitersUnlocked(sync, c, NO_THREADS);
+ }
+
+ /**
+ * awaitUninterruptibly is uninterruptible
+ */
+ public void testAwaitUninterruptibly() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ final BooleanLatch pleaseInterrupt = new BooleanLatch();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ sync.acquire();
+ assertTrue(pleaseInterrupt.releaseShared(0));
+ c.awaitUninterruptibly();
+ assertTrue(Thread.interrupted());
+ assertHasWaitersLocked(sync, c, NO_THREADS);
+ sync.release();
+ }});
+
+ pleaseInterrupt.acquireShared(0);
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, t);
+ sync.release();
+ t.interrupt();
+ assertHasWaitersUnlocked(sync, c, t);
+ assertThreadStaysAlive(t);
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, t);
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ c.signal();
+ assertHasWaitersLocked(sync, c, NO_THREADS);
+ assertHasExclusiveQueuedThreads(sync, t);
+ sync.release();
+ awaitTermination(t);
+ }
+
+ /**
+ * await/awaitNanos/awaitUntil is interruptible
+ */
+ public void testInterruptible_await() { testInterruptible(AwaitMethod.await); }
+ public void testInterruptible_awaitTimed() { testInterruptible(AwaitMethod.awaitTimed); }
+ public void testInterruptible_awaitNanos() { testInterruptible(AwaitMethod.awaitNanos); }
+ public void testInterruptible_awaitUntil() { testInterruptible(AwaitMethod.awaitUntil); }
+ public void testInterruptible(final AwaitMethod awaitMethod) {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ final BooleanLatch pleaseInterrupt = new BooleanLatch();
+ Thread t = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ sync.acquire();
+ assertTrue(pleaseInterrupt.releaseShared(0));
+ await(c, awaitMethod);
+ }});
+
+ pleaseInterrupt.acquireShared(0);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * signalAll wakes up all threads
+ */
+ public void testSignalAll_await() { testSignalAll(AwaitMethod.await); }
+ public void testSignalAll_awaitTimed() { testSignalAll(AwaitMethod.awaitTimed); }
+ public void testSignalAll_awaitNanos() { testSignalAll(AwaitMethod.awaitNanos); }
+ public void testSignalAll_awaitUntil() { testSignalAll(AwaitMethod.awaitUntil); }
+ public void testSignalAll(final AwaitMethod awaitMethod) {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ final BooleanLatch acquired1 = new BooleanLatch();
+ final BooleanLatch acquired2 = new BooleanLatch();
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ sync.acquire();
+ acquired1.releaseShared(0);
+ await(c, awaitMethod);
+ sync.release();
+ }});
+
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ sync.acquire();
+ acquired2.releaseShared(0);
+ await(c, awaitMethod);
+ sync.release();
+ }});
+
+ acquired1.acquireShared(0);
+ acquired2.acquireShared(0);
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, t1, t2);
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ c.signalAll();
+ assertHasWaitersLocked(sync, c, NO_THREADS);
+ assertHasExclusiveQueuedThreads(sync, t1, t2);
+ sync.release();
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * toString indicates current state
+ */
+ public void testToString() {
+ Mutex sync = new Mutex();
+ assertTrue(sync.toString().contains("State = " + Mutex.UNLOCKED));
+ sync.acquire();
+ assertTrue(sync.toString().contains("State = " + Mutex.LOCKED));
+ }
+
+ /**
+ * A serialized AQS deserializes with current state, but no queued threads
+ */
+ public void testSerialization() {
+ Mutex sync = new Mutex();
+ assertFalse(serialClone(sync).isHeldExclusively());
+ sync.acquire();
+ Thread t = newStartedThread(new InterruptedSyncRunnable(sync));
+ waitForQueuedThread(sync, t);
+ assertTrue(sync.isHeldExclusively());
+
+ Mutex clone = serialClone(sync);
+ assertTrue(clone.isHeldExclusively());
+ assertHasExclusiveQueuedThreads(sync, t);
+ assertHasExclusiveQueuedThreads(clone, NO_THREADS);
+ t.interrupt();
+ awaitTermination(t);
+ sync.release();
+ assertFalse(sync.isHeldExclusively());
+ assertTrue(clone.isHeldExclusively());
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ assertHasExclusiveQueuedThreads(clone, NO_THREADS);
+ }
+
+ /**
+ * tryReleaseShared setting state changes getState
+ */
+ public void testGetStateWithReleaseShared() {
+ final BooleanLatch l = new BooleanLatch();
+ assertFalse(l.isSignalled());
+ assertTrue(l.releaseShared(0));
+ assertTrue(l.isSignalled());
+ }
+
+ /**
+ * releaseShared has no effect when already signalled
+ */
+ public void testReleaseShared() {
+ final BooleanLatch l = new BooleanLatch();
+ assertFalse(l.isSignalled());
+ assertTrue(l.releaseShared(0));
+ assertTrue(l.isSignalled());
+ assertTrue(l.releaseShared(0));
+ assertTrue(l.isSignalled());
+ }
+
+ /**
+ * acquireSharedInterruptibly returns after release, but not before
+ */
+ public void testAcquireSharedInterruptibly() {
+ final BooleanLatch l = new BooleanLatch();
+
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(l.isSignalled());
+ l.acquireSharedInterruptibly(0);
+ assertTrue(l.isSignalled());
+ l.acquireSharedInterruptibly(0);
+ assertTrue(l.isSignalled());
+ }});
+
+ waitForQueuedThread(l, t);
+ assertFalse(l.isSignalled());
+ assertThreadStaysAlive(t);
+ assertHasSharedQueuedThreads(l, t);
+ assertTrue(l.releaseShared(0));
+ assertTrue(l.isSignalled());
+ awaitTermination(t);
+ }
+
+ /**
+ * tryAcquireSharedNanos returns after release, but not before
+ */
+ public void testTryAcquireSharedNanos() {
+ final BooleanLatch l = new BooleanLatch();
+
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(l.isSignalled());
+ long nanos = MILLISECONDS.toNanos(2 * LONG_DELAY_MS);
+ assertTrue(l.tryAcquireSharedNanos(0, nanos));
+ assertTrue(l.isSignalled());
+ assertTrue(l.tryAcquireSharedNanos(0, nanos));
+ assertTrue(l.isSignalled());
+ }});
+
+ waitForQueuedThread(l, t);
+ assertFalse(l.isSignalled());
+ assertThreadStaysAlive(t);
+ assertTrue(l.releaseShared(0));
+ assertTrue(l.isSignalled());
+ awaitTermination(t);
+ }
+
+ /**
+ * acquireSharedInterruptibly is interruptible
+ */
+ public void testAcquireSharedInterruptibly_Interruptible() {
+ final BooleanLatch l = new BooleanLatch();
+ Thread t = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(l.isSignalled());
+ l.acquireSharedInterruptibly(0);
+ }});
+
+ waitForQueuedThread(l, t);
+ assertFalse(l.isSignalled());
+ t.interrupt();
+ awaitTermination(t);
+ assertFalse(l.isSignalled());
+ }
+
+ /**
+ * tryAcquireSharedNanos is interruptible
+ */
+ public void testTryAcquireSharedNanos_Interruptible() {
+ final BooleanLatch l = new BooleanLatch();
+ Thread t = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(l.isSignalled());
+ long nanos = MILLISECONDS.toNanos(2 * LONG_DELAY_MS);
+ l.tryAcquireSharedNanos(0, nanos);
+ }});
+
+ waitForQueuedThread(l, t);
+ assertFalse(l.isSignalled());
+ t.interrupt();
+ awaitTermination(t);
+ assertFalse(l.isSignalled());
+ }
+
+ /**
+ * tryAcquireSharedNanos times out if not released before timeout
+ */
+ public void testTryAcquireSharedNanos_Timeout() {
+ final BooleanLatch l = new BooleanLatch();
+ final BooleanLatch observedQueued = new BooleanLatch();
+ final long timeoutMillis = timeoutMillis();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(l.isSignalled());
+ for (long millis = timeoutMillis();
+ !observedQueued.isSignalled();
+ millis *= 2) {
+ long nanos = MILLISECONDS.toNanos(millis);
+ long startTime = System.nanoTime();
+ assertFalse(l.tryAcquireSharedNanos(0, nanos));
+ assertTrue(millisElapsedSince(startTime) >= millis);
+ }
+ assertFalse(l.isSignalled());
+ }});
+
+ waitForQueuedThread(l, t);
+ observedQueued.releaseShared(0);
+ assertFalse(l.isSignalled());
+ awaitTermination(t);
+ assertFalse(l.isSignalled());
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/AbstractQueuedSynchronizerTest.java b/jsr166-tests/src/test/java/jsr166/AbstractQueuedSynchronizerTest.java
new file mode 100644
index 0000000..b9dab06
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/AbstractQueuedSynchronizerTest.java
@@ -0,0 +1,1212 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.*;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import java.util.concurrent.locks.AbstractQueuedSynchronizer;
+import java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject;
+
+public class AbstractQueuedSynchronizerTest extends JSR166TestCase {
+
+ /**
+ * A simple mutex class, adapted from the class javadoc. Exclusive
+ * acquire tests exercise this as a sample user extension. Other
+ * methods/features of AbstractQueuedSynchronizer are tested via
+ * other test classes, including those for ReentrantLock,
+ * ReentrantReadWriteLock, and Semaphore.
+ */
+ static class Mutex extends AbstractQueuedSynchronizer {
+ /** An eccentric value for locked synchronizer state. */
+ static final int LOCKED = (1 << 31) | (1 << 15);
+
+ static final int UNLOCKED = 0;
+
+ @Override public boolean isHeldExclusively() {
+ int state = getState();
+ assertTrue(state == UNLOCKED || state == LOCKED);
+ return state == LOCKED;
+ }
+
+ @Override public boolean tryAcquire(int acquires) {
+ assertEquals(LOCKED, acquires);
+ return compareAndSetState(UNLOCKED, LOCKED);
+ }
+
+ @Override public boolean tryRelease(int releases) {
+ if (getState() != LOCKED) throw new IllegalMonitorStateException();
+ assertEquals(LOCKED, releases);
+ setState(UNLOCKED);
+ return true;
+ }
+
+ public boolean tryAcquireNanos(long nanos) throws InterruptedException {
+ return tryAcquireNanos(LOCKED, nanos);
+ }
+
+ public boolean tryAcquire() {
+ return tryAcquire(LOCKED);
+ }
+
+ public boolean tryRelease() {
+ return tryRelease(LOCKED);
+ }
+
+ public void acquire() {
+ acquire(LOCKED);
+ }
+
+ public void acquireInterruptibly() throws InterruptedException {
+ acquireInterruptibly(LOCKED);
+ }
+
+ public void release() {
+ release(LOCKED);
+ }
+
+ public ConditionObject newCondition() {
+ return new ConditionObject();
+ }
+ }
+
+ /**
+ * A simple latch class, to test shared mode.
+ */
+ static class BooleanLatch extends AbstractQueuedSynchronizer {
+ public boolean isSignalled() { return getState() != 0; }
+
+ public int tryAcquireShared(int ignore) {
+ return isSignalled() ? 1 : -1;
+ }
+
+ public boolean tryReleaseShared(int ignore) {
+ setState(1);
+ return true;
+ }
+ }
+
+ /**
+ * A runnable calling acquireInterruptibly that does not expect to
+ * be interrupted.
+ */
+ class InterruptibleSyncRunnable extends CheckedRunnable {
+ final Mutex sync;
+ InterruptibleSyncRunnable(Mutex sync) { this.sync = sync; }
+ public void realRun() throws InterruptedException {
+ sync.acquireInterruptibly();
+ }
+ }
+
+ /**
+ * A runnable calling acquireInterruptibly that expects to be
+ * interrupted.
+ */
+ class InterruptedSyncRunnable extends CheckedInterruptedRunnable {
+ final Mutex sync;
+ InterruptedSyncRunnable(Mutex sync) { this.sync = sync; }
+ public void realRun() throws InterruptedException {
+ sync.acquireInterruptibly();
+ }
+ }
+
+ /** A constant to clarify calls to checking methods below. */
+ static final Thread[] NO_THREADS = new Thread[0];
+
+ /**
+ * Spin-waits until sync.isQueued(t) becomes true.
+ */
+ void waitForQueuedThread(AbstractQueuedSynchronizer sync, Thread t) {
+ long startTime = System.nanoTime();
+ while (!sync.isQueued(t)) {
+ if (millisElapsedSince(startTime) > LONG_DELAY_MS)
+ throw new AssertionFailedError("timed out");
+ Thread.yield();
+ }
+ assertTrue(t.isAlive());
+ }
+
+ /**
+ * Checks that sync has exactly the given queued threads.
+ */
+ void assertHasQueuedThreads(AbstractQueuedSynchronizer sync,
+ Thread... expected) {
+ Collection<Thread> actual = sync.getQueuedThreads();
+ assertEquals(expected.length > 0, sync.hasQueuedThreads());
+ assertEquals(expected.length, sync.getQueueLength());
+ assertEquals(expected.length, actual.size());
+ assertEquals(expected.length == 0, actual.isEmpty());
+ assertEquals(new HashSet<Thread>(actual),
+ new HashSet<Thread>(Arrays.asList(expected)));
+ }
+
+ /**
+ * Checks that sync has exactly the given (exclusive) queued threads.
+ */
+ void assertHasExclusiveQueuedThreads(AbstractQueuedSynchronizer sync,
+ Thread... expected) {
+ assertHasQueuedThreads(sync, expected);
+ assertEquals(new HashSet<Thread>(sync.getExclusiveQueuedThreads()),
+ new HashSet<Thread>(sync.getQueuedThreads()));
+ assertEquals(0, sync.getSharedQueuedThreads().size());
+ assertTrue(sync.getSharedQueuedThreads().isEmpty());
+ }
+
+ /**
+ * Checks that sync has exactly the given (shared) queued threads.
+ */
+ void assertHasSharedQueuedThreads(AbstractQueuedSynchronizer sync,
+ Thread... expected) {
+ assertHasQueuedThreads(sync, expected);
+ assertEquals(new HashSet<Thread>(sync.getSharedQueuedThreads()),
+ new HashSet<Thread>(sync.getQueuedThreads()));
+ assertEquals(0, sync.getExclusiveQueuedThreads().size());
+ assertTrue(sync.getExclusiveQueuedThreads().isEmpty());
+ }
+
+ /**
+ * Checks that condition c has exactly the given waiter threads,
+ * after acquiring mutex.
+ */
+ void assertHasWaitersUnlocked(Mutex sync, ConditionObject c,
+ Thread... threads) {
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, threads);
+ sync.release();
+ }
+
+ /**
+ * Checks that condition c has exactly the given waiter threads.
+ */
+ void assertHasWaitersLocked(Mutex sync, ConditionObject c,
+ Thread... threads) {
+ assertEquals(threads.length > 0, sync.hasWaiters(c));
+ assertEquals(threads.length, sync.getWaitQueueLength(c));
+ assertEquals(threads.length == 0, sync.getWaitingThreads(c).isEmpty());
+ assertEquals(threads.length, sync.getWaitingThreads(c).size());
+ assertEquals(new HashSet<Thread>(sync.getWaitingThreads(c)),
+ new HashSet<Thread>(Arrays.asList(threads)));
+ }
+
+ enum AwaitMethod { await, awaitTimed, awaitNanos, awaitUntil };
+
+ /**
+ * Awaits condition using the specified AwaitMethod.
+ */
+ void await(ConditionObject c, AwaitMethod awaitMethod)
+ throws InterruptedException {
+ long timeoutMillis = 2 * LONG_DELAY_MS;
+ switch (awaitMethod) {
+ case await:
+ c.await();
+ break;
+ case awaitTimed:
+ assertTrue(c.await(timeoutMillis, MILLISECONDS));
+ break;
+ case awaitNanos:
+ long nanosTimeout = MILLISECONDS.toNanos(timeoutMillis);
+ long nanosRemaining = c.awaitNanos(nanosTimeout);
+ assertTrue(nanosRemaining > 0);
+ break;
+ case awaitUntil:
+ assertTrue(c.awaitUntil(delayedDate(timeoutMillis)));
+ break;
+ }
+ }
+
+ /**
+ * Checks that awaiting the given condition times out (using the
+ * default timeout duration).
+ */
+ void assertAwaitTimesOut(ConditionObject c, AwaitMethod awaitMethod) {
+ long timeoutMillis = timeoutMillis();
+ long startTime = System.nanoTime();
+ try {
+ switch (awaitMethod) {
+ case awaitTimed:
+ assertFalse(c.await(timeoutMillis, MILLISECONDS));
+ break;
+ case awaitNanos:
+ long nanosTimeout = MILLISECONDS.toNanos(timeoutMillis);
+ long nanosRemaining = c.awaitNanos(nanosTimeout);
+ assertTrue(nanosRemaining <= 0);
+ break;
+ case awaitUntil:
+ assertFalse(c.awaitUntil(delayedDate(timeoutMillis)));
+ break;
+ default:
+ throw new UnsupportedOperationException();
+ }
+ } catch (InterruptedException ie) { threadUnexpectedException(ie); }
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
+ }
+
+ /**
+ * isHeldExclusively is false upon construction
+ */
+ public void testIsHeldExclusively() {
+ Mutex sync = new Mutex();
+ assertFalse(sync.isHeldExclusively());
+ }
+
+ /**
+ * acquiring released sync succeeds
+ */
+ public void testAcquire() {
+ Mutex sync = new Mutex();
+ sync.acquire();
+ assertTrue(sync.isHeldExclusively());
+ sync.release();
+ assertFalse(sync.isHeldExclusively());
+ }
+
+ /**
+ * tryAcquire on a released sync succeeds
+ */
+ public void testTryAcquire() {
+ Mutex sync = new Mutex();
+ assertTrue(sync.tryAcquire());
+ assertTrue(sync.isHeldExclusively());
+ sync.release();
+ assertFalse(sync.isHeldExclusively());
+ }
+
+ /**
+ * hasQueuedThreads reports whether there are waiting threads
+ */
+ public void testHasQueuedThreads() {
+ final Mutex sync = new Mutex();
+ assertFalse(sync.hasQueuedThreads());
+ sync.acquire();
+ Thread t1 = newStartedThread(new InterruptedSyncRunnable(sync));
+ waitForQueuedThread(sync, t1);
+ assertTrue(sync.hasQueuedThreads());
+ Thread t2 = newStartedThread(new InterruptibleSyncRunnable(sync));
+ waitForQueuedThread(sync, t2);
+ assertTrue(sync.hasQueuedThreads());
+ t1.interrupt();
+ awaitTermination(t1);
+ assertTrue(sync.hasQueuedThreads());
+ sync.release();
+ awaitTermination(t2);
+ assertFalse(sync.hasQueuedThreads());
+ }
+
+ /**
+ * isQueued(null) throws NullPointerException
+ */
+ public void testIsQueuedNPE() {
+ final Mutex sync = new Mutex();
+ try {
+ sync.isQueued(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * isQueued reports whether a thread is queued
+ */
+ public void testIsQueued() {
+ final Mutex sync = new Mutex();
+ Thread t1 = new Thread(new InterruptedSyncRunnable(sync));
+ Thread t2 = new Thread(new InterruptibleSyncRunnable(sync));
+ assertFalse(sync.isQueued(t1));
+ assertFalse(sync.isQueued(t2));
+ sync.acquire();
+ t1.start();
+ waitForQueuedThread(sync, t1);
+ assertTrue(sync.isQueued(t1));
+ assertFalse(sync.isQueued(t2));
+ t2.start();
+ waitForQueuedThread(sync, t2);
+ assertTrue(sync.isQueued(t1));
+ assertTrue(sync.isQueued(t2));
+ t1.interrupt();
+ awaitTermination(t1);
+ assertFalse(sync.isQueued(t1));
+ assertTrue(sync.isQueued(t2));
+ sync.release();
+ awaitTermination(t2);
+ assertFalse(sync.isQueued(t1));
+ assertFalse(sync.isQueued(t2));
+ }
+
+ /**
+ * getFirstQueuedThread returns first waiting thread or null if none
+ */
+ public void testGetFirstQueuedThread() {
+ final Mutex sync = new Mutex();
+ assertNull(sync.getFirstQueuedThread());
+ sync.acquire();
+ Thread t1 = newStartedThread(new InterruptedSyncRunnable(sync));
+ waitForQueuedThread(sync, t1);
+ assertEquals(t1, sync.getFirstQueuedThread());
+ Thread t2 = newStartedThread(new InterruptibleSyncRunnable(sync));
+ waitForQueuedThread(sync, t2);
+ assertEquals(t1, sync.getFirstQueuedThread());
+ t1.interrupt();
+ awaitTermination(t1);
+ assertEquals(t2, sync.getFirstQueuedThread());
+ sync.release();
+ awaitTermination(t2);
+ assertNull(sync.getFirstQueuedThread());
+ }
+
+ /**
+ * hasContended reports false if no thread has ever blocked, else true
+ */
+ public void testHasContended() {
+ final Mutex sync = new Mutex();
+ assertFalse(sync.hasContended());
+ sync.acquire();
+ assertFalse(sync.hasContended());
+ Thread t1 = newStartedThread(new InterruptedSyncRunnable(sync));
+ waitForQueuedThread(sync, t1);
+ assertTrue(sync.hasContended());
+ Thread t2 = newStartedThread(new InterruptibleSyncRunnable(sync));
+ waitForQueuedThread(sync, t2);
+ assertTrue(sync.hasContended());
+ t1.interrupt();
+ awaitTermination(t1);
+ assertTrue(sync.hasContended());
+ sync.release();
+ awaitTermination(t2);
+ assertTrue(sync.hasContended());
+ }
+
+ /**
+ * getQueuedThreads returns all waiting threads
+ */
+ public void testGetQueuedThreads() {
+ final Mutex sync = new Mutex();
+ Thread t1 = new Thread(new InterruptedSyncRunnable(sync));
+ Thread t2 = new Thread(new InterruptibleSyncRunnable(sync));
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ sync.acquire();
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ t1.start();
+ waitForQueuedThread(sync, t1);
+ assertHasExclusiveQueuedThreads(sync, t1);
+ assertTrue(sync.getQueuedThreads().contains(t1));
+ assertFalse(sync.getQueuedThreads().contains(t2));
+ t2.start();
+ waitForQueuedThread(sync, t2);
+ assertHasExclusiveQueuedThreads(sync, t1, t2);
+ assertTrue(sync.getQueuedThreads().contains(t1));
+ assertTrue(sync.getQueuedThreads().contains(t2));
+ t1.interrupt();
+ awaitTermination(t1);
+ assertHasExclusiveQueuedThreads(sync, t2);
+ sync.release();
+ awaitTermination(t2);
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ }
+
+ /**
+ * getExclusiveQueuedThreads returns all exclusive waiting threads
+ */
+ public void testGetExclusiveQueuedThreads() {
+ final Mutex sync = new Mutex();
+ Thread t1 = new Thread(new InterruptedSyncRunnable(sync));
+ Thread t2 = new Thread(new InterruptibleSyncRunnable(sync));
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ sync.acquire();
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ t1.start();
+ waitForQueuedThread(sync, t1);
+ assertHasExclusiveQueuedThreads(sync, t1);
+ assertTrue(sync.getExclusiveQueuedThreads().contains(t1));
+ assertFalse(sync.getExclusiveQueuedThreads().contains(t2));
+ t2.start();
+ waitForQueuedThread(sync, t2);
+ assertHasExclusiveQueuedThreads(sync, t1, t2);
+ assertTrue(sync.getExclusiveQueuedThreads().contains(t1));
+ assertTrue(sync.getExclusiveQueuedThreads().contains(t2));
+ t1.interrupt();
+ awaitTermination(t1);
+ assertHasExclusiveQueuedThreads(sync, t2);
+ sync.release();
+ awaitTermination(t2);
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ }
+
+ /**
+ * getSharedQueuedThreads does not include exclusively waiting threads
+ */
+ public void testGetSharedQueuedThreads_Exclusive() {
+ final Mutex sync = new Mutex();
+ assertTrue(sync.getSharedQueuedThreads().isEmpty());
+ sync.acquire();
+ assertTrue(sync.getSharedQueuedThreads().isEmpty());
+ Thread t1 = newStartedThread(new InterruptedSyncRunnable(sync));
+ waitForQueuedThread(sync, t1);
+ assertTrue(sync.getSharedQueuedThreads().isEmpty());
+ Thread t2 = newStartedThread(new InterruptibleSyncRunnable(sync));
+ waitForQueuedThread(sync, t2);
+ assertTrue(sync.getSharedQueuedThreads().isEmpty());
+ t1.interrupt();
+ awaitTermination(t1);
+ assertTrue(sync.getSharedQueuedThreads().isEmpty());
+ sync.release();
+ awaitTermination(t2);
+ assertTrue(sync.getSharedQueuedThreads().isEmpty());
+ }
+
+ /**
+ * getSharedQueuedThreads returns all shared waiting threads
+ */
+ public void testGetSharedQueuedThreads_Shared() {
+ final BooleanLatch l = new BooleanLatch();
+ assertHasSharedQueuedThreads(l, NO_THREADS);
+ Thread t1 = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ l.acquireSharedInterruptibly(0);
+ }});
+ waitForQueuedThread(l, t1);
+ assertHasSharedQueuedThreads(l, t1);
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ l.acquireSharedInterruptibly(0);
+ }});
+ waitForQueuedThread(l, t2);
+ assertHasSharedQueuedThreads(l, t1, t2);
+ t1.interrupt();
+ awaitTermination(t1);
+ assertHasSharedQueuedThreads(l, t2);
+ assertTrue(l.releaseShared(0));
+ awaitTermination(t2);
+ assertHasSharedQueuedThreads(l, NO_THREADS);
+ }
+
+ /**
+ * tryAcquireNanos is interruptible
+ */
+ public void testTryAcquireNanos_Interruptible() {
+ final Mutex sync = new Mutex();
+ sync.acquire();
+ Thread t = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ sync.tryAcquireNanos(MILLISECONDS.toNanos(2 * LONG_DELAY_MS));
+ }});
+
+ waitForQueuedThread(sync, t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * tryAcquire on exclusively held sync fails
+ */
+ public void testTryAcquireWhenSynced() {
+ final Mutex sync = new Mutex();
+ sync.acquire();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ assertFalse(sync.tryAcquire());
+ }});
+
+ awaitTermination(t);
+ sync.release();
+ }
+
+ /**
+ * tryAcquireNanos on an exclusively held sync times out
+ */
+ public void testAcquireNanos_Timeout() {
+ final Mutex sync = new Mutex();
+ sync.acquire();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ long startTime = System.nanoTime();
+ long nanos = MILLISECONDS.toNanos(timeoutMillis());
+ assertFalse(sync.tryAcquireNanos(nanos));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ }});
+
+ awaitTermination(t);
+ sync.release();
+ }
+
+ /**
+ * getState is true when acquired and false when not
+ */
+ public void testGetState() {
+ final Mutex sync = new Mutex();
+ sync.acquire();
+ assertTrue(sync.isHeldExclusively());
+ sync.release();
+ assertFalse(sync.isHeldExclusively());
+
+ final BooleanLatch acquired = new BooleanLatch();
+ final BooleanLatch done = new BooleanLatch();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ sync.acquire();
+ assertTrue(acquired.releaseShared(0));
+ done.acquireShared(0);
+ sync.release();
+ }});
+
+ acquired.acquireShared(0);
+ assertTrue(sync.isHeldExclusively());
+ assertTrue(done.releaseShared(0));
+ awaitTermination(t);
+ assertFalse(sync.isHeldExclusively());
+ }
+
+ /**
+ * acquireInterruptibly succeeds when released, else is interruptible
+ */
+ public void testAcquireInterruptibly() throws InterruptedException {
+ final Mutex sync = new Mutex();
+ final BooleanLatch threadStarted = new BooleanLatch();
+ sync.acquireInterruptibly();
+ Thread t = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertTrue(threadStarted.releaseShared(0));
+ sync.acquireInterruptibly();
+ }});
+
+ threadStarted.acquireShared(0);
+ waitForQueuedThread(sync, t);
+ t.interrupt();
+ awaitTermination(t);
+ assertTrue(sync.isHeldExclusively());
+ }
+
+ /**
+ * owns is true for a condition created by sync else false
+ */
+ public void testOwns() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ final Mutex sync2 = new Mutex();
+ assertTrue(sync.owns(c));
+ assertFalse(sync2.owns(c));
+ }
+
+ /**
+ * Calling await without holding sync throws IllegalMonitorStateException
+ */
+ public void testAwait_IMSE() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ for (AwaitMethod awaitMethod : AwaitMethod.values()) {
+ long startTime = System.nanoTime();
+ try {
+ await(c, awaitMethod);
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {
+ } catch (InterruptedException e) { threadUnexpectedException(e); }
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ }
+ }
+
+ /**
+ * Calling signal without holding sync throws IllegalMonitorStateException
+ */
+ public void testSignal_IMSE() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ try {
+ c.signal();
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {}
+ assertHasWaitersUnlocked(sync, c, NO_THREADS);
+ }
+
+ /**
+ * Calling signalAll without holding sync throws IllegalMonitorStateException
+ */
+ public void testSignalAll_IMSE() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ try {
+ c.signalAll();
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {}
+ }
+
+ /**
+ * await/awaitNanos/awaitUntil without a signal times out
+ */
+ public void testAwaitTimed_Timeout() { testAwait_Timeout(AwaitMethod.awaitTimed); }
+ public void testAwaitNanos_Timeout() { testAwait_Timeout(AwaitMethod.awaitNanos); }
+ public void testAwaitUntil_Timeout() { testAwait_Timeout(AwaitMethod.awaitUntil); }
+ public void testAwait_Timeout(AwaitMethod awaitMethod) {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ sync.acquire();
+ assertAwaitTimesOut(c, awaitMethod);
+ sync.release();
+ }
+
+ /**
+ * await/awaitNanos/awaitUntil returns when signalled
+ */
+ public void testSignal_await() { testSignal(AwaitMethod.await); }
+ public void testSignal_awaitTimed() { testSignal(AwaitMethod.awaitTimed); }
+ public void testSignal_awaitNanos() { testSignal(AwaitMethod.awaitNanos); }
+ public void testSignal_awaitUntil() { testSignal(AwaitMethod.awaitUntil); }
+ public void testSignal(final AwaitMethod awaitMethod) {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ final BooleanLatch acquired = new BooleanLatch();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ sync.acquire();
+ assertTrue(acquired.releaseShared(0));
+ await(c, awaitMethod);
+ sync.release();
+ }});
+
+ acquired.acquireShared(0);
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, t);
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ c.signal();
+ assertHasWaitersLocked(sync, c, NO_THREADS);
+ assertHasExclusiveQueuedThreads(sync, t);
+ sync.release();
+ awaitTermination(t);
+ }
+
+ /**
+ * hasWaiters(null) throws NullPointerException
+ */
+ public void testHasWaitersNPE() {
+ final Mutex sync = new Mutex();
+ try {
+ sync.hasWaiters(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * getWaitQueueLength(null) throws NullPointerException
+ */
+ public void testGetWaitQueueLengthNPE() {
+ final Mutex sync = new Mutex();
+ try {
+ sync.getWaitQueueLength(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * getWaitingThreads(null) throws NullPointerException
+ */
+ public void testGetWaitingThreadsNPE() {
+ final Mutex sync = new Mutex();
+ try {
+ sync.getWaitingThreads(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * hasWaiters throws IllegalArgumentException if not owned
+ */
+ public void testHasWaitersIAE() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ final Mutex sync2 = new Mutex();
+ try {
+ sync2.hasWaiters(c);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ assertHasWaitersUnlocked(sync, c, NO_THREADS);
+ }
+
+ /**
+ * hasWaiters throws IllegalMonitorStateException if not synced
+ */
+ public void testHasWaitersIMSE() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ try {
+ sync.hasWaiters(c);
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {}
+ assertHasWaitersUnlocked(sync, c, NO_THREADS);
+ }
+
+ /**
+ * getWaitQueueLength throws IllegalArgumentException if not owned
+ */
+ public void testGetWaitQueueLengthIAE() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ final Mutex sync2 = new Mutex();
+ try {
+ sync2.getWaitQueueLength(c);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ assertHasWaitersUnlocked(sync, c, NO_THREADS);
+ }
+
+ /**
+ * getWaitQueueLength throws IllegalMonitorStateException if not synced
+ */
+ public void testGetWaitQueueLengthIMSE() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ try {
+ sync.getWaitQueueLength(c);
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {}
+ assertHasWaitersUnlocked(sync, c, NO_THREADS);
+ }
+
+ /**
+ * getWaitingThreads throws IllegalArgumentException if not owned
+ */
+ public void testGetWaitingThreadsIAE() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ final Mutex sync2 = new Mutex();
+ try {
+ sync2.getWaitingThreads(c);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ assertHasWaitersUnlocked(sync, c, NO_THREADS);
+ }
+
+ /**
+ * getWaitingThreads throws IllegalMonitorStateException if not synced
+ */
+ public void testGetWaitingThreadsIMSE() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ try {
+ sync.getWaitingThreads(c);
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {}
+ assertHasWaitersUnlocked(sync, c, NO_THREADS);
+ }
+
+ /**
+ * hasWaiters returns true when a thread is waiting, else false
+ */
+ public void testHasWaiters() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ final BooleanLatch acquired = new BooleanLatch();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, NO_THREADS);
+ assertFalse(sync.hasWaiters(c));
+ assertTrue(acquired.releaseShared(0));
+ c.await();
+ sync.release();
+ }});
+
+ acquired.acquireShared(0);
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, t);
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ assertTrue(sync.hasWaiters(c));
+ c.signal();
+ assertHasWaitersLocked(sync, c, NO_THREADS);
+ assertHasExclusiveQueuedThreads(sync, t);
+ assertFalse(sync.hasWaiters(c));
+ sync.release();
+
+ awaitTermination(t);
+ assertHasWaitersUnlocked(sync, c, NO_THREADS);
+ }
+
+ /**
+ * getWaitQueueLength returns number of waiting threads
+ */
+ public void testGetWaitQueueLength() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ final BooleanLatch acquired1 = new BooleanLatch();
+ final BooleanLatch acquired2 = new BooleanLatch();
+ final Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, NO_THREADS);
+ assertEquals(0, sync.getWaitQueueLength(c));
+ assertTrue(acquired1.releaseShared(0));
+ c.await();
+ sync.release();
+ }});
+ acquired1.acquireShared(0);
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, t1);
+ assertEquals(1, sync.getWaitQueueLength(c));
+ sync.release();
+
+ final Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, t1);
+ assertEquals(1, sync.getWaitQueueLength(c));
+ assertTrue(acquired2.releaseShared(0));
+ c.await();
+ sync.release();
+ }});
+ acquired2.acquireShared(0);
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, t1, t2);
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ assertEquals(2, sync.getWaitQueueLength(c));
+ c.signalAll();
+ assertHasWaitersLocked(sync, c, NO_THREADS);
+ assertHasExclusiveQueuedThreads(sync, t1, t2);
+ assertEquals(0, sync.getWaitQueueLength(c));
+ sync.release();
+
+ awaitTermination(t1);
+ awaitTermination(t2);
+ assertHasWaitersUnlocked(sync, c, NO_THREADS);
+ }
+
+ /**
+ * getWaitingThreads returns only and all waiting threads
+ */
+ public void testGetWaitingThreads() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ final BooleanLatch acquired1 = new BooleanLatch();
+ final BooleanLatch acquired2 = new BooleanLatch();
+ final Thread t1 = new Thread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, NO_THREADS);
+ assertTrue(sync.getWaitingThreads(c).isEmpty());
+ assertTrue(acquired1.releaseShared(0));
+ c.await();
+ sync.release();
+ }});
+
+ final Thread t2 = new Thread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, t1);
+ assertTrue(sync.getWaitingThreads(c).contains(t1));
+ assertFalse(sync.getWaitingThreads(c).isEmpty());
+ assertEquals(1, sync.getWaitingThreads(c).size());
+ assertTrue(acquired2.releaseShared(0));
+ c.await();
+ sync.release();
+ }});
+
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, NO_THREADS);
+ assertFalse(sync.getWaitingThreads(c).contains(t1));
+ assertFalse(sync.getWaitingThreads(c).contains(t2));
+ assertTrue(sync.getWaitingThreads(c).isEmpty());
+ assertEquals(0, sync.getWaitingThreads(c).size());
+ sync.release();
+
+ t1.start();
+ acquired1.acquireShared(0);
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, t1);
+ assertTrue(sync.getWaitingThreads(c).contains(t1));
+ assertFalse(sync.getWaitingThreads(c).contains(t2));
+ assertFalse(sync.getWaitingThreads(c).isEmpty());
+ assertEquals(1, sync.getWaitingThreads(c).size());
+ sync.release();
+
+ t2.start();
+ acquired2.acquireShared(0);
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, t1, t2);
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ assertTrue(sync.getWaitingThreads(c).contains(t1));
+ assertTrue(sync.getWaitingThreads(c).contains(t2));
+ assertFalse(sync.getWaitingThreads(c).isEmpty());
+ assertEquals(2, sync.getWaitingThreads(c).size());
+ c.signalAll();
+ assertHasWaitersLocked(sync, c, NO_THREADS);
+ assertHasExclusiveQueuedThreads(sync, t1, t2);
+ assertFalse(sync.getWaitingThreads(c).contains(t1));
+ assertFalse(sync.getWaitingThreads(c).contains(t2));
+ assertTrue(sync.getWaitingThreads(c).isEmpty());
+ assertEquals(0, sync.getWaitingThreads(c).size());
+ sync.release();
+
+ awaitTermination(t1);
+ awaitTermination(t2);
+ assertHasWaitersUnlocked(sync, c, NO_THREADS);
+ }
+
+ /**
+ * awaitUninterruptibly is uninterruptible
+ */
+ public void testAwaitUninterruptibly() {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ final BooleanLatch pleaseInterrupt = new BooleanLatch();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ sync.acquire();
+ assertTrue(pleaseInterrupt.releaseShared(0));
+ c.awaitUninterruptibly();
+ assertTrue(Thread.interrupted());
+ assertHasWaitersLocked(sync, c, NO_THREADS);
+ sync.release();
+ }});
+
+ pleaseInterrupt.acquireShared(0);
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, t);
+ sync.release();
+ t.interrupt();
+ assertHasWaitersUnlocked(sync, c, t);
+ assertThreadStaysAlive(t);
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, t);
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ c.signal();
+ assertHasWaitersLocked(sync, c, NO_THREADS);
+ assertHasExclusiveQueuedThreads(sync, t);
+ sync.release();
+ awaitTermination(t);
+ }
+
+ /**
+ * await/awaitNanos/awaitUntil is interruptible
+ */
+ public void testInterruptible_await() { testInterruptible(AwaitMethod.await); }
+ public void testInterruptible_awaitTimed() { testInterruptible(AwaitMethod.awaitTimed); }
+ public void testInterruptible_awaitNanos() { testInterruptible(AwaitMethod.awaitNanos); }
+ public void testInterruptible_awaitUntil() { testInterruptible(AwaitMethod.awaitUntil); }
+ public void testInterruptible(final AwaitMethod awaitMethod) {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ final BooleanLatch pleaseInterrupt = new BooleanLatch();
+ Thread t = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ sync.acquire();
+ assertTrue(pleaseInterrupt.releaseShared(0));
+ await(c, awaitMethod);
+ }});
+
+ pleaseInterrupt.acquireShared(0);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * signalAll wakes up all threads
+ */
+ public void testSignalAll_await() { testSignalAll(AwaitMethod.await); }
+ public void testSignalAll_awaitTimed() { testSignalAll(AwaitMethod.awaitTimed); }
+ public void testSignalAll_awaitNanos() { testSignalAll(AwaitMethod.awaitNanos); }
+ public void testSignalAll_awaitUntil() { testSignalAll(AwaitMethod.awaitUntil); }
+ public void testSignalAll(final AwaitMethod awaitMethod) {
+ final Mutex sync = new Mutex();
+ final ConditionObject c = sync.newCondition();
+ final BooleanLatch acquired1 = new BooleanLatch();
+ final BooleanLatch acquired2 = new BooleanLatch();
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ sync.acquire();
+ acquired1.releaseShared(0);
+ await(c, awaitMethod);
+ sync.release();
+ }});
+
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ sync.acquire();
+ acquired2.releaseShared(0);
+ await(c, awaitMethod);
+ sync.release();
+ }});
+
+ acquired1.acquireShared(0);
+ acquired2.acquireShared(0);
+ sync.acquire();
+ assertHasWaitersLocked(sync, c, t1, t2);
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ c.signalAll();
+ assertHasWaitersLocked(sync, c, NO_THREADS);
+ assertHasExclusiveQueuedThreads(sync, t1, t2);
+ sync.release();
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * toString indicates current state
+ */
+ public void testToString() {
+ Mutex sync = new Mutex();
+ assertTrue(sync.toString().contains("State = " + Mutex.UNLOCKED));
+ sync.acquire();
+ assertTrue(sync.toString().contains("State = " + Mutex.LOCKED));
+ }
+
+ /**
+ * A serialized AQS deserializes with current state, but no queued threads
+ */
+ public void testSerialization() {
+ Mutex sync = new Mutex();
+ assertFalse(serialClone(sync).isHeldExclusively());
+ sync.acquire();
+ Thread t = newStartedThread(new InterruptedSyncRunnable(sync));
+ waitForQueuedThread(sync, t);
+ assertTrue(sync.isHeldExclusively());
+
+ Mutex clone = serialClone(sync);
+ assertTrue(clone.isHeldExclusively());
+ assertHasExclusiveQueuedThreads(sync, t);
+ assertHasExclusiveQueuedThreads(clone, NO_THREADS);
+ t.interrupt();
+ awaitTermination(t);
+ sync.release();
+ assertFalse(sync.isHeldExclusively());
+ assertTrue(clone.isHeldExclusively());
+ assertHasExclusiveQueuedThreads(sync, NO_THREADS);
+ assertHasExclusiveQueuedThreads(clone, NO_THREADS);
+ }
+
+ /**
+ * tryReleaseShared setting state changes getState
+ */
+ public void testGetStateWithReleaseShared() {
+ final BooleanLatch l = new BooleanLatch();
+ assertFalse(l.isSignalled());
+ assertTrue(l.releaseShared(0));
+ assertTrue(l.isSignalled());
+ }
+
+ /**
+ * releaseShared has no effect when already signalled
+ */
+ public void testReleaseShared() {
+ final BooleanLatch l = new BooleanLatch();
+ assertFalse(l.isSignalled());
+ assertTrue(l.releaseShared(0));
+ assertTrue(l.isSignalled());
+ assertTrue(l.releaseShared(0));
+ assertTrue(l.isSignalled());
+ }
+
+ /**
+ * acquireSharedInterruptibly returns after release, but not before
+ */
+ public void testAcquireSharedInterruptibly() {
+ final BooleanLatch l = new BooleanLatch();
+
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(l.isSignalled());
+ l.acquireSharedInterruptibly(0);
+ assertTrue(l.isSignalled());
+ l.acquireSharedInterruptibly(0);
+ assertTrue(l.isSignalled());
+ }});
+
+ waitForQueuedThread(l, t);
+ assertFalse(l.isSignalled());
+ assertThreadStaysAlive(t);
+ assertHasSharedQueuedThreads(l, t);
+ assertTrue(l.releaseShared(0));
+ assertTrue(l.isSignalled());
+ awaitTermination(t);
+ }
+
+ /**
+ * tryAcquireSharedNanos returns after release, but not before
+ */
+ public void testTryAcquireSharedNanos() {
+ final BooleanLatch l = new BooleanLatch();
+
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(l.isSignalled());
+ long nanos = MILLISECONDS.toNanos(2 * LONG_DELAY_MS);
+ assertTrue(l.tryAcquireSharedNanos(0, nanos));
+ assertTrue(l.isSignalled());
+ assertTrue(l.tryAcquireSharedNanos(0, nanos));
+ assertTrue(l.isSignalled());
+ }});
+
+ waitForQueuedThread(l, t);
+ assertFalse(l.isSignalled());
+ assertThreadStaysAlive(t);
+ assertTrue(l.releaseShared(0));
+ assertTrue(l.isSignalled());
+ awaitTermination(t);
+ }
+
+ /**
+ * acquireSharedInterruptibly is interruptible
+ */
+ public void testAcquireSharedInterruptibly_Interruptible() {
+ final BooleanLatch l = new BooleanLatch();
+ Thread t = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(l.isSignalled());
+ l.acquireSharedInterruptibly(0);
+ }});
+
+ waitForQueuedThread(l, t);
+ assertFalse(l.isSignalled());
+ t.interrupt();
+ awaitTermination(t);
+ assertFalse(l.isSignalled());
+ }
+
+ /**
+ * tryAcquireSharedNanos is interruptible
+ */
+ public void testTryAcquireSharedNanos_Interruptible() {
+ final BooleanLatch l = new BooleanLatch();
+ Thread t = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(l.isSignalled());
+ long nanos = MILLISECONDS.toNanos(2 * LONG_DELAY_MS);
+ l.tryAcquireSharedNanos(0, nanos);
+ }});
+
+ waitForQueuedThread(l, t);
+ assertFalse(l.isSignalled());
+ t.interrupt();
+ awaitTermination(t);
+ assertFalse(l.isSignalled());
+ }
+
+ /**
+ * tryAcquireSharedNanos times out if not released before timeout
+ */
+ public void testTryAcquireSharedNanos_Timeout() {
+ final BooleanLatch l = new BooleanLatch();
+ final BooleanLatch observedQueued = new BooleanLatch();
+ final long timeoutMillis = timeoutMillis();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(l.isSignalled());
+ for (long millis = timeoutMillis();
+ !observedQueued.isSignalled();
+ millis *= 2) {
+ long nanos = MILLISECONDS.toNanos(millis);
+ long startTime = System.nanoTime();
+ assertFalse(l.tryAcquireSharedNanos(0, nanos));
+ assertTrue(millisElapsedSince(startTime) >= millis);
+ }
+ assertFalse(l.isSignalled());
+ }});
+
+ waitForQueuedThread(l, t);
+ observedQueued.releaseShared(0);
+ assertFalse(l.isSignalled());
+ awaitTermination(t);
+ assertFalse(l.isSignalled());
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/ArrayBlockingQueueTest.java b/jsr166-tests/src/test/java/jsr166/ArrayBlockingQueueTest.java
new file mode 100644
index 0000000..ce417ad
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/ArrayBlockingQueueTest.java
@@ -0,0 +1,891 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+public class ArrayBlockingQueueTest extends JSR166TestCase {
+
+ public static class Fair extends BlockingQueueTest {
+ protected BlockingQueue emptyCollection() {
+ return new ArrayBlockingQueue(SIZE, true);
+ }
+ }
+
+ public static class NonFair extends BlockingQueueTest {
+ protected BlockingQueue emptyCollection() {
+ return new ArrayBlockingQueue(SIZE, false);
+ }
+ }
+
+ /**
+ * Returns a new queue of given size containing consecutive
+ * Integers 0 ... n.
+ */
+ private ArrayBlockingQueue<Integer> populatedQueue(int n) {
+ ArrayBlockingQueue<Integer> q = new ArrayBlockingQueue<Integer>(n);
+ assertTrue(q.isEmpty());
+ for (int i = 0; i < n; i++)
+ assertTrue(q.offer(new Integer(i)));
+ assertFalse(q.isEmpty());
+ assertEquals(0, q.remainingCapacity());
+ assertEquals(n, q.size());
+ return q;
+ }
+
+ /**
+ * A new queue has the indicated capacity
+ */
+ public void testConstructor1() {
+ assertEquals(SIZE, new ArrayBlockingQueue(SIZE).remainingCapacity());
+ }
+
+ /**
+ * Constructor throws IAE if capacity argument nonpositive
+ */
+ public void testConstructor2() {
+ try {
+ new ArrayBlockingQueue(0);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Initializing from null Collection throws NPE
+ */
+ public void testConstructor3() {
+ try {
+ new ArrayBlockingQueue(1, true, null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing from Collection of null elements throws NPE
+ */
+ public void testConstructor4() {
+ Collection<Integer> elements = Arrays.asList(new Integer[SIZE]);
+ try {
+ new ArrayBlockingQueue(SIZE, false, elements);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing from Collection with some null elements throws NPE
+ */
+ public void testConstructor5() {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = i;
+ Collection<Integer> elements = Arrays.asList(ints);
+ try {
+ new ArrayBlockingQueue(SIZE, false, Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing from too large collection throws IAE
+ */
+ public void testConstructor6() {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = i;
+ Collection<Integer> elements = Arrays.asList(ints);
+ try {
+ new ArrayBlockingQueue(SIZE - 1, false, elements);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Queue contains all elements of collection used to initialize
+ */
+ public void testConstructor7() {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = i;
+ Collection<Integer> elements = Arrays.asList(ints);
+ ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE, true, elements);
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(ints[i], q.poll());
+ }
+
+ /**
+ * Queue transitions from empty to full when elements added
+ */
+ public void testEmptyFull() {
+ ArrayBlockingQueue q = new ArrayBlockingQueue(2);
+ assertTrue(q.isEmpty());
+ assertEquals(2, q.remainingCapacity());
+ q.add(one);
+ assertFalse(q.isEmpty());
+ q.add(two);
+ assertFalse(q.isEmpty());
+ assertEquals(0, q.remainingCapacity());
+ assertFalse(q.offer(three));
+ }
+
+ /**
+ * remainingCapacity decreases on add, increases on remove
+ */
+ public void testRemainingCapacity() {
+ ArrayBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.remainingCapacity());
+ assertEquals(SIZE-i, q.size());
+ q.remove();
+ }
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(SIZE-i, q.remainingCapacity());
+ assertEquals(i, q.size());
+ q.add(new Integer(i));
+ }
+ }
+
+ /**
+ * Offer succeeds if not full; fails if full
+ */
+ public void testOffer() {
+ ArrayBlockingQueue q = new ArrayBlockingQueue(1);
+ assertTrue(q.offer(zero));
+ assertFalse(q.offer(one));
+ }
+
+ /**
+ * add succeeds if not full; throws ISE if full
+ */
+ public void testAdd() {
+ try {
+ ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.add(new Integer(i)));
+ }
+ assertEquals(0, q.remainingCapacity());
+ q.add(new Integer(SIZE));
+ shouldThrow();
+ } catch (IllegalStateException success) {}
+ }
+
+ /**
+ * addAll(this) throws IAE
+ */
+ public void testAddAllSelf() {
+ try {
+ ArrayBlockingQueue q = populatedQueue(SIZE);
+ q.addAll(q);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * addAll of a collection with any null elements throws NPE after
+ * possibly adding some elements
+ */
+ public void testAddAll3() {
+ try {
+ ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE);
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll throws ISE if not enough room
+ */
+ public void testAddAll4() {
+ try {
+ ArrayBlockingQueue q = new ArrayBlockingQueue(1);
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(i);
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (IllegalStateException success) {}
+ }
+
+ /**
+ * Queue contains all elements, in traversal order, of successful addAll
+ */
+ public void testAddAll5() {
+ Integer[] empty = new Integer[0];
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(i);
+ ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE);
+ assertFalse(q.addAll(Arrays.asList(empty)));
+ assertTrue(q.addAll(Arrays.asList(ints)));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(ints[i], q.poll());
+ }
+
+ /**
+ * all elements successfully put are contained
+ */
+ public void testPut() throws InterruptedException {
+ ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ Integer I = new Integer(i);
+ q.put(I);
+ assertTrue(q.contains(I));
+ }
+ assertEquals(0, q.remainingCapacity());
+ }
+
+ /**
+ * put blocks interruptibly if full
+ */
+ public void testBlockingPut() throws InterruptedException {
+ final ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ for (int i = 0; i < SIZE; ++i)
+ q.put(i);
+ assertEquals(SIZE, q.size());
+ assertEquals(0, q.remainingCapacity());
+
+ Thread.currentThread().interrupt();
+ try {
+ q.put(99);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ q.put(99);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ assertEquals(SIZE, q.size());
+ assertEquals(0, q.remainingCapacity());
+ }
+
+ /**
+ * put blocks interruptibly waiting for take when full
+ */
+ public void testPutWithTake() throws InterruptedException {
+ final int capacity = 2;
+ final ArrayBlockingQueue q = new ArrayBlockingQueue(capacity);
+ final CountDownLatch pleaseTake = new CountDownLatch(1);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ for (int i = 0; i < capacity; i++)
+ q.put(i);
+ pleaseTake.countDown();
+ q.put(86);
+
+ pleaseInterrupt.countDown();
+ try {
+ q.put(99);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseTake);
+ assertEquals(0, q.remainingCapacity());
+ assertEquals(0, q.take());
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ assertEquals(0, q.remainingCapacity());
+ }
+
+ /**
+ * timed offer times out if full and elements not taken
+ */
+ public void testTimedOffer() throws InterruptedException {
+ final ArrayBlockingQueue q = new ArrayBlockingQueue(2);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ q.put(new Object());
+ q.put(new Object());
+ long startTime = System.nanoTime();
+ assertFalse(q.offer(new Object(), timeoutMillis(), MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ pleaseInterrupt.countDown();
+ try {
+ q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * take retrieves elements in FIFO order
+ */
+ public void testTake() throws InterruptedException {
+ ArrayBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.take());
+ }
+ }
+
+ /**
+ * Take removes existing elements until empty, then blocks interruptibly
+ */
+ public void testBlockingTake() throws InterruptedException {
+ final ArrayBlockingQueue q = populatedQueue(SIZE);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.take());
+ }
+
+ Thread.currentThread().interrupt();
+ try {
+ q.take();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ q.take();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * poll succeeds unless empty
+ */
+ public void testPoll() {
+ ArrayBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.poll());
+ }
+ assertNull(q.poll());
+ }
+
+ /**
+ * timed poll with zero timeout succeeds when non-empty, else times out
+ */
+ public void testTimedPoll0() throws InterruptedException {
+ ArrayBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.poll(0, MILLISECONDS));
+ }
+ assertNull(q.poll(0, MILLISECONDS));
+ checkEmpty(q);
+ }
+
+ /**
+ * timed poll with nonzero timeout succeeds when non-empty, else times out
+ */
+ public void testTimedPoll() throws InterruptedException {
+ ArrayBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ long startTime = System.nanoTime();
+ assertEquals(i, q.poll(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ }
+ long startTime = System.nanoTime();
+ assertNull(q.poll(timeoutMillis(), MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ checkEmpty(q);
+ }
+
+ /**
+ * Interrupted timed poll throws InterruptedException instead of
+ * returning timeout status
+ */
+ public void testInterruptedTimedPoll() throws InterruptedException {
+ final BlockingQueue<Integer> q = populatedQueue(SIZE);
+ final CountDownLatch aboutToWait = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ for (int i = 0; i < SIZE; ++i) {
+ long t0 = System.nanoTime();
+ assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
+ }
+ long t0 = System.nanoTime();
+ aboutToWait.countDown();
+ try {
+ q.poll(MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {
+ assertTrue(millisElapsedSince(t0) < MEDIUM_DELAY_MS);
+ }
+ }});
+
+ aboutToWait.await();
+ waitForThreadToEnterWaitState(t, SMALL_DELAY_MS);
+ t.interrupt();
+ awaitTermination(t, MEDIUM_DELAY_MS);
+ checkEmpty(q);
+ }
+
+ /**
+ * peek returns next element, or null if empty
+ */
+ public void testPeek() {
+ ArrayBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.peek());
+ assertEquals(i, q.poll());
+ assertTrue(q.peek() == null ||
+ !q.peek().equals(i));
+ }
+ assertNull(q.peek());
+ }
+
+ /**
+ * element returns next element, or throws NSEE if empty
+ */
+ public void testElement() {
+ ArrayBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.element());
+ assertEquals(i, q.poll());
+ }
+ try {
+ q.element();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * remove removes next element, or throws NSEE if empty
+ */
+ public void testRemove() {
+ ArrayBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.remove());
+ }
+ try {
+ q.remove();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * contains(x) reports true when elements added but not yet removed
+ */
+ public void testContains() {
+ ArrayBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.contains(new Integer(i)));
+ assertEquals(i, q.poll());
+ assertFalse(q.contains(new Integer(i)));
+ }
+ }
+
+ /**
+ * clear removes all elements
+ */
+ public void testClear() {
+ ArrayBlockingQueue q = populatedQueue(SIZE);
+ q.clear();
+ assertTrue(q.isEmpty());
+ assertEquals(0, q.size());
+ assertEquals(SIZE, q.remainingCapacity());
+ q.add(one);
+ assertFalse(q.isEmpty());
+ assertTrue(q.contains(one));
+ q.clear();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * containsAll(c) is true when c contains a subset of elements
+ */
+ public void testContainsAll() {
+ ArrayBlockingQueue q = populatedQueue(SIZE);
+ ArrayBlockingQueue p = new ArrayBlockingQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.containsAll(p));
+ assertFalse(p.containsAll(q));
+ p.add(new Integer(i));
+ }
+ assertTrue(p.containsAll(q));
+ }
+
+ /**
+ * retainAll(c) retains only those elements of c and reports true if changed
+ */
+ public void testRetainAll() {
+ ArrayBlockingQueue q = populatedQueue(SIZE);
+ ArrayBlockingQueue p = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ boolean changed = q.retainAll(p);
+ if (i == 0)
+ assertFalse(changed);
+ else
+ assertTrue(changed);
+
+ assertTrue(q.containsAll(p));
+ assertEquals(SIZE-i, q.size());
+ p.remove();
+ }
+ }
+
+ /**
+ * removeAll(c) removes only those elements of c and reports true if changed
+ */
+ public void testRemoveAll() {
+ for (int i = 1; i < SIZE; ++i) {
+ ArrayBlockingQueue q = populatedQueue(SIZE);
+ ArrayBlockingQueue p = populatedQueue(i);
+ assertTrue(q.removeAll(p));
+ assertEquals(SIZE-i, q.size());
+ for (int j = 0; j < i; ++j) {
+ Integer I = (Integer)(p.remove());
+ assertFalse(q.contains(I));
+ }
+ }
+ }
+
+ void checkToArray(ArrayBlockingQueue q) {
+ int size = q.size();
+ Object[] o = q.toArray();
+ assertEquals(size, o.length);
+ Iterator it = q.iterator();
+ for (int i = 0; i < size; i++) {
+ Integer x = (Integer) it.next();
+ assertEquals((Integer)o[0] + i, (int) x);
+ assertSame(o[i], x);
+ }
+ }
+
+ /**
+ * toArray() contains all elements in FIFO order
+ */
+ public void testToArray() {
+ ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ checkToArray(q);
+ q.add(i);
+ }
+ // Provoke wraparound
+ for (int i = 0; i < SIZE; i++) {
+ checkToArray(q);
+ assertEquals(i, q.poll());
+ checkToArray(q);
+ q.add(SIZE+i);
+ }
+ for (int i = 0; i < SIZE; i++) {
+ checkToArray(q);
+ assertEquals(SIZE+i, q.poll());
+ }
+ }
+
+ void checkToArray2(ArrayBlockingQueue q) {
+ int size = q.size();
+ Integer[] a1 = size == 0 ? null : new Integer[size-1];
+ Integer[] a2 = new Integer[size];
+ Integer[] a3 = new Integer[size+2];
+ if (size > 0) Arrays.fill(a1, 42);
+ Arrays.fill(a2, 42);
+ Arrays.fill(a3, 42);
+ Integer[] b1 = size == 0 ? null : (Integer[]) q.toArray(a1);
+ Integer[] b2 = (Integer[]) q.toArray(a2);
+ Integer[] b3 = (Integer[]) q.toArray(a3);
+ assertSame(a2, b2);
+ assertSame(a3, b3);
+ Iterator it = q.iterator();
+ for (int i = 0; i < size; i++) {
+ Integer x = (Integer) it.next();
+ assertSame(b1[i], x);
+ assertEquals(b1[0] + i, (int) x);
+ assertSame(b2[i], x);
+ assertSame(b3[i], x);
+ }
+ assertNull(a3[size]);
+ assertEquals(42, (int) a3[size+1]);
+ if (size > 0) {
+ assertNotSame(a1, b1);
+ assertEquals(size, b1.length);
+ for (int i = 0; i < a1.length; i++) {
+ assertEquals(42, (int) a1[i]);
+ }
+ }
+ }
+
+ /**
+ * toArray(a) contains all elements in FIFO order
+ */
+ public void testToArray2() {
+ ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ checkToArray2(q);
+ q.add(i);
+ }
+ // Provoke wraparound
+ for (int i = 0; i < SIZE; i++) {
+ checkToArray2(q);
+ assertEquals(i, q.poll());
+ checkToArray2(q);
+ q.add(SIZE+i);
+ }
+ for (int i = 0; i < SIZE; i++) {
+ checkToArray2(q);
+ assertEquals(SIZE+i, q.poll());
+ }
+ }
+
+ /**
+ * toArray(incompatible array type) throws ArrayStoreException
+ */
+ public void testToArray1_BadArg() {
+ ArrayBlockingQueue q = populatedQueue(SIZE);
+ try {
+ q.toArray(new String[10]);
+ shouldThrow();
+ } catch (ArrayStoreException success) {}
+ }
+
+ /**
+ * iterator iterates through all elements
+ */
+ public void testIterator() throws InterruptedException {
+ ArrayBlockingQueue q = populatedQueue(SIZE);
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ assertEquals(it.next(), q.take());
+ }
+ }
+
+ /**
+ * iterator.remove removes current element
+ */
+ public void testIteratorRemove() {
+ final ArrayBlockingQueue q = new ArrayBlockingQueue(3);
+ q.add(two);
+ q.add(one);
+ q.add(three);
+
+ Iterator it = q.iterator();
+ it.next();
+ it.remove();
+
+ it = q.iterator();
+ assertSame(it.next(), one);
+ assertSame(it.next(), three);
+ assertFalse(it.hasNext());
+ }
+
+ /**
+ * iterator ordering is FIFO
+ */
+ public void testIteratorOrdering() {
+ final ArrayBlockingQueue q = new ArrayBlockingQueue(3);
+ q.add(one);
+ q.add(two);
+ q.add(three);
+
+ assertEquals("queue should be full", 0, q.remainingCapacity());
+
+ int k = 0;
+ for (Iterator it = q.iterator(); it.hasNext();) {
+ assertEquals(++k, it.next());
+ }
+ assertEquals(3, k);
+ }
+
+ /**
+ * Modifications do not cause iterators to fail
+ */
+ public void testWeaklyConsistentIteration() {
+ final ArrayBlockingQueue q = new ArrayBlockingQueue(3);
+ q.add(one);
+ q.add(two);
+ q.add(three);
+ for (Iterator it = q.iterator(); it.hasNext();) {
+ q.remove();
+ it.next();
+ }
+ assertEquals(0, q.size());
+ }
+
+ /**
+ * toString contains toStrings of elements
+ */
+ public void testToString() {
+ ArrayBlockingQueue q = populatedQueue(SIZE);
+ String s = q.toString();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(s.contains(String.valueOf(i)));
+ }
+ }
+
+ /**
+ * offer transfers elements across Executor tasks
+ */
+ public void testOfferInExecutor() {
+ final ArrayBlockingQueue q = new ArrayBlockingQueue(2);
+ q.add(one);
+ q.add(two);
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+ final CheckedBarrier threadsStarted = new CheckedBarrier(2);
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(q.offer(three));
+ threadsStarted.await();
+ assertTrue(q.offer(three, LONG_DELAY_MS, MILLISECONDS));
+ assertEquals(0, q.remainingCapacity());
+ }});
+
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ assertEquals(0, q.remainingCapacity());
+ assertSame(one, q.take());
+ }});
+
+ joinPool(executor);
+ }
+
+ /**
+ * timed poll retrieves elements across Executor threads
+ */
+ public void testPollInExecutor() {
+ final ArrayBlockingQueue q = new ArrayBlockingQueue(2);
+ final CheckedBarrier threadsStarted = new CheckedBarrier(2);
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertNull(q.poll());
+ threadsStarted.await();
+ assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS));
+ checkEmpty(q);
+ }});
+
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ q.put(one);
+ }});
+
+ joinPool(executor);
+ }
+
+ /**
+ * A deserialized serialized queue has same elements in same order
+ */
+ public void testSerialization() throws Exception {
+ Queue x = populatedQueue(SIZE);
+ Queue y = serialClone(x);
+
+ assertNotSame(x, y);
+ assertEquals(x.size(), y.size());
+ assertEquals(x.toString(), y.toString());
+ assertTrue(Arrays.equals(x.toArray(), y.toArray()));
+ while (!x.isEmpty()) {
+ assertFalse(y.isEmpty());
+ assertEquals(x.remove(), y.remove());
+ }
+ assertTrue(y.isEmpty());
+ }
+
+ /**
+ * drainTo(c) empties queue into another collection c
+ */
+ public void testDrainTo() {
+ ArrayBlockingQueue q = populatedQueue(SIZE);
+ ArrayList l = new ArrayList();
+ q.drainTo(l);
+ assertEquals(0, q.size());
+ assertEquals(SIZE, l.size());
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(l.get(i), new Integer(i));
+ q.add(zero);
+ q.add(one);
+ assertFalse(q.isEmpty());
+ assertTrue(q.contains(zero));
+ assertTrue(q.contains(one));
+ l.clear();
+ q.drainTo(l);
+ assertEquals(0, q.size());
+ assertEquals(2, l.size());
+ for (int i = 0; i < 2; ++i)
+ assertEquals(l.get(i), new Integer(i));
+ }
+
+ /**
+ * drainTo empties full queue, unblocking a waiting put.
+ */
+ public void testDrainToWithActivePut() throws InterruptedException {
+ final ArrayBlockingQueue q = populatedQueue(SIZE);
+ Thread t = new Thread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ q.put(new Integer(SIZE+1));
+ }});
+
+ t.start();
+ ArrayList l = new ArrayList();
+ q.drainTo(l);
+ assertTrue(l.size() >= SIZE);
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(l.get(i), new Integer(i));
+ t.join();
+ assertTrue(q.size() + l.size() >= SIZE);
+ }
+
+ /**
+ * drainTo(c, n) empties first min(n, size) elements of queue into c
+ */
+ public void testDrainToN() {
+ ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE*2);
+ for (int i = 0; i < SIZE + 2; ++i) {
+ for (int j = 0; j < SIZE; j++)
+ assertTrue(q.offer(new Integer(j)));
+ ArrayList l = new ArrayList();
+ q.drainTo(l, i);
+ int k = (i < SIZE) ? i : SIZE;
+ assertEquals(k, l.size());
+ assertEquals(SIZE-k, q.size());
+ for (int j = 0; j < k; ++j)
+ assertEquals(l.get(j), new Integer(j));
+ while (q.poll() != null) ;
+ }
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/ArrayDequeTest.java b/jsr166-tests/src/test/java/jsr166/ArrayDequeTest.java
new file mode 100644
index 0000000..d18a560
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/ArrayDequeTest.java
@@ -0,0 +1,888 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.Arrays;
+import java.util.ArrayDeque;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+import java.util.Random;
+
+public class ArrayDequeTest extends JSR166TestCase {
+
+ /**
+ * Returns a new deque of given size containing consecutive
+ * Integers 0 ... n.
+ */
+ private ArrayDeque<Integer> populatedDeque(int n) {
+ ArrayDeque<Integer> q = new ArrayDeque<Integer>();
+ assertTrue(q.isEmpty());
+ for (int i = 0; i < n; ++i)
+ assertTrue(q.offerLast(new Integer(i)));
+ assertFalse(q.isEmpty());
+ assertEquals(n, q.size());
+ return q;
+ }
+
+ /**
+ * new deque is empty
+ */
+ public void testConstructor1() {
+ assertEquals(0, new ArrayDeque().size());
+ }
+
+ /**
+ * Initializing from null Collection throws NPE
+ */
+ public void testConstructor3() {
+ try {
+ ArrayDeque q = new ArrayDeque((Collection)null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing from Collection of null elements throws NPE
+ */
+ public void testConstructor4() {
+ try {
+ Integer[] ints = new Integer[SIZE];
+ ArrayDeque q = new ArrayDeque(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing from Collection with some null elements throws NPE
+ */
+ public void testConstructor5() {
+ try {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
+ ArrayDeque q = new ArrayDeque(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Deque contains all elements of collection used to initialize
+ */
+ public void testConstructor6() {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(i);
+ ArrayDeque q = new ArrayDeque(Arrays.asList(ints));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(ints[i], q.pollFirst());
+ }
+
+ /**
+ * isEmpty is true before add, false after
+ */
+ public void testEmpty() {
+ ArrayDeque q = new ArrayDeque();
+ assertTrue(q.isEmpty());
+ q.add(new Integer(1));
+ assertFalse(q.isEmpty());
+ q.add(new Integer(2));
+ q.removeFirst();
+ q.removeFirst();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * size changes when elements added and removed
+ */
+ public void testSize() {
+ ArrayDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(SIZE-i, q.size());
+ q.removeFirst();
+ }
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.size());
+ q.add(new Integer(i));
+ }
+ }
+
+ /**
+ * push(null) throws NPE
+ */
+ public void testPushNull() {
+ try {
+ ArrayDeque q = new ArrayDeque(1);
+ q.push(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * peekFirst() returns element inserted with push
+ */
+ public void testPush() {
+ ArrayDeque q = populatedDeque(3);
+ q.pollLast();
+ q.push(four);
+ assertSame(four, q.peekFirst());
+ }
+
+ /**
+ * pop() removes next element, or throws NSEE if empty
+ */
+ public void testPop() {
+ ArrayDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.pop());
+ }
+ try {
+ q.pop();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * offer(null) throws NPE
+ */
+ public void testOfferNull() {
+ try {
+ ArrayDeque q = new ArrayDeque();
+ q.offer(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * offerFirst(null) throws NPE
+ */
+ public void testOfferFirstNull() {
+ try {
+ ArrayDeque q = new ArrayDeque();
+ q.offerFirst(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * offerLast(null) throws NPE
+ */
+ public void testOfferLastNull() {
+ try {
+ ArrayDeque q = new ArrayDeque();
+ q.offerLast(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * offer(x) succeeds
+ */
+ public void testOffer() {
+ ArrayDeque q = new ArrayDeque();
+ assertTrue(q.offer(zero));
+ assertTrue(q.offer(one));
+ assertSame(zero, q.peekFirst());
+ assertSame(one, q.peekLast());
+ }
+
+ /**
+ * offerFirst(x) succeeds
+ */
+ public void testOfferFirst() {
+ ArrayDeque q = new ArrayDeque();
+ assertTrue(q.offerFirst(zero));
+ assertTrue(q.offerFirst(one));
+ assertSame(one, q.peekFirst());
+ assertSame(zero, q.peekLast());
+ }
+
+ /**
+ * offerLast(x) succeeds
+ */
+ public void testOfferLast() {
+ ArrayDeque q = new ArrayDeque();
+ assertTrue(q.offerLast(zero));
+ assertTrue(q.offerLast(one));
+ assertSame(zero, q.peekFirst());
+ assertSame(one, q.peekLast());
+ }
+
+ /**
+ * add(null) throws NPE
+ */
+ public void testAddNull() {
+ try {
+ ArrayDeque q = new ArrayDeque();
+ q.add(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addFirst(null) throws NPE
+ */
+ public void testAddFirstNull() {
+ try {
+ ArrayDeque q = new ArrayDeque();
+ q.addFirst(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addLast(null) throws NPE
+ */
+ public void testAddLastNull() {
+ try {
+ ArrayDeque q = new ArrayDeque();
+ q.addLast(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * add(x) succeeds
+ */
+ public void testAdd() {
+ ArrayDeque q = new ArrayDeque();
+ assertTrue(q.add(zero));
+ assertTrue(q.add(one));
+ assertSame(zero, q.peekFirst());
+ assertSame(one, q.peekLast());
+ }
+
+ /**
+ * addFirst(x) succeeds
+ */
+ public void testAddFirst() {
+ ArrayDeque q = new ArrayDeque();
+ q.addFirst(zero);
+ q.addFirst(one);
+ assertSame(one, q.peekFirst());
+ assertSame(zero, q.peekLast());
+ }
+
+ /**
+ * addLast(x) succeeds
+ */
+ public void testAddLast() {
+ ArrayDeque q = new ArrayDeque();
+ q.addLast(zero);
+ q.addLast(one);
+ assertSame(zero, q.peekFirst());
+ assertSame(one, q.peekLast());
+ }
+
+ /**
+ * addAll(null) throws NPE
+ */
+ public void testAddAll1() {
+ try {
+ ArrayDeque q = new ArrayDeque();
+ q.addAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll of a collection with null elements throws NPE
+ */
+ public void testAddAll2() {
+ try {
+ ArrayDeque q = new ArrayDeque();
+ Integer[] ints = new Integer[SIZE];
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll of a collection with any null elements throws NPE after
+ * possibly adding some elements
+ */
+ public void testAddAll3() {
+ try {
+ ArrayDeque q = new ArrayDeque();
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Deque contains all elements, in traversal order, of successful addAll
+ */
+ public void testAddAll5() {
+ Integer[] empty = new Integer[0];
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(i);
+ ArrayDeque q = new ArrayDeque();
+ assertFalse(q.addAll(Arrays.asList(empty)));
+ assertTrue(q.addAll(Arrays.asList(ints)));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(ints[i], q.pollFirst());
+ }
+
+ /**
+ * pollFirst() succeeds unless empty
+ */
+ public void testPollFirst() {
+ ArrayDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.pollFirst());
+ }
+ assertNull(q.pollFirst());
+ }
+
+ /**
+ * pollLast() succeeds unless empty
+ */
+ public void testPollLast() {
+ ArrayDeque q = populatedDeque(SIZE);
+ for (int i = SIZE-1; i >= 0; --i) {
+ assertEquals(i, q.pollLast());
+ }
+ assertNull(q.pollLast());
+ }
+
+ /**
+ * poll() succeeds unless empty
+ */
+ public void testPoll() {
+ ArrayDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.poll());
+ }
+ assertNull(q.poll());
+ }
+
+ /**
+ * remove() removes next element, or throws NSEE if empty
+ */
+ public void testRemove() {
+ ArrayDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.remove());
+ }
+ try {
+ q.remove();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * remove(x) removes x and returns true if present
+ */
+ public void testRemoveElement() {
+ ArrayDeque q = populatedDeque(SIZE);
+ for (int i = 1; i < SIZE; i+=2) {
+ assertTrue(q.contains(i));
+ assertTrue(q.remove(i));
+ assertFalse(q.contains(i));
+ assertTrue(q.contains(i-1));
+ }
+ for (int i = 0; i < SIZE; i+=2) {
+ assertTrue(q.contains(i));
+ assertTrue(q.remove(i));
+ assertFalse(q.contains(i));
+ assertFalse(q.remove(i+1));
+ assertFalse(q.contains(i+1));
+ }
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * peekFirst() returns next element, or null if empty
+ */
+ public void testPeekFirst() {
+ ArrayDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.peekFirst());
+ assertEquals(i, q.pollFirst());
+ assertTrue(q.peekFirst() == null ||
+ !q.peekFirst().equals(i));
+ }
+ assertNull(q.peekFirst());
+ }
+
+ /**
+ * peek() returns next element, or null if empty
+ */
+ public void testPeek() {
+ ArrayDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.peek());
+ assertEquals(i, q.poll());
+ assertTrue(q.peek() == null ||
+ !q.peek().equals(i));
+ }
+ assertNull(q.peek());
+ }
+
+ /**
+ * peekLast() returns next element, or null if empty
+ */
+ public void testPeekLast() {
+ ArrayDeque q = populatedDeque(SIZE);
+ for (int i = SIZE-1; i >= 0; --i) {
+ assertEquals(i, q.peekLast());
+ assertEquals(i, q.pollLast());
+ assertTrue(q.peekLast() == null ||
+ !q.peekLast().equals(i));
+ }
+ assertNull(q.peekLast());
+ }
+
+ /**
+ * element() returns first element, or throws NSEE if empty
+ */
+ public void testElement() {
+ ArrayDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.element());
+ assertEquals(i, q.poll());
+ }
+ try {
+ q.element();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * getFirst() returns first element, or throws NSEE if empty
+ */
+ public void testFirstElement() {
+ ArrayDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.getFirst());
+ assertEquals(i, q.pollFirst());
+ }
+ try {
+ q.getFirst();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * getLast() returns last element, or throws NSEE if empty
+ */
+ public void testLastElement() {
+ ArrayDeque q = populatedDeque(SIZE);
+ for (int i = SIZE-1; i >= 0; --i) {
+ assertEquals(i, q.getLast());
+ assertEquals(i, q.pollLast());
+ }
+ try {
+ q.getLast();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ assertNull(q.peekLast());
+ }
+
+ /**
+ * removeFirst() removes first element, or throws NSEE if empty
+ */
+ public void testRemoveFirst() {
+ ArrayDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.removeFirst());
+ }
+ try {
+ q.removeFirst();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ assertNull(q.peekFirst());
+ }
+
+ /**
+ * removeLast() removes last element, or throws NSEE if empty
+ */
+ public void testRemoveLast() {
+ ArrayDeque q = populatedDeque(SIZE);
+ for (int i = SIZE - 1; i >= 0; --i) {
+ assertEquals(i, q.removeLast());
+ }
+ try {
+ q.removeLast();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ assertNull(q.peekLast());
+ }
+
+ /**
+ * removeFirstOccurrence(x) removes x and returns true if present
+ */
+ public void testRemoveFirstOccurrence() {
+ ArrayDeque q = populatedDeque(SIZE);
+ for (int i = 1; i < SIZE; i+=2) {
+ assertTrue(q.removeFirstOccurrence(new Integer(i)));
+ }
+ for (int i = 0; i < SIZE; i+=2) {
+ assertTrue(q.removeFirstOccurrence(new Integer(i)));
+ assertFalse(q.removeFirstOccurrence(new Integer(i+1)));
+ }
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * removeLastOccurrence(x) removes x and returns true if present
+ */
+ public void testRemoveLastOccurrence() {
+ ArrayDeque q = populatedDeque(SIZE);
+ for (int i = 1; i < SIZE; i+=2) {
+ assertTrue(q.removeLastOccurrence(new Integer(i)));
+ }
+ for (int i = 0; i < SIZE; i+=2) {
+ assertTrue(q.removeLastOccurrence(new Integer(i)));
+ assertFalse(q.removeLastOccurrence(new Integer(i+1)));
+ }
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * contains(x) reports true when elements added but not yet removed
+ */
+ public void testContains() {
+ ArrayDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.contains(new Integer(i)));
+ assertEquals(i, q.pollFirst());
+ assertFalse(q.contains(new Integer(i)));
+ }
+ }
+
+ /**
+ * clear removes all elements
+ */
+ public void testClear() {
+ ArrayDeque q = populatedDeque(SIZE);
+ q.clear();
+ assertTrue(q.isEmpty());
+ assertEquals(0, q.size());
+ assertTrue(q.add(new Integer(1)));
+ assertFalse(q.isEmpty());
+ q.clear();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * containsAll(c) is true when c contains a subset of elements
+ */
+ public void testContainsAll() {
+ ArrayDeque q = populatedDeque(SIZE);
+ ArrayDeque p = new ArrayDeque();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.containsAll(p));
+ assertFalse(p.containsAll(q));
+ assertTrue(p.add(new Integer(i)));
+ }
+ assertTrue(p.containsAll(q));
+ }
+
+ /**
+ * retainAll(c) retains only those elements of c and reports true if changed
+ */
+ public void testRetainAll() {
+ ArrayDeque q = populatedDeque(SIZE);
+ ArrayDeque p = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ boolean changed = q.retainAll(p);
+ assertEquals(changed, (i > 0));
+ assertTrue(q.containsAll(p));
+ assertEquals(SIZE-i, q.size());
+ p.removeFirst();
+ }
+ }
+
+ /**
+ * removeAll(c) removes only those elements of c and reports true if changed
+ */
+ public void testRemoveAll() {
+ for (int i = 1; i < SIZE; ++i) {
+ ArrayDeque q = populatedDeque(SIZE);
+ ArrayDeque p = populatedDeque(i);
+ assertTrue(q.removeAll(p));
+ assertEquals(SIZE-i, q.size());
+ for (int j = 0; j < i; ++j) {
+ assertFalse(q.contains(p.removeFirst()));
+ }
+ }
+ }
+
+ void checkToArray(ArrayDeque q) {
+ int size = q.size();
+ Object[] o = q.toArray();
+ assertEquals(size, o.length);
+ Iterator it = q.iterator();
+ for (int i = 0; i < size; i++) {
+ Integer x = (Integer) it.next();
+ assertEquals((Integer)o[0] + i, (int) x);
+ assertSame(o[i], x);
+ }
+ }
+
+ /**
+ * toArray() contains all elements in FIFO order
+ */
+ public void testToArray() {
+ ArrayDeque q = new ArrayDeque();
+ for (int i = 0; i < SIZE; i++) {
+ checkToArray(q);
+ q.addLast(i);
+ }
+ // Provoke wraparound
+ for (int i = 0; i < SIZE; i++) {
+ checkToArray(q);
+ assertEquals(i, q.poll());
+ q.addLast(SIZE+i);
+ }
+ for (int i = 0; i < SIZE; i++) {
+ checkToArray(q);
+ assertEquals(SIZE+i, q.poll());
+ }
+ }
+
+ void checkToArray2(ArrayDeque q) {
+ int size = q.size();
+ Integer[] a1 = size == 0 ? null : new Integer[size-1];
+ Integer[] a2 = new Integer[size];
+ Integer[] a3 = new Integer[size+2];
+ if (size > 0) Arrays.fill(a1, 42);
+ Arrays.fill(a2, 42);
+ Arrays.fill(a3, 42);
+ Integer[] b1 = size == 0 ? null : (Integer[]) q.toArray(a1);
+ Integer[] b2 = (Integer[]) q.toArray(a2);
+ Integer[] b3 = (Integer[]) q.toArray(a3);
+ assertSame(a2, b2);
+ assertSame(a3, b3);
+ Iterator it = q.iterator();
+ for (int i = 0; i < size; i++) {
+ Integer x = (Integer) it.next();
+ assertSame(b1[i], x);
+ assertEquals(b1[0] + i, (int) x);
+ assertSame(b2[i], x);
+ assertSame(b3[i], x);
+ }
+ assertNull(a3[size]);
+ assertEquals(42, (int) a3[size+1]);
+ if (size > 0) {
+ assertNotSame(a1, b1);
+ assertEquals(size, b1.length);
+ for (int i = 0; i < a1.length; i++) {
+ assertEquals(42, (int) a1[i]);
+ }
+ }
+ }
+
+ /**
+ * toArray(a) contains all elements in FIFO order
+ */
+ public void testToArray2() {
+ ArrayDeque q = new ArrayDeque();
+ for (int i = 0; i < SIZE; i++) {
+ checkToArray2(q);
+ q.addLast(i);
+ }
+ // Provoke wraparound
+ for (int i = 0; i < SIZE; i++) {
+ checkToArray2(q);
+ assertEquals(i, q.poll());
+ q.addLast(SIZE+i);
+ }
+ for (int i = 0; i < SIZE; i++) {
+ checkToArray2(q);
+ assertEquals(SIZE+i, q.poll());
+ }
+ }
+
+ /**
+ * toArray(null) throws NullPointerException
+ */
+ public void testToArray_NullArg() {
+ ArrayDeque l = new ArrayDeque();
+ l.add(new Object());
+ try {
+ l.toArray(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * toArray(incompatible array type) throws ArrayStoreException
+ */
+ public void testToArray1_BadArg() {
+ ArrayDeque l = new ArrayDeque();
+ l.add(new Integer(5));
+ try {
+ l.toArray(new String[10]);
+ shouldThrow();
+ } catch (ArrayStoreException success) {}
+ }
+
+ /**
+ * Iterator iterates through all elements
+ */
+ public void testIterator() {
+ ArrayDeque q = populatedDeque(SIZE);
+ int i = 0;
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ assertTrue(q.contains(it.next()));
+ ++i;
+ }
+ assertEquals(i, SIZE);
+ }
+
+ /**
+ * Iterator ordering is FIFO
+ */
+ public void testIteratorOrdering() {
+ final ArrayDeque q = new ArrayDeque();
+ q.add(one);
+ q.add(two);
+ q.add(three);
+ int k = 0;
+ for (Iterator it = q.iterator(); it.hasNext();) {
+ assertEquals(++k, it.next());
+ }
+
+ assertEquals(3, k);
+ }
+
+ /**
+ * iterator.remove() removes current element
+ */
+ public void testIteratorRemove() {
+ final ArrayDeque q = new ArrayDeque();
+ final Random rng = new Random();
+ for (int iters = 0; iters < 100; ++iters) {
+ int max = rng.nextInt(5) + 2;
+ int split = rng.nextInt(max-1) + 1;
+ for (int j = 1; j <= max; ++j)
+ q.add(new Integer(j));
+ Iterator it = q.iterator();
+ for (int j = 1; j <= split; ++j)
+ assertEquals(it.next(), new Integer(j));
+ it.remove();
+ assertEquals(it.next(), new Integer(split+1));
+ for (int j = 1; j <= split; ++j)
+ q.remove(new Integer(j));
+ it = q.iterator();
+ for (int j = split+1; j <= max; ++j) {
+ assertEquals(it.next(), new Integer(j));
+ it.remove();
+ }
+ assertFalse(it.hasNext());
+ assertTrue(q.isEmpty());
+ }
+ }
+
+ /**
+ * Descending iterator iterates through all elements
+ */
+ public void testDescendingIterator() {
+ ArrayDeque q = populatedDeque(SIZE);
+ int i = 0;
+ Iterator it = q.descendingIterator();
+ while (it.hasNext()) {
+ assertTrue(q.contains(it.next()));
+ ++i;
+ }
+ assertEquals(i, SIZE);
+ assertFalse(it.hasNext());
+ try {
+ it.next();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * Descending iterator ordering is reverse FIFO
+ */
+ public void testDescendingIteratorOrdering() {
+ final ArrayDeque q = new ArrayDeque();
+ for (int iters = 0; iters < 100; ++iters) {
+ q.add(new Integer(3));
+ q.add(new Integer(2));
+ q.add(new Integer(1));
+ int k = 0;
+ for (Iterator it = q.descendingIterator(); it.hasNext();) {
+ assertEquals(++k, it.next());
+ }
+
+ assertEquals(3, k);
+ q.remove();
+ q.remove();
+ q.remove();
+ }
+ }
+
+ /**
+ * descendingIterator.remove() removes current element
+ */
+ public void testDescendingIteratorRemove() {
+ final ArrayDeque q = new ArrayDeque();
+ final Random rng = new Random();
+ for (int iters = 0; iters < 100; ++iters) {
+ int max = rng.nextInt(5) + 2;
+ int split = rng.nextInt(max-1) + 1;
+ for (int j = max; j >= 1; --j)
+ q.add(new Integer(j));
+ Iterator it = q.descendingIterator();
+ for (int j = 1; j <= split; ++j)
+ assertEquals(it.next(), new Integer(j));
+ it.remove();
+ assertEquals(it.next(), new Integer(split+1));
+ for (int j = 1; j <= split; ++j)
+ q.remove(new Integer(j));
+ it = q.descendingIterator();
+ for (int j = split+1; j <= max; ++j) {
+ assertEquals(it.next(), new Integer(j));
+ it.remove();
+ }
+ assertFalse(it.hasNext());
+ assertTrue(q.isEmpty());
+ }
+ }
+
+ /**
+ * toString() contains toStrings of elements
+ */
+ public void testToString() {
+ ArrayDeque q = populatedDeque(SIZE);
+ String s = q.toString();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(s.contains(String.valueOf(i)));
+ }
+ }
+
+ /**
+ * A deserialized serialized deque has same elements in same order
+ */
+ public void testSerialization() throws Exception {
+ Queue x = populatedDeque(SIZE);
+ Queue y = serialClone(x);
+
+ assertNotSame(y, x);
+ assertEquals(x.size(), y.size());
+ assertEquals(x.toString(), y.toString());
+ assertTrue(Arrays.equals(x.toArray(), y.toArray()));
+ while (!x.isEmpty()) {
+ assertFalse(y.isEmpty());
+ assertEquals(x.remove(), y.remove());
+ }
+ assertTrue(y.isEmpty());
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicBooleanTest.java b/jsr166-tests/src/test/java/jsr166/AtomicBooleanTest.java
new file mode 100644
index 0000000..7a50120
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/AtomicBooleanTest.java
@@ -0,0 +1,136 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class AtomicBooleanTest extends JSR166TestCase {
+
+ /**
+ * constructor initializes to given value
+ */
+ public void testConstructor() {
+ assertTrue(new AtomicBoolean(true).get());
+ assertFalse(new AtomicBoolean(false).get());
+ }
+
+ /**
+ * default constructed initializes to false
+ */
+ public void testConstructor2() {
+ AtomicBoolean ai = new AtomicBoolean();
+ assertFalse(ai.get());
+ }
+
+ /**
+ * get returns the last value set
+ */
+ public void testGetSet() {
+ AtomicBoolean ai = new AtomicBoolean(true);
+ assertTrue(ai.get());
+ ai.set(false);
+ assertFalse(ai.get());
+ ai.set(true);
+ assertTrue(ai.get());
+ }
+
+ /**
+ * get returns the last value lazySet in same thread
+ */
+ public void testGetLazySet() {
+ AtomicBoolean ai = new AtomicBoolean(true);
+ assertTrue(ai.get());
+ ai.lazySet(false);
+ assertFalse(ai.get());
+ ai.lazySet(true);
+ assertTrue(ai.get());
+ }
+
+ /**
+ * compareAndSet succeeds in changing value if equal to expected else fails
+ */
+ public void testCompareAndSet() {
+ AtomicBoolean ai = new AtomicBoolean(true);
+ assertTrue(ai.compareAndSet(true, false));
+ assertFalse(ai.get());
+ assertTrue(ai.compareAndSet(false, false));
+ assertFalse(ai.get());
+ assertFalse(ai.compareAndSet(true, false));
+ assertFalse(ai.get());
+ assertTrue(ai.compareAndSet(false, true));
+ assertTrue(ai.get());
+ }
+
+ /**
+ * compareAndSet in one thread enables another waiting for value
+ * to succeed
+ */
+ public void testCompareAndSetInMultipleThreads() throws Exception {
+ final AtomicBoolean ai = new AtomicBoolean(true);
+ Thread t = new Thread(new CheckedRunnable() {
+ public void realRun() {
+ while (!ai.compareAndSet(false, true)) Thread.yield();
+ }});
+
+ t.start();
+ assertTrue(ai.compareAndSet(true, false));
+ t.join(LONG_DELAY_MS);
+ assertFalse(t.isAlive());
+ }
+
+ /**
+ * repeated weakCompareAndSet succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSet() {
+ AtomicBoolean ai = new AtomicBoolean(true);
+ while (!ai.weakCompareAndSet(true, false));
+ assertFalse(ai.get());
+ while (!ai.weakCompareAndSet(false, false));
+ assertFalse(ai.get());
+ while (!ai.weakCompareAndSet(false, true));
+ assertTrue(ai.get());
+ }
+
+ /**
+ * getAndSet returns previous value and sets to given value
+ */
+ public void testGetAndSet() {
+ AtomicBoolean ai = new AtomicBoolean(true);
+ assertEquals(true, ai.getAndSet(false));
+ assertEquals(false, ai.getAndSet(false));
+ assertEquals(false, ai.getAndSet(true));
+ assertTrue(ai.get());
+ }
+
+ /**
+ * a deserialized serialized atomic holds same value
+ */
+ public void testSerialization() throws Exception {
+ AtomicBoolean x = new AtomicBoolean();
+ AtomicBoolean y = serialClone(x);
+ x.set(true);
+ AtomicBoolean z = serialClone(x);
+ assertTrue(x.get());
+ assertFalse(y.get());
+ assertTrue(z.get());
+ }
+
+ /**
+ * toString returns current value.
+ */
+ public void testToString() {
+ AtomicBoolean ai = new AtomicBoolean();
+ assertEquals(Boolean.toString(false), ai.toString());
+ ai.set(true);
+ assertEquals(Boolean.toString(true), ai.toString());
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicIntegerArrayTest.java b/jsr166-tests/src/test/java/jsr166/AtomicIntegerArrayTest.java
new file mode 100644
index 0000000..e81a107
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/AtomicIntegerArrayTest.java
@@ -0,0 +1,337 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicIntegerArray;
+
+public class AtomicIntegerArrayTest extends JSR166TestCase {
+
+ /**
+ * constructor creates array of given size with all elements zero
+ */
+ public void testConstructor() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++)
+ assertEquals(0, aa.get(i));
+ }
+
+ /**
+ * constructor with null array throws NPE
+ */
+ public void testConstructor2NPE() {
+ try {
+ int[] a = null;
+ AtomicIntegerArray aa = new AtomicIntegerArray(a);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * constructor with array is of same size and has all elements
+ */
+ public void testConstructor2() {
+ int[] a = { 17, 3, -42, 99, -7 };
+ AtomicIntegerArray aa = new AtomicIntegerArray(a);
+ assertEquals(a.length, aa.length());
+ for (int i = 0; i < a.length; i++)
+ assertEquals(a[i], aa.get(i));
+ }
+
+ /**
+ * get and set for out of bound indices throw IndexOutOfBoundsException
+ */
+ public void testIndexing() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int index : new int[] { -1, SIZE }) {
+ try {
+ aa.get(index);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ try {
+ aa.set(index, 1);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ try {
+ aa.lazySet(index, 1);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ try {
+ aa.compareAndSet(index, 1, 2);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ try {
+ aa.weakCompareAndSet(index, 1, 2);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ try {
+ aa.getAndAdd(index, 1);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ try {
+ aa.addAndGet(index, 1);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
+ }
+
+ /**
+ * get returns the last value set at index
+ */
+ public void testGetSet() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(1, aa.get(i));
+ aa.set(i, 2);
+ assertEquals(2, aa.get(i));
+ aa.set(i, -3);
+ assertEquals(-3, aa.get(i));
+ }
+ }
+
+ /**
+ * get returns the last value lazySet at index by same thread
+ */
+ public void testGetLazySet() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.lazySet(i, 1);
+ assertEquals(1, aa.get(i));
+ aa.lazySet(i, 2);
+ assertEquals(2, aa.get(i));
+ aa.lazySet(i, -3);
+ assertEquals(-3, aa.get(i));
+ }
+ }
+
+ /**
+ * compareAndSet succeeds in changing value if equal to expected else fails
+ */
+ public void testCompareAndSet() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertTrue(aa.compareAndSet(i, 1, 2));
+ assertTrue(aa.compareAndSet(i, 2, -4));
+ assertEquals(-4, aa.get(i));
+ assertFalse(aa.compareAndSet(i, -5, 7));
+ assertEquals(-4, aa.get(i));
+ assertTrue(aa.compareAndSet(i, -4, 7));
+ assertEquals(7, aa.get(i));
+ }
+ }
+
+ /**
+ * compareAndSet in one thread enables another waiting for value
+ * to succeed
+ */
+ public void testCompareAndSetInMultipleThreads() throws Exception {
+ final AtomicIntegerArray a = new AtomicIntegerArray(1);
+ a.set(0, 1);
+ Thread t = new Thread(new CheckedRunnable() {
+ public void realRun() {
+ while (!a.compareAndSet(0, 2, 3))
+ Thread.yield();
+ }});
+
+ t.start();
+ assertTrue(a.compareAndSet(0, 1, 2));
+ t.join(LONG_DELAY_MS);
+ assertFalse(t.isAlive());
+ assertEquals(3, a.get(0));
+ }
+
+ /**
+ * repeated weakCompareAndSet succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSet() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ while (!aa.weakCompareAndSet(i, 1, 2));
+ while (!aa.weakCompareAndSet(i, 2, -4));
+ assertEquals(-4, aa.get(i));
+ while (!aa.weakCompareAndSet(i, -4, 7));
+ assertEquals(7, aa.get(i));
+ }
+ }
+
+ /**
+ * getAndSet returns previous value and sets to given value at given index
+ */
+ public void testGetAndSet() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(1, aa.getAndSet(i, 0));
+ assertEquals(0, aa.getAndSet(i, -10));
+ assertEquals(-10, aa.getAndSet(i, 1));
+ }
+ }
+
+ /**
+ * getAndAdd returns previous value and adds given value
+ */
+ public void testGetAndAdd() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(1, aa.getAndAdd(i, 2));
+ assertEquals(3, aa.get(i));
+ assertEquals(3, aa.getAndAdd(i, -4));
+ assertEquals(-1, aa.get(i));
+ }
+ }
+
+ /**
+ * getAndDecrement returns previous value and decrements
+ */
+ public void testGetAndDecrement() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(1, aa.getAndDecrement(i));
+ assertEquals(0, aa.getAndDecrement(i));
+ assertEquals(-1, aa.getAndDecrement(i));
+ }
+ }
+
+ /**
+ * getAndIncrement returns previous value and increments
+ */
+ public void testGetAndIncrement() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(1, aa.getAndIncrement(i));
+ assertEquals(2, aa.get(i));
+ aa.set(i, -2);
+ assertEquals(-2, aa.getAndIncrement(i));
+ assertEquals(-1, aa.getAndIncrement(i));
+ assertEquals(0, aa.getAndIncrement(i));
+ assertEquals(1, aa.get(i));
+ }
+ }
+
+ /**
+ * addAndGet adds given value to current, and returns current value
+ */
+ public void testAddAndGet() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(3, aa.addAndGet(i, 2));
+ assertEquals(3, aa.get(i));
+ assertEquals(-1, aa.addAndGet(i, -4));
+ assertEquals(-1, aa.get(i));
+ }
+ }
+
+ /**
+ * decrementAndGet decrements and returns current value
+ */
+ public void testDecrementAndGet() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(0, aa.decrementAndGet(i));
+ assertEquals(-1, aa.decrementAndGet(i));
+ assertEquals(-2, aa.decrementAndGet(i));
+ assertEquals(-2, aa.get(i));
+ }
+ }
+
+ /**
+ * incrementAndGet increments and returns current value
+ */
+ public void testIncrementAndGet() {
+ AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(2, aa.incrementAndGet(i));
+ assertEquals(2, aa.get(i));
+ aa.set(i, -2);
+ assertEquals(-1, aa.incrementAndGet(i));
+ assertEquals(0, aa.incrementAndGet(i));
+ assertEquals(1, aa.incrementAndGet(i));
+ assertEquals(1, aa.get(i));
+ }
+ }
+
+ static final int COUNTDOWN = 100000;
+
+ class Counter extends CheckedRunnable {
+ final AtomicIntegerArray aa;
+ volatile int counts;
+ Counter(AtomicIntegerArray a) { aa = a; }
+ public void realRun() {
+ for (;;) {
+ boolean done = true;
+ for (int i = 0; i < aa.length(); i++) {
+ int v = aa.get(i);
+ assertTrue(v >= 0);
+ if (v != 0) {
+ done = false;
+ if (aa.compareAndSet(i, v, v-1))
+ ++counts;
+ }
+ }
+ if (done)
+ break;
+ }
+ }
+ }
+
+ /**
+ * Multiple threads using same array of counters successfully
+ * update a number of times equal to total count
+ */
+ public void testCountingInMultipleThreads() throws InterruptedException {
+ final AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++)
+ aa.set(i, COUNTDOWN);
+ Counter c1 = new Counter(aa);
+ Counter c2 = new Counter(aa);
+ Thread t1 = new Thread(c1);
+ Thread t2 = new Thread(c2);
+ t1.start();
+ t2.start();
+ t1.join();
+ t2.join();
+ assertEquals(c1.counts+c2.counts, SIZE * COUNTDOWN);
+ }
+
+ /**
+ * a deserialized serialized array holds same values
+ */
+ public void testSerialization() throws Exception {
+ AtomicIntegerArray x = new AtomicIntegerArray(SIZE);
+ for (int i = 0; i < SIZE; i++)
+ x.set(i, -i);
+ AtomicIntegerArray y = serialClone(x);
+ assertNotSame(x, y);
+ assertEquals(x.length(), y.length());
+ for (int i = 0; i < SIZE; i++) {
+ assertEquals(x.get(i), y.get(i));
+ }
+ }
+
+ /**
+ * toString returns current value.
+ */
+ public void testToString() {
+ int[] a = { 17, 3, -42, 99, -7 };
+ AtomicIntegerArray aa = new AtomicIntegerArray(a);
+ assertEquals(Arrays.toString(a), aa.toString());
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicIntegerFieldUpdaterTest.java b/jsr166-tests/src/test/java/jsr166/AtomicIntegerFieldUpdaterTest.java
new file mode 100644
index 0000000..f0c1ae6
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/AtomicIntegerFieldUpdaterTest.java
@@ -0,0 +1,232 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
+
+public class AtomicIntegerFieldUpdaterTest extends JSR166TestCase {
+ volatile int x = 0;
+ int w;
+ long z;
+
+ AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> updaterFor(String fieldName) {
+ return AtomicIntegerFieldUpdater.newUpdater
+ (AtomicIntegerFieldUpdaterTest.class, fieldName);
+ }
+
+ /**
+ * Construction with non-existent field throws RuntimeException
+ */
+ public void testConstructor() {
+ try {
+ updaterFor("y");
+ shouldThrow();
+ } catch (RuntimeException success) {
+ assertNotNull(success.getCause());
+ }
+ }
+
+ /**
+ * construction with field not of given type throws IllegalArgumentException
+ */
+ public void testConstructor2() {
+ try {
+ updaterFor("z");
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * construction with non-volatile field throws IllegalArgumentException
+ */
+ public void testConstructor3() {
+ try {
+ updaterFor("w");
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * get returns the last value set or assigned
+ */
+ public void testGetSet() {
+ AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a;
+ a = updaterFor("x");
+ x = 1;
+ assertEquals(1, a.get(this));
+ a.set(this, 2);
+ assertEquals(2, a.get(this));
+ a.set(this, -3);
+ assertEquals(-3, a.get(this));
+ }
+
+ /**
+ * get returns the last value lazySet by same thread
+ */
+ public void testGetLazySet() {
+ AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a;
+ a = updaterFor("x");
+ x = 1;
+ assertEquals(1, a.get(this));
+ a.lazySet(this, 2);
+ assertEquals(2, a.get(this));
+ a.lazySet(this, -3);
+ assertEquals(-3, a.get(this));
+ }
+
+ /**
+ * compareAndSet succeeds in changing value if equal to expected else fails
+ */
+ public void testCompareAndSet() {
+ AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a;
+ a = updaterFor("x");
+ x = 1;
+ assertTrue(a.compareAndSet(this, 1, 2));
+ assertTrue(a.compareAndSet(this, 2, -4));
+ assertEquals(-4, a.get(this));
+ assertFalse(a.compareAndSet(this, -5, 7));
+ assertEquals(-4, a.get(this));
+ assertTrue(a.compareAndSet(this, -4, 7));
+ assertEquals(7, a.get(this));
+ }
+
+ /**
+ * compareAndSet in one thread enables another waiting for value
+ * to succeed
+ */
+ public void testCompareAndSetInMultipleThreads() throws Exception {
+ x = 1;
+ final AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a;
+ a = updaterFor("x");
+
+ Thread t = new Thread(new CheckedRunnable() {
+ public void realRun() {
+ while (!a.compareAndSet(AtomicIntegerFieldUpdaterTest.this, 2, 3))
+ Thread.yield();
+ }});
+
+ t.start();
+ assertTrue(a.compareAndSet(this, 1, 2));
+ t.join(LONG_DELAY_MS);
+ assertFalse(t.isAlive());
+ assertEquals(3, a.get(this));
+ }
+
+ /**
+ * repeated weakCompareAndSet succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSet() {
+ AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a;
+ a = updaterFor("x");
+ x = 1;
+ while (!a.weakCompareAndSet(this, 1, 2));
+ while (!a.weakCompareAndSet(this, 2, -4));
+ assertEquals(-4, a.get(this));
+ while (!a.weakCompareAndSet(this, -4, 7));
+ assertEquals(7, a.get(this));
+ }
+
+ /**
+ * getAndSet returns previous value and sets to given value
+ */
+ public void testGetAndSet() {
+ AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a;
+ a = updaterFor("x");
+ x = 1;
+ assertEquals(1, a.getAndSet(this, 0));
+ assertEquals(0, a.getAndSet(this, -10));
+ assertEquals(-10, a.getAndSet(this, 1));
+ }
+
+ /**
+ * getAndAdd returns previous value and adds given value
+ */
+ public void testGetAndAdd() {
+ AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a;
+ a = updaterFor("x");
+ x = 1;
+ assertEquals(1, a.getAndAdd(this, 2));
+ assertEquals(3, a.get(this));
+ assertEquals(3, a.getAndAdd(this, -4));
+ assertEquals(-1, a.get(this));
+ }
+
+ /**
+ * getAndDecrement returns previous value and decrements
+ */
+ public void testGetAndDecrement() {
+ AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a;
+ a = updaterFor("x");
+ x = 1;
+ assertEquals(1, a.getAndDecrement(this));
+ assertEquals(0, a.getAndDecrement(this));
+ assertEquals(-1, a.getAndDecrement(this));
+ }
+
+ /**
+ * getAndIncrement returns previous value and increments
+ */
+ public void testGetAndIncrement() {
+ AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a;
+ a = updaterFor("x");
+ x = 1;
+ assertEquals(1, a.getAndIncrement(this));
+ assertEquals(2, a.get(this));
+ a.set(this, -2);
+ assertEquals(-2, a.getAndIncrement(this));
+ assertEquals(-1, a.getAndIncrement(this));
+ assertEquals(0, a.getAndIncrement(this));
+ assertEquals(1, a.get(this));
+ }
+
+ /**
+ * addAndGet adds given value to current, and returns current value
+ */
+ public void testAddAndGet() {
+ AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a;
+ a = updaterFor("x");
+ x = 1;
+ assertEquals(3, a.addAndGet(this, 2));
+ assertEquals(3, a.get(this));
+ assertEquals(-1, a.addAndGet(this, -4));
+ assertEquals(-1, a.get(this));
+ }
+
+ /**
+ * decrementAndGet decrements and returns current value
+ */
+ public void testDecrementAndGet() {
+ AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a;
+ a = updaterFor("x");
+ x = 1;
+ assertEquals(0, a.decrementAndGet(this));
+ assertEquals(-1, a.decrementAndGet(this));
+ assertEquals(-2, a.decrementAndGet(this));
+ assertEquals(-2, a.get(this));
+ }
+
+ /**
+ * incrementAndGet increments and returns current value
+ */
+ public void testIncrementAndGet() {
+ AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a;
+ a = updaterFor("x");
+ x = 1;
+ assertEquals(2, a.incrementAndGet(this));
+ assertEquals(2, a.get(this));
+ a.set(this, -2);
+ assertEquals(-1, a.incrementAndGet(this));
+ assertEquals(0, a.incrementAndGet(this));
+ assertEquals(1, a.incrementAndGet(this));
+ assertEquals(1, a.get(this));
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicIntegerTest.java b/jsr166-tests/src/test/java/jsr166/AtomicIntegerTest.java
new file mode 100644
index 0000000..2afaa73
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/AtomicIntegerTest.java
@@ -0,0 +1,261 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class AtomicIntegerTest extends JSR166TestCase {
+
+ final int[] VALUES = {
+ Integer.MIN_VALUE, -1, 0, 1, 42, Integer.MAX_VALUE,
+ };
+
+ /**
+ * constructor initializes to given value
+ */
+ public void testConstructor() {
+ AtomicInteger ai = new AtomicInteger(1);
+ assertEquals(1, ai.get());
+ }
+
+ /**
+ * default constructed initializes to zero
+ */
+ public void testConstructor2() {
+ AtomicInteger ai = new AtomicInteger();
+ assertEquals(0, ai.get());
+ }
+
+ /**
+ * get returns the last value set
+ */
+ public void testGetSet() {
+ AtomicInteger ai = new AtomicInteger(1);
+ assertEquals(1, ai.get());
+ ai.set(2);
+ assertEquals(2, ai.get());
+ ai.set(-3);
+ assertEquals(-3, ai.get());
+ }
+
+ /**
+ * get returns the last value lazySet in same thread
+ */
+ public void testGetLazySet() {
+ AtomicInteger ai = new AtomicInteger(1);
+ assertEquals(1, ai.get());
+ ai.lazySet(2);
+ assertEquals(2, ai.get());
+ ai.lazySet(-3);
+ assertEquals(-3, ai.get());
+ }
+
+ /**
+ * compareAndSet succeeds in changing value if equal to expected else fails
+ */
+ public void testCompareAndSet() {
+ AtomicInteger ai = new AtomicInteger(1);
+ assertTrue(ai.compareAndSet(1, 2));
+ assertTrue(ai.compareAndSet(2, -4));
+ assertEquals(-4, ai.get());
+ assertFalse(ai.compareAndSet(-5, 7));
+ assertEquals(-4, ai.get());
+ assertTrue(ai.compareAndSet(-4, 7));
+ assertEquals(7, ai.get());
+ }
+
+ /**
+ * compareAndSet in one thread enables another waiting for value
+ * to succeed
+ */
+ public void testCompareAndSetInMultipleThreads() throws Exception {
+ final AtomicInteger ai = new AtomicInteger(1);
+ Thread t = new Thread(new CheckedRunnable() {
+ public void realRun() {
+ while (!ai.compareAndSet(2, 3))
+ Thread.yield();
+ }});
+
+ t.start();
+ assertTrue(ai.compareAndSet(1, 2));
+ t.join(LONG_DELAY_MS);
+ assertFalse(t.isAlive());
+ assertEquals(3, ai.get());
+ }
+
+ /**
+ * repeated weakCompareAndSet succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSet() {
+ AtomicInteger ai = new AtomicInteger(1);
+ while (!ai.weakCompareAndSet(1, 2));
+ while (!ai.weakCompareAndSet(2, -4));
+ assertEquals(-4, ai.get());
+ while (!ai.weakCompareAndSet(-4, 7));
+ assertEquals(7, ai.get());
+ }
+
+ /**
+ * getAndSet returns previous value and sets to given value
+ */
+ public void testGetAndSet() {
+ AtomicInteger ai = new AtomicInteger(1);
+ assertEquals(1, ai.getAndSet(0));
+ assertEquals(0, ai.getAndSet(-10));
+ assertEquals(-10, ai.getAndSet(1));
+ }
+
+ /**
+ * getAndAdd returns previous value and adds given value
+ */
+ public void testGetAndAdd() {
+ AtomicInteger ai = new AtomicInteger(1);
+ assertEquals(1, ai.getAndAdd(2));
+ assertEquals(3, ai.get());
+ assertEquals(3, ai.getAndAdd(-4));
+ assertEquals(-1, ai.get());
+ }
+
+ /**
+ * getAndDecrement returns previous value and decrements
+ */
+ public void testGetAndDecrement() {
+ AtomicInteger ai = new AtomicInteger(1);
+ assertEquals(1, ai.getAndDecrement());
+ assertEquals(0, ai.getAndDecrement());
+ assertEquals(-1, ai.getAndDecrement());
+ }
+
+ /**
+ * getAndIncrement returns previous value and increments
+ */
+ public void testGetAndIncrement() {
+ AtomicInteger ai = new AtomicInteger(1);
+ assertEquals(1, ai.getAndIncrement());
+ assertEquals(2, ai.get());
+ ai.set(-2);
+ assertEquals(-2, ai.getAndIncrement());
+ assertEquals(-1, ai.getAndIncrement());
+ assertEquals(0, ai.getAndIncrement());
+ assertEquals(1, ai.get());
+ }
+
+ /**
+ * addAndGet adds given value to current, and returns current value
+ */
+ public void testAddAndGet() {
+ AtomicInteger ai = new AtomicInteger(1);
+ assertEquals(3, ai.addAndGet(2));
+ assertEquals(3, ai.get());
+ assertEquals(-1, ai.addAndGet(-4));
+ assertEquals(-1, ai.get());
+ }
+
+ /**
+ * decrementAndGet decrements and returns current value
+ */
+ public void testDecrementAndGet() {
+ AtomicInteger ai = new AtomicInteger(1);
+ assertEquals(0, ai.decrementAndGet());
+ assertEquals(-1, ai.decrementAndGet());
+ assertEquals(-2, ai.decrementAndGet());
+ assertEquals(-2, ai.get());
+ }
+
+ /**
+ * incrementAndGet increments and returns current value
+ */
+ public void testIncrementAndGet() {
+ AtomicInteger ai = new AtomicInteger(1);
+ assertEquals(2, ai.incrementAndGet());
+ assertEquals(2, ai.get());
+ ai.set(-2);
+ assertEquals(-1, ai.incrementAndGet());
+ assertEquals(0, ai.incrementAndGet());
+ assertEquals(1, ai.incrementAndGet());
+ assertEquals(1, ai.get());
+ }
+
+ /**
+ * a deserialized serialized atomic holds same value
+ */
+ public void testSerialization() throws Exception {
+ AtomicInteger x = new AtomicInteger();
+ AtomicInteger y = serialClone(x);
+ assertNotSame(x, y);
+ x.set(22);
+ AtomicInteger z = serialClone(x);
+ assertEquals(22, x.get());
+ assertEquals(0, y.get());
+ assertEquals(22, z.get());
+ }
+
+ /**
+ * toString returns current value.
+ */
+ public void testToString() {
+ AtomicInteger ai = new AtomicInteger();
+ assertEquals("0", ai.toString());
+ for (int x : VALUES) {
+ ai.set(x);
+ assertEquals(Integer.toString(x), ai.toString());
+ }
+ }
+
+ /**
+ * intValue returns current value.
+ */
+ public void testIntValue() {
+ AtomicInteger ai = new AtomicInteger();
+ assertEquals(0, ai.intValue());
+ for (int x : VALUES) {
+ ai.set(x);
+ assertEquals(x, ai.intValue());
+ }
+ }
+
+ /**
+ * longValue returns current value.
+ */
+ public void testLongValue() {
+ AtomicInteger ai = new AtomicInteger();
+ assertEquals(0L, ai.longValue());
+ for (int x : VALUES) {
+ ai.set(x);
+ assertEquals((long)x, ai.longValue());
+ }
+ }
+
+ /**
+ * floatValue returns current value.
+ */
+ public void testFloatValue() {
+ AtomicInteger ai = new AtomicInteger();
+ assertEquals(0.0f, ai.floatValue());
+ for (int x : VALUES) {
+ ai.set(x);
+ assertEquals((float)x, ai.floatValue());
+ }
+ }
+
+ /**
+ * doubleValue returns current value.
+ */
+ public void testDoubleValue() {
+ AtomicInteger ai = new AtomicInteger();
+ assertEquals(0.0d, ai.doubleValue());
+ for (int x : VALUES) {
+ ai.set(x);
+ assertEquals((double)x, ai.doubleValue());
+ }
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicLongArrayTest.java b/jsr166-tests/src/test/java/jsr166/AtomicLongArrayTest.java
new file mode 100644
index 0000000..53be5dc
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/AtomicLongArrayTest.java
@@ -0,0 +1,337 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicLongArray;
+
+public class AtomicLongArrayTest extends JSR166TestCase {
+
+ /**
+ * constructor creates array of given size with all elements zero
+ */
+ public void testConstructor() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++)
+ assertEquals(0, aa.get(i));
+ }
+
+ /**
+ * constructor with null array throws NPE
+ */
+ public void testConstructor2NPE() {
+ try {
+ long[] a = null;
+ AtomicLongArray aa = new AtomicLongArray(a);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * constructor with array is of same size and has all elements
+ */
+ public void testConstructor2() {
+ long[] a = { 17L, 3L, -42L, 99L, -7L };
+ AtomicLongArray aa = new AtomicLongArray(a);
+ assertEquals(a.length, aa.length());
+ for (int i = 0; i < a.length; i++)
+ assertEquals(a[i], aa.get(i));
+ }
+
+ /**
+ * get and set for out of bound indices throw IndexOutOfBoundsException
+ */
+ public void testIndexing() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int index : new int[] { -1, SIZE }) {
+ try {
+ aa.get(index);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ try {
+ aa.set(index, 1);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ try {
+ aa.lazySet(index, 1);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ try {
+ aa.compareAndSet(index, 1, 2);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ try {
+ aa.weakCompareAndSet(index, 1, 2);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ try {
+ aa.getAndAdd(index, 1);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ try {
+ aa.addAndGet(index, 1);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
+ }
+
+ /**
+ * get returns the last value set at index
+ */
+ public void testGetSet() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(1, aa.get(i));
+ aa.set(i, 2);
+ assertEquals(2, aa.get(i));
+ aa.set(i, -3);
+ assertEquals(-3, aa.get(i));
+ }
+ }
+
+ /**
+ * get returns the last value lazySet at index by same thread
+ */
+ public void testGetLazySet() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.lazySet(i, 1);
+ assertEquals(1, aa.get(i));
+ aa.lazySet(i, 2);
+ assertEquals(2, aa.get(i));
+ aa.lazySet(i, -3);
+ assertEquals(-3, aa.get(i));
+ }
+ }
+
+ /**
+ * compareAndSet succeeds in changing value if equal to expected else fails
+ */
+ public void testCompareAndSet() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertTrue(aa.compareAndSet(i, 1, 2));
+ assertTrue(aa.compareAndSet(i, 2, -4));
+ assertEquals(-4, aa.get(i));
+ assertFalse(aa.compareAndSet(i, -5, 7));
+ assertEquals(-4, aa.get(i));
+ assertTrue(aa.compareAndSet(i, -4, 7));
+ assertEquals(7, aa.get(i));
+ }
+ }
+
+ /**
+ * compareAndSet in one thread enables another waiting for value
+ * to succeed
+ */
+ public void testCompareAndSetInMultipleThreads() throws InterruptedException {
+ final AtomicLongArray a = new AtomicLongArray(1);
+ a.set(0, 1);
+ Thread t = new Thread(new CheckedRunnable() {
+ public void realRun() {
+ while (!a.compareAndSet(0, 2, 3))
+ Thread.yield();
+ }});
+
+ t.start();
+ assertTrue(a.compareAndSet(0, 1, 2));
+ t.join(LONG_DELAY_MS);
+ assertFalse(t.isAlive());
+ assertEquals(3, a.get(0));
+ }
+
+ /**
+ * repeated weakCompareAndSet succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSet() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ while (!aa.weakCompareAndSet(i, 1, 2));
+ while (!aa.weakCompareAndSet(i, 2, -4));
+ assertEquals(-4, aa.get(i));
+ while (!aa.weakCompareAndSet(i, -4, 7));
+ assertEquals(7, aa.get(i));
+ }
+ }
+
+ /**
+ * getAndSet returns previous value and sets to given value at given index
+ */
+ public void testGetAndSet() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(1, aa.getAndSet(i, 0));
+ assertEquals(0, aa.getAndSet(i, -10));
+ assertEquals(-10, aa.getAndSet(i, 1));
+ }
+ }
+
+ /**
+ * getAndAdd returns previous value and adds given value
+ */
+ public void testGetAndAdd() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(1, aa.getAndAdd(i, 2));
+ assertEquals(3, aa.get(i));
+ assertEquals(3, aa.getAndAdd(i, -4));
+ assertEquals(-1, aa.get(i));
+ }
+ }
+
+ /**
+ * getAndDecrement returns previous value and decrements
+ */
+ public void testGetAndDecrement() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(1, aa.getAndDecrement(i));
+ assertEquals(0, aa.getAndDecrement(i));
+ assertEquals(-1, aa.getAndDecrement(i));
+ }
+ }
+
+ /**
+ * getAndIncrement returns previous value and increments
+ */
+ public void testGetAndIncrement() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(1, aa.getAndIncrement(i));
+ assertEquals(2, aa.get(i));
+ aa.set(i, -2);
+ assertEquals(-2, aa.getAndIncrement(i));
+ assertEquals(-1, aa.getAndIncrement(i));
+ assertEquals(0, aa.getAndIncrement(i));
+ assertEquals(1, aa.get(i));
+ }
+ }
+
+ /**
+ * addAndGet adds given value to current, and returns current value
+ */
+ public void testAddAndGet() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(3, aa.addAndGet(i, 2));
+ assertEquals(3, aa.get(i));
+ assertEquals(-1, aa.addAndGet(i, -4));
+ assertEquals(-1, aa.get(i));
+ }
+ }
+
+ /**
+ * decrementAndGet decrements and returns current value
+ */
+ public void testDecrementAndGet() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(0, aa.decrementAndGet(i));
+ assertEquals(-1, aa.decrementAndGet(i));
+ assertEquals(-2, aa.decrementAndGet(i));
+ assertEquals(-2, aa.get(i));
+ }
+ }
+
+ /**
+ * incrementAndGet increments and returns current value
+ */
+ public void testIncrementAndGet() {
+ AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, 1);
+ assertEquals(2, aa.incrementAndGet(i));
+ assertEquals(2, aa.get(i));
+ aa.set(i, -2);
+ assertEquals(-1, aa.incrementAndGet(i));
+ assertEquals(0, aa.incrementAndGet(i));
+ assertEquals(1, aa.incrementAndGet(i));
+ assertEquals(1, aa.get(i));
+ }
+ }
+
+ static final long COUNTDOWN = 100000;
+
+ class Counter extends CheckedRunnable {
+ final AtomicLongArray aa;
+ volatile long counts;
+ Counter(AtomicLongArray a) { aa = a; }
+ public void realRun() {
+ for (;;) {
+ boolean done = true;
+ for (int i = 0; i < aa.length(); i++) {
+ long v = aa.get(i);
+ assertTrue(v >= 0);
+ if (v != 0) {
+ done = false;
+ if (aa.compareAndSet(i, v, v-1))
+ ++counts;
+ }
+ }
+ if (done)
+ break;
+ }
+ }
+ }
+
+ /**
+ * Multiple threads using same array of counters successfully
+ * update a number of times equal to total count
+ */
+ public void testCountingInMultipleThreads() throws InterruptedException {
+ final AtomicLongArray aa = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++)
+ aa.set(i, COUNTDOWN);
+ Counter c1 = new Counter(aa);
+ Counter c2 = new Counter(aa);
+ Thread t1 = new Thread(c1);
+ Thread t2 = new Thread(c2);
+ t1.start();
+ t2.start();
+ t1.join();
+ t2.join();
+ assertEquals(c1.counts+c2.counts, SIZE * COUNTDOWN);
+ }
+
+ /**
+ * a deserialized serialized array holds same values
+ */
+ public void testSerialization() throws Exception {
+ AtomicLongArray x = new AtomicLongArray(SIZE);
+ for (int i = 0; i < SIZE; i++)
+ x.set(i, -i);
+ AtomicLongArray y = serialClone(x);
+ assertNotSame(x, y);
+ assertEquals(x.length(), y.length());
+ for (int i = 0; i < SIZE; i++) {
+ assertEquals(x.get(i), y.get(i));
+ }
+ }
+
+ /**
+ * toString returns current value.
+ */
+ public void testToString() {
+ long[] a = { 17, 3, -42, 99, -7 };
+ AtomicLongArray aa = new AtomicLongArray(a);
+ assertEquals(Arrays.toString(a), aa.toString());
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicLongFieldUpdaterTest.java b/jsr166-tests/src/test/java/jsr166/AtomicLongFieldUpdaterTest.java
new file mode 100644
index 0000000..c9374e0
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/AtomicLongFieldUpdaterTest.java
@@ -0,0 +1,232 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.concurrent.atomic.AtomicLongFieldUpdater;
+
+public class AtomicLongFieldUpdaterTest extends JSR166TestCase {
+ volatile long x = 0;
+ int z;
+ long w;
+
+ AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> updaterFor(String fieldName) {
+ return AtomicLongFieldUpdater.newUpdater
+ (AtomicLongFieldUpdaterTest.class, fieldName);
+ }
+
+ /**
+ * Construction with non-existent field throws RuntimeException
+ */
+ public void testConstructor() {
+ try {
+ updaterFor("y");
+ shouldThrow();
+ } catch (RuntimeException success) {
+ assertNotNull(success.getCause());
+ }
+ }
+
+ /**
+ * construction with field not of given type throws IllegalArgumentException
+ */
+ public void testConstructor2() {
+ try {
+ updaterFor("z");
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * construction with non-volatile field throws IllegalArgumentException
+ */
+ public void testConstructor3() {
+ try {
+ updaterFor("w");
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * get returns the last value set or assigned
+ */
+ public void testGetSet() {
+ AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a;
+ a = updaterFor("x");
+ x = 1;
+ assertEquals(1, a.get(this));
+ a.set(this, 2);
+ assertEquals(2, a.get(this));
+ a.set(this, -3);
+ assertEquals(-3, a.get(this));
+ }
+
+ /**
+ * get returns the last value lazySet by same thread
+ */
+ public void testGetLazySet() {
+ AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a;
+ a = updaterFor("x");
+ x = 1;
+ assertEquals(1, a.get(this));
+ a.lazySet(this, 2);
+ assertEquals(2, a.get(this));
+ a.lazySet(this, -3);
+ assertEquals(-3, a.get(this));
+ }
+
+ /**
+ * compareAndSet succeeds in changing value if equal to expected else fails
+ */
+ public void testCompareAndSet() {
+ AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a;
+ a = updaterFor("x");
+ x = 1;
+ assertTrue(a.compareAndSet(this, 1, 2));
+ assertTrue(a.compareAndSet(this, 2, -4));
+ assertEquals(-4, a.get(this));
+ assertFalse(a.compareAndSet(this, -5, 7));
+ assertEquals(-4, a.get(this));
+ assertTrue(a.compareAndSet(this, -4, 7));
+ assertEquals(7, a.get(this));
+ }
+
+ /**
+ * compareAndSet in one thread enables another waiting for value
+ * to succeed
+ */
+ public void testCompareAndSetInMultipleThreads() throws Exception {
+ x = 1;
+ final AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a;
+ a = updaterFor("x");
+
+ Thread t = new Thread(new CheckedRunnable() {
+ public void realRun() {
+ while (!a.compareAndSet(AtomicLongFieldUpdaterTest.this, 2, 3))
+ Thread.yield();
+ }});
+
+ t.start();
+ assertTrue(a.compareAndSet(this, 1, 2));
+ t.join(LONG_DELAY_MS);
+ assertFalse(t.isAlive());
+ assertEquals(3, a.get(this));
+ }
+
+ /**
+ * repeated weakCompareAndSet succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSet() {
+ AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a;
+ a = updaterFor("x");
+ x = 1;
+ while (!a.weakCompareAndSet(this, 1, 2));
+ while (!a.weakCompareAndSet(this, 2, -4));
+ assertEquals(-4, a.get(this));
+ while (!a.weakCompareAndSet(this, -4, 7));
+ assertEquals(7, a.get(this));
+ }
+
+ /**
+ * getAndSet returns previous value and sets to given value
+ */
+ public void testGetAndSet() {
+ AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a;
+ a = updaterFor("x");
+ x = 1;
+ assertEquals(1, a.getAndSet(this, 0));
+ assertEquals(0, a.getAndSet(this, -10));
+ assertEquals(-10, a.getAndSet(this, 1));
+ }
+
+ /**
+ * getAndAdd returns previous value and adds given value
+ */
+ public void testGetAndAdd() {
+ AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a;
+ a = updaterFor("x");
+ x = 1;
+ assertEquals(1, a.getAndAdd(this, 2));
+ assertEquals(3, a.get(this));
+ assertEquals(3, a.getAndAdd(this, -4));
+ assertEquals(-1, a.get(this));
+ }
+
+ /**
+ * getAndDecrement returns previous value and decrements
+ */
+ public void testGetAndDecrement() {
+ AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a;
+ a = updaterFor("x");
+ x = 1;
+ assertEquals(1, a.getAndDecrement(this));
+ assertEquals(0, a.getAndDecrement(this));
+ assertEquals(-1, a.getAndDecrement(this));
+ }
+
+ /**
+ * getAndIncrement returns previous value and increments
+ */
+ public void testGetAndIncrement() {
+ AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a;
+ a = updaterFor("x");
+ x = 1;
+ assertEquals(1, a.getAndIncrement(this));
+ assertEquals(2, a.get(this));
+ a.set(this, -2);
+ assertEquals(-2, a.getAndIncrement(this));
+ assertEquals(-1, a.getAndIncrement(this));
+ assertEquals(0, a.getAndIncrement(this));
+ assertEquals(1, a.get(this));
+ }
+
+ /**
+ * addAndGet adds given value to current, and returns current value
+ */
+ public void testAddAndGet() {
+ AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a;
+ a = updaterFor("x");
+ x = 1;
+ assertEquals(3, a.addAndGet(this, 2));
+ assertEquals(3, a.get(this));
+ assertEquals(-1, a.addAndGet(this, -4));
+ assertEquals(-1, a.get(this));
+ }
+
+ /**
+ * decrementAndGet decrements and returns current value
+ */
+ public void testDecrementAndGet() {
+ AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a;
+ a = updaterFor("x");
+ x = 1;
+ assertEquals(0, a.decrementAndGet(this));
+ assertEquals(-1, a.decrementAndGet(this));
+ assertEquals(-2, a.decrementAndGet(this));
+ assertEquals(-2, a.get(this));
+ }
+
+ /**
+ * incrementAndGet increments and returns current value
+ */
+ public void testIncrementAndGet() {
+ AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a;
+ a = updaterFor("x");
+ x = 1;
+ assertEquals(2, a.incrementAndGet(this));
+ assertEquals(2, a.get(this));
+ a.set(this, -2);
+ assertEquals(-1, a.incrementAndGet(this));
+ assertEquals(0, a.incrementAndGet(this));
+ assertEquals(1, a.incrementAndGet(this));
+ assertEquals(1, a.get(this));
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicLongTest.java b/jsr166-tests/src/test/java/jsr166/AtomicLongTest.java
new file mode 100644
index 0000000..d300367
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/AtomicLongTest.java
@@ -0,0 +1,264 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.concurrent.atomic.AtomicLong;
+
+public class AtomicLongTest extends JSR166TestCase {
+
+ final long[] VALUES = {
+ Long.MIN_VALUE,
+ Integer.MIN_VALUE, -1, 0, 1, 42, Integer.MAX_VALUE,
+ Long.MAX_VALUE,
+ };
+
+ /**
+ * constructor initializes to given value
+ */
+ public void testConstructor() {
+ AtomicLong ai = new AtomicLong(1);
+ assertEquals(1, ai.get());
+ }
+
+ /**
+ * default constructed initializes to zero
+ */
+ public void testConstructor2() {
+ AtomicLong ai = new AtomicLong();
+ assertEquals(0, ai.get());
+ }
+
+ /**
+ * get returns the last value set
+ */
+ public void testGetSet() {
+ AtomicLong ai = new AtomicLong(1);
+ assertEquals(1, ai.get());
+ ai.set(2);
+ assertEquals(2, ai.get());
+ ai.set(-3);
+ assertEquals(-3, ai.get());
+ }
+
+ /**
+ * get returns the last value lazySet in same thread
+ */
+ public void testGetLazySet() {
+ AtomicLong ai = new AtomicLong(1);
+ assertEquals(1, ai.get());
+ ai.lazySet(2);
+ assertEquals(2, ai.get());
+ ai.lazySet(-3);
+ assertEquals(-3, ai.get());
+ }
+
+ /**
+ * compareAndSet succeeds in changing value if equal to expected else fails
+ */
+ public void testCompareAndSet() {
+ AtomicLong ai = new AtomicLong(1);
+ assertTrue(ai.compareAndSet(1, 2));
+ assertTrue(ai.compareAndSet(2, -4));
+ assertEquals(-4, ai.get());
+ assertFalse(ai.compareAndSet(-5, 7));
+ assertEquals(-4, ai.get());
+ assertTrue(ai.compareAndSet(-4, 7));
+ assertEquals(7, ai.get());
+ }
+
+ /**
+ * compareAndSet in one thread enables another waiting for value
+ * to succeed
+ */
+ public void testCompareAndSetInMultipleThreads() throws Exception {
+ final AtomicLong ai = new AtomicLong(1);
+ Thread t = new Thread(new CheckedRunnable() {
+ public void realRun() {
+ while (!ai.compareAndSet(2, 3))
+ Thread.yield();
+ }});
+
+ t.start();
+ assertTrue(ai.compareAndSet(1, 2));
+ t.join(LONG_DELAY_MS);
+ assertFalse(t.isAlive());
+ assertEquals(3, ai.get());
+ }
+
+ /**
+ * repeated weakCompareAndSet succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSet() {
+ AtomicLong ai = new AtomicLong(1);
+ while (!ai.weakCompareAndSet(1, 2));
+ while (!ai.weakCompareAndSet(2, -4));
+ assertEquals(-4, ai.get());
+ while (!ai.weakCompareAndSet(-4, 7));
+ assertEquals(7, ai.get());
+ }
+
+ /**
+ * getAndSet returns previous value and sets to given value
+ */
+ public void testGetAndSet() {
+ AtomicLong ai = new AtomicLong(1);
+ assertEquals(1, ai.getAndSet(0));
+ assertEquals(0, ai.getAndSet(-10));
+ assertEquals(-10, ai.getAndSet(1));
+ }
+
+ /**
+ * getAndAdd returns previous value and adds given value
+ */
+ public void testGetAndAdd() {
+ AtomicLong ai = new AtomicLong(1);
+ assertEquals(1, ai.getAndAdd(2));
+ assertEquals(3, ai.get());
+ assertEquals(3, ai.getAndAdd(-4));
+ assertEquals(-1, ai.get());
+ }
+
+ /**
+ * getAndDecrement returns previous value and decrements
+ */
+ public void testGetAndDecrement() {
+ AtomicLong ai = new AtomicLong(1);
+ assertEquals(1, ai.getAndDecrement());
+ assertEquals(0, ai.getAndDecrement());
+ assertEquals(-1, ai.getAndDecrement());
+ }
+
+ /**
+ * getAndIncrement returns previous value and increments
+ */
+ public void testGetAndIncrement() {
+ AtomicLong ai = new AtomicLong(1);
+ assertEquals(1, ai.getAndIncrement());
+ assertEquals(2, ai.get());
+ ai.set(-2);
+ assertEquals(-2, ai.getAndIncrement());
+ assertEquals(-1, ai.getAndIncrement());
+ assertEquals(0, ai.getAndIncrement());
+ assertEquals(1, ai.get());
+ }
+
+ /**
+ * addAndGet adds given value to current, and returns current value
+ */
+ public void testAddAndGet() {
+ AtomicLong ai = new AtomicLong(1);
+ assertEquals(3, ai.addAndGet(2));
+ assertEquals(3, ai.get());
+ assertEquals(-1, ai.addAndGet(-4));
+ assertEquals(-1, ai.get());
+ }
+
+ /**
+ * decrementAndGet decrements and returns current value
+ */
+ public void testDecrementAndGet() {
+ AtomicLong ai = new AtomicLong(1);
+ assertEquals(0, ai.decrementAndGet());
+ assertEquals(-1, ai.decrementAndGet());
+ assertEquals(-2, ai.decrementAndGet());
+ assertEquals(-2, ai.get());
+ }
+
+ /**
+ * incrementAndGet increments and returns current value
+ */
+ public void testIncrementAndGet() {
+ AtomicLong ai = new AtomicLong(1);
+ assertEquals(2, ai.incrementAndGet());
+ assertEquals(2, ai.get());
+ ai.set(-2);
+ assertEquals(-1, ai.incrementAndGet());
+ assertEquals(0, ai.incrementAndGet());
+ assertEquals(1, ai.incrementAndGet());
+ assertEquals(1, ai.get());
+ }
+
+ /**
+ * a deserialized serialized atomic holds same value
+ */
+ public void testSerialization() throws Exception {
+ AtomicLong x = new AtomicLong();
+ AtomicLong y = serialClone(x);
+ assertNotSame(x, y);
+ x.set(-22);
+ AtomicLong z = serialClone(x);
+ assertNotSame(y, z);
+ assertEquals(-22, x.get());
+ assertEquals(0, y.get());
+ assertEquals(-22, z.get());
+ }
+
+ /**
+ * toString returns current value.
+ */
+ public void testToString() {
+ AtomicLong ai = new AtomicLong();
+ assertEquals("0", ai.toString());
+ for (long x : VALUES) {
+ ai.set(x);
+ assertEquals(Long.toString(x), ai.toString());
+ }
+ }
+
+ /**
+ * intValue returns current value.
+ */
+ public void testIntValue() {
+ AtomicLong ai = new AtomicLong();
+ assertEquals(0, ai.intValue());
+ for (long x : VALUES) {
+ ai.set(x);
+ assertEquals((int)x, ai.intValue());
+ }
+ }
+
+ /**
+ * longValue returns current value.
+ */
+ public void testLongValue() {
+ AtomicLong ai = new AtomicLong();
+ assertEquals(0L, ai.longValue());
+ for (long x : VALUES) {
+ ai.set(x);
+ assertEquals(x, ai.longValue());
+ }
+ }
+
+ /**
+ * floatValue returns current value.
+ */
+ public void testFloatValue() {
+ AtomicLong ai = new AtomicLong();
+ assertEquals(0.0f, ai.floatValue());
+ for (long x : VALUES) {
+ ai.set(x);
+ assertEquals((float)x, ai.floatValue());
+ }
+ }
+
+ /**
+ * doubleValue returns current value.
+ */
+ public void testDoubleValue() {
+ AtomicLong ai = new AtomicLong();
+ assertEquals(0.0d, ai.doubleValue());
+ for (long x : VALUES) {
+ ai.set(x);
+ assertEquals((double)x, ai.doubleValue());
+ }
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicMarkableReferenceTest.java b/jsr166-tests/src/test/java/jsr166/AtomicMarkableReferenceTest.java
new file mode 100644
index 0000000..fd1f2f1
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/AtomicMarkableReferenceTest.java
@@ -0,0 +1,147 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.concurrent.atomic.AtomicMarkableReference;
+
+public class AtomicMarkableReferenceTest extends JSR166TestCase {
+
+ /**
+ * constructor initializes to given reference and mark
+ */
+ public void testConstructor() {
+ AtomicMarkableReference ai = new AtomicMarkableReference(one, false);
+ assertSame(one, ai.getReference());
+ assertFalse(ai.isMarked());
+ AtomicMarkableReference a2 = new AtomicMarkableReference(null, true);
+ assertNull(a2.getReference());
+ assertTrue(a2.isMarked());
+ }
+
+ /**
+ * get returns the last values of reference and mark set
+ */
+ public void testGetSet() {
+ boolean[] mark = new boolean[1];
+ AtomicMarkableReference ai = new AtomicMarkableReference(one, false);
+ assertSame(one, ai.getReference());
+ assertFalse(ai.isMarked());
+ assertSame(one, ai.get(mark));
+ assertFalse(mark[0]);
+ ai.set(two, false);
+ assertSame(two, ai.getReference());
+ assertFalse(ai.isMarked());
+ assertSame(two, ai.get(mark));
+ assertFalse(mark[0]);
+ ai.set(one, true);
+ assertSame(one, ai.getReference());
+ assertTrue(ai.isMarked());
+ assertSame(one, ai.get(mark));
+ assertTrue(mark[0]);
+ }
+
+ /**
+ * attemptMark succeeds in single thread
+ */
+ public void testAttemptMark() {
+ boolean[] mark = new boolean[1];
+ AtomicMarkableReference ai = new AtomicMarkableReference(one, false);
+ assertFalse(ai.isMarked());
+ assertTrue(ai.attemptMark(one, true));
+ assertTrue(ai.isMarked());
+ assertSame(one, ai.get(mark));
+ assertTrue(mark[0]);
+ }
+
+ /**
+ * compareAndSet succeeds in changing values if equal to expected reference
+ * and mark else fails
+ */
+ public void testCompareAndSet() {
+ boolean[] mark = new boolean[1];
+ AtomicMarkableReference ai = new AtomicMarkableReference(one, false);
+ assertSame(one, ai.get(mark));
+ assertFalse(ai.isMarked());
+ assertFalse(mark[0]);
+
+ assertTrue(ai.compareAndSet(one, two, false, false));
+ assertSame(two, ai.get(mark));
+ assertFalse(mark[0]);
+
+ assertTrue(ai.compareAndSet(two, m3, false, true));
+ assertSame(m3, ai.get(mark));
+ assertTrue(mark[0]);
+
+ assertFalse(ai.compareAndSet(two, m3, true, true));
+ assertSame(m3, ai.get(mark));
+ assertTrue(mark[0]);
+ }
+
+ /**
+ * compareAndSet in one thread enables another waiting for reference value
+ * to succeed
+ */
+ public void testCompareAndSetInMultipleThreads() throws Exception {
+ final AtomicMarkableReference ai = new AtomicMarkableReference(one, false);
+ Thread t = new Thread(new CheckedRunnable() {
+ public void realRun() {
+ while (!ai.compareAndSet(two, three, false, false))
+ Thread.yield();
+ }});
+
+ t.start();
+ assertTrue(ai.compareAndSet(one, two, false, false));
+ t.join(LONG_DELAY_MS);
+ assertFalse(t.isAlive());
+ assertSame(three, ai.getReference());
+ assertFalse(ai.isMarked());
+ }
+
+ /**
+ * compareAndSet in one thread enables another waiting for mark value
+ * to succeed
+ */
+ public void testCompareAndSetInMultipleThreads2() throws Exception {
+ final AtomicMarkableReference ai = new AtomicMarkableReference(one, false);
+ Thread t = new Thread(new CheckedRunnable() {
+ public void realRun() {
+ while (!ai.compareAndSet(one, one, true, false))
+ Thread.yield();
+ }});
+
+ t.start();
+ assertTrue(ai.compareAndSet(one, one, false, true));
+ t.join(LONG_DELAY_MS);
+ assertFalse(t.isAlive());
+ assertSame(one, ai.getReference());
+ assertFalse(ai.isMarked());
+ }
+
+ /**
+ * repeated weakCompareAndSet succeeds in changing values when equal
+ * to expected
+ */
+ public void testWeakCompareAndSet() {
+ boolean[] mark = new boolean[1];
+ AtomicMarkableReference ai = new AtomicMarkableReference(one, false);
+ assertSame(one, ai.get(mark));
+ assertFalse(ai.isMarked());
+ assertFalse(mark[0]);
+
+ while (!ai.weakCompareAndSet(one, two, false, false));
+ assertSame(two, ai.get(mark));
+ assertFalse(mark[0]);
+
+ while (!ai.weakCompareAndSet(two, m3, false, true));
+ assertSame(m3, ai.get(mark));
+ assertTrue(mark[0]);
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicReferenceArrayTest.java b/jsr166-tests/src/test/java/jsr166/AtomicReferenceArrayTest.java
new file mode 100644
index 0000000..0a4f3d9
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/AtomicReferenceArrayTest.java
@@ -0,0 +1,213 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicReferenceArray;
+
+public class AtomicReferenceArrayTest extends JSR166TestCase {
+
+ /**
+ * constructor creates array of given size with all elements null
+ */
+ public void testConstructor() {
+ AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<Integer>(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ assertNull(aa.get(i));
+ }
+ }
+
+ /**
+ * constructor with null array throws NPE
+ */
+ public void testConstructor2NPE() {
+ try {
+ Integer[] a = null;
+ AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<Integer>(a);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * constructor with array is of same size and has all elements
+ */
+ public void testConstructor2() {
+ Integer[] a = { two, one, three, four, seven };
+ AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<Integer>(a);
+ assertEquals(a.length, aa.length());
+ for (int i = 0; i < a.length; i++)
+ assertEquals(a[i], aa.get(i));
+ }
+
+ /**
+ * Initialize AtomicReferenceArray<Class> with SubClass[]
+ */
+ public void testConstructorSubClassArray() {
+ Integer[] a = { two, one, three, four, seven };
+ AtomicReferenceArray<Number> aa = new AtomicReferenceArray<Number>(a);
+ assertEquals(a.length, aa.length());
+ for (int i = 0; i < a.length; i++) {
+ assertSame(a[i], aa.get(i));
+ Long x = Long.valueOf(i);
+ aa.set(i, x);
+ assertSame(x, aa.get(i));
+ }
+ }
+
+ /**
+ * get and set for out of bound indices throw IndexOutOfBoundsException
+ */
+ public void testIndexing() {
+ AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<Integer>(SIZE);
+ for (int index : new int[] { -1, SIZE }) {
+ try {
+ aa.get(index);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ try {
+ aa.set(index, null);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ try {
+ aa.lazySet(index, null);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ try {
+ aa.compareAndSet(index, null, null);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ try {
+ aa.weakCompareAndSet(index, null, null);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
+ }
+
+ /**
+ * get returns the last value set at index
+ */
+ public void testGetSet() {
+ AtomicReferenceArray aa = new AtomicReferenceArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, one);
+ assertSame(one, aa.get(i));
+ aa.set(i, two);
+ assertSame(two, aa.get(i));
+ aa.set(i, m3);
+ assertSame(m3, aa.get(i));
+ }
+ }
+
+ /**
+ * get returns the last value lazySet at index by same thread
+ */
+ public void testGetLazySet() {
+ AtomicReferenceArray aa = new AtomicReferenceArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.lazySet(i, one);
+ assertSame(one, aa.get(i));
+ aa.lazySet(i, two);
+ assertSame(two, aa.get(i));
+ aa.lazySet(i, m3);
+ assertSame(m3, aa.get(i));
+ }
+ }
+
+ /**
+ * compareAndSet succeeds in changing value if equal to expected else fails
+ */
+ public void testCompareAndSet() {
+ AtomicReferenceArray aa = new AtomicReferenceArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, one);
+ assertTrue(aa.compareAndSet(i, one, two));
+ assertTrue(aa.compareAndSet(i, two, m4));
+ assertSame(m4, aa.get(i));
+ assertFalse(aa.compareAndSet(i, m5, seven));
+ assertSame(m4, aa.get(i));
+ assertTrue(aa.compareAndSet(i, m4, seven));
+ assertSame(seven, aa.get(i));
+ }
+ }
+
+ /**
+ * compareAndSet in one thread enables another waiting for value
+ * to succeed
+ */
+ public void testCompareAndSetInMultipleThreads() throws InterruptedException {
+ final AtomicReferenceArray a = new AtomicReferenceArray(1);
+ a.set(0, one);
+ Thread t = new Thread(new CheckedRunnable() {
+ public void realRun() {
+ while (!a.compareAndSet(0, two, three))
+ Thread.yield();
+ }});
+
+ t.start();
+ assertTrue(a.compareAndSet(0, one, two));
+ t.join(LONG_DELAY_MS);
+ assertFalse(t.isAlive());
+ assertSame(three, a.get(0));
+ }
+
+ /**
+ * repeated weakCompareAndSet succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSet() {
+ AtomicReferenceArray aa = new AtomicReferenceArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, one);
+ while (!aa.weakCompareAndSet(i, one, two));
+ while (!aa.weakCompareAndSet(i, two, m4));
+ assertSame(m4, aa.get(i));
+ while (!aa.weakCompareAndSet(i, m4, seven));
+ assertSame(seven, aa.get(i));
+ }
+ }
+
+ /**
+ * getAndSet returns previous value and sets to given value at given index
+ */
+ public void testGetAndSet() {
+ AtomicReferenceArray aa = new AtomicReferenceArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ aa.set(i, one);
+ assertSame(one, aa.getAndSet(i, zero));
+ assertSame(zero, aa.getAndSet(i, m10));
+ assertSame(m10, aa.getAndSet(i, one));
+ }
+ }
+
+ /**
+ * a deserialized serialized array holds same values
+ */
+ public void testSerialization() throws Exception {
+ AtomicReferenceArray x = new AtomicReferenceArray(SIZE);
+ for (int i = 0; i < SIZE; i++) {
+ x.set(i, new Integer(-i));
+ }
+ AtomicReferenceArray y = serialClone(x);
+ assertNotSame(x, y);
+ assertEquals(x.length(), y.length());
+ for (int i = 0; i < SIZE; i++) {
+ assertEquals(x.get(i), y.get(i));
+ }
+ }
+
+ /**
+ * toString returns current value.
+ */
+ public void testToString() {
+ Integer[] a = { two, one, three, four, seven };
+ AtomicReferenceArray<Integer> aa = new AtomicReferenceArray<Integer>(a);
+ assertEquals(Arrays.toString(a), aa.toString());
+ }
+}
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicReferenceFieldUpdaterTest.java b/jsr166-tests/src/test/java/jsr166/AtomicReferenceFieldUpdaterTest.java
new file mode 100644
index 0000000..271c7b7
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/AtomicReferenceFieldUpdaterTest.java
@@ -0,0 +1,160 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+public class AtomicReferenceFieldUpdaterTest extends JSR166TestCase {
+ volatile Integer x = null;
+ Object z;
+ Integer w;
+ volatile int i;
+
+ AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> updaterFor(String fieldName) {
+ return AtomicReferenceFieldUpdater.newUpdater
+ (AtomicReferenceFieldUpdaterTest.class, Integer.class, fieldName);
+ }
+
+ /**
+ * Construction with non-existent field throws RuntimeException
+ */
+ public void testConstructor() {
+ try {
+ updaterFor("y");
+ shouldThrow();
+ } catch (RuntimeException success) {
+ assertNotNull(success.getCause());
+ }
+ }
+
+ /**
+ * construction with field not of given type throws ClassCastException
+ */
+ public void testConstructor2() {
+ try {
+ updaterFor("z");
+ shouldThrow();
+ } catch (ClassCastException success) {}
+ }
+
+ /**
+ * Constructor with non-volatile field throws IllegalArgumentException
+ */
+ public void testConstructor3() {
+ try {
+ updaterFor("w");
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor with non-reference field throws ClassCastException
+ */
+ public void testConstructor4() {
+ try {
+ updaterFor("i");
+ shouldThrow();
+ } catch (ClassCastException success) {}
+ }
+
+ /**
+ * get returns the last value set or assigned
+ */
+ public void testGetSet() {
+ AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer>a;
+ a = updaterFor("x");
+ x = one;
+ assertSame(one, a.get(this));
+ a.set(this, two);
+ assertSame(two, a.get(this));
+ a.set(this, m3);
+ assertSame(m3, a.get(this));
+ }
+
+ /**
+ * get returns the last value lazySet by same thread
+ */
+ public void testGetLazySet() {
+ AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer>a;
+ a = updaterFor("x");
+ x = one;
+ assertSame(one, a.get(this));
+ a.lazySet(this, two);
+ assertSame(two, a.get(this));
+ a.lazySet(this, m3);
+ assertSame(m3, a.get(this));
+ }
+
+ /**
+ * compareAndSet succeeds in changing value if equal to expected else fails
+ */
+ public void testCompareAndSet() {
+ AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer>a;
+ a = updaterFor("x");
+ x = one;
+ assertTrue(a.compareAndSet(this, one, two));
+ assertTrue(a.compareAndSet(this, two, m4));
+ assertSame(m4, a.get(this));
+ assertFalse(a.compareAndSet(this, m5, seven));
+ assertFalse(seven == a.get(this));
+ assertTrue(a.compareAndSet(this, m4, seven));
+ assertSame(seven, a.get(this));
+ }
+
+ /**
+ * compareAndSet in one thread enables another waiting for value
+ * to succeed
+ */
+ public void testCompareAndSetInMultipleThreads() throws Exception {
+ x = one;
+ final AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer>a;
+ a = updaterFor("x");
+
+ Thread t = new Thread(new CheckedRunnable() {
+ public void realRun() {
+ while (!a.compareAndSet(AtomicReferenceFieldUpdaterTest.this, two, three))
+ Thread.yield();
+ }});
+
+ t.start();
+ assertTrue(a.compareAndSet(this, one, two));
+ t.join(LONG_DELAY_MS);
+ assertFalse(t.isAlive());
+ assertSame(three, a.get(this));
+ }
+
+ /**
+ * repeated weakCompareAndSet succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSet() {
+ AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer>a;
+ a = updaterFor("x");
+ x = one;
+ while (!a.weakCompareAndSet(this, one, two));
+ while (!a.weakCompareAndSet(this, two, m4));
+ assertSame(m4, a.get(this));
+ while (!a.weakCompareAndSet(this, m4, seven));
+ assertSame(seven, a.get(this));
+ }
+
+ /**
+ * getAndSet returns previous value and sets to given value
+ */
+ public void testGetAndSet() {
+ AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer>a;
+ a = updaterFor("x");
+ x = one;
+ assertSame(one, a.getAndSet(this, zero));
+ assertSame(zero, a.getAndSet(this, m10));
+ assertSame(m10, a.getAndSet(this, 1));
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicReferenceTest.java b/jsr166-tests/src/test/java/jsr166/AtomicReferenceTest.java
new file mode 100644
index 0000000..8032546
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/AtomicReferenceTest.java
@@ -0,0 +1,137 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class AtomicReferenceTest extends JSR166TestCase {
+
+ /**
+ * constructor initializes to given value
+ */
+ public void testConstructor() {
+ AtomicReference ai = new AtomicReference(one);
+ assertSame(one, ai.get());
+ }
+
+ /**
+ * default constructed initializes to null
+ */
+ public void testConstructor2() {
+ AtomicReference ai = new AtomicReference();
+ assertNull(ai.get());
+ }
+
+ /**
+ * get returns the last value set
+ */
+ public void testGetSet() {
+ AtomicReference ai = new AtomicReference(one);
+ assertSame(one, ai.get());
+ ai.set(two);
+ assertSame(two, ai.get());
+ ai.set(m3);
+ assertSame(m3, ai.get());
+ }
+
+ /**
+ * get returns the last value lazySet in same thread
+ */
+ public void testGetLazySet() {
+ AtomicReference ai = new AtomicReference(one);
+ assertSame(one, ai.get());
+ ai.lazySet(two);
+ assertSame(two, ai.get());
+ ai.lazySet(m3);
+ assertSame(m3, ai.get());
+ }
+
+ /**
+ * compareAndSet succeeds in changing value if equal to expected else fails
+ */
+ public void testCompareAndSet() {
+ AtomicReference ai = new AtomicReference(one);
+ assertTrue(ai.compareAndSet(one, two));
+ assertTrue(ai.compareAndSet(two, m4));
+ assertSame(m4, ai.get());
+ assertFalse(ai.compareAndSet(m5, seven));
+ assertSame(m4, ai.get());
+ assertTrue(ai.compareAndSet(m4, seven));
+ assertSame(seven, ai.get());
+ }
+
+ /**
+ * compareAndSet in one thread enables another waiting for value
+ * to succeed
+ */
+ public void testCompareAndSetInMultipleThreads() throws Exception {
+ final AtomicReference ai = new AtomicReference(one);
+ Thread t = new Thread(new CheckedRunnable() {
+ public void realRun() {
+ while (!ai.compareAndSet(two, three))
+ Thread.yield();
+ }});
+
+ t.start();
+ assertTrue(ai.compareAndSet(one, two));
+ t.join(LONG_DELAY_MS);
+ assertFalse(t.isAlive());
+ assertSame(three, ai.get());
+ }
+
+ /**
+ * repeated weakCompareAndSet succeeds in changing value when equal
+ * to expected
+ */
+ public void testWeakCompareAndSet() {
+ AtomicReference ai = new AtomicReference(one);
+ while (!ai.weakCompareAndSet(one, two));
+ while (!ai.weakCompareAndSet(two, m4));
+ assertSame(m4, ai.get());
+ while (!ai.weakCompareAndSet(m4, seven));
+ assertSame(seven, ai.get());
+ }
+
+ /**
+ * getAndSet returns previous value and sets to given value
+ */
+ public void testGetAndSet() {
+ AtomicReference ai = new AtomicReference(one);
+ assertSame(one, ai.getAndSet(zero));
+ assertSame(zero, ai.getAndSet(m10));
+ assertSame(m10, ai.getAndSet(one));
+ }
+
+ /**
+ * a deserialized serialized atomic holds same value
+ */
+ public void testSerialization() throws Exception {
+ AtomicReference x = new AtomicReference();
+ AtomicReference y = serialClone(x);
+ assertNotSame(x, y);
+ x.set(one);
+ AtomicReference z = serialClone(x);
+ assertNotSame(y, z);
+ assertEquals(one, x.get());
+ assertEquals(null, y.get());
+ assertEquals(one, z.get());
+ }
+
+ /**
+ * toString returns current value.
+ */
+ public void testToString() {
+ AtomicReference<Integer> ai = new AtomicReference<Integer>(one);
+ assertEquals(one.toString(), ai.toString());
+ ai.set(two);
+ assertEquals(two.toString(), ai.toString());
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/AtomicStampedReferenceTest.java b/jsr166-tests/src/test/java/jsr166/AtomicStampedReferenceTest.java
new file mode 100644
index 0000000..3e6445e
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/AtomicStampedReferenceTest.java
@@ -0,0 +1,147 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.concurrent.atomic.AtomicStampedReference;
+
+public class AtomicStampedReferenceTest extends JSR166TestCase {
+
+ /**
+ * constructor initializes to given reference and stamp
+ */
+ public void testConstructor() {
+ AtomicStampedReference ai = new AtomicStampedReference(one, 0);
+ assertSame(one, ai.getReference());
+ assertEquals(0, ai.getStamp());
+ AtomicStampedReference a2 = new AtomicStampedReference(null, 1);
+ assertNull(a2.getReference());
+ assertEquals(1, a2.getStamp());
+ }
+
+ /**
+ * get returns the last values of reference and stamp set
+ */
+ public void testGetSet() {
+ int[] mark = new int[1];
+ AtomicStampedReference ai = new AtomicStampedReference(one, 0);
+ assertSame(one, ai.getReference());
+ assertEquals(0, ai.getStamp());
+ assertSame(one, ai.get(mark));
+ assertEquals(0, mark[0]);
+ ai.set(two, 0);
+ assertSame(two, ai.getReference());
+ assertEquals(0, ai.getStamp());
+ assertSame(two, ai.get(mark));
+ assertEquals(0, mark[0]);
+ ai.set(one, 1);
+ assertSame(one, ai.getReference());
+ assertEquals(1, ai.getStamp());
+ assertSame(one, ai.get(mark));
+ assertEquals(1, mark[0]);
+ }
+
+ /**
+ * attemptStamp succeeds in single thread
+ */
+ public void testAttemptStamp() {
+ int[] mark = new int[1];
+ AtomicStampedReference ai = new AtomicStampedReference(one, 0);
+ assertEquals(0, ai.getStamp());
+ assertTrue(ai.attemptStamp(one, 1));
+ assertEquals(1, ai.getStamp());
+ assertSame(one, ai.get(mark));
+ assertEquals(1, mark[0]);
+ }
+
+ /**
+ * compareAndSet succeeds in changing values if equal to expected reference
+ * and stamp else fails
+ */
+ public void testCompareAndSet() {
+ int[] mark = new int[1];
+ AtomicStampedReference ai = new AtomicStampedReference(one, 0);
+ assertSame(one, ai.get(mark));
+ assertEquals(0, ai.getStamp());
+ assertEquals(0, mark[0]);
+
+ assertTrue(ai.compareAndSet(one, two, 0, 0));
+ assertSame(two, ai.get(mark));
+ assertEquals(0, mark[0]);
+
+ assertTrue(ai.compareAndSet(two, m3, 0, 1));
+ assertSame(m3, ai.get(mark));
+ assertEquals(1, mark[0]);
+
+ assertFalse(ai.compareAndSet(two, m3, 1, 1));
+ assertSame(m3, ai.get(mark));
+ assertEquals(1, mark[0]);
+ }
+
+ /**
+ * compareAndSet in one thread enables another waiting for reference value
+ * to succeed
+ */
+ public void testCompareAndSetInMultipleThreads() throws Exception {
+ final AtomicStampedReference ai = new AtomicStampedReference(one, 0);
+ Thread t = new Thread(new CheckedRunnable() {
+ public void realRun() {
+ while (!ai.compareAndSet(two, three, 0, 0))
+ Thread.yield();
+ }});
+
+ t.start();
+ assertTrue(ai.compareAndSet(one, two, 0, 0));
+ t.join(LONG_DELAY_MS);
+ assertFalse(t.isAlive());
+ assertSame(three, ai.getReference());
+ assertEquals(0, ai.getStamp());
+ }
+
+ /**
+ * compareAndSet in one thread enables another waiting for stamp value
+ * to succeed
+ */
+ public void testCompareAndSetInMultipleThreads2() throws Exception {
+ final AtomicStampedReference ai = new AtomicStampedReference(one, 0);
+ Thread t = new Thread(new CheckedRunnable() {
+ public void realRun() {
+ while (!ai.compareAndSet(one, one, 1, 2))
+ Thread.yield();
+ }});
+
+ t.start();
+ assertTrue(ai.compareAndSet(one, one, 0, 1));
+ t.join(LONG_DELAY_MS);
+ assertFalse(t.isAlive());
+ assertSame(one, ai.getReference());
+ assertEquals(2, ai.getStamp());
+ }
+
+ /**
+ * repeated weakCompareAndSet succeeds in changing values when equal
+ * to expected
+ */
+ public void testWeakCompareAndSet() {
+ int[] mark = new int[1];
+ AtomicStampedReference ai = new AtomicStampedReference(one, 0);
+ assertSame(one, ai.get(mark));
+ assertEquals(0, ai.getStamp());
+ assertEquals(0, mark[0]);
+
+ while (!ai.weakCompareAndSet(one, two, 0, 0));
+ assertSame(two, ai.get(mark));
+ assertEquals(0, mark[0]);
+
+ while (!ai.weakCompareAndSet(two, m3, 0, 1));
+ assertSame(m3, ai.get(mark));
+ assertEquals(1, mark[0]);
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/BlockingQueueTest.java b/jsr166-tests/src/test/java/jsr166/BlockingQueueTest.java
new file mode 100644
index 0000000..1ed7559
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/BlockingQueueTest.java
@@ -0,0 +1,366 @@
+/*
+ * Written by Doug Lea and Martin Buchholz with assistance from members
+ * of JCP JSR-166 Expert Group and released to the public domain, as
+ * explained at http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Queue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+/**
+ * Contains "contract" tests applicable to all BlockingQueue implementations.
+ */
+public abstract class BlockingQueueTest extends JSR166TestCase {
+ /*
+ * This is the start of an attempt to refactor the tests for the
+ * various related implementations of related interfaces without
+ * too much duplicated code. junit does not really support such
+ * testing. Here subclasses of TestCase not only contain tests,
+ * but also configuration information that describes the
+ * implementation class, most importantly how to instantiate
+ * instances.
+ */
+
+ //----------------------------------------------------------------
+ // Configuration methods
+ //----------------------------------------------------------------
+
+ /** Returns an empty instance of the implementation class. */
+ protected abstract BlockingQueue emptyCollection();
+
+ /**
+ * Returns an element suitable for insertion in the collection.
+ * Override for collections with unusual element types.
+ */
+ protected Object makeElement(int i) {
+ return Integer.valueOf(i);
+ }
+
+ //----------------------------------------------------------------
+ // Tests
+ //----------------------------------------------------------------
+
+ /**
+ * offer(null) throws NullPointerException
+ */
+ public void testOfferNull() {
+ final Queue q = emptyCollection();
+ try {
+ q.offer(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * add(null) throws NullPointerException
+ */
+ public void testAddNull() {
+ final Collection q = emptyCollection();
+ try {
+ q.add(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * timed offer(null) throws NullPointerException
+ */
+ public void testTimedOfferNull() throws InterruptedException {
+ final BlockingQueue q = emptyCollection();
+ long startTime = System.nanoTime();
+ try {
+ q.offer(null, LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ }
+
+ /**
+ * put(null) throws NullPointerException
+ */
+ public void testPutNull() throws InterruptedException {
+ final BlockingQueue q = emptyCollection();
+ try {
+ q.put(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * put(null) throws NullPointerException
+ */
+ public void testAddAllNull() throws InterruptedException {
+ final Collection q = emptyCollection();
+ try {
+ q.addAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll of a collection with null elements throws NullPointerException
+ */
+ public void testAddAllNullElements() {
+ final Collection q = emptyCollection();
+ final Collection<Integer> elements = Arrays.asList(new Integer[SIZE]);
+ try {
+ q.addAll(elements);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * toArray(null) throws NullPointerException
+ */
+ public void testToArray_NullArray() {
+ final Collection q = emptyCollection();
+ try {
+ q.toArray(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * drainTo(null) throws NullPointerException
+ */
+ public void testDrainToNull() {
+ final BlockingQueue q = emptyCollection();
+ try {
+ q.drainTo(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * drainTo(this) throws IllegalArgumentException
+ */
+ public void testDrainToSelf() {
+ final BlockingQueue q = emptyCollection();
+ try {
+ q.drainTo(q);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * drainTo(null, n) throws NullPointerException
+ */
+ public void testDrainToNullN() {
+ final BlockingQueue q = emptyCollection();
+ try {
+ q.drainTo(null, 0);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * drainTo(this, n) throws IllegalArgumentException
+ */
+ public void testDrainToSelfN() {
+ final BlockingQueue q = emptyCollection();
+ try {
+ q.drainTo(q, 0);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * drainTo(c, n) returns 0 and does nothing when n <= 0
+ */
+ public void testDrainToNonPositiveMaxElements() {
+ final BlockingQueue q = emptyCollection();
+ final int[] ns = { 0, -1, -42, Integer.MIN_VALUE };
+ for (int n : ns)
+ assertEquals(0, q.drainTo(new ArrayList(), n));
+ if (q.remainingCapacity() > 0) {
+ // Not SynchronousQueue, that is
+ Object one = makeElement(1);
+ q.add(one);
+ ArrayList c = new ArrayList();
+ for (int n : ns)
+ assertEquals(0, q.drainTo(new ArrayList(), n));
+ assertEquals(1, q.size());
+ assertSame(one, q.poll());
+ assertTrue(c.isEmpty());
+ }
+ }
+
+ /**
+ * timed poll before a delayed offer times out; after offer succeeds;
+ * on interruption throws
+ */
+ public void testTimedPollWithOffer() throws InterruptedException {
+ final BlockingQueue q = emptyCollection();
+ final CheckedBarrier barrier = new CheckedBarrier(2);
+ final Object zero = makeElement(0);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ long startTime = System.nanoTime();
+ assertNull(q.poll(timeoutMillis(), MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+
+ barrier.await();
+
+ assertSame(zero, q.poll(LONG_DELAY_MS, MILLISECONDS));
+
+ Thread.currentThread().interrupt();
+ try {
+ q.poll(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ barrier.await();
+ try {
+ q.poll(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ barrier.await();
+ long startTime = System.nanoTime();
+ assertTrue(q.offer(zero, LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+
+ barrier.await();
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * take() blocks interruptibly when empty
+ */
+ public void testTakeFromEmptyBlocksInterruptibly() {
+ final BlockingQueue q = emptyCollection();
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ threadStarted.countDown();
+ try {
+ q.take();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(threadStarted);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * take() throws InterruptedException immediately if interrupted
+ * before waiting
+ */
+ public void testTakeFromEmptyAfterInterrupt() {
+ final BlockingQueue q = emptyCollection();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ Thread.currentThread().interrupt();
+ try {
+ q.take();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ awaitTermination(t);
+ }
+
+ /**
+ * timed poll() blocks interruptibly when empty
+ */
+ public void testTimedPollFromEmptyBlocksInterruptibly() {
+ final BlockingQueue q = emptyCollection();
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ threadStarted.countDown();
+ try {
+ q.poll(2 * LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(threadStarted);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * timed poll() throws InterruptedException immediately if
+ * interrupted before waiting
+ */
+ public void testTimedPollFromEmptyAfterInterrupt() {
+ final BlockingQueue q = emptyCollection();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ Thread.currentThread().interrupt();
+ try {
+ q.poll(2 * LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ awaitTermination(t);
+ }
+
+ /**
+ * remove(x) removes x and returns true if present
+ * TODO: move to superclass CollectionTest.java
+ */
+ public void testRemoveElement() {
+ final BlockingQueue q = emptyCollection();
+ final int size = Math.min(q.remainingCapacity(), SIZE);
+ final Object[] elts = new Object[size];
+ assertFalse(q.contains(makeElement(99)));
+ assertFalse(q.remove(makeElement(99)));
+ checkEmpty(q);
+ for (int i = 0; i < size; i++)
+ q.add(elts[i] = makeElement(i));
+ for (int i = 1; i < size; i+=2) {
+ for (int pass = 0; pass < 2; pass++) {
+ assertEquals((pass == 0), q.contains(elts[i]));
+ assertEquals((pass == 0), q.remove(elts[i]));
+ assertFalse(q.contains(elts[i]));
+ assertTrue(q.contains(elts[i-1]));
+ if (i < size - 1)
+ assertTrue(q.contains(elts[i+1]));
+ }
+ }
+ if (size > 0)
+ assertTrue(q.contains(elts[0]));
+ for (int i = size-2; i >= 0; i-=2) {
+ assertTrue(q.contains(elts[i]));
+ assertFalse(q.contains(elts[i+1]));
+ assertTrue(q.remove(elts[i]));
+ assertFalse(q.contains(elts[i]));
+ assertFalse(q.remove(elts[i+1]));
+ assertFalse(q.contains(elts[i+1]));
+ }
+ checkEmpty(q);
+ }
+
+ /** For debugging. */
+ public void XXXXtestFails() {
+ fail(emptyCollection().getClass().toString());
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/ConcurrentHashMapTest.java b/jsr166-tests/src/test/java/jsr166/ConcurrentHashMapTest.java
new file mode 100644
index 0000000..5d9e2ac
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/ConcurrentHashMapTest.java
@@ -0,0 +1,686 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class ConcurrentHashMapTest extends JSR166TestCase {
+
+ /**
+ * Returns a new map from Integers 1-5 to Strings "A"-"E".
+ */
+ private static ConcurrentHashMap map5() {
+ ConcurrentHashMap map = new ConcurrentHashMap(5);
+ assertTrue(map.isEmpty());
+ map.put(one, "A");
+ map.put(two, "B");
+ map.put(three, "C");
+ map.put(four, "D");
+ map.put(five, "E");
+ assertFalse(map.isEmpty());
+ assertEquals(5, map.size());
+ return map;
+ }
+
+ // classes for testing Comparable fallbacks
+ static class BI implements Comparable<BI> {
+ private final int value;
+ BI(int value) { this.value = value; }
+ public int compareTo(BI other) {
+ return Integer.compare(value, other.value);
+ }
+ public boolean equals(Object x) {
+ return (x instanceof BI) && ((BI)x).value == value;
+ }
+ public int hashCode() { return 42; }
+ }
+ static class CI extends BI { CI(int value) { super(value); } }
+ static class DI extends BI { DI(int value) { super(value); } }
+
+ static class BS implements Comparable<BS> {
+ private final String value;
+ BS(String value) { this.value = value; }
+ public int compareTo(BS other) {
+ return value.compareTo(other.value);
+ }
+ public boolean equals(Object x) {
+ return (x instanceof BS) && value.equals(((BS)x).value);
+ }
+ public int hashCode() { return 42; }
+ }
+
+ static class LexicographicList<E extends Comparable<E>> extends ArrayList<E>
+ implements Comparable<LexicographicList<E>> {
+ static long total;
+ static long n;
+ LexicographicList(Collection<E> c) { super(c); }
+ LexicographicList(E e) { super(Collections.singleton(e)); }
+ public int compareTo(LexicographicList<E> other) {
+ long start = System.currentTimeMillis();
+ int common = Math.min(size(), other.size());
+ int r = 0;
+ for (int i = 0; i < common; i++) {
+ if ((r = get(i).compareTo(other.get(i))) != 0)
+ break;
+ }
+ if (r == 0)
+ r = Integer.compare(size(), other.size());
+ total += System.currentTimeMillis() - start;
+ n++;
+ return r;
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Inserted elements that are subclasses of the same Comparable
+ * class are found.
+ */
+ public void testComparableFamily() {
+ ConcurrentHashMap<BI, Boolean> m =
+ new ConcurrentHashMap<BI, Boolean>();
+ for (int i = 0; i < 1000; i++) {
+ assertTrue(m.put(new CI(i), true) == null);
+ }
+ for (int i = 0; i < 1000; i++) {
+ assertTrue(m.containsKey(new CI(i)));
+ assertTrue(m.containsKey(new DI(i)));
+ }
+ }
+
+ /**
+ * Elements of classes with erased generic type parameters based
+ * on Comparable can be inserted and found.
+ */
+ public void testGenericComparable() {
+ ConcurrentHashMap<Object, Boolean> m =
+ new ConcurrentHashMap<Object, Boolean>();
+ for (int i = 0; i < 1000; i++) {
+ BI bi = new BI(i);
+ BS bs = new BS(String.valueOf(i));
+ LexicographicList<BI> bis = new LexicographicList<BI>(bi);
+ LexicographicList<BS> bss = new LexicographicList<BS>(bs);
+ assertTrue(m.putIfAbsent(bis, true) == null);
+ assertTrue(m.containsKey(bis));
+ if (m.putIfAbsent(bss, true) == null)
+ assertTrue(m.containsKey(bss));
+ assertTrue(m.containsKey(bis));
+ }
+ for (int i = 0; i < 1000; i++) {
+ assertTrue(m.containsKey(new ArrayList(Collections.singleton(new BI(i)))));
+ }
+ }
+
+ /**
+ * Elements of non-comparable classes equal to those of classes
+ * with erased generic type parameters based on Comparable can be
+ * inserted and found.
+ */
+ public void testGenericComparable2() {
+ ConcurrentHashMap<Object, Boolean> m =
+ new ConcurrentHashMap<Object, Boolean>();
+ for (int i = 0; i < 1000; i++) {
+ m.put(new ArrayList(Collections.singleton(new BI(i))), true);
+ }
+
+ for (int i = 0; i < 1000; i++) {
+ LexicographicList<BI> bis = new LexicographicList<BI>(new BI(i));
+ assertTrue(m.containsKey(bis));
+ }
+ }
+
+ /**
+ * clear removes all pairs
+ */
+ public void testClear() {
+ ConcurrentHashMap map = map5();
+ map.clear();
+ assertEquals(0, map.size());
+ }
+
+ /**
+ * Maps with same contents are equal
+ */
+ public void testEquals() {
+ ConcurrentHashMap map1 = map5();
+ ConcurrentHashMap map2 = map5();
+ assertEquals(map1, map2);
+ assertEquals(map2, map1);
+ map1.clear();
+ assertFalse(map1.equals(map2));
+ assertFalse(map2.equals(map1));
+ }
+
+ /**
+ * contains returns true for contained value
+ */
+ public void testContains() {
+ ConcurrentHashMap map = map5();
+ assertTrue(map.contains("A"));
+ assertFalse(map.contains("Z"));
+ }
+
+ /**
+ * containsKey returns true for contained key
+ */
+ public void testContainsKey() {
+ ConcurrentHashMap map = map5();
+ assertTrue(map.containsKey(one));
+ assertFalse(map.containsKey(zero));
+ }
+
+ /**
+ * containsValue returns true for held values
+ */
+ public void testContainsValue() {
+ ConcurrentHashMap map = map5();
+ assertTrue(map.containsValue("A"));
+ assertFalse(map.containsValue("Z"));
+ }
+
+ /**
+ * enumeration returns an enumeration containing the correct
+ * elements
+ */
+ public void testEnumeration() {
+ ConcurrentHashMap map = map5();
+ Enumeration e = map.elements();
+ int count = 0;
+ while (e.hasMoreElements()) {
+ count++;
+ e.nextElement();
+ }
+ assertEquals(5, count);
+ }
+
+ /**
+ * get returns the correct element at the given key,
+ * or null if not present
+ */
+ public void testGet() {
+ ConcurrentHashMap map = map5();
+ assertEquals("A", (String)map.get(one));
+ ConcurrentHashMap empty = new ConcurrentHashMap();
+ assertNull(map.get("anything"));
+ }
+
+ /**
+ * isEmpty is true of empty map and false for non-empty
+ */
+ public void testIsEmpty() {
+ ConcurrentHashMap empty = new ConcurrentHashMap();
+ ConcurrentHashMap map = map5();
+ assertTrue(empty.isEmpty());
+ assertFalse(map.isEmpty());
+ }
+
+ /**
+ * keys returns an enumeration containing all the keys from the map
+ */
+ public void testKeys() {
+ ConcurrentHashMap map = map5();
+ Enumeration e = map.keys();
+ int count = 0;
+ while (e.hasMoreElements()) {
+ count++;
+ e.nextElement();
+ }
+ assertEquals(5, count);
+ }
+
+ /**
+ * keySet returns a Set containing all the keys
+ */
+ public void testKeySet() {
+ ConcurrentHashMap map = map5();
+ Set s = map.keySet();
+ assertEquals(5, s.size());
+ assertTrue(s.contains(one));
+ assertTrue(s.contains(two));
+ assertTrue(s.contains(three));
+ assertTrue(s.contains(four));
+ assertTrue(s.contains(five));
+ }
+
+ /**
+ * keySet.toArray returns contains all keys
+ */
+ public void testKeySetToArray() {
+ ConcurrentHashMap map = map5();
+ Set s = map.keySet();
+ Object[] ar = s.toArray();
+ assertTrue(s.containsAll(Arrays.asList(ar)));
+ assertEquals(5, ar.length);
+ ar[0] = m10;
+ assertFalse(s.containsAll(Arrays.asList(ar)));
+ }
+
+ /**
+ * Values.toArray contains all values
+ */
+ public void testValuesToArray() {
+ ConcurrentHashMap map = map5();
+ Collection v = map.values();
+ Object[] ar = v.toArray();
+ ArrayList s = new ArrayList(Arrays.asList(ar));
+ assertEquals(5, ar.length);
+ assertTrue(s.contains("A"));
+ assertTrue(s.contains("B"));
+ assertTrue(s.contains("C"));
+ assertTrue(s.contains("D"));
+ assertTrue(s.contains("E"));
+ }
+
+ /**
+ * entrySet.toArray contains all entries
+ */
+ public void testEntrySetToArray() {
+ ConcurrentHashMap map = map5();
+ Set s = map.entrySet();
+ Object[] ar = s.toArray();
+ assertEquals(5, ar.length);
+ for (int i = 0; i < 5; ++i) {
+ assertTrue(map.containsKey(((Map.Entry)(ar[i])).getKey()));
+ assertTrue(map.containsValue(((Map.Entry)(ar[i])).getValue()));
+ }
+ }
+
+ /**
+ * values collection contains all values
+ */
+ public void testValues() {
+ ConcurrentHashMap map = map5();
+ Collection s = map.values();
+ assertEquals(5, s.size());
+ assertTrue(s.contains("A"));
+ assertTrue(s.contains("B"));
+ assertTrue(s.contains("C"));
+ assertTrue(s.contains("D"));
+ assertTrue(s.contains("E"));
+ }
+
+ /**
+ * entrySet contains all pairs
+ */
+ public void testEntrySet() {
+ ConcurrentHashMap map = map5();
+ Set s = map.entrySet();
+ assertEquals(5, s.size());
+ Iterator it = s.iterator();
+ while (it.hasNext()) {
+ Map.Entry e = (Map.Entry) it.next();
+ assertTrue(
+ (e.getKey().equals(one) && e.getValue().equals("A")) ||
+ (e.getKey().equals(two) && e.getValue().equals("B")) ||
+ (e.getKey().equals(three) && e.getValue().equals("C")) ||
+ (e.getKey().equals(four) && e.getValue().equals("D")) ||
+ (e.getKey().equals(five) && e.getValue().equals("E")));
+ }
+ }
+
+ /**
+ * putAll adds all key-value pairs from the given map
+ */
+ public void testPutAll() {
+ ConcurrentHashMap empty = new ConcurrentHashMap();
+ ConcurrentHashMap map = map5();
+ empty.putAll(map);
+ assertEquals(5, empty.size());
+ assertTrue(empty.containsKey(one));
+ assertTrue(empty.containsKey(two));
+ assertTrue(empty.containsKey(three));
+ assertTrue(empty.containsKey(four));
+ assertTrue(empty.containsKey(five));
+ }
+
+ /**
+ * putIfAbsent works when the given key is not present
+ */
+ public void testPutIfAbsent() {
+ ConcurrentHashMap map = map5();
+ map.putIfAbsent(six, "Z");
+ assertTrue(map.containsKey(six));
+ }
+
+ /**
+ * putIfAbsent does not add the pair if the key is already present
+ */
+ public void testPutIfAbsent2() {
+ ConcurrentHashMap map = map5();
+ assertEquals("A", map.putIfAbsent(one, "Z"));
+ }
+
+ /**
+ * replace fails when the given key is not present
+ */
+ public void testReplace() {
+ ConcurrentHashMap map = map5();
+ assertNull(map.replace(six, "Z"));
+ assertFalse(map.containsKey(six));
+ }
+
+ /**
+ * replace succeeds if the key is already present
+ */
+ public void testReplace2() {
+ ConcurrentHashMap map = map5();
+ assertNotNull(map.replace(one, "Z"));
+ assertEquals("Z", map.get(one));
+ }
+
+ /**
+ * replace value fails when the given key not mapped to expected value
+ */
+ public void testReplaceValue() {
+ ConcurrentHashMap map = map5();
+ assertEquals("A", map.get(one));
+ assertFalse(map.replace(one, "Z", "Z"));
+ assertEquals("A", map.get(one));
+ }
+
+ /**
+ * replace value succeeds when the given key mapped to expected value
+ */
+ public void testReplaceValue2() {
+ ConcurrentHashMap map = map5();
+ assertEquals("A", map.get(one));
+ assertTrue(map.replace(one, "A", "Z"));
+ assertEquals("Z", map.get(one));
+ }
+
+ /**
+ * remove removes the correct key-value pair from the map
+ */
+ public void testRemove() {
+ ConcurrentHashMap map = map5();
+ map.remove(five);
+ assertEquals(4, map.size());
+ assertFalse(map.containsKey(five));
+ }
+
+ /**
+ * remove(key,value) removes only if pair present
+ */
+ public void testRemove2() {
+ ConcurrentHashMap map = map5();
+ map.remove(five, "E");
+ assertEquals(4, map.size());
+ assertFalse(map.containsKey(five));
+ map.remove(four, "A");
+ assertEquals(4, map.size());
+ assertTrue(map.containsKey(four));
+ }
+
+ /**
+ * size returns the correct values
+ */
+ public void testSize() {
+ ConcurrentHashMap map = map5();
+ ConcurrentHashMap empty = new ConcurrentHashMap();
+ assertEquals(0, empty.size());
+ assertEquals(5, map.size());
+ }
+
+ /**
+ * toString contains toString of elements
+ */
+ public void testToString() {
+ ConcurrentHashMap map = map5();
+ String s = map.toString();
+ for (int i = 1; i <= 5; ++i) {
+ assertTrue(s.contains(String.valueOf(i)));
+ }
+ }
+
+ // Exception tests
+
+ /**
+ * Cannot create with negative capacity
+ */
+ public void testConstructor1() {
+ try {
+ new ConcurrentHashMap(-1,0,1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Cannot create with negative concurrency level
+ */
+ public void testConstructor2() {
+ try {
+ new ConcurrentHashMap(1,0,-1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Cannot create with only negative capacity
+ */
+ public void testConstructor3() {
+ try {
+ new ConcurrentHashMap(-1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * get(null) throws NPE
+ */
+ public void testGet_NullPointerException() {
+ try {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
+ c.get(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * containsKey(null) throws NPE
+ */
+ public void testContainsKey_NullPointerException() {
+ try {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
+ c.containsKey(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * containsValue(null) throws NPE
+ */
+ public void testContainsValue_NullPointerException() {
+ try {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
+ c.containsValue(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * contains(null) throws NPE
+ */
+ public void testContains_NullPointerException() {
+ try {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
+ c.contains(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * put(null,x) throws NPE
+ */
+ public void testPut1_NullPointerException() {
+ try {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
+ c.put(null, "whatever");
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * put(x, null) throws NPE
+ */
+ public void testPut2_NullPointerException() {
+ try {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
+ c.put("whatever", null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * putIfAbsent(null, x) throws NPE
+ */
+ public void testPutIfAbsent1_NullPointerException() {
+ try {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
+ c.putIfAbsent(null, "whatever");
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * replace(null, x) throws NPE
+ */
+ public void testReplace_NullPointerException() {
+ try {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
+ c.replace(null, "whatever");
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * replace(null, x, y) throws NPE
+ */
+ public void testReplaceValue_NullPointerException() {
+ try {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
+ c.replace(null, one, "whatever");
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * putIfAbsent(x, null) throws NPE
+ */
+ public void testPutIfAbsent2_NullPointerException() {
+ try {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
+ c.putIfAbsent("whatever", null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * replace(x, null) throws NPE
+ */
+ public void testReplace2_NullPointerException() {
+ try {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
+ c.replace("whatever", null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * replace(x, null, y) throws NPE
+ */
+ public void testReplaceValue2_NullPointerException() {
+ try {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
+ c.replace("whatever", null, "A");
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * replace(x, y, null) throws NPE
+ */
+ public void testReplaceValue3_NullPointerException() {
+ try {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
+ c.replace("whatever", one, null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * remove(null) throws NPE
+ */
+ public void testRemove1_NullPointerException() {
+ try {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
+ c.put("sadsdf", "asdads");
+ c.remove(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * remove(null, x) throws NPE
+ */
+ public void testRemove2_NullPointerException() {
+ try {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
+ c.put("sadsdf", "asdads");
+ c.remove(null, "whatever");
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * remove(x, null) returns false
+ */
+ public void testRemove3() {
+ ConcurrentHashMap c = new ConcurrentHashMap(5);
+ c.put("sadsdf", "asdads");
+ assertFalse(c.remove("sadsdf", null));
+ }
+
+ /**
+ * A deserialized map equals original
+ */
+ public void testSerialization() throws Exception {
+ Map x = map5();
+ Map y = serialClone(x);
+
+ assertNotSame(x, y);
+ assertEquals(x.size(), y.size());
+ assertEquals(x, y);
+ assertEquals(y, x);
+ }
+
+ /**
+ * SetValue of an EntrySet entry sets value in the map.
+ */
+ public void testSetValueWriteThrough() {
+ // Adapted from a bug report by Eric Zoerner
+ ConcurrentHashMap map = new ConcurrentHashMap(2, 5.0f, 1);
+ assertTrue(map.isEmpty());
+ for (int i = 0; i < 20; i++)
+ map.put(new Integer(i), new Integer(i));
+ assertFalse(map.isEmpty());
+ Map.Entry entry1 = (Map.Entry)map.entrySet().iterator().next();
+ // Unless it happens to be first (in which case remainder of
+ // test is skipped), remove a possibly-colliding key from map
+ // which, under some implementations, may cause entry1 to be
+ // cloned in map
+ if (!entry1.getKey().equals(new Integer(16))) {
+ map.remove(new Integer(16));
+ entry1.setValue("XYZ");
+ assertTrue(map.containsValue("XYZ")); // fails if write-through broken
+ }
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/ConcurrentLinkedDequeTest.java b/jsr166-tests/src/test/java/jsr166/ConcurrentLinkedDequeTest.java
new file mode 100644
index 0000000..f5b8318
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/ConcurrentLinkedDequeTest.java
@@ -0,0 +1,858 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+import java.util.Random;
+import java.util.concurrent.ConcurrentLinkedDeque;
+
+public class ConcurrentLinkedDequeTest extends JSR166TestCase {
+
+ /**
+ * Returns a new deque of given size containing consecutive
+ * Integers 0 ... n.
+ */
+ private ConcurrentLinkedDeque<Integer> populatedDeque(int n) {
+ ConcurrentLinkedDeque<Integer> q = new ConcurrentLinkedDeque<Integer>();
+ assertTrue(q.isEmpty());
+ for (int i = 0; i < n; ++i)
+ assertTrue(q.offer(new Integer(i)));
+ assertFalse(q.isEmpty());
+ assertEquals(n, q.size());
+ return q;
+ }
+
+ /**
+ * new deque is empty
+ */
+ public void testConstructor1() {
+ assertTrue(new ConcurrentLinkedDeque().isEmpty());
+ assertEquals(0, new ConcurrentLinkedDeque().size());
+ }
+
+ /**
+ * Initializing from null Collection throws NPE
+ */
+ public void testConstructor3() {
+ try {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque((Collection)null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing from Collection of null elements throws NPE
+ */
+ public void testConstructor4() {
+ try {
+ Integer[] ints = new Integer[SIZE];
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing from Collection with some null elements throws NPE
+ */
+ public void testConstructor5() {
+ try {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Deque contains all elements of collection used to initialize
+ */
+ public void testConstructor6() {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(i);
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque(Arrays.asList(ints));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(ints[i], q.poll());
+ }
+
+ /**
+ * isEmpty is true before add, false after
+ */
+ public void testEmpty() {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ assertTrue(q.isEmpty());
+ q.add(one);
+ assertFalse(q.isEmpty());
+ q.add(two);
+ q.remove();
+ q.remove();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * size() changes when elements added and removed
+ */
+ public void testSize() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(SIZE-i, q.size());
+ q.remove();
+ }
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.size());
+ q.add(new Integer(i));
+ }
+ }
+
+ /**
+ * push(null) throws NPE
+ */
+ public void testPushNull() {
+ try {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ q.push(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * peekFirst() returns element inserted with push
+ */
+ public void testPush() {
+ ConcurrentLinkedDeque q = populatedDeque(3);
+ q.pollLast();
+ q.push(four);
+ assertSame(four, q.peekFirst());
+ }
+
+ /**
+ * pop() removes first element, or throws NSEE if empty
+ */
+ public void testPop() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.pop());
+ }
+ try {
+ q.pop();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * offer(null) throws NPE
+ */
+ public void testOfferNull() {
+ try {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ q.offer(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * offerFirst(null) throws NPE
+ */
+ public void testOfferFirstNull() {
+ try {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ q.offerFirst(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * offerLast(null) throws NPE
+ */
+ public void testOfferLastNull() {
+ try {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ q.offerLast(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * offer(x) succeeds
+ */
+ public void testOffer() {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ assertTrue(q.offer(zero));
+ assertTrue(q.offer(one));
+ assertSame(zero, q.peekFirst());
+ assertSame(one, q.peekLast());
+ }
+
+ /**
+ * offerFirst(x) succeeds
+ */
+ public void testOfferFirst() {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ assertTrue(q.offerFirst(zero));
+ assertTrue(q.offerFirst(one));
+ assertSame(one, q.peekFirst());
+ assertSame(zero, q.peekLast());
+ }
+
+ /**
+ * offerLast(x) succeeds
+ */
+ public void testOfferLast() {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ assertTrue(q.offerLast(zero));
+ assertTrue(q.offerLast(one));
+ assertSame(zero, q.peekFirst());
+ assertSame(one, q.peekLast());
+ }
+
+ /**
+ * add(null) throws NPE
+ */
+ public void testAddNull() {
+ try {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ q.add(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addFirst(null) throws NPE
+ */
+ public void testAddFirstNull() {
+ try {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ q.addFirst(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addLast(null) throws NPE
+ */
+ public void testAddLastNull() {
+ try {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ q.addLast(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * add(x) succeeds
+ */
+ public void testAdd() {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ assertTrue(q.add(zero));
+ assertTrue(q.add(one));
+ assertSame(zero, q.peekFirst());
+ assertSame(one, q.peekLast());
+ }
+
+ /**
+ * addFirst(x) succeeds
+ */
+ public void testAddFirst() {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ q.addFirst(zero);
+ q.addFirst(one);
+ assertSame(one, q.peekFirst());
+ assertSame(zero, q.peekLast());
+ }
+
+ /**
+ * addLast(x) succeeds
+ */
+ public void testAddLast() {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ q.addLast(zero);
+ q.addLast(one);
+ assertSame(zero, q.peekFirst());
+ assertSame(one, q.peekLast());
+ }
+
+ /**
+ * addAll(null) throws NPE
+ */
+ public void testAddAll1() {
+ try {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ q.addAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll(this) throws IAE
+ */
+ public void testAddAllSelf() {
+ try {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ q.addAll(q);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * addAll of a collection with null elements throws NPE
+ */
+ public void testAddAll2() {
+ try {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ Integer[] ints = new Integer[SIZE];
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll of a collection with any null elements throws NPE after
+ * possibly adding some elements
+ */
+ public void testAddAll3() {
+ try {
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Deque contains all elements, in traversal order, of successful addAll
+ */
+ public void testAddAll5() {
+ Integer[] empty = new Integer[0];
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(i);
+ ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ assertFalse(q.addAll(Arrays.asList(empty)));
+ assertTrue(q.addAll(Arrays.asList(ints)));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(ints[i], q.poll());
+ }
+
+ /**
+ * pollFirst() succeeds unless empty
+ */
+ public void testPollFirst() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.pollFirst());
+ }
+ assertNull(q.pollFirst());
+ }
+
+ /**
+ * pollLast() succeeds unless empty
+ */
+ public void testPollLast() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ for (int i = SIZE-1; i >= 0; --i) {
+ assertEquals(i, q.pollLast());
+ }
+ assertNull(q.pollLast());
+ }
+
+ /**
+ * poll() succeeds unless empty
+ */
+ public void testPoll() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.poll());
+ }
+ assertNull(q.poll());
+ }
+
+ /**
+ * peek() returns next element, or null if empty
+ */
+ public void testPeek() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.peek());
+ assertEquals(i, q.poll());
+ assertTrue(q.peek() == null ||
+ !q.peek().equals(i));
+ }
+ assertNull(q.peek());
+ }
+
+ /**
+ * element() returns first element, or throws NSEE if empty
+ */
+ public void testElement() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.element());
+ assertEquals(i, q.poll());
+ }
+ try {
+ q.element();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * remove() removes next element, or throws NSEE if empty
+ */
+ public void testRemove() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.remove());
+ }
+ try {
+ q.remove();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * remove(x) removes x and returns true if present
+ */
+ public void testRemoveElement() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ for (int i = 1; i < SIZE; i+=2) {
+ assertTrue(q.contains(i));
+ assertTrue(q.remove(i));
+ assertFalse(q.contains(i));
+ assertTrue(q.contains(i-1));
+ }
+ for (int i = 0; i < SIZE; i+=2) {
+ assertTrue(q.contains(i));
+ assertTrue(q.remove(i));
+ assertFalse(q.contains(i));
+ assertFalse(q.remove(i+1));
+ assertFalse(q.contains(i+1));
+ }
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * peekFirst() returns next element, or null if empty
+ */
+ public void testPeekFirst() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.peekFirst());
+ assertEquals(i, q.pollFirst());
+ assertTrue(q.peekFirst() == null ||
+ !q.peekFirst().equals(i));
+ }
+ assertNull(q.peekFirst());
+ }
+
+ /**
+ * peekLast() returns next element, or null if empty
+ */
+ public void testPeekLast() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ for (int i = SIZE-1; i >= 0; --i) {
+ assertEquals(i, q.peekLast());
+ assertEquals(i, q.pollLast());
+ assertTrue(q.peekLast() == null ||
+ !q.peekLast().equals(i));
+ }
+ assertNull(q.peekLast());
+ }
+
+ /**
+ * getFirst() returns first element, or throws NSEE if empty
+ */
+ public void testFirstElement() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.getFirst());
+ assertEquals(i, q.pollFirst());
+ }
+ try {
+ q.getFirst();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * getLast() returns last element, or throws NSEE if empty
+ */
+ public void testLastElement() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ for (int i = SIZE-1; i >= 0; --i) {
+ assertEquals(i, q.getLast());
+ assertEquals(i, q.pollLast());
+ }
+ try {
+ q.getLast();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ assertNull(q.peekLast());
+ }
+
+ /**
+ * removeFirst() removes first element, or throws NSEE if empty
+ */
+ public void testRemoveFirst() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.removeFirst());
+ }
+ try {
+ q.removeFirst();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ assertNull(q.peekFirst());
+ }
+
+ /**
+ * removeLast() removes last element, or throws NSEE if empty
+ */
+ public void testRemoveLast() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ for (int i = SIZE - 1; i >= 0; --i) {
+ assertEquals(i, q.removeLast());
+ }
+ try {
+ q.removeLast();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ assertNull(q.peekLast());
+ }
+
+ /**
+ * removeFirstOccurrence(x) removes x and returns true if present
+ */
+ public void testRemoveFirstOccurrence() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ for (int i = 1; i < SIZE; i+=2) {
+ assertTrue(q.removeFirstOccurrence(new Integer(i)));
+ }
+ for (int i = 0; i < SIZE; i+=2) {
+ assertTrue(q.removeFirstOccurrence(new Integer(i)));
+ assertFalse(q.removeFirstOccurrence(new Integer(i+1)));
+ }
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * removeLastOccurrence(x) removes x and returns true if present
+ */
+ public void testRemoveLastOccurrence() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ for (int i = 1; i < SIZE; i+=2) {
+ assertTrue(q.removeLastOccurrence(new Integer(i)));
+ }
+ for (int i = 0; i < SIZE; i+=2) {
+ assertTrue(q.removeLastOccurrence(new Integer(i)));
+ assertFalse(q.removeLastOccurrence(new Integer(i+1)));
+ }
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * contains(x) reports true when elements added but not yet removed
+ */
+ public void testContains() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.contains(new Integer(i)));
+ q.poll();
+ assertFalse(q.contains(new Integer(i)));
+ }
+ }
+
+ /**
+ * clear() removes all elements
+ */
+ public void testClear() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ q.clear();
+ assertTrue(q.isEmpty());
+ assertEquals(0, q.size());
+ q.add(one);
+ assertFalse(q.isEmpty());
+ q.clear();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * containsAll(c) is true when c contains a subset of elements
+ */
+ public void testContainsAll() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ ConcurrentLinkedDeque p = new ConcurrentLinkedDeque();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.containsAll(p));
+ assertFalse(p.containsAll(q));
+ p.add(new Integer(i));
+ }
+ assertTrue(p.containsAll(q));
+ }
+
+ /**
+ * retainAll(c) retains only those elements of c and reports true if change
+ */
+ public void testRetainAll() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ ConcurrentLinkedDeque p = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ boolean changed = q.retainAll(p);
+ if (i == 0)
+ assertFalse(changed);
+ else
+ assertTrue(changed);
+
+ assertTrue(q.containsAll(p));
+ assertEquals(SIZE-i, q.size());
+ p.remove();
+ }
+ }
+
+ /**
+ * removeAll(c) removes only those elements of c and reports true if changed
+ */
+ public void testRemoveAll() {
+ for (int i = 1; i < SIZE; ++i) {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ ConcurrentLinkedDeque p = populatedDeque(i);
+ assertTrue(q.removeAll(p));
+ assertEquals(SIZE-i, q.size());
+ for (int j = 0; j < i; ++j) {
+ Integer I = (Integer)(p.remove());
+ assertFalse(q.contains(I));
+ }
+ }
+ }
+
+ /**
+ * toArray() contains all elements in FIFO order
+ */
+ public void testToArray() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ Object[] o = q.toArray();
+ for (int i = 0; i < o.length; i++)
+ assertSame(o[i], q.poll());
+ }
+
+ /**
+ * toArray(a) contains all elements in FIFO order
+ */
+ public void testToArray2() {
+ ConcurrentLinkedDeque<Integer> q = populatedDeque(SIZE);
+ Integer[] ints = new Integer[SIZE];
+ Integer[] array = q.toArray(ints);
+ assertSame(ints, array);
+ for (int i = 0; i < ints.length; i++)
+ assertSame(ints[i], q.poll());
+ }
+
+ /**
+ * toArray(null) throws NullPointerException
+ */
+ public void testToArray_NullArg() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ try {
+ q.toArray(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * toArray(incompatible array type) throws ArrayStoreException
+ */
+ public void testToArray1_BadArg() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ try {
+ q.toArray(new String[10]);
+ shouldThrow();
+ } catch (ArrayStoreException success) {}
+ }
+
+ /**
+ * Iterator iterates through all elements
+ */
+ public void testIterator() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ int i = 0;
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ assertTrue(q.contains(it.next()));
+ ++i;
+ }
+ assertEquals(i, SIZE);
+ }
+
+ /**
+ * Iterator ordering is FIFO
+ */
+ public void testIteratorOrdering() {
+ final ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ q.add(one);
+ q.add(two);
+ q.add(three);
+
+ int k = 0;
+ for (Iterator it = q.iterator(); it.hasNext();) {
+ assertEquals(++k, it.next());
+ }
+
+ assertEquals(3, k);
+ }
+
+ /**
+ * Modifications do not cause iterators to fail
+ */
+ public void testWeaklyConsistentIteration() {
+ final ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ q.add(one);
+ q.add(two);
+ q.add(three);
+
+ for (Iterator it = q.iterator(); it.hasNext();) {
+ q.remove();
+ it.next();
+ }
+
+ assertEquals("deque should be empty again", 0, q.size());
+ }
+
+ /**
+ * iterator.remove() removes current element
+ */
+ public void testIteratorRemove() {
+ final ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ final Random rng = new Random();
+ for (int iters = 0; iters < 100; ++iters) {
+ int max = rng.nextInt(5) + 2;
+ int split = rng.nextInt(max-1) + 1;
+ for (int j = 1; j <= max; ++j)
+ q.add(new Integer(j));
+ Iterator it = q.iterator();
+ for (int j = 1; j <= split; ++j)
+ assertEquals(it.next(), new Integer(j));
+ it.remove();
+ assertEquals(it.next(), new Integer(split+1));
+ for (int j = 1; j <= split; ++j)
+ q.remove(new Integer(j));
+ it = q.iterator();
+ for (int j = split+1; j <= max; ++j) {
+ assertEquals(it.next(), new Integer(j));
+ it.remove();
+ }
+ assertFalse(it.hasNext());
+ assertTrue(q.isEmpty());
+ }
+ }
+
+ /**
+ * Descending iterator iterates through all elements
+ */
+ public void testDescendingIterator() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ int i = 0;
+ Iterator it = q.descendingIterator();
+ while (it.hasNext()) {
+ assertTrue(q.contains(it.next()));
+ ++i;
+ }
+ assertEquals(i, SIZE);
+ assertFalse(it.hasNext());
+ try {
+ it.next();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * Descending iterator ordering is reverse FIFO
+ */
+ public void testDescendingIteratorOrdering() {
+ final ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ for (int iters = 0; iters < 100; ++iters) {
+ q.add(new Integer(3));
+ q.add(new Integer(2));
+ q.add(new Integer(1));
+ int k = 0;
+ for (Iterator it = q.descendingIterator(); it.hasNext();) {
+ assertEquals(++k, it.next());
+ }
+
+ assertEquals(3, k);
+ q.remove();
+ q.remove();
+ q.remove();
+ }
+ }
+
+ /**
+ * descendingIterator.remove() removes current element
+ */
+ public void testDescendingIteratorRemove() {
+ final ConcurrentLinkedDeque q = new ConcurrentLinkedDeque();
+ final Random rng = new Random();
+ for (int iters = 0; iters < 100; ++iters) {
+ int max = rng.nextInt(5) + 2;
+ int split = rng.nextInt(max-1) + 1;
+ for (int j = max; j >= 1; --j)
+ q.add(new Integer(j));
+ Iterator it = q.descendingIterator();
+ for (int j = 1; j <= split; ++j)
+ assertEquals(it.next(), new Integer(j));
+ it.remove();
+ assertEquals(it.next(), new Integer(split+1));
+ for (int j = 1; j <= split; ++j)
+ q.remove(new Integer(j));
+ it = q.descendingIterator();
+ for (int j = split+1; j <= max; ++j) {
+ assertEquals(it.next(), new Integer(j));
+ it.remove();
+ }
+ assertFalse(it.hasNext());
+ assertTrue(q.isEmpty());
+ }
+ }
+
+ /**
+ * toString() contains toStrings of elements
+ */
+ public void testToString() {
+ ConcurrentLinkedDeque q = populatedDeque(SIZE);
+ String s = q.toString();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(s.contains(String.valueOf(i)));
+ }
+ }
+
+ /**
+ * A deserialized serialized deque has same elements in same order
+ */
+ public void testSerialization() throws Exception {
+ Queue x = populatedDeque(SIZE);
+ Queue y = serialClone(x);
+
+ assertNotSame(x, y);
+ assertEquals(x.size(), y.size());
+ assertEquals(x.toString(), y.toString());
+ assertTrue(Arrays.equals(x.toArray(), y.toArray()));
+ while (!x.isEmpty()) {
+ assertFalse(y.isEmpty());
+ assertEquals(x.remove(), y.remove());
+ }
+ assertTrue(y.isEmpty());
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/ConcurrentLinkedQueueTest.java b/jsr166-tests/src/test/java/jsr166/ConcurrentLinkedQueueTest.java
new file mode 100644
index 0000000..7924034
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/ConcurrentLinkedQueueTest.java
@@ -0,0 +1,511 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+public class ConcurrentLinkedQueueTest extends JSR166TestCase {
+
+ /**
+ * Returns a new queue of given size containing consecutive
+ * Integers 0 ... n.
+ */
+ private ConcurrentLinkedQueue<Integer> populatedQueue(int n) {
+ ConcurrentLinkedQueue<Integer> q = new ConcurrentLinkedQueue<Integer>();
+ assertTrue(q.isEmpty());
+ for (int i = 0; i < n; ++i)
+ assertTrue(q.offer(new Integer(i)));
+ assertFalse(q.isEmpty());
+ assertEquals(n, q.size());
+ return q;
+ }
+
+ /**
+ * new queue is empty
+ */
+ public void testConstructor1() {
+ assertEquals(0, new ConcurrentLinkedQueue().size());
+ }
+
+ /**
+ * Initializing from null Collection throws NPE
+ */
+ public void testConstructor3() {
+ try {
+ ConcurrentLinkedQueue q = new ConcurrentLinkedQueue((Collection)null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing from Collection of null elements throws NPE
+ */
+ public void testConstructor4() {
+ try {
+ Integer[] ints = new Integer[SIZE];
+ ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing from Collection with some null elements throws NPE
+ */
+ public void testConstructor5() {
+ try {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
+ ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Queue contains all elements of collection used to initialize
+ */
+ public void testConstructor6() {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(i);
+ ConcurrentLinkedQueue q = new ConcurrentLinkedQueue(Arrays.asList(ints));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(ints[i], q.poll());
+ }
+
+ /**
+ * isEmpty is true before add, false after
+ */
+ public void testEmpty() {
+ ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
+ assertTrue(q.isEmpty());
+ q.add(one);
+ assertFalse(q.isEmpty());
+ q.add(two);
+ q.remove();
+ q.remove();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * size changes when elements added and removed
+ */
+ public void testSize() {
+ ConcurrentLinkedQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(SIZE-i, q.size());
+ q.remove();
+ }
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.size());
+ q.add(new Integer(i));
+ }
+ }
+
+ /**
+ * offer(null) throws NPE
+ */
+ public void testOfferNull() {
+ try {
+ ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
+ q.offer(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * add(null) throws NPE
+ */
+ public void testAddNull() {
+ try {
+ ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
+ q.add(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Offer returns true
+ */
+ public void testOffer() {
+ ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
+ assertTrue(q.offer(zero));
+ assertTrue(q.offer(one));
+ }
+
+ /**
+ * add returns true
+ */
+ public void testAdd() {
+ ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.size());
+ assertTrue(q.add(new Integer(i)));
+ }
+ }
+
+ /**
+ * addAll(null) throws NPE
+ */
+ public void testAddAll1() {
+ try {
+ ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
+ q.addAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll(this) throws IAE
+ */
+ public void testAddAllSelf() {
+ try {
+ ConcurrentLinkedQueue q = populatedQueue(SIZE);
+ q.addAll(q);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * addAll of a collection with null elements throws NPE
+ */
+ public void testAddAll2() {
+ try {
+ ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
+ Integer[] ints = new Integer[SIZE];
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll of a collection with any null elements throws NPE after
+ * possibly adding some elements
+ */
+ public void testAddAll3() {
+ try {
+ ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Queue contains all elements, in traversal order, of successful addAll
+ */
+ public void testAddAll5() {
+ Integer[] empty = new Integer[0];
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(i);
+ ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
+ assertFalse(q.addAll(Arrays.asList(empty)));
+ assertTrue(q.addAll(Arrays.asList(ints)));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(ints[i], q.poll());
+ }
+
+ /**
+ * poll succeeds unless empty
+ */
+ public void testPoll() {
+ ConcurrentLinkedQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.poll());
+ }
+ assertNull(q.poll());
+ }
+
+ /**
+ * peek returns next element, or null if empty
+ */
+ public void testPeek() {
+ ConcurrentLinkedQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.peek());
+ assertEquals(i, q.poll());
+ assertTrue(q.peek() == null ||
+ !q.peek().equals(i));
+ }
+ assertNull(q.peek());
+ }
+
+ /**
+ * element returns next element, or throws NSEE if empty
+ */
+ public void testElement() {
+ ConcurrentLinkedQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.element());
+ assertEquals(i, q.poll());
+ }
+ try {
+ q.element();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * remove removes next element, or throws NSEE if empty
+ */
+ public void testRemove() {
+ ConcurrentLinkedQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.remove());
+ }
+ try {
+ q.remove();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * remove(x) removes x and returns true if present
+ */
+ public void testRemoveElement() {
+ ConcurrentLinkedQueue q = populatedQueue(SIZE);
+ for (int i = 1; i < SIZE; i+=2) {
+ assertTrue(q.contains(i));
+ assertTrue(q.remove(i));
+ assertFalse(q.contains(i));
+ assertTrue(q.contains(i-1));
+ }
+ for (int i = 0; i < SIZE; i+=2) {
+ assertTrue(q.contains(i));
+ assertTrue(q.remove(i));
+ assertFalse(q.contains(i));
+ assertFalse(q.remove(i+1));
+ assertFalse(q.contains(i+1));
+ }
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * contains(x) reports true when elements added but not yet removed
+ */
+ public void testContains() {
+ ConcurrentLinkedQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.contains(new Integer(i)));
+ q.poll();
+ assertFalse(q.contains(new Integer(i)));
+ }
+ }
+
+ /**
+ * clear removes all elements
+ */
+ public void testClear() {
+ ConcurrentLinkedQueue q = populatedQueue(SIZE);
+ q.clear();
+ assertTrue(q.isEmpty());
+ assertEquals(0, q.size());
+ q.add(one);
+ assertFalse(q.isEmpty());
+ q.clear();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * containsAll(c) is true when c contains a subset of elements
+ */
+ public void testContainsAll() {
+ ConcurrentLinkedQueue q = populatedQueue(SIZE);
+ ConcurrentLinkedQueue p = new ConcurrentLinkedQueue();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.containsAll(p));
+ assertFalse(p.containsAll(q));
+ p.add(new Integer(i));
+ }
+ assertTrue(p.containsAll(q));
+ }
+
+ /**
+ * retainAll(c) retains only those elements of c and reports true if change
+ */
+ public void testRetainAll() {
+ ConcurrentLinkedQueue q = populatedQueue(SIZE);
+ ConcurrentLinkedQueue p = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ boolean changed = q.retainAll(p);
+ if (i == 0)
+ assertFalse(changed);
+ else
+ assertTrue(changed);
+
+ assertTrue(q.containsAll(p));
+ assertEquals(SIZE-i, q.size());
+ p.remove();
+ }
+ }
+
+ /**
+ * removeAll(c) removes only those elements of c and reports true if changed
+ */
+ public void testRemoveAll() {
+ for (int i = 1; i < SIZE; ++i) {
+ ConcurrentLinkedQueue q = populatedQueue(SIZE);
+ ConcurrentLinkedQueue p = populatedQueue(i);
+ assertTrue(q.removeAll(p));
+ assertEquals(SIZE-i, q.size());
+ for (int j = 0; j < i; ++j) {
+ Integer I = (Integer)(p.remove());
+ assertFalse(q.contains(I));
+ }
+ }
+ }
+
+ /**
+ * toArray contains all elements in FIFO order
+ */
+ public void testToArray() {
+ ConcurrentLinkedQueue q = populatedQueue(SIZE);
+ Object[] o = q.toArray();
+ for (int i = 0; i < o.length; i++)
+ assertSame(o[i], q.poll());
+ }
+
+ /**
+ * toArray(a) contains all elements in FIFO order
+ */
+ public void testToArray2() {
+ ConcurrentLinkedQueue<Integer> q = populatedQueue(SIZE);
+ Integer[] ints = new Integer[SIZE];
+ Integer[] array = q.toArray(ints);
+ assertSame(ints, array);
+ for (int i = 0; i < ints.length; i++)
+ assertSame(ints[i], q.poll());
+ }
+
+ /**
+ * toArray(null) throws NullPointerException
+ */
+ public void testToArray_NullArg() {
+ ConcurrentLinkedQueue q = populatedQueue(SIZE);
+ try {
+ q.toArray(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * toArray(incompatible array type) throws ArrayStoreException
+ */
+ public void testToArray1_BadArg() {
+ ConcurrentLinkedQueue q = populatedQueue(SIZE);
+ try {
+ q.toArray(new String[10]);
+ shouldThrow();
+ } catch (ArrayStoreException success) {}
+ }
+
+ /**
+ * iterator iterates through all elements
+ */
+ public void testIterator() {
+ ConcurrentLinkedQueue q = populatedQueue(SIZE);
+ int i = 0;
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ assertTrue(q.contains(it.next()));
+ ++i;
+ }
+ assertEquals(i, SIZE);
+ }
+
+ /**
+ * iterator ordering is FIFO
+ */
+ public void testIteratorOrdering() {
+ final ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
+ q.add(one);
+ q.add(two);
+ q.add(three);
+
+ int k = 0;
+ for (Iterator it = q.iterator(); it.hasNext();) {
+ assertEquals(++k, it.next());
+ }
+
+ assertEquals(3, k);
+ }
+
+ /**
+ * Modifications do not cause iterators to fail
+ */
+ public void testWeaklyConsistentIteration() {
+ final ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
+ q.add(one);
+ q.add(two);
+ q.add(three);
+
+ for (Iterator it = q.iterator(); it.hasNext();) {
+ q.remove();
+ it.next();
+ }
+
+ assertEquals("queue should be empty again", 0, q.size());
+ }
+
+ /**
+ * iterator.remove removes current element
+ */
+ public void testIteratorRemove() {
+ final ConcurrentLinkedQueue q = new ConcurrentLinkedQueue();
+ q.add(one);
+ q.add(two);
+ q.add(three);
+ Iterator it = q.iterator();
+ it.next();
+ it.remove();
+ it = q.iterator();
+ assertSame(it.next(), two);
+ assertSame(it.next(), three);
+ assertFalse(it.hasNext());
+ }
+
+ /**
+ * toString contains toStrings of elements
+ */
+ public void testToString() {
+ ConcurrentLinkedQueue q = populatedQueue(SIZE);
+ String s = q.toString();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(s.contains(String.valueOf(i)));
+ }
+ }
+
+ /**
+ * A deserialized serialized queue has same elements in same order
+ */
+ public void testSerialization() throws Exception {
+ Queue x = populatedQueue(SIZE);
+ Queue y = serialClone(x);
+
+ assertNotSame(x, y);
+ assertEquals(x.size(), y.size());
+ assertEquals(x.toString(), y.toString());
+ assertTrue(Arrays.equals(x.toArray(), y.toArray()));
+ while (!x.isEmpty()) {
+ assertFalse(y.isEmpty());
+ assertEquals(x.remove(), y.remove());
+ }
+ assertTrue(y.isEmpty());
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListMapTest.java b/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListMapTest.java
new file mode 100644
index 0000000..4359287
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListMapTest.java
@@ -0,0 +1,1263 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.*;
+import java.util.concurrent.ConcurrentSkipListMap;
+
+public class ConcurrentSkipListMapTest extends JSR166TestCase {
+
+ /**
+ * Returns a new map from Integers 1-5 to Strings "A"-"E".
+ */
+ private static ConcurrentSkipListMap map5() {
+ ConcurrentSkipListMap map = new ConcurrentSkipListMap();
+ assertTrue(map.isEmpty());
+ map.put(one, "A");
+ map.put(five, "E");
+ map.put(three, "C");
+ map.put(two, "B");
+ map.put(four, "D");
+ assertFalse(map.isEmpty());
+ assertEquals(5, map.size());
+ return map;
+ }
+
+ /**
+ * clear removes all pairs
+ */
+ public void testClear() {
+ ConcurrentSkipListMap map = map5();
+ map.clear();
+ assertEquals(0, map.size());
+ }
+
+ /**
+ * copy constructor creates map equal to source map
+ */
+ public void testConstructFromSorted() {
+ ConcurrentSkipListMap map = map5();
+ ConcurrentSkipListMap map2 = new ConcurrentSkipListMap(map);
+ assertEquals(map, map2);
+ }
+
+ /**
+ * Maps with same contents are equal
+ */
+ public void testEquals() {
+ ConcurrentSkipListMap map1 = map5();
+ ConcurrentSkipListMap map2 = map5();
+ assertEquals(map1, map2);
+ assertEquals(map2, map1);
+ map1.clear();
+ assertFalse(map1.equals(map2));
+ assertFalse(map2.equals(map1));
+ }
+
+ /**
+ * containsKey returns true for contained key
+ */
+ public void testContainsKey() {
+ ConcurrentSkipListMap map = map5();
+ assertTrue(map.containsKey(one));
+ assertFalse(map.containsKey(zero));
+ }
+
+ /**
+ * containsValue returns true for held values
+ */
+ public void testContainsValue() {
+ ConcurrentSkipListMap map = map5();
+ assertTrue(map.containsValue("A"));
+ assertFalse(map.containsValue("Z"));
+ }
+
+ /**
+ * get returns the correct element at the given key,
+ * or null if not present
+ */
+ public void testGet() {
+ ConcurrentSkipListMap map = map5();
+ assertEquals("A", (String)map.get(one));
+ ConcurrentSkipListMap empty = new ConcurrentSkipListMap();
+ assertNull(empty.get(one));
+ }
+
+ /**
+ * isEmpty is true of empty map and false for non-empty
+ */
+ public void testIsEmpty() {
+ ConcurrentSkipListMap empty = new ConcurrentSkipListMap();
+ ConcurrentSkipListMap map = map5();
+ assertTrue(empty.isEmpty());
+ assertFalse(map.isEmpty());
+ }
+
+ /**
+ * firstKey returns first key
+ */
+ public void testFirstKey() {
+ ConcurrentSkipListMap map = map5();
+ assertEquals(one, map.firstKey());
+ }
+
+ /**
+ * lastKey returns last key
+ */
+ public void testLastKey() {
+ ConcurrentSkipListMap map = map5();
+ assertEquals(five, map.lastKey());
+ }
+
+ /**
+ * keySet.toArray returns contains all keys
+ */
+ public void testKeySetToArray() {
+ ConcurrentSkipListMap map = map5();
+ Set s = map.keySet();
+ Object[] ar = s.toArray();
+ assertTrue(s.containsAll(Arrays.asList(ar)));
+ assertEquals(5, ar.length);
+ ar[0] = m10;
+ assertFalse(s.containsAll(Arrays.asList(ar)));
+ }
+
+ /**
+ * descendingkeySet.toArray returns contains all keys
+ */
+ public void testDescendingKeySetToArray() {
+ ConcurrentSkipListMap map = map5();
+ Set s = map.descendingKeySet();
+ Object[] ar = s.toArray();
+ assertEquals(5, ar.length);
+ assertTrue(s.containsAll(Arrays.asList(ar)));
+ ar[0] = m10;
+ assertFalse(s.containsAll(Arrays.asList(ar)));
+ }
+
+ /**
+ * keySet returns a Set containing all the keys
+ */
+ public void testKeySet() {
+ ConcurrentSkipListMap map = map5();
+ Set s = map.keySet();
+ assertEquals(5, s.size());
+ assertTrue(s.contains(one));
+ assertTrue(s.contains(two));
+ assertTrue(s.contains(three));
+ assertTrue(s.contains(four));
+ assertTrue(s.contains(five));
+ }
+
+ /**
+ * keySet is ordered
+ */
+ public void testKeySetOrder() {
+ ConcurrentSkipListMap map = map5();
+ Set s = map.keySet();
+ Iterator i = s.iterator();
+ Integer last = (Integer)i.next();
+ assertEquals(last, one);
+ int count = 1;
+ while (i.hasNext()) {
+ Integer k = (Integer)i.next();
+ assertTrue(last.compareTo(k) < 0);
+ last = k;
+ ++count;
+ }
+ assertEquals(5, count);
+ }
+
+ /**
+ * descending iterator of key set is inverse ordered
+ */
+ public void testKeySetDescendingIteratorOrder() {
+ ConcurrentSkipListMap map = map5();
+ NavigableSet s = map.navigableKeySet();
+ Iterator i = s.descendingIterator();
+ Integer last = (Integer)i.next();
+ assertEquals(last, five);
+ int count = 1;
+ while (i.hasNext()) {
+ Integer k = (Integer)i.next();
+ assertTrue(last.compareTo(k) > 0);
+ last = k;
+ ++count;
+ }
+ assertEquals(5, count);
+ }
+
+ /**
+ * descendingKeySet is ordered
+ */
+ public void testDescendingKeySetOrder() {
+ ConcurrentSkipListMap map = map5();
+ Set s = map.descendingKeySet();
+ Iterator i = s.iterator();
+ Integer last = (Integer)i.next();
+ assertEquals(last, five);
+ int count = 1;
+ while (i.hasNext()) {
+ Integer k = (Integer)i.next();
+ assertTrue(last.compareTo(k) > 0);
+ last = k;
+ ++count;
+ }
+ assertEquals(5, count);
+ }
+
+ /**
+ * descending iterator of descendingKeySet is ordered
+ */
+ public void testDescendingKeySetDescendingIteratorOrder() {
+ ConcurrentSkipListMap map = map5();
+ NavigableSet s = map.descendingKeySet();
+ Iterator i = s.descendingIterator();
+ Integer last = (Integer)i.next();
+ assertEquals(last, one);
+ int count = 1;
+ while (i.hasNext()) {
+ Integer k = (Integer)i.next();
+ assertTrue(last.compareTo(k) < 0);
+ last = k;
+ ++count;
+ }
+ assertEquals(5, count);
+ }
+
+ /**
+ * Values.toArray contains all values
+ */
+ public void testValuesToArray() {
+ ConcurrentSkipListMap map = map5();
+ Collection v = map.values();
+ Object[] ar = v.toArray();
+ ArrayList s = new ArrayList(Arrays.asList(ar));
+ assertEquals(5, ar.length);
+ assertTrue(s.contains("A"));
+ assertTrue(s.contains("B"));
+ assertTrue(s.contains("C"));
+ assertTrue(s.contains("D"));
+ assertTrue(s.contains("E"));
+ }
+
+ /**
+ * values collection contains all values
+ */
+ public void testValues() {
+ ConcurrentSkipListMap map = map5();
+ Collection s = map.values();
+ assertEquals(5, s.size());
+ assertTrue(s.contains("A"));
+ assertTrue(s.contains("B"));
+ assertTrue(s.contains("C"));
+ assertTrue(s.contains("D"));
+ assertTrue(s.contains("E"));
+ }
+
+ /**
+ * entrySet contains all pairs
+ */
+ public void testEntrySet() {
+ ConcurrentSkipListMap map = map5();
+ Set s = map.entrySet();
+ assertEquals(5, s.size());
+ Iterator it = s.iterator();
+ while (it.hasNext()) {
+ Map.Entry e = (Map.Entry) it.next();
+ assertTrue(
+ (e.getKey().equals(one) && e.getValue().equals("A")) ||
+ (e.getKey().equals(two) && e.getValue().equals("B")) ||
+ (e.getKey().equals(three) && e.getValue().equals("C")) ||
+ (e.getKey().equals(four) && e.getValue().equals("D")) ||
+ (e.getKey().equals(five) && e.getValue().equals("E")));
+ }
+ }
+
+ /**
+ * descendingEntrySet contains all pairs
+ */
+ public void testDescendingEntrySet() {
+ ConcurrentSkipListMap map = map5();
+ Set s = map.descendingMap().entrySet();
+ assertEquals(5, s.size());
+ Iterator it = s.iterator();
+ while (it.hasNext()) {
+ Map.Entry e = (Map.Entry) it.next();
+ assertTrue(
+ (e.getKey().equals(one) && e.getValue().equals("A")) ||
+ (e.getKey().equals(two) && e.getValue().equals("B")) ||
+ (e.getKey().equals(three) && e.getValue().equals("C")) ||
+ (e.getKey().equals(four) && e.getValue().equals("D")) ||
+ (e.getKey().equals(five) && e.getValue().equals("E")));
+ }
+ }
+
+ /**
+ * entrySet.toArray contains all entries
+ */
+ public void testEntrySetToArray() {
+ ConcurrentSkipListMap map = map5();
+ Set s = map.entrySet();
+ Object[] ar = s.toArray();
+ assertEquals(5, ar.length);
+ for (int i = 0; i < 5; ++i) {
+ assertTrue(map.containsKey(((Map.Entry)(ar[i])).getKey()));
+ assertTrue(map.containsValue(((Map.Entry)(ar[i])).getValue()));
+ }
+ }
+
+ /**
+ * descendingEntrySet.toArray contains all entries
+ */
+ public void testDescendingEntrySetToArray() {
+ ConcurrentSkipListMap map = map5();
+ Set s = map.descendingMap().entrySet();
+ Object[] ar = s.toArray();
+ assertEquals(5, ar.length);
+ for (int i = 0; i < 5; ++i) {
+ assertTrue(map.containsKey(((Map.Entry)(ar[i])).getKey()));
+ assertTrue(map.containsValue(((Map.Entry)(ar[i])).getValue()));
+ }
+ }
+
+ /**
+ * putAll adds all key-value pairs from the given map
+ */
+ public void testPutAll() {
+ ConcurrentSkipListMap empty = new ConcurrentSkipListMap();
+ ConcurrentSkipListMap map = map5();
+ empty.putAll(map);
+ assertEquals(5, empty.size());
+ assertTrue(empty.containsKey(one));
+ assertTrue(empty.containsKey(two));
+ assertTrue(empty.containsKey(three));
+ assertTrue(empty.containsKey(four));
+ assertTrue(empty.containsKey(five));
+ }
+
+ /**
+ * putIfAbsent works when the given key is not present
+ */
+ public void testPutIfAbsent() {
+ ConcurrentSkipListMap map = map5();
+ map.putIfAbsent(six, "Z");
+ assertTrue(map.containsKey(six));
+ }
+
+ /**
+ * putIfAbsent does not add the pair if the key is already present
+ */
+ public void testPutIfAbsent2() {
+ ConcurrentSkipListMap map = map5();
+ assertEquals("A", map.putIfAbsent(one, "Z"));
+ }
+
+ /**
+ * replace fails when the given key is not present
+ */
+ public void testReplace() {
+ ConcurrentSkipListMap map = map5();
+ assertNull(map.replace(six, "Z"));
+ assertFalse(map.containsKey(six));
+ }
+
+ /**
+ * replace succeeds if the key is already present
+ */
+ public void testReplace2() {
+ ConcurrentSkipListMap map = map5();
+ assertNotNull(map.replace(one, "Z"));
+ assertEquals("Z", map.get(one));
+ }
+
+ /**
+ * replace value fails when the given key not mapped to expected value
+ */
+ public void testReplaceValue() {
+ ConcurrentSkipListMap map = map5();
+ assertEquals("A", map.get(one));
+ assertFalse(map.replace(one, "Z", "Z"));
+ assertEquals("A", map.get(one));
+ }
+
+ /**
+ * replace value succeeds when the given key mapped to expected value
+ */
+ public void testReplaceValue2() {
+ ConcurrentSkipListMap map = map5();
+ assertEquals("A", map.get(one));
+ assertTrue(map.replace(one, "A", "Z"));
+ assertEquals("Z", map.get(one));
+ }
+
+ /**
+ * remove removes the correct key-value pair from the map
+ */
+ public void testRemove() {
+ ConcurrentSkipListMap map = map5();
+ map.remove(five);
+ assertEquals(4, map.size());
+ assertFalse(map.containsKey(five));
+ }
+
+ /**
+ * remove(key,value) removes only if pair present
+ */
+ public void testRemove2() {
+ ConcurrentSkipListMap map = map5();
+ assertTrue(map.containsKey(five));
+ assertEquals("E", map.get(five));
+ map.remove(five, "E");
+ assertEquals(4, map.size());
+ assertFalse(map.containsKey(five));
+ map.remove(four, "A");
+ assertEquals(4, map.size());
+ assertTrue(map.containsKey(four));
+ }
+
+ /**
+ * lowerEntry returns preceding entry.
+ */
+ public void testLowerEntry() {
+ ConcurrentSkipListMap map = map5();
+ Map.Entry e1 = map.lowerEntry(three);
+ assertEquals(two, e1.getKey());
+
+ Map.Entry e2 = map.lowerEntry(six);
+ assertEquals(five, e2.getKey());
+
+ Map.Entry e3 = map.lowerEntry(one);
+ assertNull(e3);
+
+ Map.Entry e4 = map.lowerEntry(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * higherEntry returns next entry.
+ */
+ public void testHigherEntry() {
+ ConcurrentSkipListMap map = map5();
+ Map.Entry e1 = map.higherEntry(three);
+ assertEquals(four, e1.getKey());
+
+ Map.Entry e2 = map.higherEntry(zero);
+ assertEquals(one, e2.getKey());
+
+ Map.Entry e3 = map.higherEntry(five);
+ assertNull(e3);
+
+ Map.Entry e4 = map.higherEntry(six);
+ assertNull(e4);
+ }
+
+ /**
+ * floorEntry returns preceding entry.
+ */
+ public void testFloorEntry() {
+ ConcurrentSkipListMap map = map5();
+ Map.Entry e1 = map.floorEntry(three);
+ assertEquals(three, e1.getKey());
+
+ Map.Entry e2 = map.floorEntry(six);
+ assertEquals(five, e2.getKey());
+
+ Map.Entry e3 = map.floorEntry(one);
+ assertEquals(one, e3.getKey());
+
+ Map.Entry e4 = map.floorEntry(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * ceilingEntry returns next entry.
+ */
+ public void testCeilingEntry() {
+ ConcurrentSkipListMap map = map5();
+ Map.Entry e1 = map.ceilingEntry(three);
+ assertEquals(three, e1.getKey());
+
+ Map.Entry e2 = map.ceilingEntry(zero);
+ assertEquals(one, e2.getKey());
+
+ Map.Entry e3 = map.ceilingEntry(five);
+ assertEquals(five, e3.getKey());
+
+ Map.Entry e4 = map.ceilingEntry(six);
+ assertNull(e4);
+ }
+
+ /**
+ * lowerEntry, higherEntry, ceilingEntry, and floorEntry return
+ * immutable entries
+ */
+ public void testEntryImmutability() {
+ ConcurrentSkipListMap map = map5();
+ Map.Entry e = map.lowerEntry(three);
+ assertEquals(two, e.getKey());
+ try {
+ e.setValue("X");
+ shouldThrow();
+ } catch (UnsupportedOperationException success) {}
+ e = map.higherEntry(zero);
+ assertEquals(one, e.getKey());
+ try {
+ e.setValue("X");
+ shouldThrow();
+ } catch (UnsupportedOperationException success) {}
+ e = map.floorEntry(one);
+ assertEquals(one, e.getKey());
+ try {
+ e.setValue("X");
+ shouldThrow();
+ } catch (UnsupportedOperationException success) {}
+ e = map.ceilingEntry(five);
+ assertEquals(five, e.getKey());
+ try {
+ e.setValue("X");
+ shouldThrow();
+ } catch (UnsupportedOperationException success) {}
+ }
+
+ /**
+ * lowerKey returns preceding element
+ */
+ public void testLowerKey() {
+ ConcurrentSkipListMap q = map5();
+ Object e1 = q.lowerKey(three);
+ assertEquals(two, e1);
+
+ Object e2 = q.lowerKey(six);
+ assertEquals(five, e2);
+
+ Object e3 = q.lowerKey(one);
+ assertNull(e3);
+
+ Object e4 = q.lowerKey(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * higherKey returns next element
+ */
+ public void testHigherKey() {
+ ConcurrentSkipListMap q = map5();
+ Object e1 = q.higherKey(three);
+ assertEquals(four, e1);
+
+ Object e2 = q.higherKey(zero);
+ assertEquals(one, e2);
+
+ Object e3 = q.higherKey(five);
+ assertNull(e3);
+
+ Object e4 = q.higherKey(six);
+ assertNull(e4);
+ }
+
+ /**
+ * floorKey returns preceding element
+ */
+ public void testFloorKey() {
+ ConcurrentSkipListMap q = map5();
+ Object e1 = q.floorKey(three);
+ assertEquals(three, e1);
+
+ Object e2 = q.floorKey(six);
+ assertEquals(five, e2);
+
+ Object e3 = q.floorKey(one);
+ assertEquals(one, e3);
+
+ Object e4 = q.floorKey(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * ceilingKey returns next element
+ */
+ public void testCeilingKey() {
+ ConcurrentSkipListMap q = map5();
+ Object e1 = q.ceilingKey(three);
+ assertEquals(three, e1);
+
+ Object e2 = q.ceilingKey(zero);
+ assertEquals(one, e2);
+
+ Object e3 = q.ceilingKey(five);
+ assertEquals(five, e3);
+
+ Object e4 = q.ceilingKey(six);
+ assertNull(e4);
+ }
+
+ /**
+ * pollFirstEntry returns entries in order
+ */
+ public void testPollFirstEntry() {
+ ConcurrentSkipListMap map = map5();
+ Map.Entry e = map.pollFirstEntry();
+ assertEquals(one, e.getKey());
+ assertEquals("A", e.getValue());
+ e = map.pollFirstEntry();
+ assertEquals(two, e.getKey());
+ map.put(one, "A");
+ e = map.pollFirstEntry();
+ assertEquals(one, e.getKey());
+ assertEquals("A", e.getValue());
+ e = map.pollFirstEntry();
+ assertEquals(three, e.getKey());
+ map.remove(four);
+ e = map.pollFirstEntry();
+ assertEquals(five, e.getKey());
+ try {
+ e.setValue("A");
+ shouldThrow();
+ } catch (UnsupportedOperationException success) {}
+ e = map.pollFirstEntry();
+ assertNull(e);
+ }
+
+ /**
+ * pollLastEntry returns entries in order
+ */
+ public void testPollLastEntry() {
+ ConcurrentSkipListMap map = map5();
+ Map.Entry e = map.pollLastEntry();
+ assertEquals(five, e.getKey());
+ assertEquals("E", e.getValue());
+ e = map.pollLastEntry();
+ assertEquals(four, e.getKey());
+ map.put(five, "E");
+ e = map.pollLastEntry();
+ assertEquals(five, e.getKey());
+ assertEquals("E", e.getValue());
+ e = map.pollLastEntry();
+ assertEquals(three, e.getKey());
+ map.remove(two);
+ e = map.pollLastEntry();
+ assertEquals(one, e.getKey());
+ try {
+ e.setValue("E");
+ shouldThrow();
+ } catch (UnsupportedOperationException success) {}
+ e = map.pollLastEntry();
+ assertNull(e);
+ }
+
+ /**
+ * size returns the correct values
+ */
+ public void testSize() {
+ ConcurrentSkipListMap map = map5();
+ ConcurrentSkipListMap empty = new ConcurrentSkipListMap();
+ assertEquals(0, empty.size());
+ assertEquals(5, map.size());
+ }
+
+ /**
+ * toString contains toString of elements
+ */
+ public void testToString() {
+ ConcurrentSkipListMap map = map5();
+ String s = map.toString();
+ for (int i = 1; i <= 5; ++i) {
+ assertTrue(s.contains(String.valueOf(i)));
+ }
+ }
+
+ // Exception tests
+
+ /**
+ * get(null) of nonempty map throws NPE
+ */
+ public void testGet_NullPointerException() {
+ try {
+ ConcurrentSkipListMap c = map5();
+ c.get(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * containsKey(null) of nonempty map throws NPE
+ */
+ public void testContainsKey_NullPointerException() {
+ try {
+ ConcurrentSkipListMap c = map5();
+ c.containsKey(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * containsValue(null) throws NPE
+ */
+ public void testContainsValue_NullPointerException() {
+ try {
+ ConcurrentSkipListMap c = new ConcurrentSkipListMap();
+ c.containsValue(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * put(null,x) throws NPE
+ */
+ public void testPut1_NullPointerException() {
+ try {
+ ConcurrentSkipListMap c = map5();
+ c.put(null, "whatever");
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * putIfAbsent(null, x) throws NPE
+ */
+ public void testPutIfAbsent1_NullPointerException() {
+ try {
+ ConcurrentSkipListMap c = map5();
+ c.putIfAbsent(null, "whatever");
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * replace(null, x) throws NPE
+ */
+ public void testReplace_NullPointerException() {
+ try {
+ ConcurrentSkipListMap c = map5();
+ c.replace(null, "whatever");
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * replace(null, x, y) throws NPE
+ */
+ public void testReplaceValue_NullPointerException() {
+ try {
+ ConcurrentSkipListMap c = map5();
+ c.replace(null, one, "whatever");
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * remove(null) throws NPE
+ */
+ public void testRemove1_NullPointerException() {
+ try {
+ ConcurrentSkipListMap c = new ConcurrentSkipListMap();
+ c.put("sadsdf", "asdads");
+ c.remove(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * remove(null, x) throws NPE
+ */
+ public void testRemove2_NullPointerException() {
+ try {
+ ConcurrentSkipListMap c = new ConcurrentSkipListMap();
+ c.put("sadsdf", "asdads");
+ c.remove(null, "whatever");
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * remove(x, null) returns false
+ */
+ public void testRemove3() {
+ ConcurrentSkipListMap c = new ConcurrentSkipListMap();
+ c.put("sadsdf", "asdads");
+ assertFalse(c.remove("sadsdf", null));
+ }
+
+ /**
+ * A deserialized map equals original
+ */
+ public void testSerialization() throws Exception {
+ NavigableMap x = map5();
+ NavigableMap y = serialClone(x);
+
+ assertNotSame(x, y);
+ assertEquals(x.size(), y.size());
+ assertEquals(x.toString(), y.toString());
+ assertEquals(x, y);
+ assertEquals(y, x);
+ }
+
+ /**
+ * subMap returns map with keys in requested range
+ */
+ public void testSubMapContents() {
+ ConcurrentSkipListMap map = map5();
+ NavigableMap sm = map.subMap(two, true, four, false);
+ assertEquals(two, sm.firstKey());
+ assertEquals(three, sm.lastKey());
+ assertEquals(2, sm.size());
+ assertFalse(sm.containsKey(one));
+ assertTrue(sm.containsKey(two));
+ assertTrue(sm.containsKey(three));
+ assertFalse(sm.containsKey(four));
+ assertFalse(sm.containsKey(five));
+ Iterator i = sm.keySet().iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ k = (Integer)(i.next());
+ assertEquals(three, k);
+ assertFalse(i.hasNext());
+ Iterator r = sm.descendingKeySet().iterator();
+ k = (Integer)(r.next());
+ assertEquals(three, k);
+ k = (Integer)(r.next());
+ assertEquals(two, k);
+ assertFalse(r.hasNext());
+
+ Iterator j = sm.keySet().iterator();
+ j.next();
+ j.remove();
+ assertFalse(map.containsKey(two));
+ assertEquals(4, map.size());
+ assertEquals(1, sm.size());
+ assertEquals(three, sm.firstKey());
+ assertEquals(three, sm.lastKey());
+ assertEquals("C", sm.remove(three));
+ assertTrue(sm.isEmpty());
+ assertEquals(3, map.size());
+ }
+
+ public void testSubMapContents2() {
+ ConcurrentSkipListMap map = map5();
+ NavigableMap sm = map.subMap(two, true, three, false);
+ assertEquals(1, sm.size());
+ assertEquals(two, sm.firstKey());
+ assertEquals(two, sm.lastKey());
+ assertFalse(sm.containsKey(one));
+ assertTrue(sm.containsKey(two));
+ assertFalse(sm.containsKey(three));
+ assertFalse(sm.containsKey(four));
+ assertFalse(sm.containsKey(five));
+ Iterator i = sm.keySet().iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ assertFalse(i.hasNext());
+ Iterator r = sm.descendingKeySet().iterator();
+ k = (Integer)(r.next());
+ assertEquals(two, k);
+ assertFalse(r.hasNext());
+
+ Iterator j = sm.keySet().iterator();
+ j.next();
+ j.remove();
+ assertFalse(map.containsKey(two));
+ assertEquals(4, map.size());
+ assertEquals(0, sm.size());
+ assertTrue(sm.isEmpty());
+ assertSame(sm.remove(three), null);
+ assertEquals(4, map.size());
+ }
+
+ /**
+ * headMap returns map with keys in requested range
+ */
+ public void testHeadMapContents() {
+ ConcurrentSkipListMap map = map5();
+ NavigableMap sm = map.headMap(four, false);
+ assertTrue(sm.containsKey(one));
+ assertTrue(sm.containsKey(two));
+ assertTrue(sm.containsKey(three));
+ assertFalse(sm.containsKey(four));
+ assertFalse(sm.containsKey(five));
+ Iterator i = sm.keySet().iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(one, k);
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ k = (Integer)(i.next());
+ assertEquals(three, k);
+ assertFalse(i.hasNext());
+ sm.clear();
+ assertTrue(sm.isEmpty());
+ assertEquals(2, map.size());
+ assertEquals(four, map.firstKey());
+ }
+
+ /**
+ * tailMap returns map with keys in requested range
+ */
+ public void testTailMapContents() {
+ ConcurrentSkipListMap map = map5();
+ NavigableMap sm = map.tailMap(two, true);
+ assertFalse(sm.containsKey(one));
+ assertTrue(sm.containsKey(two));
+ assertTrue(sm.containsKey(three));
+ assertTrue(sm.containsKey(four));
+ assertTrue(sm.containsKey(five));
+ Iterator i = sm.keySet().iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ k = (Integer)(i.next());
+ assertEquals(three, k);
+ k = (Integer)(i.next());
+ assertEquals(four, k);
+ k = (Integer)(i.next());
+ assertEquals(five, k);
+ assertFalse(i.hasNext());
+ Iterator r = sm.descendingKeySet().iterator();
+ k = (Integer)(r.next());
+ assertEquals(five, k);
+ k = (Integer)(r.next());
+ assertEquals(four, k);
+ k = (Integer)(r.next());
+ assertEquals(three, k);
+ k = (Integer)(r.next());
+ assertEquals(two, k);
+ assertFalse(r.hasNext());
+
+ Iterator ei = sm.entrySet().iterator();
+ Map.Entry e;
+ e = (Map.Entry)(ei.next());
+ assertEquals(two, e.getKey());
+ assertEquals("B", e.getValue());
+ e = (Map.Entry)(ei.next());
+ assertEquals(three, e.getKey());
+ assertEquals("C", e.getValue());
+ e = (Map.Entry)(ei.next());
+ assertEquals(four, e.getKey());
+ assertEquals("D", e.getValue());
+ e = (Map.Entry)(ei.next());
+ assertEquals(five, e.getKey());
+ assertEquals("E", e.getValue());
+ assertFalse(i.hasNext());
+
+ NavigableMap ssm = sm.tailMap(four, true);
+ assertEquals(four, ssm.firstKey());
+ assertEquals(five, ssm.lastKey());
+ assertEquals("D", ssm.remove(four));
+ assertEquals(1, ssm.size());
+ assertEquals(3, sm.size());
+ assertEquals(4, map.size());
+ }
+
+ Random rnd = new Random(666);
+ BitSet bs;
+
+ /**
+ * Submaps of submaps subdivide correctly
+ */
+ public void testRecursiveSubMaps() throws Exception {
+ int mapSize = expensiveTests ? 1000 : 100;
+ Class cl = ConcurrentSkipListMap.class;
+ NavigableMap<Integer, Integer> map = newMap(cl);
+ bs = new BitSet(mapSize);
+
+ populate(map, mapSize);
+ check(map, 0, mapSize - 1, true);
+ check(map.descendingMap(), 0, mapSize - 1, false);
+
+ mutateMap(map, 0, mapSize - 1);
+ check(map, 0, mapSize - 1, true);
+ check(map.descendingMap(), 0, mapSize - 1, false);
+
+ bashSubMap(map.subMap(0, true, mapSize, false),
+ 0, mapSize - 1, true);
+ }
+
+ static NavigableMap<Integer, Integer> newMap(Class cl) throws Exception {
+ NavigableMap<Integer, Integer> result =
+ (NavigableMap<Integer, Integer>) cl.newInstance();
+ assertEquals(0, result.size());
+ assertFalse(result.keySet().iterator().hasNext());
+ return result;
+ }
+
+ void populate(NavigableMap<Integer, Integer> map, int limit) {
+ for (int i = 0, n = 2 * limit / 3; i < n; i++) {
+ int key = rnd.nextInt(limit);
+ put(map, key);
+ }
+ }
+
+ void mutateMap(NavigableMap<Integer, Integer> map, int min, int max) {
+ int size = map.size();
+ int rangeSize = max - min + 1;
+
+ // Remove a bunch of entries directly
+ for (int i = 0, n = rangeSize / 2; i < n; i++) {
+ remove(map, min - 5 + rnd.nextInt(rangeSize + 10));
+ }
+
+ // Remove a bunch of entries with iterator
+ for (Iterator<Integer> it = map.keySet().iterator(); it.hasNext(); ) {
+ if (rnd.nextBoolean()) {
+ bs.clear(it.next());
+ it.remove();
+ }
+ }
+
+ // Add entries till we're back to original size
+ while (map.size() < size) {
+ int key = min + rnd.nextInt(rangeSize);
+ assertTrue(key >= min && key<= max);
+ put(map, key);
+ }
+ }
+
+ void mutateSubMap(NavigableMap<Integer, Integer> map, int min, int max) {
+ int size = map.size();
+ int rangeSize = max - min + 1;
+
+ // Remove a bunch of entries directly
+ for (int i = 0, n = rangeSize / 2; i < n; i++) {
+ remove(map, min - 5 + rnd.nextInt(rangeSize + 10));
+ }
+
+ // Remove a bunch of entries with iterator
+ for (Iterator<Integer> it = map.keySet().iterator(); it.hasNext(); ) {
+ if (rnd.nextBoolean()) {
+ bs.clear(it.next());
+ it.remove();
+ }
+ }
+
+ // Add entries till we're back to original size
+ while (map.size() < size) {
+ int key = min - 5 + rnd.nextInt(rangeSize + 10);
+ if (key >= min && key<= max) {
+ put(map, key);
+ } else {
+ try {
+ map.put(key, 2 * key);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+ }
+ }
+
+ void put(NavigableMap<Integer, Integer> map, int key) {
+ if (map.put(key, 2 * key) == null)
+ bs.set(key);
+ }
+
+ void remove(NavigableMap<Integer, Integer> map, int key) {
+ if (map.remove(key) != null)
+ bs.clear(key);
+ }
+
+ void bashSubMap(NavigableMap<Integer, Integer> map,
+ int min, int max, boolean ascending) {
+ check(map, min, max, ascending);
+ check(map.descendingMap(), min, max, !ascending);
+
+ mutateSubMap(map, min, max);
+ check(map, min, max, ascending);
+ check(map.descendingMap(), min, max, !ascending);
+
+ // Recurse
+ if (max - min < 2)
+ return;
+ int midPoint = (min + max) / 2;
+
+ // headMap - pick direction and endpoint inclusion randomly
+ boolean incl = rnd.nextBoolean();
+ NavigableMap<Integer,Integer> hm = map.headMap(midPoint, incl);
+ if (ascending) {
+ if (rnd.nextBoolean())
+ bashSubMap(hm, min, midPoint - (incl ? 0 : 1), true);
+ else
+ bashSubMap(hm.descendingMap(), min, midPoint - (incl ? 0 : 1),
+ false);
+ } else {
+ if (rnd.nextBoolean())
+ bashSubMap(hm, midPoint + (incl ? 0 : 1), max, false);
+ else
+ bashSubMap(hm.descendingMap(), midPoint + (incl ? 0 : 1), max,
+ true);
+ }
+
+ // tailMap - pick direction and endpoint inclusion randomly
+ incl = rnd.nextBoolean();
+ NavigableMap<Integer,Integer> tm = map.tailMap(midPoint,incl);
+ if (ascending) {
+ if (rnd.nextBoolean())
+ bashSubMap(tm, midPoint + (incl ? 0 : 1), max, true);
+ else
+ bashSubMap(tm.descendingMap(), midPoint + (incl ? 0 : 1), max,
+ false);
+ } else {
+ if (rnd.nextBoolean()) {
+ bashSubMap(tm, min, midPoint - (incl ? 0 : 1), false);
+ } else {
+ bashSubMap(tm.descendingMap(), min, midPoint - (incl ? 0 : 1),
+ true);
+ }
+ }
+
+ // subMap - pick direction and endpoint inclusion randomly
+ int rangeSize = max - min + 1;
+ int[] endpoints = new int[2];
+ endpoints[0] = min + rnd.nextInt(rangeSize);
+ endpoints[1] = min + rnd.nextInt(rangeSize);
+ Arrays.sort(endpoints);
+ boolean lowIncl = rnd.nextBoolean();
+ boolean highIncl = rnd.nextBoolean();
+ if (ascending) {
+ NavigableMap<Integer,Integer> sm = map.subMap(
+ endpoints[0], lowIncl, endpoints[1], highIncl);
+ if (rnd.nextBoolean())
+ bashSubMap(sm, endpoints[0] + (lowIncl ? 0 : 1),
+ endpoints[1] - (highIncl ? 0 : 1), true);
+ else
+ bashSubMap(sm.descendingMap(), endpoints[0] + (lowIncl ? 0 : 1),
+ endpoints[1] - (highIncl ? 0 : 1), false);
+ } else {
+ NavigableMap<Integer,Integer> sm = map.subMap(
+ endpoints[1], highIncl, endpoints[0], lowIncl);
+ if (rnd.nextBoolean())
+ bashSubMap(sm, endpoints[0] + (lowIncl ? 0 : 1),
+ endpoints[1] - (highIncl ? 0 : 1), false);
+ else
+ bashSubMap(sm.descendingMap(), endpoints[0] + (lowIncl ? 0 : 1),
+ endpoints[1] - (highIncl ? 0 : 1), true);
+ }
+ }
+
+ /**
+ * min and max are both inclusive. If max < min, interval is empty.
+ */
+ void check(NavigableMap<Integer, Integer> map,
+ final int min, final int max, final boolean ascending) {
+ class ReferenceSet {
+ int lower(int key) {
+ return ascending ? lowerAscending(key) : higherAscending(key);
+ }
+ int floor(int key) {
+ return ascending ? floorAscending(key) : ceilingAscending(key);
+ }
+ int ceiling(int key) {
+ return ascending ? ceilingAscending(key) : floorAscending(key);
+ }
+ int higher(int key) {
+ return ascending ? higherAscending(key) : lowerAscending(key);
+ }
+ int first() {
+ return ascending ? firstAscending() : lastAscending();
+ }
+ int last() {
+ return ascending ? lastAscending() : firstAscending();
+ }
+ int lowerAscending(int key) {
+ return floorAscending(key - 1);
+ }
+ int floorAscending(int key) {
+ if (key < min)
+ return -1;
+ else if (key > max)
+ key = max;
+
+ // BitSet should support this! Test would run much faster
+ while (key >= min) {
+ if (bs.get(key))
+ return key;
+ key--;
+ }
+ return -1;
+ }
+ int ceilingAscending(int key) {
+ if (key < min)
+ key = min;
+ else if (key > max)
+ return -1;
+ int result = bs.nextSetBit(key);
+ return result > max ? -1 : result;
+ }
+ int higherAscending(int key) {
+ return ceilingAscending(key + 1);
+ }
+ private int firstAscending() {
+ int result = ceilingAscending(min);
+ return result > max ? -1 : result;
+ }
+ private int lastAscending() {
+ int result = floorAscending(max);
+ return result < min ? -1 : result;
+ }
+ }
+ ReferenceSet rs = new ReferenceSet();
+
+ // Test contents using containsKey
+ int size = 0;
+ for (int i = min; i <= max; i++) {
+ boolean bsContainsI = bs.get(i);
+ assertEquals(bsContainsI, map.containsKey(i));
+ if (bsContainsI)
+ size++;
+ }
+ assertEquals(size, map.size());
+
+ // Test contents using contains keySet iterator
+ int size2 = 0;
+ int previousKey = -1;
+ for (int key : map.keySet()) {
+ assertTrue(bs.get(key));
+ size2++;
+ assertTrue(previousKey < 0 ||
+ (ascending ? key - previousKey > 0 : key - previousKey < 0));
+ previousKey = key;
+ }
+ assertEquals(size2, size);
+
+ // Test navigation ops
+ for (int key = min - 1; key <= max + 1; key++) {
+ assertEq(map.lowerKey(key), rs.lower(key));
+ assertEq(map.floorKey(key), rs.floor(key));
+ assertEq(map.higherKey(key), rs.higher(key));
+ assertEq(map.ceilingKey(key), rs.ceiling(key));
+ }
+
+ // Test extrema
+ if (map.size() != 0) {
+ assertEq(map.firstKey(), rs.first());
+ assertEq(map.lastKey(), rs.last());
+ } else {
+ assertEq(rs.first(), -1);
+ assertEq(rs.last(), -1);
+ try {
+ map.firstKey();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ try {
+ map.lastKey();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+ }
+
+ static void assertEq(Integer i, int j) {
+ if (i == null)
+ assertEquals(j, -1);
+ else
+ assertEquals((int) i, j);
+ }
+
+ static boolean eq(Integer i, int j) {
+ return i == null ? j == -1 : i == j;
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSetTest.java b/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSetTest.java
new file mode 100644
index 0000000..1fd3c5f
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSetTest.java
@@ -0,0 +1,982 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.NavigableSet;
+import java.util.NoSuchElementException;
+import java.util.Random;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.concurrent.ConcurrentSkipListSet;
+
+public class ConcurrentSkipListSetTest extends JSR166TestCase {
+
+ static class MyReverseComparator implements Comparator {
+ public int compare(Object x, Object y) {
+ return ((Comparable)y).compareTo(x);
+ }
+ }
+
+ /**
+ * Returns a new set of given size containing consecutive
+ * Integers 0 ... n.
+ */
+ private ConcurrentSkipListSet<Integer> populatedSet(int n) {
+ ConcurrentSkipListSet<Integer> q =
+ new ConcurrentSkipListSet<Integer>();
+ assertTrue(q.isEmpty());
+ for (int i = n-1; i >= 0; i-=2)
+ assertTrue(q.add(new Integer(i)));
+ for (int i = (n & 1); i < n; i+=2)
+ assertTrue(q.add(new Integer(i)));
+ assertFalse(q.isEmpty());
+ assertEquals(n, q.size());
+ return q;
+ }
+
+ /**
+ * Returns a new set of first 5 ints.
+ */
+ private ConcurrentSkipListSet set5() {
+ ConcurrentSkipListSet q = new ConcurrentSkipListSet();
+ assertTrue(q.isEmpty());
+ q.add(one);
+ q.add(two);
+ q.add(three);
+ q.add(four);
+ q.add(five);
+ assertEquals(5, q.size());
+ return q;
+ }
+
+ /**
+ * A new set has unbounded capacity
+ */
+ public void testConstructor1() {
+ assertEquals(0, new ConcurrentSkipListSet().size());
+ }
+
+ /**
+ * Initializing from null Collection throws NPE
+ */
+ public void testConstructor3() {
+ try {
+ ConcurrentSkipListSet q = new ConcurrentSkipListSet((Collection)null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing from Collection of null elements throws NPE
+ */
+ public void testConstructor4() {
+ try {
+ Integer[] ints = new Integer[SIZE];
+ ConcurrentSkipListSet q = new ConcurrentSkipListSet(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing from Collection with some null elements throws NPE
+ */
+ public void testConstructor5() {
+ try {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
+ ConcurrentSkipListSet q = new ConcurrentSkipListSet(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Set contains all elements of collection used to initialize
+ */
+ public void testConstructor6() {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(i);
+ ConcurrentSkipListSet q = new ConcurrentSkipListSet(Arrays.asList(ints));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(ints[i], q.pollFirst());
+ }
+
+ /**
+ * The comparator used in constructor is used
+ */
+ public void testConstructor7() {
+ MyReverseComparator cmp = new MyReverseComparator();
+ ConcurrentSkipListSet q = new ConcurrentSkipListSet(cmp);
+ assertEquals(cmp, q.comparator());
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(i);
+ q.addAll(Arrays.asList(ints));
+ for (int i = SIZE-1; i >= 0; --i)
+ assertEquals(ints[i], q.pollFirst());
+ }
+
+ /**
+ * isEmpty is true before add, false after
+ */
+ public void testEmpty() {
+ ConcurrentSkipListSet q = new ConcurrentSkipListSet();
+ assertTrue(q.isEmpty());
+ q.add(new Integer(1));
+ assertFalse(q.isEmpty());
+ q.add(new Integer(2));
+ q.pollFirst();
+ q.pollFirst();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * size changes when elements added and removed
+ */
+ public void testSize() {
+ ConcurrentSkipListSet q = populatedSet(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(SIZE-i, q.size());
+ q.pollFirst();
+ }
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.size());
+ q.add(new Integer(i));
+ }
+ }
+
+ /**
+ * add(null) throws NPE
+ */
+ public void testAddNull() {
+ try {
+ ConcurrentSkipListSet q = new ConcurrentSkipListSet();
+ q.add(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Add of comparable element succeeds
+ */
+ public void testAdd() {
+ ConcurrentSkipListSet q = new ConcurrentSkipListSet();
+ assertTrue(q.add(zero));
+ assertTrue(q.add(one));
+ }
+
+ /**
+ * Add of duplicate element fails
+ */
+ public void testAddDup() {
+ ConcurrentSkipListSet q = new ConcurrentSkipListSet();
+ assertTrue(q.add(zero));
+ assertFalse(q.add(zero));
+ }
+
+ /**
+ * Add of non-Comparable throws CCE
+ */
+ public void testAddNonComparable() {
+ try {
+ ConcurrentSkipListSet q = new ConcurrentSkipListSet();
+ q.add(new Object());
+ q.add(new Object());
+ q.add(new Object());
+ shouldThrow();
+ } catch (ClassCastException success) {}
+ }
+
+ /**
+ * addAll(null) throws NPE
+ */
+ public void testAddAll1() {
+ try {
+ ConcurrentSkipListSet q = new ConcurrentSkipListSet();
+ q.addAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll of a collection with null elements throws NPE
+ */
+ public void testAddAll2() {
+ try {
+ ConcurrentSkipListSet q = new ConcurrentSkipListSet();
+ Integer[] ints = new Integer[SIZE];
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll of a collection with any null elements throws NPE after
+ * possibly adding some elements
+ */
+ public void testAddAll3() {
+ try {
+ ConcurrentSkipListSet q = new ConcurrentSkipListSet();
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Set contains all elements of successful addAll
+ */
+ public void testAddAll5() {
+ Integer[] empty = new Integer[0];
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(SIZE-1-i);
+ ConcurrentSkipListSet q = new ConcurrentSkipListSet();
+ assertFalse(q.addAll(Arrays.asList(empty)));
+ assertTrue(q.addAll(Arrays.asList(ints)));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(i, q.pollFirst());
+ }
+
+ /**
+ * pollFirst succeeds unless empty
+ */
+ public void testPollFirst() {
+ ConcurrentSkipListSet q = populatedSet(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.pollFirst());
+ }
+ assertNull(q.pollFirst());
+ }
+
+ /**
+ * pollLast succeeds unless empty
+ */
+ public void testPollLast() {
+ ConcurrentSkipListSet q = populatedSet(SIZE);
+ for (int i = SIZE-1; i >= 0; --i) {
+ assertEquals(i, q.pollLast());
+ }
+ assertNull(q.pollFirst());
+ }
+
+ /**
+ * remove(x) removes x and returns true if present
+ */
+ public void testRemoveElement() {
+ ConcurrentSkipListSet q = populatedSet(SIZE);
+ for (int i = 1; i < SIZE; i+=2) {
+ assertTrue(q.contains(i));
+ assertTrue(q.remove(i));
+ assertFalse(q.contains(i));
+ assertTrue(q.contains(i-1));
+ }
+ for (int i = 0; i < SIZE; i+=2) {
+ assertTrue(q.contains(i));
+ assertTrue(q.remove(i));
+ assertFalse(q.contains(i));
+ assertFalse(q.remove(i+1));
+ assertFalse(q.contains(i+1));
+ }
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * contains(x) reports true when elements added but not yet removed
+ */
+ public void testContains() {
+ ConcurrentSkipListSet q = populatedSet(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.contains(new Integer(i)));
+ q.pollFirst();
+ assertFalse(q.contains(new Integer(i)));
+ }
+ }
+
+ /**
+ * clear removes all elements
+ */
+ public void testClear() {
+ ConcurrentSkipListSet q = populatedSet(SIZE);
+ q.clear();
+ assertTrue(q.isEmpty());
+ assertEquals(0, q.size());
+ q.add(new Integer(1));
+ assertFalse(q.isEmpty());
+ q.clear();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * containsAll(c) is true when c contains a subset of elements
+ */
+ public void testContainsAll() {
+ ConcurrentSkipListSet q = populatedSet(SIZE);
+ ConcurrentSkipListSet p = new ConcurrentSkipListSet();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.containsAll(p));
+ assertFalse(p.containsAll(q));
+ p.add(new Integer(i));
+ }
+ assertTrue(p.containsAll(q));
+ }
+
+ /**
+ * retainAll(c) retains only those elements of c and reports true if changed
+ */
+ public void testRetainAll() {
+ ConcurrentSkipListSet q = populatedSet(SIZE);
+ ConcurrentSkipListSet p = populatedSet(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ boolean changed = q.retainAll(p);
+ if (i == 0)
+ assertFalse(changed);
+ else
+ assertTrue(changed);
+
+ assertTrue(q.containsAll(p));
+ assertEquals(SIZE-i, q.size());
+ p.pollFirst();
+ }
+ }
+
+ /**
+ * removeAll(c) removes only those elements of c and reports true if changed
+ */
+ public void testRemoveAll() {
+ for (int i = 1; i < SIZE; ++i) {
+ ConcurrentSkipListSet q = populatedSet(SIZE);
+ ConcurrentSkipListSet p = populatedSet(i);
+ assertTrue(q.removeAll(p));
+ assertEquals(SIZE-i, q.size());
+ for (int j = 0; j < i; ++j) {
+ Integer I = (Integer)(p.pollFirst());
+ assertFalse(q.contains(I));
+ }
+ }
+ }
+
+ /**
+ * lower returns preceding element
+ */
+ public void testLower() {
+ ConcurrentSkipListSet q = set5();
+ Object e1 = q.lower(three);
+ assertEquals(two, e1);
+
+ Object e2 = q.lower(six);
+ assertEquals(five, e2);
+
+ Object e3 = q.lower(one);
+ assertNull(e3);
+
+ Object e4 = q.lower(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * higher returns next element
+ */
+ public void testHigher() {
+ ConcurrentSkipListSet q = set5();
+ Object e1 = q.higher(three);
+ assertEquals(four, e1);
+
+ Object e2 = q.higher(zero);
+ assertEquals(one, e2);
+
+ Object e3 = q.higher(five);
+ assertNull(e3);
+
+ Object e4 = q.higher(six);
+ assertNull(e4);
+ }
+
+ /**
+ * floor returns preceding element
+ */
+ public void testFloor() {
+ ConcurrentSkipListSet q = set5();
+ Object e1 = q.floor(three);
+ assertEquals(three, e1);
+
+ Object e2 = q.floor(six);
+ assertEquals(five, e2);
+
+ Object e3 = q.floor(one);
+ assertEquals(one, e3);
+
+ Object e4 = q.floor(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * ceiling returns next element
+ */
+ public void testCeiling() {
+ ConcurrentSkipListSet q = set5();
+ Object e1 = q.ceiling(three);
+ assertEquals(three, e1);
+
+ Object e2 = q.ceiling(zero);
+ assertEquals(one, e2);
+
+ Object e3 = q.ceiling(five);
+ assertEquals(five, e3);
+
+ Object e4 = q.ceiling(six);
+ assertNull(e4);
+ }
+
+ /**
+ * toArray contains all elements in sorted order
+ */
+ public void testToArray() {
+ ConcurrentSkipListSet q = populatedSet(SIZE);
+ Object[] o = q.toArray();
+ for (int i = 0; i < o.length; i++)
+ assertSame(o[i], q.pollFirst());
+ }
+
+ /**
+ * toArray(a) contains all elements in sorted order
+ */
+ public void testToArray2() {
+ ConcurrentSkipListSet<Integer> q = populatedSet(SIZE);
+ Integer[] ints = new Integer[SIZE];
+ assertSame(ints, q.toArray(ints));
+ for (int i = 0; i < ints.length; i++)
+ assertSame(ints[i], q.pollFirst());
+ }
+
+ /**
+ * iterator iterates through all elements
+ */
+ public void testIterator() {
+ ConcurrentSkipListSet q = populatedSet(SIZE);
+ int i = 0;
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ assertTrue(q.contains(it.next()));
+ ++i;
+ }
+ assertEquals(i, SIZE);
+ }
+
+ /**
+ * iterator of empty set has no elements
+ */
+ public void testEmptyIterator() {
+ ConcurrentSkipListSet q = new ConcurrentSkipListSet();
+ int i = 0;
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ assertTrue(q.contains(it.next()));
+ ++i;
+ }
+ assertEquals(0, i);
+ }
+
+ /**
+ * iterator.remove removes current element
+ */
+ public void testIteratorRemove() {
+ final ConcurrentSkipListSet q = new ConcurrentSkipListSet();
+ q.add(new Integer(2));
+ q.add(new Integer(1));
+ q.add(new Integer(3));
+
+ Iterator it = q.iterator();
+ it.next();
+ it.remove();
+
+ it = q.iterator();
+ assertEquals(it.next(), new Integer(2));
+ assertEquals(it.next(), new Integer(3));
+ assertFalse(it.hasNext());
+ }
+
+ /**
+ * toString contains toStrings of elements
+ */
+ public void testToString() {
+ ConcurrentSkipListSet q = populatedSet(SIZE);
+ String s = q.toString();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(s.contains(String.valueOf(i)));
+ }
+ }
+
+ /**
+ * A deserialized serialized set has same elements
+ */
+ public void testSerialization() throws Exception {
+ NavigableSet x = populatedSet(SIZE);
+ NavigableSet y = serialClone(x);
+
+ assertNotSame(x, y);
+ assertEquals(x.size(), y.size());
+ assertEquals(x, y);
+ assertEquals(y, x);
+ while (!x.isEmpty()) {
+ assertFalse(y.isEmpty());
+ assertEquals(x.pollFirst(), y.pollFirst());
+ }
+ assertTrue(y.isEmpty());
+ }
+
+ /**
+ * subSet returns set with keys in requested range
+ */
+ public void testSubSetContents() {
+ ConcurrentSkipListSet set = set5();
+ SortedSet sm = set.subSet(two, four);
+ assertEquals(two, sm.first());
+ assertEquals(three, sm.last());
+ assertEquals(2, sm.size());
+ assertFalse(sm.contains(one));
+ assertTrue(sm.contains(two));
+ assertTrue(sm.contains(three));
+ assertFalse(sm.contains(four));
+ assertFalse(sm.contains(five));
+ Iterator i = sm.iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ k = (Integer)(i.next());
+ assertEquals(three, k);
+ assertFalse(i.hasNext());
+ Iterator j = sm.iterator();
+ j.next();
+ j.remove();
+ assertFalse(set.contains(two));
+ assertEquals(4, set.size());
+ assertEquals(1, sm.size());
+ assertEquals(three, sm.first());
+ assertEquals(three, sm.last());
+ assertTrue(sm.remove(three));
+ assertTrue(sm.isEmpty());
+ assertEquals(3, set.size());
+ }
+
+ public void testSubSetContents2() {
+ ConcurrentSkipListSet set = set5();
+ SortedSet sm = set.subSet(two, three);
+ assertEquals(1, sm.size());
+ assertEquals(two, sm.first());
+ assertEquals(two, sm.last());
+ assertFalse(sm.contains(one));
+ assertTrue(sm.contains(two));
+ assertFalse(sm.contains(three));
+ assertFalse(sm.contains(four));
+ assertFalse(sm.contains(five));
+ Iterator i = sm.iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ assertFalse(i.hasNext());
+ Iterator j = sm.iterator();
+ j.next();
+ j.remove();
+ assertFalse(set.contains(two));
+ assertEquals(4, set.size());
+ assertEquals(0, sm.size());
+ assertTrue(sm.isEmpty());
+ assertFalse(sm.remove(three));
+ assertEquals(4, set.size());
+ }
+
+ /**
+ * headSet returns set with keys in requested range
+ */
+ public void testHeadSetContents() {
+ ConcurrentSkipListSet set = set5();
+ SortedSet sm = set.headSet(four);
+ assertTrue(sm.contains(one));
+ assertTrue(sm.contains(two));
+ assertTrue(sm.contains(three));
+ assertFalse(sm.contains(four));
+ assertFalse(sm.contains(five));
+ Iterator i = sm.iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(one, k);
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ k = (Integer)(i.next());
+ assertEquals(three, k);
+ assertFalse(i.hasNext());
+ sm.clear();
+ assertTrue(sm.isEmpty());
+ assertEquals(2, set.size());
+ assertEquals(four, set.first());
+ }
+
+ /**
+ * tailSet returns set with keys in requested range
+ */
+ public void testTailSetContents() {
+ ConcurrentSkipListSet set = set5();
+ SortedSet sm = set.tailSet(two);
+ assertFalse(sm.contains(one));
+ assertTrue(sm.contains(two));
+ assertTrue(sm.contains(three));
+ assertTrue(sm.contains(four));
+ assertTrue(sm.contains(five));
+ Iterator i = sm.iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ k = (Integer)(i.next());
+ assertEquals(three, k);
+ k = (Integer)(i.next());
+ assertEquals(four, k);
+ k = (Integer)(i.next());
+ assertEquals(five, k);
+ assertFalse(i.hasNext());
+
+ SortedSet ssm = sm.tailSet(four);
+ assertEquals(four, ssm.first());
+ assertEquals(five, ssm.last());
+ assertTrue(ssm.remove(four));
+ assertEquals(1, ssm.size());
+ assertEquals(3, sm.size());
+ assertEquals(4, set.size());
+ }
+
+ Random rnd = new Random(666);
+
+ /**
+ * Subsets of subsets subdivide correctly
+ */
+ public void testRecursiveSubSets() throws Exception {
+ int setSize = expensiveTests ? 1000 : 100;
+ Class cl = ConcurrentSkipListSet.class;
+
+ NavigableSet<Integer> set = newSet(cl);
+ BitSet bs = new BitSet(setSize);
+
+ populate(set, setSize, bs);
+ check(set, 0, setSize - 1, true, bs);
+ check(set.descendingSet(), 0, setSize - 1, false, bs);
+
+ mutateSet(set, 0, setSize - 1, bs);
+ check(set, 0, setSize - 1, true, bs);
+ check(set.descendingSet(), 0, setSize - 1, false, bs);
+
+ bashSubSet(set.subSet(0, true, setSize, false),
+ 0, setSize - 1, true, bs);
+ }
+
+ /**
+ * addAll is idempotent
+ */
+ public void testAddAll_idempotent() throws Exception {
+ Set x = populatedSet(SIZE);
+ Set y = new ConcurrentSkipListSet(x);
+ y.addAll(x);
+ assertEquals(x, y);
+ assertEquals(y, x);
+ }
+
+ static NavigableSet<Integer> newSet(Class cl) throws Exception {
+ NavigableSet<Integer> result = (NavigableSet<Integer>) cl.newInstance();
+ assertEquals(0, result.size());
+ assertFalse(result.iterator().hasNext());
+ return result;
+ }
+
+ void populate(NavigableSet<Integer> set, int limit, BitSet bs) {
+ for (int i = 0, n = 2 * limit / 3; i < n; i++) {
+ int element = rnd.nextInt(limit);
+ put(set, element, bs);
+ }
+ }
+
+ void mutateSet(NavigableSet<Integer> set, int min, int max, BitSet bs) {
+ int size = set.size();
+ int rangeSize = max - min + 1;
+
+ // Remove a bunch of entries directly
+ for (int i = 0, n = rangeSize / 2; i < n; i++) {
+ remove(set, min - 5 + rnd.nextInt(rangeSize + 10), bs);
+ }
+
+ // Remove a bunch of entries with iterator
+ for (Iterator<Integer> it = set.iterator(); it.hasNext(); ) {
+ if (rnd.nextBoolean()) {
+ bs.clear(it.next());
+ it.remove();
+ }
+ }
+
+ // Add entries till we're back to original size
+ while (set.size() < size) {
+ int element = min + rnd.nextInt(rangeSize);
+ assertTrue(element >= min && element<= max);
+ put(set, element, bs);
+ }
+ }
+
+ void mutateSubSet(NavigableSet<Integer> set, int min, int max,
+ BitSet bs) {
+ int size = set.size();
+ int rangeSize = max - min + 1;
+
+ // Remove a bunch of entries directly
+ for (int i = 0, n = rangeSize / 2; i < n; i++) {
+ remove(set, min - 5 + rnd.nextInt(rangeSize + 10), bs);
+ }
+
+ // Remove a bunch of entries with iterator
+ for (Iterator<Integer> it = set.iterator(); it.hasNext(); ) {
+ if (rnd.nextBoolean()) {
+ bs.clear(it.next());
+ it.remove();
+ }
+ }
+
+ // Add entries till we're back to original size
+ while (set.size() < size) {
+ int element = min - 5 + rnd.nextInt(rangeSize + 10);
+ if (element >= min && element<= max) {
+ put(set, element, bs);
+ } else {
+ try {
+ set.add(element);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+ }
+ }
+
+ void put(NavigableSet<Integer> set, int element, BitSet bs) {
+ if (set.add(element))
+ bs.set(element);
+ }
+
+ void remove(NavigableSet<Integer> set, int element, BitSet bs) {
+ if (set.remove(element))
+ bs.clear(element);
+ }
+
+ void bashSubSet(NavigableSet<Integer> set,
+ int min, int max, boolean ascending,
+ BitSet bs) {
+ check(set, min, max, ascending, bs);
+ check(set.descendingSet(), min, max, !ascending, bs);
+
+ mutateSubSet(set, min, max, bs);
+ check(set, min, max, ascending, bs);
+ check(set.descendingSet(), min, max, !ascending, bs);
+
+ // Recurse
+ if (max - min < 2)
+ return;
+ int midPoint = (min + max) / 2;
+
+ // headSet - pick direction and endpoint inclusion randomly
+ boolean incl = rnd.nextBoolean();
+ NavigableSet<Integer> hm = set.headSet(midPoint, incl);
+ if (ascending) {
+ if (rnd.nextBoolean())
+ bashSubSet(hm, min, midPoint - (incl ? 0 : 1), true, bs);
+ else
+ bashSubSet(hm.descendingSet(), min, midPoint - (incl ? 0 : 1),
+ false, bs);
+ } else {
+ if (rnd.nextBoolean())
+ bashSubSet(hm, midPoint + (incl ? 0 : 1), max, false, bs);
+ else
+ bashSubSet(hm.descendingSet(), midPoint + (incl ? 0 : 1), max,
+ true, bs);
+ }
+
+ // tailSet - pick direction and endpoint inclusion randomly
+ incl = rnd.nextBoolean();
+ NavigableSet<Integer> tm = set.tailSet(midPoint,incl);
+ if (ascending) {
+ if (rnd.nextBoolean())
+ bashSubSet(tm, midPoint + (incl ? 0 : 1), max, true, bs);
+ else
+ bashSubSet(tm.descendingSet(), midPoint + (incl ? 0 : 1), max,
+ false, bs);
+ } else {
+ if (rnd.nextBoolean()) {
+ bashSubSet(tm, min, midPoint - (incl ? 0 : 1), false, bs);
+ } else {
+ bashSubSet(tm.descendingSet(), min, midPoint - (incl ? 0 : 1),
+ true, bs);
+ }
+ }
+
+ // subSet - pick direction and endpoint inclusion randomly
+ int rangeSize = max - min + 1;
+ int[] endpoints = new int[2];
+ endpoints[0] = min + rnd.nextInt(rangeSize);
+ endpoints[1] = min + rnd.nextInt(rangeSize);
+ Arrays.sort(endpoints);
+ boolean lowIncl = rnd.nextBoolean();
+ boolean highIncl = rnd.nextBoolean();
+ if (ascending) {
+ NavigableSet<Integer> sm = set.subSet(
+ endpoints[0], lowIncl, endpoints[1], highIncl);
+ if (rnd.nextBoolean())
+ bashSubSet(sm, endpoints[0] + (lowIncl ? 0 : 1),
+ endpoints[1] - (highIncl ? 0 : 1), true, bs);
+ else
+ bashSubSet(sm.descendingSet(), endpoints[0] + (lowIncl ? 0 : 1),
+ endpoints[1] - (highIncl ? 0 : 1), false, bs);
+ } else {
+ NavigableSet<Integer> sm = set.subSet(
+ endpoints[1], highIncl, endpoints[0], lowIncl);
+ if (rnd.nextBoolean())
+ bashSubSet(sm, endpoints[0] + (lowIncl ? 0 : 1),
+ endpoints[1] - (highIncl ? 0 : 1), false, bs);
+ else
+ bashSubSet(sm.descendingSet(), endpoints[0] + (lowIncl ? 0 : 1),
+ endpoints[1] - (highIncl ? 0 : 1), true, bs);
+ }
+ }
+
+ /**
+ * min and max are both inclusive. If max < min, interval is empty.
+ */
+ void check(NavigableSet<Integer> set,
+ final int min, final int max, final boolean ascending,
+ final BitSet bs) {
+ class ReferenceSet {
+ int lower(int element) {
+ return ascending ?
+ lowerAscending(element) : higherAscending(element);
+ }
+ int floor(int element) {
+ return ascending ?
+ floorAscending(element) : ceilingAscending(element);
+ }
+ int ceiling(int element) {
+ return ascending ?
+ ceilingAscending(element) : floorAscending(element);
+ }
+ int higher(int element) {
+ return ascending ?
+ higherAscending(element) : lowerAscending(element);
+ }
+ int first() {
+ return ascending ? firstAscending() : lastAscending();
+ }
+ int last() {
+ return ascending ? lastAscending() : firstAscending();
+ }
+ int lowerAscending(int element) {
+ return floorAscending(element - 1);
+ }
+ int floorAscending(int element) {
+ if (element < min)
+ return -1;
+ else if (element > max)
+ element = max;
+
+ // BitSet should support this! Test would run much faster
+ while (element >= min) {
+ if (bs.get(element))
+ return element;
+ element--;
+ }
+ return -1;
+ }
+ int ceilingAscending(int element) {
+ if (element < min)
+ element = min;
+ else if (element > max)
+ return -1;
+ int result = bs.nextSetBit(element);
+ return result > max ? -1 : result;
+ }
+ int higherAscending(int element) {
+ return ceilingAscending(element + 1);
+ }
+ private int firstAscending() {
+ int result = ceilingAscending(min);
+ return result > max ? -1 : result;
+ }
+ private int lastAscending() {
+ int result = floorAscending(max);
+ return result < min ? -1 : result;
+ }
+ }
+ ReferenceSet rs = new ReferenceSet();
+
+ // Test contents using containsElement
+ int size = 0;
+ for (int i = min; i <= max; i++) {
+ boolean bsContainsI = bs.get(i);
+ assertEquals(bsContainsI, set.contains(i));
+ if (bsContainsI)
+ size++;
+ }
+ assertEquals(size, set.size());
+
+ // Test contents using contains elementSet iterator
+ int size2 = 0;
+ int previousElement = -1;
+ for (int element : set) {
+ assertTrue(bs.get(element));
+ size2++;
+ assertTrue(previousElement < 0 || (ascending ?
+ element - previousElement > 0 : element - previousElement < 0));
+ previousElement = element;
+ }
+ assertEquals(size2, size);
+
+ // Test navigation ops
+ for (int element = min - 1; element <= max + 1; element++) {
+ assertEq(set.lower(element), rs.lower(element));
+ assertEq(set.floor(element), rs.floor(element));
+ assertEq(set.higher(element), rs.higher(element));
+ assertEq(set.ceiling(element), rs.ceiling(element));
+ }
+
+ // Test extrema
+ if (set.size() != 0) {
+ assertEq(set.first(), rs.first());
+ assertEq(set.last(), rs.last());
+ } else {
+ assertEq(rs.first(), -1);
+ assertEq(rs.last(), -1);
+ try {
+ set.first();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ try {
+ set.last();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+ }
+
+ static void assertEq(Integer i, int j) {
+ if (i == null)
+ assertEquals(j, -1);
+ else
+ assertEquals((int) i, j);
+ }
+
+ static boolean eq(Integer i, int j) {
+ return i == null ? j == -1 : i == j;
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubMapTest.java b/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubMapTest.java
new file mode 100644
index 0000000..7247657
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubMapTest.java
@@ -0,0 +1,1410 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.concurrent.ConcurrentNavigableMap;
+import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.*;
+
+public class ConcurrentSkipListSubMapTest extends JSR166TestCase {
+
+ /**
+ * Returns a new map from Integers 1-5 to Strings "A"-"E".
+ */
+ private static ConcurrentNavigableMap map5() {
+ ConcurrentSkipListMap map = new ConcurrentSkipListMap();
+ assertTrue(map.isEmpty());
+ map.put(zero, "Z");
+ map.put(one, "A");
+ map.put(five, "E");
+ map.put(three, "C");
+ map.put(two, "B");
+ map.put(four, "D");
+ map.put(seven, "F");
+ assertFalse(map.isEmpty());
+ assertEquals(7, map.size());
+ return map.subMap(one, true, seven, false);
+ }
+
+ /**
+ * Returns a new map from Integers -5 to -1 to Strings "A"-"E".
+ */
+ private static ConcurrentNavigableMap dmap5() {
+ ConcurrentSkipListMap map = new ConcurrentSkipListMap();
+ assertTrue(map.isEmpty());
+ map.put(m1, "A");
+ map.put(m5, "E");
+ map.put(m3, "C");
+ map.put(m2, "B");
+ map.put(m4, "D");
+ assertFalse(map.isEmpty());
+ assertEquals(5, map.size());
+ return map.descendingMap();
+ }
+
+ private static ConcurrentNavigableMap map0() {
+ ConcurrentSkipListMap map = new ConcurrentSkipListMap();
+ assertTrue(map.isEmpty());
+ return map.tailMap(one, true);
+ }
+
+ private static ConcurrentNavigableMap dmap0() {
+ ConcurrentSkipListMap map = new ConcurrentSkipListMap();
+ assertTrue(map.isEmpty());
+ return map;
+ }
+
+ /**
+ * clear removes all pairs
+ */
+ public void testClear() {
+ ConcurrentNavigableMap map = map5();
+ map.clear();
+ assertEquals(0, map.size());
+ }
+
+ /**
+ * Maps with same contents are equal
+ */
+ public void testEquals() {
+ ConcurrentNavigableMap map1 = map5();
+ ConcurrentNavigableMap map2 = map5();
+ assertEquals(map1, map2);
+ assertEquals(map2, map1);
+ map1.clear();
+ assertFalse(map1.equals(map2));
+ assertFalse(map2.equals(map1));
+ }
+
+ /**
+ * containsKey returns true for contained key
+ */
+ public void testContainsKey() {
+ ConcurrentNavigableMap map = map5();
+ assertTrue(map.containsKey(one));
+ assertFalse(map.containsKey(zero));
+ }
+
+ /**
+ * containsValue returns true for held values
+ */
+ public void testContainsValue() {
+ ConcurrentNavigableMap map = map5();
+ assertTrue(map.containsValue("A"));
+ assertFalse(map.containsValue("Z"));
+ }
+
+ /**
+ * get returns the correct element at the given key,
+ * or null if not present
+ */
+ public void testGet() {
+ ConcurrentNavigableMap map = map5();
+ assertEquals("A", (String)map.get(one));
+ ConcurrentNavigableMap empty = map0();
+ assertNull(empty.get(one));
+ }
+
+ /**
+ * isEmpty is true of empty map and false for non-empty
+ */
+ public void testIsEmpty() {
+ ConcurrentNavigableMap empty = map0();
+ ConcurrentNavigableMap map = map5();
+ assertTrue(empty.isEmpty());
+ assertFalse(map.isEmpty());
+ }
+
+ /**
+ * firstKey returns first key
+ */
+ public void testFirstKey() {
+ ConcurrentNavigableMap map = map5();
+ assertEquals(one, map.firstKey());
+ }
+
+ /**
+ * lastKey returns last key
+ */
+ public void testLastKey() {
+ ConcurrentNavigableMap map = map5();
+ assertEquals(five, map.lastKey());
+ }
+
+ /**
+ * keySet returns a Set containing all the keys
+ */
+ public void testKeySet() {
+ ConcurrentNavigableMap map = map5();
+ Set s = map.keySet();
+ assertEquals(5, s.size());
+ assertTrue(s.contains(one));
+ assertTrue(s.contains(two));
+ assertTrue(s.contains(three));
+ assertTrue(s.contains(four));
+ assertTrue(s.contains(five));
+ }
+
+ /**
+ * keySet is ordered
+ */
+ public void testKeySetOrder() {
+ ConcurrentNavigableMap map = map5();
+ Set s = map.keySet();
+ Iterator i = s.iterator();
+ Integer last = (Integer)i.next();
+ assertEquals(last, one);
+ while (i.hasNext()) {
+ Integer k = (Integer)i.next();
+ assertTrue(last.compareTo(k) < 0);
+ last = k;
+ }
+ }
+
+ /**
+ * values collection contains all values
+ */
+ public void testValues() {
+ ConcurrentNavigableMap map = map5();
+ Collection s = map.values();
+ assertEquals(5, s.size());
+ assertTrue(s.contains("A"));
+ assertTrue(s.contains("B"));
+ assertTrue(s.contains("C"));
+ assertTrue(s.contains("D"));
+ assertTrue(s.contains("E"));
+ }
+
+ /**
+ * keySet.toArray returns contains all keys
+ */
+ public void testKeySetToArray() {
+ ConcurrentNavigableMap map = map5();
+ Set s = map.keySet();
+ Object[] ar = s.toArray();
+ assertTrue(s.containsAll(Arrays.asList(ar)));
+ assertEquals(5, ar.length);
+ ar[0] = m10;
+ assertFalse(s.containsAll(Arrays.asList(ar)));
+ }
+
+ /**
+ * descendingkeySet.toArray returns contains all keys
+ */
+ public void testDescendingKeySetToArray() {
+ ConcurrentNavigableMap map = map5();
+ Set s = map.descendingKeySet();
+ Object[] ar = s.toArray();
+ assertEquals(5, ar.length);
+ assertTrue(s.containsAll(Arrays.asList(ar)));
+ ar[0] = m10;
+ assertFalse(s.containsAll(Arrays.asList(ar)));
+ }
+
+ /**
+ * Values.toArray contains all values
+ */
+ public void testValuesToArray() {
+ ConcurrentNavigableMap map = map5();
+ Collection v = map.values();
+ Object[] ar = v.toArray();
+ ArrayList s = new ArrayList(Arrays.asList(ar));
+ assertEquals(5, ar.length);
+ assertTrue(s.contains("A"));
+ assertTrue(s.contains("B"));
+ assertTrue(s.contains("C"));
+ assertTrue(s.contains("D"));
+ assertTrue(s.contains("E"));
+ }
+
+ /**
+ * entrySet contains all pairs
+ */
+ public void testEntrySet() {
+ ConcurrentNavigableMap map = map5();
+ Set s = map.entrySet();
+ assertEquals(5, s.size());
+ Iterator it = s.iterator();
+ while (it.hasNext()) {
+ Map.Entry e = (Map.Entry) it.next();
+ assertTrue(
+ (e.getKey().equals(one) && e.getValue().equals("A")) ||
+ (e.getKey().equals(two) && e.getValue().equals("B")) ||
+ (e.getKey().equals(three) && e.getValue().equals("C")) ||
+ (e.getKey().equals(four) && e.getValue().equals("D")) ||
+ (e.getKey().equals(five) && e.getValue().equals("E")));
+ }
+ }
+
+ /**
+ * putAll adds all key-value pairs from the given map
+ */
+ public void testPutAll() {
+ ConcurrentNavigableMap empty = map0();
+ ConcurrentNavigableMap map = map5();
+ empty.putAll(map);
+ assertEquals(5, empty.size());
+ assertTrue(empty.containsKey(one));
+ assertTrue(empty.containsKey(two));
+ assertTrue(empty.containsKey(three));
+ assertTrue(empty.containsKey(four));
+ assertTrue(empty.containsKey(five));
+ }
+
+ /**
+ * putIfAbsent works when the given key is not present
+ */
+ public void testPutIfAbsent() {
+ ConcurrentNavigableMap map = map5();
+ map.putIfAbsent(six, "Z");
+ assertTrue(map.containsKey(six));
+ }
+
+ /**
+ * putIfAbsent does not add the pair if the key is already present
+ */
+ public void testPutIfAbsent2() {
+ ConcurrentNavigableMap map = map5();
+ assertEquals("A", map.putIfAbsent(one, "Z"));
+ }
+
+ /**
+ * replace fails when the given key is not present
+ */
+ public void testReplace() {
+ ConcurrentNavigableMap map = map5();
+ assertNull(map.replace(six, "Z"));
+ assertFalse(map.containsKey(six));
+ }
+
+ /**
+ * replace succeeds if the key is already present
+ */
+ public void testReplace2() {
+ ConcurrentNavigableMap map = map5();
+ assertNotNull(map.replace(one, "Z"));
+ assertEquals("Z", map.get(one));
+ }
+
+ /**
+ * replace value fails when the given key not mapped to expected value
+ */
+ public void testReplaceValue() {
+ ConcurrentNavigableMap map = map5();
+ assertEquals("A", map.get(one));
+ assertFalse(map.replace(one, "Z", "Z"));
+ assertEquals("A", map.get(one));
+ }
+
+ /**
+ * replace value succeeds when the given key mapped to expected value
+ */
+ public void testReplaceValue2() {
+ ConcurrentNavigableMap map = map5();
+ assertEquals("A", map.get(one));
+ assertTrue(map.replace(one, "A", "Z"));
+ assertEquals("Z", map.get(one));
+ }
+
+ /**
+ * remove removes the correct key-value pair from the map
+ */
+ public void testRemove() {
+ ConcurrentNavigableMap map = map5();
+ map.remove(five);
+ assertEquals(4, map.size());
+ assertFalse(map.containsKey(five));
+ }
+
+ /**
+ * remove(key,value) removes only if pair present
+ */
+ public void testRemove2() {
+ ConcurrentNavigableMap map = map5();
+ assertTrue(map.containsKey(five));
+ assertEquals("E", map.get(five));
+ map.remove(five, "E");
+ assertEquals(4, map.size());
+ assertFalse(map.containsKey(five));
+ map.remove(four, "A");
+ assertEquals(4, map.size());
+ assertTrue(map.containsKey(four));
+ }
+
+ /**
+ * lowerEntry returns preceding entry.
+ */
+ public void testLowerEntry() {
+ ConcurrentNavigableMap map = map5();
+ Map.Entry e1 = map.lowerEntry(three);
+ assertEquals(two, e1.getKey());
+
+ Map.Entry e2 = map.lowerEntry(six);
+ assertEquals(five, e2.getKey());
+
+ Map.Entry e3 = map.lowerEntry(one);
+ assertNull(e3);
+
+ Map.Entry e4 = map.lowerEntry(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * higherEntry returns next entry.
+ */
+ public void testHigherEntry() {
+ ConcurrentNavigableMap map = map5();
+ Map.Entry e1 = map.higherEntry(three);
+ assertEquals(four, e1.getKey());
+
+ Map.Entry e2 = map.higherEntry(zero);
+ assertEquals(one, e2.getKey());
+
+ Map.Entry e3 = map.higherEntry(five);
+ assertNull(e3);
+
+ Map.Entry e4 = map.higherEntry(six);
+ assertNull(e4);
+ }
+
+ /**
+ * floorEntry returns preceding entry.
+ */
+ public void testFloorEntry() {
+ ConcurrentNavigableMap map = map5();
+ Map.Entry e1 = map.floorEntry(three);
+ assertEquals(three, e1.getKey());
+
+ Map.Entry e2 = map.floorEntry(six);
+ assertEquals(five, e2.getKey());
+
+ Map.Entry e3 = map.floorEntry(one);
+ assertEquals(one, e3.getKey());
+
+ Map.Entry e4 = map.floorEntry(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * ceilingEntry returns next entry.
+ */
+ public void testCeilingEntry() {
+ ConcurrentNavigableMap map = map5();
+ Map.Entry e1 = map.ceilingEntry(three);
+ assertEquals(three, e1.getKey());
+
+ Map.Entry e2 = map.ceilingEntry(zero);
+ assertEquals(one, e2.getKey());
+
+ Map.Entry e3 = map.ceilingEntry(five);
+ assertEquals(five, e3.getKey());
+
+ Map.Entry e4 = map.ceilingEntry(six);
+ assertNull(e4);
+ }
+
+ /**
+ * pollFirstEntry returns entries in order
+ */
+ public void testPollFirstEntry() {
+ ConcurrentNavigableMap map = map5();
+ Map.Entry e = map.pollFirstEntry();
+ assertEquals(one, e.getKey());
+ assertEquals("A", e.getValue());
+ e = map.pollFirstEntry();
+ assertEquals(two, e.getKey());
+ map.put(one, "A");
+ e = map.pollFirstEntry();
+ assertEquals(one, e.getKey());
+ assertEquals("A", e.getValue());
+ e = map.pollFirstEntry();
+ assertEquals(three, e.getKey());
+ map.remove(four);
+ e = map.pollFirstEntry();
+ assertEquals(five, e.getKey());
+ try {
+ e.setValue("A");
+ shouldThrow();
+ } catch (UnsupportedOperationException success) {}
+ e = map.pollFirstEntry();
+ assertNull(e);
+ }
+
+ /**
+ * pollLastEntry returns entries in order
+ */
+ public void testPollLastEntry() {
+ ConcurrentNavigableMap map = map5();
+ Map.Entry e = map.pollLastEntry();
+ assertEquals(five, e.getKey());
+ assertEquals("E", e.getValue());
+ e = map.pollLastEntry();
+ assertEquals(four, e.getKey());
+ map.put(five, "E");
+ e = map.pollLastEntry();
+ assertEquals(five, e.getKey());
+ assertEquals("E", e.getValue());
+ e = map.pollLastEntry();
+ assertEquals(three, e.getKey());
+ map.remove(two);
+ e = map.pollLastEntry();
+ assertEquals(one, e.getKey());
+ try {
+ e.setValue("E");
+ shouldThrow();
+ } catch (UnsupportedOperationException success) {}
+ e = map.pollLastEntry();
+ assertNull(e);
+ }
+
+ /**
+ * size returns the correct values
+ */
+ public void testSize() {
+ ConcurrentNavigableMap map = map5();
+ ConcurrentNavigableMap empty = map0();
+ assertEquals(0, empty.size());
+ assertEquals(5, map.size());
+ }
+
+ /**
+ * toString contains toString of elements
+ */
+ public void testToString() {
+ ConcurrentNavigableMap map = map5();
+ String s = map.toString();
+ for (int i = 1; i <= 5; ++i) {
+ assertTrue(s.contains(String.valueOf(i)));
+ }
+ }
+
+ // Exception tests
+
+ /**
+ * get(null) of nonempty map throws NPE
+ */
+ public void testGet_NullPointerException() {
+ try {
+ ConcurrentNavigableMap c = map5();
+ c.get(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * containsKey(null) of nonempty map throws NPE
+ */
+ public void testContainsKey_NullPointerException() {
+ try {
+ ConcurrentNavigableMap c = map5();
+ c.containsKey(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * containsValue(null) throws NPE
+ */
+ public void testContainsValue_NullPointerException() {
+ try {
+ ConcurrentNavigableMap c = map0();
+ c.containsValue(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * put(null,x) throws NPE
+ */
+ public void testPut1_NullPointerException() {
+ try {
+ ConcurrentNavigableMap c = map5();
+ c.put(null, "whatever");
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * putIfAbsent(null, x) throws NPE
+ */
+ public void testPutIfAbsent1_NullPointerException() {
+ try {
+ ConcurrentNavigableMap c = map5();
+ c.putIfAbsent(null, "whatever");
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * replace(null, x) throws NPE
+ */
+ public void testReplace_NullPointerException() {
+ try {
+ ConcurrentNavigableMap c = map5();
+ c.replace(null, "whatever");
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * replace(null, x, y) throws NPE
+ */
+ public void testReplaceValue_NullPointerException() {
+ try {
+ ConcurrentNavigableMap c = map5();
+ c.replace(null, one, "whatever");
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * remove(null) throws NPE
+ */
+ public void testRemove1_NullPointerException() {
+ try {
+ ConcurrentNavigableMap c = map5();
+ c.remove(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * remove(null, x) throws NPE
+ */
+ public void testRemove2_NullPointerException() {
+ try {
+ ConcurrentNavigableMap c = map5();
+ c.remove(null, "whatever");
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * A deserialized map equals original
+ */
+ public void testSerialization() throws Exception {
+ NavigableMap x = map5();
+ NavigableMap y = serialClone(x);
+
+ assertNotSame(x, y);
+ assertEquals(x.size(), y.size());
+ assertEquals(x.toString(), y.toString());
+ assertEquals(x, y);
+ assertEquals(y, x);
+ }
+
+ /**
+ * subMap returns map with keys in requested range
+ */
+ public void testSubMapContents() {
+ ConcurrentNavigableMap map = map5();
+ SortedMap sm = map.subMap(two, four);
+ assertEquals(two, sm.firstKey());
+ assertEquals(three, sm.lastKey());
+ assertEquals(2, sm.size());
+ assertFalse(sm.containsKey(one));
+ assertTrue(sm.containsKey(two));
+ assertTrue(sm.containsKey(three));
+ assertFalse(sm.containsKey(four));
+ assertFalse(sm.containsKey(five));
+ Iterator i = sm.keySet().iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ k = (Integer)(i.next());
+ assertEquals(three, k);
+ assertFalse(i.hasNext());
+ Iterator j = sm.keySet().iterator();
+ j.next();
+ j.remove();
+ assertFalse(map.containsKey(two));
+ assertEquals(4, map.size());
+ assertEquals(1, sm.size());
+ assertEquals(three, sm.firstKey());
+ assertEquals(three, sm.lastKey());
+ assertEquals("C", sm.remove(three));
+ assertTrue(sm.isEmpty());
+ assertEquals(3, map.size());
+ }
+
+ public void testSubMapContents2() {
+ ConcurrentNavigableMap map = map5();
+ SortedMap sm = map.subMap(two, three);
+ assertEquals(1, sm.size());
+ assertEquals(two, sm.firstKey());
+ assertEquals(two, sm.lastKey());
+ assertFalse(sm.containsKey(one));
+ assertTrue(sm.containsKey(two));
+ assertFalse(sm.containsKey(three));
+ assertFalse(sm.containsKey(four));
+ assertFalse(sm.containsKey(five));
+ Iterator i = sm.keySet().iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ assertFalse(i.hasNext());
+ Iterator j = sm.keySet().iterator();
+ j.next();
+ j.remove();
+ assertFalse(map.containsKey(two));
+ assertEquals(4, map.size());
+ assertEquals(0, sm.size());
+ assertTrue(sm.isEmpty());
+ assertSame(sm.remove(three), null);
+ assertEquals(4, map.size());
+ }
+
+ /**
+ * headMap returns map with keys in requested range
+ */
+ public void testHeadMapContents() {
+ ConcurrentNavigableMap map = map5();
+ SortedMap sm = map.headMap(four);
+ assertTrue(sm.containsKey(one));
+ assertTrue(sm.containsKey(two));
+ assertTrue(sm.containsKey(three));
+ assertFalse(sm.containsKey(four));
+ assertFalse(sm.containsKey(five));
+ Iterator i = sm.keySet().iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(one, k);
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ k = (Integer)(i.next());
+ assertEquals(three, k);
+ assertFalse(i.hasNext());
+ sm.clear();
+ assertTrue(sm.isEmpty());
+ assertEquals(2, map.size());
+ assertEquals(four, map.firstKey());
+ }
+
+ /**
+ * headMap returns map with keys in requested range
+ */
+ public void testTailMapContents() {
+ ConcurrentNavigableMap map = map5();
+ SortedMap sm = map.tailMap(two);
+ assertFalse(sm.containsKey(one));
+ assertTrue(sm.containsKey(two));
+ assertTrue(sm.containsKey(three));
+ assertTrue(sm.containsKey(four));
+ assertTrue(sm.containsKey(five));
+ Iterator i = sm.keySet().iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ k = (Integer)(i.next());
+ assertEquals(three, k);
+ k = (Integer)(i.next());
+ assertEquals(four, k);
+ k = (Integer)(i.next());
+ assertEquals(five, k);
+ assertFalse(i.hasNext());
+
+ Iterator ei = sm.entrySet().iterator();
+ Map.Entry e;
+ e = (Map.Entry)(ei.next());
+ assertEquals(two, e.getKey());
+ assertEquals("B", e.getValue());
+ e = (Map.Entry)(ei.next());
+ assertEquals(three, e.getKey());
+ assertEquals("C", e.getValue());
+ e = (Map.Entry)(ei.next());
+ assertEquals(four, e.getKey());
+ assertEquals("D", e.getValue());
+ e = (Map.Entry)(ei.next());
+ assertEquals(five, e.getKey());
+ assertEquals("E", e.getValue());
+ assertFalse(i.hasNext());
+
+ SortedMap ssm = sm.tailMap(four);
+ assertEquals(four, ssm.firstKey());
+ assertEquals(five, ssm.lastKey());
+ assertEquals("D", ssm.remove(four));
+ assertEquals(1, ssm.size());
+ assertEquals(3, sm.size());
+ assertEquals(4, map.size());
+ }
+
+ /**
+ * clear removes all pairs
+ */
+ public void testDescendingClear() {
+ ConcurrentNavigableMap map = dmap5();
+ map.clear();
+ assertEquals(0, map.size());
+ }
+
+ /**
+ * Maps with same contents are equal
+ */
+ public void testDescendingEquals() {
+ ConcurrentNavigableMap map1 = dmap5();
+ ConcurrentNavigableMap map2 = dmap5();
+ assertEquals(map1, map2);
+ assertEquals(map2, map1);
+ map1.clear();
+ assertFalse(map1.equals(map2));
+ assertFalse(map2.equals(map1));
+ }
+
+ /**
+ * containsKey returns true for contained key
+ */
+ public void testDescendingContainsKey() {
+ ConcurrentNavigableMap map = dmap5();
+ assertTrue(map.containsKey(m1));
+ assertFalse(map.containsKey(zero));
+ }
+
+ /**
+ * containsValue returns true for held values
+ */
+ public void testDescendingContainsValue() {
+ ConcurrentNavigableMap map = dmap5();
+ assertTrue(map.containsValue("A"));
+ assertFalse(map.containsValue("Z"));
+ }
+
+ /**
+ * get returns the correct element at the given key,
+ * or null if not present
+ */
+ public void testDescendingGet() {
+ ConcurrentNavigableMap map = dmap5();
+ assertEquals("A", (String)map.get(m1));
+ ConcurrentNavigableMap empty = dmap0();
+ assertNull(empty.get(m1));
+ }
+
+ /**
+ * isEmpty is true of empty map and false for non-empty
+ */
+ public void testDescendingIsEmpty() {
+ ConcurrentNavigableMap empty = dmap0();
+ ConcurrentNavigableMap map = dmap5();
+ assertTrue(empty.isEmpty());
+ assertFalse(map.isEmpty());
+ }
+
+ /**
+ * firstKey returns first key
+ */
+ public void testDescendingFirstKey() {
+ ConcurrentNavigableMap map = dmap5();
+ assertEquals(m1, map.firstKey());
+ }
+
+ /**
+ * lastKey returns last key
+ */
+ public void testDescendingLastKey() {
+ ConcurrentNavigableMap map = dmap5();
+ assertEquals(m5, map.lastKey());
+ }
+
+ /**
+ * keySet returns a Set containing all the keys
+ */
+ public void testDescendingKeySet() {
+ ConcurrentNavigableMap map = dmap5();
+ Set s = map.keySet();
+ assertEquals(5, s.size());
+ assertTrue(s.contains(m1));
+ assertTrue(s.contains(m2));
+ assertTrue(s.contains(m3));
+ assertTrue(s.contains(m4));
+ assertTrue(s.contains(m5));
+ }
+
+ /**
+ * keySet is ordered
+ */
+ public void testDescendingKeySetOrder() {
+ ConcurrentNavigableMap map = dmap5();
+ Set s = map.keySet();
+ Iterator i = s.iterator();
+ Integer last = (Integer)i.next();
+ assertEquals(last, m1);
+ while (i.hasNext()) {
+ Integer k = (Integer)i.next();
+ assertTrue(last.compareTo(k) > 0);
+ last = k;
+ }
+ }
+
+ /**
+ * values collection contains all values
+ */
+ public void testDescendingValues() {
+ ConcurrentNavigableMap map = dmap5();
+ Collection s = map.values();
+ assertEquals(5, s.size());
+ assertTrue(s.contains("A"));
+ assertTrue(s.contains("B"));
+ assertTrue(s.contains("C"));
+ assertTrue(s.contains("D"));
+ assertTrue(s.contains("E"));
+ }
+
+ /**
+ * keySet.toArray returns contains all keys
+ */
+ public void testDescendingAscendingKeySetToArray() {
+ ConcurrentNavigableMap map = dmap5();
+ Set s = map.keySet();
+ Object[] ar = s.toArray();
+ assertTrue(s.containsAll(Arrays.asList(ar)));
+ assertEquals(5, ar.length);
+ ar[0] = m10;
+ assertFalse(s.containsAll(Arrays.asList(ar)));
+ }
+
+ /**
+ * descendingkeySet.toArray returns contains all keys
+ */
+ public void testDescendingDescendingKeySetToArray() {
+ ConcurrentNavigableMap map = dmap5();
+ Set s = map.descendingKeySet();
+ Object[] ar = s.toArray();
+ assertEquals(5, ar.length);
+ assertTrue(s.containsAll(Arrays.asList(ar)));
+ ar[0] = m10;
+ assertFalse(s.containsAll(Arrays.asList(ar)));
+ }
+
+ /**
+ * Values.toArray contains all values
+ */
+ public void testDescendingValuesToArray() {
+ ConcurrentNavigableMap map = dmap5();
+ Collection v = map.values();
+ Object[] ar = v.toArray();
+ ArrayList s = new ArrayList(Arrays.asList(ar));
+ assertEquals(5, ar.length);
+ assertTrue(s.contains("A"));
+ assertTrue(s.contains("B"));
+ assertTrue(s.contains("C"));
+ assertTrue(s.contains("D"));
+ assertTrue(s.contains("E"));
+ }
+
+ /**
+ * entrySet contains all pairs
+ */
+ public void testDescendingEntrySet() {
+ ConcurrentNavigableMap map = dmap5();
+ Set s = map.entrySet();
+ assertEquals(5, s.size());
+ Iterator it = s.iterator();
+ while (it.hasNext()) {
+ Map.Entry e = (Map.Entry) it.next();
+ assertTrue(
+ (e.getKey().equals(m1) && e.getValue().equals("A")) ||
+ (e.getKey().equals(m2) && e.getValue().equals("B")) ||
+ (e.getKey().equals(m3) && e.getValue().equals("C")) ||
+ (e.getKey().equals(m4) && e.getValue().equals("D")) ||
+ (e.getKey().equals(m5) && e.getValue().equals("E")));
+ }
+ }
+
+ /**
+ * putAll adds all key-value pairs from the given map
+ */
+ public void testDescendingPutAll() {
+ ConcurrentNavigableMap empty = dmap0();
+ ConcurrentNavigableMap map = dmap5();
+ empty.putAll(map);
+ assertEquals(5, empty.size());
+ assertTrue(empty.containsKey(m1));
+ assertTrue(empty.containsKey(m2));
+ assertTrue(empty.containsKey(m3));
+ assertTrue(empty.containsKey(m4));
+ assertTrue(empty.containsKey(m5));
+ }
+
+ /**
+ * putIfAbsent works when the given key is not present
+ */
+ public void testDescendingPutIfAbsent() {
+ ConcurrentNavigableMap map = dmap5();
+ map.putIfAbsent(six, "Z");
+ assertTrue(map.containsKey(six));
+ }
+
+ /**
+ * putIfAbsent does not add the pair if the key is already present
+ */
+ public void testDescendingPutIfAbsent2() {
+ ConcurrentNavigableMap map = dmap5();
+ assertEquals("A", map.putIfAbsent(m1, "Z"));
+ }
+
+ /**
+ * replace fails when the given key is not present
+ */
+ public void testDescendingReplace() {
+ ConcurrentNavigableMap map = dmap5();
+ assertNull(map.replace(six, "Z"));
+ assertFalse(map.containsKey(six));
+ }
+
+ /**
+ * replace succeeds if the key is already present
+ */
+ public void testDescendingReplace2() {
+ ConcurrentNavigableMap map = dmap5();
+ assertNotNull(map.replace(m1, "Z"));
+ assertEquals("Z", map.get(m1));
+ }
+
+ /**
+ * replace value fails when the given key not mapped to expected value
+ */
+ public void testDescendingReplaceValue() {
+ ConcurrentNavigableMap map = dmap5();
+ assertEquals("A", map.get(m1));
+ assertFalse(map.replace(m1, "Z", "Z"));
+ assertEquals("A", map.get(m1));
+ }
+
+ /**
+ * replace value succeeds when the given key mapped to expected value
+ */
+ public void testDescendingReplaceValue2() {
+ ConcurrentNavigableMap map = dmap5();
+ assertEquals("A", map.get(m1));
+ assertTrue(map.replace(m1, "A", "Z"));
+ assertEquals("Z", map.get(m1));
+ }
+
+ /**
+ * remove removes the correct key-value pair from the map
+ */
+ public void testDescendingRemove() {
+ ConcurrentNavigableMap map = dmap5();
+ map.remove(m5);
+ assertEquals(4, map.size());
+ assertFalse(map.containsKey(m5));
+ }
+
+ /**
+ * remove(key,value) removes only if pair present
+ */
+ public void testDescendingRemove2() {
+ ConcurrentNavigableMap map = dmap5();
+ assertTrue(map.containsKey(m5));
+ assertEquals("E", map.get(m5));
+ map.remove(m5, "E");
+ assertEquals(4, map.size());
+ assertFalse(map.containsKey(m5));
+ map.remove(m4, "A");
+ assertEquals(4, map.size());
+ assertTrue(map.containsKey(m4));
+ }
+
+ /**
+ * lowerEntry returns preceding entry.
+ */
+ public void testDescendingLowerEntry() {
+ ConcurrentNavigableMap map = dmap5();
+ Map.Entry e1 = map.lowerEntry(m3);
+ assertEquals(m2, e1.getKey());
+
+ Map.Entry e2 = map.lowerEntry(m6);
+ assertEquals(m5, e2.getKey());
+
+ Map.Entry e3 = map.lowerEntry(m1);
+ assertNull(e3);
+
+ Map.Entry e4 = map.lowerEntry(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * higherEntry returns next entry.
+ */
+ public void testDescendingHigherEntry() {
+ ConcurrentNavigableMap map = dmap5();
+ Map.Entry e1 = map.higherEntry(m3);
+ assertEquals(m4, e1.getKey());
+
+ Map.Entry e2 = map.higherEntry(zero);
+ assertEquals(m1, e2.getKey());
+
+ Map.Entry e3 = map.higherEntry(m5);
+ assertNull(e3);
+
+ Map.Entry e4 = map.higherEntry(m6);
+ assertNull(e4);
+ }
+
+ /**
+ * floorEntry returns preceding entry.
+ */
+ public void testDescendingFloorEntry() {
+ ConcurrentNavigableMap map = dmap5();
+ Map.Entry e1 = map.floorEntry(m3);
+ assertEquals(m3, e1.getKey());
+
+ Map.Entry e2 = map.floorEntry(m6);
+ assertEquals(m5, e2.getKey());
+
+ Map.Entry e3 = map.floorEntry(m1);
+ assertEquals(m1, e3.getKey());
+
+ Map.Entry e4 = map.floorEntry(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * ceilingEntry returns next entry.
+ */
+ public void testDescendingCeilingEntry() {
+ ConcurrentNavigableMap map = dmap5();
+ Map.Entry e1 = map.ceilingEntry(m3);
+ assertEquals(m3, e1.getKey());
+
+ Map.Entry e2 = map.ceilingEntry(zero);
+ assertEquals(m1, e2.getKey());
+
+ Map.Entry e3 = map.ceilingEntry(m5);
+ assertEquals(m5, e3.getKey());
+
+ Map.Entry e4 = map.ceilingEntry(m6);
+ assertNull(e4);
+ }
+
+ /**
+ * pollFirstEntry returns entries in order
+ */
+ public void testDescendingPollFirstEntry() {
+ ConcurrentNavigableMap map = dmap5();
+ Map.Entry e = map.pollFirstEntry();
+ assertEquals(m1, e.getKey());
+ assertEquals("A", e.getValue());
+ e = map.pollFirstEntry();
+ assertEquals(m2, e.getKey());
+ map.put(m1, "A");
+ e = map.pollFirstEntry();
+ assertEquals(m1, e.getKey());
+ assertEquals("A", e.getValue());
+ e = map.pollFirstEntry();
+ assertEquals(m3, e.getKey());
+ map.remove(m4);
+ e = map.pollFirstEntry();
+ assertEquals(m5, e.getKey());
+ try {
+ e.setValue("A");
+ shouldThrow();
+ } catch (UnsupportedOperationException success) {}
+ e = map.pollFirstEntry();
+ assertNull(e);
+ }
+
+ /**
+ * pollLastEntry returns entries in order
+ */
+ public void testDescendingPollLastEntry() {
+ ConcurrentNavigableMap map = dmap5();
+ Map.Entry e = map.pollLastEntry();
+ assertEquals(m5, e.getKey());
+ assertEquals("E", e.getValue());
+ e = map.pollLastEntry();
+ assertEquals(m4, e.getKey());
+ map.put(m5, "E");
+ e = map.pollLastEntry();
+ assertEquals(m5, e.getKey());
+ assertEquals("E", e.getValue());
+ e = map.pollLastEntry();
+ assertEquals(m3, e.getKey());
+ map.remove(m2);
+ e = map.pollLastEntry();
+ assertEquals(m1, e.getKey());
+ try {
+ e.setValue("E");
+ shouldThrow();
+ } catch (UnsupportedOperationException success) {}
+ e = map.pollLastEntry();
+ assertNull(e);
+ }
+
+ /**
+ * size returns the correct values
+ */
+ public void testDescendingSize() {
+ ConcurrentNavigableMap map = dmap5();
+ ConcurrentNavigableMap empty = dmap0();
+ assertEquals(0, empty.size());
+ assertEquals(5, map.size());
+ }
+
+ /**
+ * toString contains toString of elements
+ */
+ public void testDescendingToString() {
+ ConcurrentNavigableMap map = dmap5();
+ String s = map.toString();
+ for (int i = 1; i <= 5; ++i) {
+ assertTrue(s.contains(String.valueOf(i)));
+ }
+ }
+
+ // Exception testDescendings
+
+ /**
+ * get(null) of empty map throws NPE
+ */
+ public void testDescendingGet_NullPointerException() {
+ try {
+ ConcurrentNavigableMap c = dmap5();
+ c.get(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * containsKey(null) of empty map throws NPE
+ */
+ public void testDescendingContainsKey_NullPointerException() {
+ try {
+ ConcurrentNavigableMap c = dmap5();
+ c.containsKey(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * containsValue(null) throws NPE
+ */
+ public void testDescendingContainsValue_NullPointerException() {
+ try {
+ ConcurrentNavigableMap c = dmap0();
+ c.containsValue(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * put(null,x) throws NPE
+ */
+ public void testDescendingPut1_NullPointerException() {
+ try {
+ ConcurrentNavigableMap c = dmap5();
+ c.put(null, "whatever");
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * putIfAbsent(null, x) throws NPE
+ */
+ public void testDescendingPutIfAbsent1_NullPointerException() {
+ try {
+ ConcurrentNavigableMap c = dmap5();
+ c.putIfAbsent(null, "whatever");
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * replace(null, x) throws NPE
+ */
+ public void testDescendingReplace_NullPointerException() {
+ try {
+ ConcurrentNavigableMap c = dmap5();
+ c.replace(null, "whatever");
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * replace(null, x, y) throws NPE
+ */
+ public void testDescendingReplaceValue_NullPointerException() {
+ try {
+ ConcurrentNavigableMap c = dmap5();
+ c.replace(null, m1, "whatever");
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * remove(null) throws NPE
+ */
+ public void testDescendingRemove1_NullPointerException() {
+ try {
+ ConcurrentNavigableMap c = dmap5();
+ c.remove(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * remove(null, x) throws NPE
+ */
+ public void testDescendingRemove2_NullPointerException() {
+ try {
+ ConcurrentNavigableMap c = dmap5();
+ c.remove(null, "whatever");
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * A deserialized map equals original
+ */
+ public void testDescendingSerialization() throws Exception {
+ NavigableMap x = dmap5();
+ NavigableMap y = serialClone(x);
+
+ assertNotSame(x, y);
+ assertEquals(x.size(), y.size());
+ assertEquals(x.toString(), y.toString());
+ assertEquals(x, y);
+ assertEquals(y, x);
+ }
+
+ /**
+ * subMap returns map with keys in requested range
+ */
+ public void testDescendingSubMapContents() {
+ ConcurrentNavigableMap map = dmap5();
+ SortedMap sm = map.subMap(m2, m4);
+ assertEquals(m2, sm.firstKey());
+ assertEquals(m3, sm.lastKey());
+ assertEquals(2, sm.size());
+ assertFalse(sm.containsKey(m1));
+ assertTrue(sm.containsKey(m2));
+ assertTrue(sm.containsKey(m3));
+ assertFalse(sm.containsKey(m4));
+ assertFalse(sm.containsKey(m5));
+ Iterator i = sm.keySet().iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(m2, k);
+ k = (Integer)(i.next());
+ assertEquals(m3, k);
+ assertFalse(i.hasNext());
+ Iterator j = sm.keySet().iterator();
+ j.next();
+ j.remove();
+ assertFalse(map.containsKey(m2));
+ assertEquals(4, map.size());
+ assertEquals(1, sm.size());
+ assertEquals(m3, sm.firstKey());
+ assertEquals(m3, sm.lastKey());
+ assertEquals("C", sm.remove(m3));
+ assertTrue(sm.isEmpty());
+ assertEquals(3, map.size());
+ }
+
+ public void testDescendingSubMapContents2() {
+ ConcurrentNavigableMap map = dmap5();
+ SortedMap sm = map.subMap(m2, m3);
+ assertEquals(1, sm.size());
+ assertEquals(m2, sm.firstKey());
+ assertEquals(m2, sm.lastKey());
+ assertFalse(sm.containsKey(m1));
+ assertTrue(sm.containsKey(m2));
+ assertFalse(sm.containsKey(m3));
+ assertFalse(sm.containsKey(m4));
+ assertFalse(sm.containsKey(m5));
+ Iterator i = sm.keySet().iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(m2, k);
+ assertFalse(i.hasNext());
+ Iterator j = sm.keySet().iterator();
+ j.next();
+ j.remove();
+ assertFalse(map.containsKey(m2));
+ assertEquals(4, map.size());
+ assertEquals(0, sm.size());
+ assertTrue(sm.isEmpty());
+ assertSame(sm.remove(m3), null);
+ assertEquals(4, map.size());
+ }
+
+ /**
+ * headMap returns map with keys in requested range
+ */
+ public void testDescendingHeadMapContents() {
+ ConcurrentNavigableMap map = dmap5();
+ SortedMap sm = map.headMap(m4);
+ assertTrue(sm.containsKey(m1));
+ assertTrue(sm.containsKey(m2));
+ assertTrue(sm.containsKey(m3));
+ assertFalse(sm.containsKey(m4));
+ assertFalse(sm.containsKey(m5));
+ Iterator i = sm.keySet().iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(m1, k);
+ k = (Integer)(i.next());
+ assertEquals(m2, k);
+ k = (Integer)(i.next());
+ assertEquals(m3, k);
+ assertFalse(i.hasNext());
+ sm.clear();
+ assertTrue(sm.isEmpty());
+ assertEquals(2, map.size());
+ assertEquals(m4, map.firstKey());
+ }
+
+ /**
+ * headMap returns map with keys in requested range
+ */
+ public void testDescendingTailMapContents() {
+ ConcurrentNavigableMap map = dmap5();
+ SortedMap sm = map.tailMap(m2);
+ assertFalse(sm.containsKey(m1));
+ assertTrue(sm.containsKey(m2));
+ assertTrue(sm.containsKey(m3));
+ assertTrue(sm.containsKey(m4));
+ assertTrue(sm.containsKey(m5));
+ Iterator i = sm.keySet().iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(m2, k);
+ k = (Integer)(i.next());
+ assertEquals(m3, k);
+ k = (Integer)(i.next());
+ assertEquals(m4, k);
+ k = (Integer)(i.next());
+ assertEquals(m5, k);
+ assertFalse(i.hasNext());
+
+ Iterator ei = sm.entrySet().iterator();
+ Map.Entry e;
+ e = (Map.Entry)(ei.next());
+ assertEquals(m2, e.getKey());
+ assertEquals("B", e.getValue());
+ e = (Map.Entry)(ei.next());
+ assertEquals(m3, e.getKey());
+ assertEquals("C", e.getValue());
+ e = (Map.Entry)(ei.next());
+ assertEquals(m4, e.getKey());
+ assertEquals("D", e.getValue());
+ e = (Map.Entry)(ei.next());
+ assertEquals(m5, e.getKey());
+ assertEquals("E", e.getValue());
+ assertFalse(i.hasNext());
+
+ SortedMap ssm = sm.tailMap(m4);
+ assertEquals(m4, ssm.firstKey());
+ assertEquals(m5, ssm.lastKey());
+ assertEquals("D", ssm.remove(m4));
+ assertEquals(1, ssm.size());
+ assertEquals(3, sm.size());
+ assertEquals(4, map.size());
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubSetTest.java b/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubSetTest.java
new file mode 100644
index 0000000..43c1759
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/ConcurrentSkipListSubSetTest.java
@@ -0,0 +1,1123 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.NavigableSet;
+import java.util.NoSuchElementException;
+import java.util.Random;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.concurrent.ConcurrentSkipListSet;
+
+public class ConcurrentSkipListSubSetTest extends JSR166TestCase {
+
+ static class MyReverseComparator implements Comparator {
+ public int compare(Object x, Object y) {
+ return ((Comparable)y).compareTo(x);
+ }
+ }
+
+ /**
+ * Returns a new set of given size containing consecutive
+ * Integers 0 ... n.
+ */
+ private NavigableSet<Integer> populatedSet(int n) {
+ ConcurrentSkipListSet<Integer> q =
+ new ConcurrentSkipListSet<Integer>();
+ assertTrue(q.isEmpty());
+
+ for (int i = n-1; i >= 0; i-=2)
+ assertTrue(q.add(new Integer(i)));
+ for (int i = (n & 1); i < n; i+=2)
+ assertTrue(q.add(new Integer(i)));
+ assertTrue(q.add(new Integer(-n)));
+ assertTrue(q.add(new Integer(n)));
+ NavigableSet s = q.subSet(new Integer(0), true, new Integer(n), false);
+ assertFalse(s.isEmpty());
+ assertEquals(n, s.size());
+ return s;
+ }
+
+ /**
+ * Returns a new set of first 5 ints.
+ */
+ private NavigableSet set5() {
+ ConcurrentSkipListSet q = new ConcurrentSkipListSet();
+ assertTrue(q.isEmpty());
+ q.add(one);
+ q.add(two);
+ q.add(three);
+ q.add(four);
+ q.add(five);
+ q.add(zero);
+ q.add(seven);
+ NavigableSet s = q.subSet(one, true, seven, false);
+ assertEquals(5, s.size());
+ return s;
+ }
+
+ /**
+ * Returns a new set of first 5 negative ints.
+ */
+ private NavigableSet dset5() {
+ ConcurrentSkipListSet q = new ConcurrentSkipListSet();
+ assertTrue(q.isEmpty());
+ q.add(m1);
+ q.add(m2);
+ q.add(m3);
+ q.add(m4);
+ q.add(m5);
+ NavigableSet s = q.descendingSet();
+ assertEquals(5, s.size());
+ return s;
+ }
+
+ private static NavigableSet set0() {
+ ConcurrentSkipListSet set = new ConcurrentSkipListSet();
+ assertTrue(set.isEmpty());
+ return set.tailSet(m1, true);
+ }
+
+ private static NavigableSet dset0() {
+ ConcurrentSkipListSet set = new ConcurrentSkipListSet();
+ assertTrue(set.isEmpty());
+ return set;
+ }
+
+ /**
+ * A new set has unbounded capacity
+ */
+ public void testConstructor1() {
+ assertEquals(0, set0().size());
+ }
+
+ /**
+ * isEmpty is true before add, false after
+ */
+ public void testEmpty() {
+ NavigableSet q = set0();
+ assertTrue(q.isEmpty());
+ q.add(new Integer(1));
+ assertFalse(q.isEmpty());
+ q.add(new Integer(2));
+ q.pollFirst();
+ q.pollFirst();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * size changes when elements added and removed
+ */
+ public void testSize() {
+ NavigableSet q = populatedSet(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(SIZE-i, q.size());
+ q.pollFirst();
+ }
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.size());
+ q.add(new Integer(i));
+ }
+ }
+
+ /**
+ * add(null) throws NPE
+ */
+ public void testAddNull() {
+ try {
+ NavigableSet q = set0();
+ q.add(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Add of comparable element succeeds
+ */
+ public void testAdd() {
+ NavigableSet q = set0();
+ assertTrue(q.add(six));
+ }
+
+ /**
+ * Add of duplicate element fails
+ */
+ public void testAddDup() {
+ NavigableSet q = set0();
+ assertTrue(q.add(six));
+ assertFalse(q.add(six));
+ }
+
+ /**
+ * Add of non-Comparable throws CCE
+ */
+ public void testAddNonComparable() {
+ try {
+ NavigableSet q = set0();
+ q.add(new Object());
+ q.add(new Object());
+ q.add(new Object());
+ shouldThrow();
+ } catch (ClassCastException success) {}
+ }
+
+ /**
+ * addAll(null) throws NPE
+ */
+ public void testAddAll1() {
+ try {
+ NavigableSet q = set0();
+ q.addAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll of a collection with null elements throws NPE
+ */
+ public void testAddAll2() {
+ try {
+ NavigableSet q = set0();
+ Integer[] ints = new Integer[SIZE];
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll of a collection with any null elements throws NPE after
+ * possibly adding some elements
+ */
+ public void testAddAll3() {
+ try {
+ NavigableSet q = set0();
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i+SIZE);
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Set contains all elements of successful addAll
+ */
+ public void testAddAll5() {
+ Integer[] empty = new Integer[0];
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(SIZE-1- i);
+ NavigableSet q = set0();
+ assertFalse(q.addAll(Arrays.asList(empty)));
+ assertTrue(q.addAll(Arrays.asList(ints)));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(new Integer(i), q.pollFirst());
+ }
+
+ /**
+ * poll succeeds unless empty
+ */
+ public void testPoll() {
+ NavigableSet q = populatedSet(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.pollFirst());
+ }
+ assertNull(q.pollFirst());
+ }
+
+ /**
+ * remove(x) removes x and returns true if present
+ */
+ public void testRemoveElement() {
+ NavigableSet q = populatedSet(SIZE);
+ for (int i = 1; i < SIZE; i+=2) {
+ assertTrue(q.contains(i));
+ assertTrue(q.remove(i));
+ assertFalse(q.contains(i));
+ assertTrue(q.contains(i-1));
+ }
+ for (int i = 0; i < SIZE; i+=2) {
+ assertTrue(q.contains(i));
+ assertTrue(q.remove(i));
+ assertFalse(q.contains(i));
+ assertFalse(q.remove(i+1));
+ assertFalse(q.contains(i+1));
+ }
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * contains(x) reports true when elements added but not yet removed
+ */
+ public void testContains() {
+ NavigableSet q = populatedSet(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.contains(new Integer(i)));
+ q.pollFirst();
+ assertFalse(q.contains(new Integer(i)));
+ }
+ }
+
+ /**
+ * clear removes all elements
+ */
+ public void testClear() {
+ NavigableSet q = populatedSet(SIZE);
+ q.clear();
+ assertTrue(q.isEmpty());
+ assertEquals(0, q.size());
+ q.add(new Integer(1));
+ assertFalse(q.isEmpty());
+ q.clear();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * containsAll(c) is true when c contains a subset of elements
+ */
+ public void testContainsAll() {
+ NavigableSet q = populatedSet(SIZE);
+ NavigableSet p = set0();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.containsAll(p));
+ assertFalse(p.containsAll(q));
+ p.add(new Integer(i));
+ }
+ assertTrue(p.containsAll(q));
+ }
+
+ /**
+ * retainAll(c) retains only those elements of c and reports true if changed
+ */
+ public void testRetainAll() {
+ NavigableSet q = populatedSet(SIZE);
+ NavigableSet p = populatedSet(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ boolean changed = q.retainAll(p);
+ if (i == 0)
+ assertFalse(changed);
+ else
+ assertTrue(changed);
+
+ assertTrue(q.containsAll(p));
+ assertEquals(SIZE-i, q.size());
+ p.pollFirst();
+ }
+ }
+
+ /**
+ * removeAll(c) removes only those elements of c and reports true if changed
+ */
+ public void testRemoveAll() {
+ for (int i = 1; i < SIZE; ++i) {
+ NavigableSet q = populatedSet(SIZE);
+ NavigableSet p = populatedSet(i);
+ assertTrue(q.removeAll(p));
+ assertEquals(SIZE-i, q.size());
+ for (int j = 0; j < i; ++j) {
+ Integer I = (Integer)(p.pollFirst());
+ assertFalse(q.contains(I));
+ }
+ }
+ }
+
+ /**
+ * lower returns preceding element
+ */
+ public void testLower() {
+ NavigableSet q = set5();
+ Object e1 = q.lower(three);
+ assertEquals(two, e1);
+
+ Object e2 = q.lower(six);
+ assertEquals(five, e2);
+
+ Object e3 = q.lower(one);
+ assertNull(e3);
+
+ Object e4 = q.lower(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * higher returns next element
+ */
+ public void testHigher() {
+ NavigableSet q = set5();
+ Object e1 = q.higher(three);
+ assertEquals(four, e1);
+
+ Object e2 = q.higher(zero);
+ assertEquals(one, e2);
+
+ Object e3 = q.higher(five);
+ assertNull(e3);
+
+ Object e4 = q.higher(six);
+ assertNull(e4);
+ }
+
+ /**
+ * floor returns preceding element
+ */
+ public void testFloor() {
+ NavigableSet q = set5();
+ Object e1 = q.floor(three);
+ assertEquals(three, e1);
+
+ Object e2 = q.floor(six);
+ assertEquals(five, e2);
+
+ Object e3 = q.floor(one);
+ assertEquals(one, e3);
+
+ Object e4 = q.floor(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * ceiling returns next element
+ */
+ public void testCeiling() {
+ NavigableSet q = set5();
+ Object e1 = q.ceiling(three);
+ assertEquals(three, e1);
+
+ Object e2 = q.ceiling(zero);
+ assertEquals(one, e2);
+
+ Object e3 = q.ceiling(five);
+ assertEquals(five, e3);
+
+ Object e4 = q.ceiling(six);
+ assertNull(e4);
+ }
+
+ /**
+ * toArray contains all elements in sorted order
+ */
+ public void testToArray() {
+ NavigableSet q = populatedSet(SIZE);
+ Object[] o = q.toArray();
+ for (int i = 0; i < o.length; i++)
+ assertSame(o[i], q.pollFirst());
+ }
+
+ /**
+ * toArray(a) contains all elements in sorted order
+ */
+ public void testToArray2() {
+ NavigableSet<Integer> q = populatedSet(SIZE);
+ Integer[] ints = new Integer[SIZE];
+ Integer[] array = q.toArray(ints);
+ assertSame(ints, array);
+ for (int i = 0; i < ints.length; i++)
+ assertSame(ints[i], q.pollFirst());
+ }
+
+ /**
+ * iterator iterates through all elements
+ */
+ public void testIterator() {
+ NavigableSet q = populatedSet(SIZE);
+ int i = 0;
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ assertTrue(q.contains(it.next()));
+ ++i;
+ }
+ assertEquals(i, SIZE);
+ }
+
+ /**
+ * iterator of empty set has no elements
+ */
+ public void testEmptyIterator() {
+ NavigableSet q = set0();
+ int i = 0;
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ assertTrue(q.contains(it.next()));
+ ++i;
+ }
+ assertEquals(0, i);
+ }
+
+ /**
+ * iterator.remove removes current element
+ */
+ public void testIteratorRemove() {
+ final NavigableSet q = set0();
+ q.add(new Integer(2));
+ q.add(new Integer(1));
+ q.add(new Integer(3));
+
+ Iterator it = q.iterator();
+ it.next();
+ it.remove();
+
+ it = q.iterator();
+ assertEquals(it.next(), new Integer(2));
+ assertEquals(it.next(), new Integer(3));
+ assertFalse(it.hasNext());
+ }
+
+ /**
+ * toString contains toStrings of elements
+ */
+ public void testToString() {
+ NavigableSet q = populatedSet(SIZE);
+ String s = q.toString();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(s.contains(String.valueOf(i)));
+ }
+ }
+
+ /**
+ * A deserialized serialized set has same elements
+ */
+ public void testSerialization() throws Exception {
+ NavigableSet x = populatedSet(SIZE);
+ NavigableSet y = serialClone(x);
+
+ assertNotSame(y, x);
+ assertEquals(x.size(), y.size());
+ assertEquals(x, y);
+ assertEquals(y, x);
+ while (!x.isEmpty()) {
+ assertFalse(y.isEmpty());
+ assertEquals(x.pollFirst(), y.pollFirst());
+ }
+ assertTrue(y.isEmpty());
+ }
+
+ /**
+ * subSet returns set with keys in requested range
+ */
+ public void testSubSetContents() {
+ NavigableSet set = set5();
+ SortedSet sm = set.subSet(two, four);
+ assertEquals(two, sm.first());
+ assertEquals(three, sm.last());
+ assertEquals(2, sm.size());
+ assertFalse(sm.contains(one));
+ assertTrue(sm.contains(two));
+ assertTrue(sm.contains(three));
+ assertFalse(sm.contains(four));
+ assertFalse(sm.contains(five));
+ Iterator i = sm.iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ k = (Integer)(i.next());
+ assertEquals(three, k);
+ assertFalse(i.hasNext());
+ Iterator j = sm.iterator();
+ j.next();
+ j.remove();
+ assertFalse(set.contains(two));
+ assertEquals(4, set.size());
+ assertEquals(1, sm.size());
+ assertEquals(three, sm.first());
+ assertEquals(three, sm.last());
+ assertTrue(sm.remove(three));
+ assertTrue(sm.isEmpty());
+ assertEquals(3, set.size());
+ }
+
+ public void testSubSetContents2() {
+ NavigableSet set = set5();
+ SortedSet sm = set.subSet(two, three);
+ assertEquals(1, sm.size());
+ assertEquals(two, sm.first());
+ assertEquals(two, sm.last());
+ assertFalse(sm.contains(one));
+ assertTrue(sm.contains(two));
+ assertFalse(sm.contains(three));
+ assertFalse(sm.contains(four));
+ assertFalse(sm.contains(five));
+ Iterator i = sm.iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ assertFalse(i.hasNext());
+ Iterator j = sm.iterator();
+ j.next();
+ j.remove();
+ assertFalse(set.contains(two));
+ assertEquals(4, set.size());
+ assertEquals(0, sm.size());
+ assertTrue(sm.isEmpty());
+ assertFalse(sm.remove(three));
+ assertEquals(4, set.size());
+ }
+
+ /**
+ * headSet returns set with keys in requested range
+ */
+ public void testHeadSetContents() {
+ NavigableSet set = set5();
+ SortedSet sm = set.headSet(four);
+ assertTrue(sm.contains(one));
+ assertTrue(sm.contains(two));
+ assertTrue(sm.contains(three));
+ assertFalse(sm.contains(four));
+ assertFalse(sm.contains(five));
+ Iterator i = sm.iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(one, k);
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ k = (Integer)(i.next());
+ assertEquals(three, k);
+ assertFalse(i.hasNext());
+ sm.clear();
+ assertTrue(sm.isEmpty());
+ assertEquals(2, set.size());
+ assertEquals(four, set.first());
+ }
+
+ /**
+ * tailSet returns set with keys in requested range
+ */
+ public void testTailSetContents() {
+ NavigableSet set = set5();
+ SortedSet sm = set.tailSet(two);
+ assertFalse(sm.contains(one));
+ assertTrue(sm.contains(two));
+ assertTrue(sm.contains(three));
+ assertTrue(sm.contains(four));
+ assertTrue(sm.contains(five));
+ Iterator i = sm.iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ k = (Integer)(i.next());
+ assertEquals(three, k);
+ k = (Integer)(i.next());
+ assertEquals(four, k);
+ k = (Integer)(i.next());
+ assertEquals(five, k);
+ assertFalse(i.hasNext());
+
+ SortedSet ssm = sm.tailSet(four);
+ assertEquals(four, ssm.first());
+ assertEquals(five, ssm.last());
+ assertTrue(ssm.remove(four));
+ assertEquals(1, ssm.size());
+ assertEquals(3, sm.size());
+ assertEquals(4, set.size());
+ }
+
+ /**
+ * size changes when elements added and removed
+ */
+ public void testDescendingSize() {
+ NavigableSet q = populatedSet(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(SIZE-i, q.size());
+ q.pollFirst();
+ }
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.size());
+ q.add(new Integer(i));
+ }
+ }
+
+ /**
+ * add(null) throws NPE
+ */
+ public void testDescendingAddNull() {
+ try {
+ NavigableSet q = dset0();
+ q.add(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Add of comparable element succeeds
+ */
+ public void testDescendingAdd() {
+ NavigableSet q = dset0();
+ assertTrue(q.add(m6));
+ }
+
+ /**
+ * Add of duplicate element fails
+ */
+ public void testDescendingAddDup() {
+ NavigableSet q = dset0();
+ assertTrue(q.add(m6));
+ assertFalse(q.add(m6));
+ }
+
+ /**
+ * Add of non-Comparable throws CCE
+ */
+ public void testDescendingAddNonComparable() {
+ try {
+ NavigableSet q = dset0();
+ q.add(new Object());
+ q.add(new Object());
+ q.add(new Object());
+ shouldThrow();
+ } catch (ClassCastException success) {}
+ }
+
+ /**
+ * addAll(null) throws NPE
+ */
+ public void testDescendingAddAll1() {
+ try {
+ NavigableSet q = dset0();
+ q.addAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll of a collection with null elements throws NPE
+ */
+ public void testDescendingAddAll2() {
+ try {
+ NavigableSet q = dset0();
+ Integer[] ints = new Integer[SIZE];
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll of a collection with any null elements throws NPE after
+ * possibly adding some elements
+ */
+ public void testDescendingAddAll3() {
+ try {
+ NavigableSet q = dset0();
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i+SIZE);
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Set contains all elements of successful addAll
+ */
+ public void testDescendingAddAll5() {
+ Integer[] empty = new Integer[0];
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(SIZE-1- i);
+ NavigableSet q = dset0();
+ assertFalse(q.addAll(Arrays.asList(empty)));
+ assertTrue(q.addAll(Arrays.asList(ints)));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(new Integer(i), q.pollFirst());
+ }
+
+ /**
+ * poll succeeds unless empty
+ */
+ public void testDescendingPoll() {
+ NavigableSet q = populatedSet(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.pollFirst());
+ }
+ assertNull(q.pollFirst());
+ }
+
+ /**
+ * remove(x) removes x and returns true if present
+ */
+ public void testDescendingRemoveElement() {
+ NavigableSet q = populatedSet(SIZE);
+ for (int i = 1; i < SIZE; i+=2) {
+ assertTrue(q.remove(new Integer(i)));
+ }
+ for (int i = 0; i < SIZE; i+=2) {
+ assertTrue(q.remove(new Integer(i)));
+ assertFalse(q.remove(new Integer(i+1)));
+ }
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * contains(x) reports true when elements added but not yet removed
+ */
+ public void testDescendingContains() {
+ NavigableSet q = populatedSet(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.contains(new Integer(i)));
+ q.pollFirst();
+ assertFalse(q.contains(new Integer(i)));
+ }
+ }
+
+ /**
+ * clear removes all elements
+ */
+ public void testDescendingClear() {
+ NavigableSet q = populatedSet(SIZE);
+ q.clear();
+ assertTrue(q.isEmpty());
+ assertEquals(0, q.size());
+ q.add(new Integer(1));
+ assertFalse(q.isEmpty());
+ q.clear();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * containsAll(c) is true when c contains a subset of elements
+ */
+ public void testDescendingContainsAll() {
+ NavigableSet q = populatedSet(SIZE);
+ NavigableSet p = dset0();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.containsAll(p));
+ assertFalse(p.containsAll(q));
+ p.add(new Integer(i));
+ }
+ assertTrue(p.containsAll(q));
+ }
+
+ /**
+ * retainAll(c) retains only those elements of c and reports true if changed
+ */
+ public void testDescendingRetainAll() {
+ NavigableSet q = populatedSet(SIZE);
+ NavigableSet p = populatedSet(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ boolean changed = q.retainAll(p);
+ if (i == 0)
+ assertFalse(changed);
+ else
+ assertTrue(changed);
+
+ assertTrue(q.containsAll(p));
+ assertEquals(SIZE-i, q.size());
+ p.pollFirst();
+ }
+ }
+
+ /**
+ * removeAll(c) removes only those elements of c and reports true if changed
+ */
+ public void testDescendingRemoveAll() {
+ for (int i = 1; i < SIZE; ++i) {
+ NavigableSet q = populatedSet(SIZE);
+ NavigableSet p = populatedSet(i);
+ assertTrue(q.removeAll(p));
+ assertEquals(SIZE-i, q.size());
+ for (int j = 0; j < i; ++j) {
+ Integer I = (Integer)(p.pollFirst());
+ assertFalse(q.contains(I));
+ }
+ }
+ }
+
+ /**
+ * lower returns preceding element
+ */
+ public void testDescendingLower() {
+ NavigableSet q = dset5();
+ Object e1 = q.lower(m3);
+ assertEquals(m2, e1);
+
+ Object e2 = q.lower(m6);
+ assertEquals(m5, e2);
+
+ Object e3 = q.lower(m1);
+ assertNull(e3);
+
+ Object e4 = q.lower(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * higher returns next element
+ */
+ public void testDescendingHigher() {
+ NavigableSet q = dset5();
+ Object e1 = q.higher(m3);
+ assertEquals(m4, e1);
+
+ Object e2 = q.higher(zero);
+ assertEquals(m1, e2);
+
+ Object e3 = q.higher(m5);
+ assertNull(e3);
+
+ Object e4 = q.higher(m6);
+ assertNull(e4);
+ }
+
+ /**
+ * floor returns preceding element
+ */
+ public void testDescendingFloor() {
+ NavigableSet q = dset5();
+ Object e1 = q.floor(m3);
+ assertEquals(m3, e1);
+
+ Object e2 = q.floor(m6);
+ assertEquals(m5, e2);
+
+ Object e3 = q.floor(m1);
+ assertEquals(m1, e3);
+
+ Object e4 = q.floor(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * ceiling returns next element
+ */
+ public void testDescendingCeiling() {
+ NavigableSet q = dset5();
+ Object e1 = q.ceiling(m3);
+ assertEquals(m3, e1);
+
+ Object e2 = q.ceiling(zero);
+ assertEquals(m1, e2);
+
+ Object e3 = q.ceiling(m5);
+ assertEquals(m5, e3);
+
+ Object e4 = q.ceiling(m6);
+ assertNull(e4);
+ }
+
+ /**
+ * toArray contains all elements
+ */
+ public void testDescendingToArray() {
+ NavigableSet q = populatedSet(SIZE);
+ Object[] o = q.toArray();
+ Arrays.sort(o);
+ for (int i = 0; i < o.length; i++)
+ assertEquals(o[i], q.pollFirst());
+ }
+
+ /**
+ * toArray(a) contains all elements
+ */
+ public void testDescendingToArray2() {
+ NavigableSet q = populatedSet(SIZE);
+ Integer[] ints = new Integer[SIZE];
+ assertSame(ints, q.toArray(ints));
+ Arrays.sort(ints);
+ for (int i = 0; i < ints.length; i++)
+ assertEquals(ints[i], q.pollFirst());
+ }
+
+ /**
+ * iterator iterates through all elements
+ */
+ public void testDescendingIterator() {
+ NavigableSet q = populatedSet(SIZE);
+ int i = 0;
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ assertTrue(q.contains(it.next()));
+ ++i;
+ }
+ assertEquals(i, SIZE);
+ }
+
+ /**
+ * iterator of empty set has no elements
+ */
+ public void testDescendingEmptyIterator() {
+ NavigableSet q = dset0();
+ int i = 0;
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ assertTrue(q.contains(it.next()));
+ ++i;
+ }
+ assertEquals(0, i);
+ }
+
+ /**
+ * iterator.remove removes current element
+ */
+ public void testDescendingIteratorRemove() {
+ final NavigableSet q = dset0();
+ q.add(new Integer(2));
+ q.add(new Integer(1));
+ q.add(new Integer(3));
+
+ Iterator it = q.iterator();
+ it.next();
+ it.remove();
+
+ it = q.iterator();
+ assertEquals(it.next(), new Integer(2));
+ assertEquals(it.next(), new Integer(3));
+ assertFalse(it.hasNext());
+ }
+
+ /**
+ * toString contains toStrings of elements
+ */
+ public void testDescendingToString() {
+ NavigableSet q = populatedSet(SIZE);
+ String s = q.toString();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(s.contains(String.valueOf(i)));
+ }
+ }
+
+ /**
+ * A deserialized serialized set has same elements
+ */
+ public void testDescendingSerialization() throws Exception {
+ NavigableSet x = dset5();
+ NavigableSet y = serialClone(x);
+
+ assertNotSame(y, x);
+ assertEquals(x.size(), y.size());
+ assertEquals(x, y);
+ assertEquals(y, x);
+ while (!x.isEmpty()) {
+ assertFalse(y.isEmpty());
+ assertEquals(x.pollFirst(), y.pollFirst());
+ }
+ assertTrue(y.isEmpty());
+ }
+
+ /**
+ * subSet returns set with keys in requested range
+ */
+ public void testDescendingSubSetContents() {
+ NavigableSet set = dset5();
+ SortedSet sm = set.subSet(m2, m4);
+ assertEquals(m2, sm.first());
+ assertEquals(m3, sm.last());
+ assertEquals(2, sm.size());
+ assertFalse(sm.contains(m1));
+ assertTrue(sm.contains(m2));
+ assertTrue(sm.contains(m3));
+ assertFalse(sm.contains(m4));
+ assertFalse(sm.contains(m5));
+ Iterator i = sm.iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(m2, k);
+ k = (Integer)(i.next());
+ assertEquals(m3, k);
+ assertFalse(i.hasNext());
+ Iterator j = sm.iterator();
+ j.next();
+ j.remove();
+ assertFalse(set.contains(m2));
+ assertEquals(4, set.size());
+ assertEquals(1, sm.size());
+ assertEquals(m3, sm.first());
+ assertEquals(m3, sm.last());
+ assertTrue(sm.remove(m3));
+ assertTrue(sm.isEmpty());
+ assertEquals(3, set.size());
+ }
+
+ public void testDescendingSubSetContents2() {
+ NavigableSet set = dset5();
+ SortedSet sm = set.subSet(m2, m3);
+ assertEquals(1, sm.size());
+ assertEquals(m2, sm.first());
+ assertEquals(m2, sm.last());
+ assertFalse(sm.contains(m1));
+ assertTrue(sm.contains(m2));
+ assertFalse(sm.contains(m3));
+ assertFalse(sm.contains(m4));
+ assertFalse(sm.contains(m5));
+ Iterator i = sm.iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(m2, k);
+ assertFalse(i.hasNext());
+ Iterator j = sm.iterator();
+ j.next();
+ j.remove();
+ assertFalse(set.contains(m2));
+ assertEquals(4, set.size());
+ assertEquals(0, sm.size());
+ assertTrue(sm.isEmpty());
+ assertFalse(sm.remove(m3));
+ assertEquals(4, set.size());
+ }
+
+ /**
+ * headSet returns set with keys in requested range
+ */
+ public void testDescendingHeadSetContents() {
+ NavigableSet set = dset5();
+ SortedSet sm = set.headSet(m4);
+ assertTrue(sm.contains(m1));
+ assertTrue(sm.contains(m2));
+ assertTrue(sm.contains(m3));
+ assertFalse(sm.contains(m4));
+ assertFalse(sm.contains(m5));
+ Iterator i = sm.iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(m1, k);
+ k = (Integer)(i.next());
+ assertEquals(m2, k);
+ k = (Integer)(i.next());
+ assertEquals(m3, k);
+ assertFalse(i.hasNext());
+ sm.clear();
+ assertTrue(sm.isEmpty());
+ assertEquals(2, set.size());
+ assertEquals(m4, set.first());
+ }
+
+ /**
+ * tailSet returns set with keys in requested range
+ */
+ public void testDescendingTailSetContents() {
+ NavigableSet set = dset5();
+ SortedSet sm = set.tailSet(m2);
+ assertFalse(sm.contains(m1));
+ assertTrue(sm.contains(m2));
+ assertTrue(sm.contains(m3));
+ assertTrue(sm.contains(m4));
+ assertTrue(sm.contains(m5));
+ Iterator i = sm.iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(m2, k);
+ k = (Integer)(i.next());
+ assertEquals(m3, k);
+ k = (Integer)(i.next());
+ assertEquals(m4, k);
+ k = (Integer)(i.next());
+ assertEquals(m5, k);
+ assertFalse(i.hasNext());
+
+ SortedSet ssm = sm.tailSet(m4);
+ assertEquals(m4, ssm.first());
+ assertEquals(m5, ssm.last());
+ assertTrue(ssm.remove(m4));
+ assertEquals(1, ssm.size());
+ assertEquals(3, sm.size());
+ assertEquals(4, set.size());
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/CopyOnWriteArrayListTest.java b/jsr166-tests/src/test/java/jsr166/CopyOnWriteArrayListTest.java
new file mode 100644
index 0000000..6bef8be
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/CopyOnWriteArrayListTest.java
@@ -0,0 +1,705 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+import java.util.Vector;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+public class CopyOnWriteArrayListTest extends JSR166TestCase {
+
+ static CopyOnWriteArrayList<Integer> populatedArray(int n) {
+ CopyOnWriteArrayList<Integer> a = new CopyOnWriteArrayList<Integer>();
+ assertTrue(a.isEmpty());
+ for (int i = 0; i < n; i++)
+ a.add(i);
+ assertFalse(a.isEmpty());
+ assertEquals(n, a.size());
+ return a;
+ }
+
+ static CopyOnWriteArrayList<Integer> populatedArray(Integer[] elements) {
+ CopyOnWriteArrayList<Integer> a = new CopyOnWriteArrayList<Integer>();
+ assertTrue(a.isEmpty());
+ for (int i = 0; i < elements.length; i++)
+ a.add(elements[i]);
+ assertFalse(a.isEmpty());
+ assertEquals(elements.length, a.size());
+ return a;
+ }
+
+ /**
+ * a new list is empty
+ */
+ public void testConstructor() {
+ CopyOnWriteArrayList a = new CopyOnWriteArrayList();
+ assertTrue(a.isEmpty());
+ }
+
+ /**
+ * new list contains all elements of initializing array
+ */
+ public void testConstructor2() {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
+ CopyOnWriteArrayList a = new CopyOnWriteArrayList(ints);
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(ints[i], a.get(i));
+ }
+
+ /**
+ * new list contains all elements of initializing collection
+ */
+ public void testConstructor3() {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
+ CopyOnWriteArrayList a = new CopyOnWriteArrayList(Arrays.asList(ints));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(ints[i], a.get(i));
+ }
+
+ /**
+ * addAll adds each element from the given collection
+ */
+ public void testAddAll() {
+ CopyOnWriteArrayList full = populatedArray(3);
+ Vector v = new Vector();
+ v.add(three);
+ v.add(four);
+ v.add(five);
+ full.addAll(v);
+ assertEquals(6, full.size());
+ }
+
+ /**
+ * addAllAbsent adds each element from the given collection that did not
+ * already exist in the List
+ */
+ public void testAddAllAbsent() {
+ CopyOnWriteArrayList full = populatedArray(3);
+ Vector v = new Vector();
+ v.add(three);
+ v.add(four);
+ v.add(one); // will not add this element
+ full.addAllAbsent(v);
+ assertEquals(5, full.size());
+ }
+
+ /**
+ * addIfAbsent will not add the element if it already exists in the list
+ */
+ public void testAddIfAbsent() {
+ CopyOnWriteArrayList full = populatedArray(SIZE);
+ full.addIfAbsent(one);
+ assertEquals(SIZE, full.size());
+ }
+
+ /**
+ * addIfAbsent adds the element when it does not exist in the list
+ */
+ public void testAddIfAbsent2() {
+ CopyOnWriteArrayList full = populatedArray(SIZE);
+ full.addIfAbsent(three);
+ assertTrue(full.contains(three));
+ }
+
+ /**
+ * clear removes all elements from the list
+ */
+ public void testClear() {
+ CopyOnWriteArrayList full = populatedArray(SIZE);
+ full.clear();
+ assertEquals(0, full.size());
+ }
+
+ /**
+ * Cloned list is equal
+ */
+ public void testClone() {
+ CopyOnWriteArrayList l1 = populatedArray(SIZE);
+ CopyOnWriteArrayList l2 = (CopyOnWriteArrayList)(l1.clone());
+ assertEquals(l1, l2);
+ l1.clear();
+ assertFalse(l1.equals(l2));
+ }
+
+ /**
+ * contains is true for added elements
+ */
+ public void testContains() {
+ CopyOnWriteArrayList full = populatedArray(3);
+ assertTrue(full.contains(one));
+ assertFalse(full.contains(five));
+ }
+
+ /**
+ * adding at an index places it in the indicated index
+ */
+ public void testAddIndex() {
+ CopyOnWriteArrayList full = populatedArray(3);
+ full.add(0, m1);
+ assertEquals(4, full.size());
+ assertEquals(m1, full.get(0));
+ assertEquals(zero, full.get(1));
+
+ full.add(2, m2);
+ assertEquals(5, full.size());
+ assertEquals(m2, full.get(2));
+ assertEquals(two, full.get(4));
+ }
+
+ /**
+ * lists with same elements are equal and have same hashCode
+ */
+ public void testEquals() {
+ CopyOnWriteArrayList a = populatedArray(3);
+ CopyOnWriteArrayList b = populatedArray(3);
+ assertTrue(a.equals(b));
+ assertTrue(b.equals(a));
+ assertEquals(a.hashCode(), b.hashCode());
+ a.add(m1);
+ assertFalse(a.equals(b));
+ assertFalse(b.equals(a));
+ b.add(m1);
+ assertTrue(a.equals(b));
+ assertTrue(b.equals(a));
+ assertEquals(a.hashCode(), b.hashCode());
+ }
+
+ /**
+ * containsAll returns true for collection with subset of elements
+ */
+ public void testContainsAll() {
+ CopyOnWriteArrayList full = populatedArray(3);
+ Vector v = new Vector();
+ v.add(one);
+ v.add(two);
+ assertTrue(full.containsAll(v));
+ v.add(six);
+ assertFalse(full.containsAll(v));
+ }
+
+ /**
+ * get returns the value at the given index
+ */
+ public void testGet() {
+ CopyOnWriteArrayList full = populatedArray(3);
+ assertEquals(0, full.get(0));
+ }
+
+ /**
+ * indexOf gives the index for the given object
+ */
+ public void testIndexOf() {
+ CopyOnWriteArrayList full = populatedArray(3);
+ assertEquals(1, full.indexOf(one));
+ assertEquals(-1, full.indexOf("puppies"));
+ }
+
+ /**
+ * indexOf gives the index based on the given index
+ * at which to start searching
+ */
+ public void testIndexOf2() {
+ CopyOnWriteArrayList full = populatedArray(3);
+ assertEquals(1, full.indexOf(one, 0));
+ assertEquals(-1, full.indexOf(one, 2));
+ }
+
+ /**
+ * isEmpty returns true when empty, else false
+ */
+ public void testIsEmpty() {
+ CopyOnWriteArrayList empty = new CopyOnWriteArrayList();
+ CopyOnWriteArrayList full = populatedArray(SIZE);
+ assertTrue(empty.isEmpty());
+ assertFalse(full.isEmpty());
+ }
+
+ /**
+ * iterator() returns an iterator containing the elements of the
+ * list in insertion order
+ */
+ public void testIterator() {
+ Collection empty = new CopyOnWriteArrayList();
+ assertFalse(empty.iterator().hasNext());
+ try {
+ empty.iterator().next();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+
+ Integer[] elements = new Integer[SIZE];
+ for (int i = 0; i < SIZE; i++)
+ elements[i] = i;
+ Collections.shuffle(Arrays.asList(elements));
+ Collection<Integer> full = populatedArray(elements);
+
+ Iterator it = full.iterator();
+ for (int j = 0; j < SIZE; j++) {
+ assertTrue(it.hasNext());
+ assertEquals(elements[j], it.next());
+ }
+ assertFalse(it.hasNext());
+ try {
+ it.next();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * iterator.remove throws UnsupportedOperationException
+ */
+ public void testIteratorRemove() {
+ CopyOnWriteArrayList full = populatedArray(SIZE);
+ Iterator it = full.iterator();
+ it.next();
+ try {
+ it.remove();
+ shouldThrow();
+ } catch (UnsupportedOperationException success) {}
+ }
+
+ /**
+ * toString contains toString of elements
+ */
+ public void testToString() {
+ assertEquals("[]", new CopyOnWriteArrayList().toString());
+ CopyOnWriteArrayList full = populatedArray(3);
+ String s = full.toString();
+ for (int i = 0; i < 3; ++i)
+ assertTrue(s.contains(String.valueOf(i)));
+ assertEquals(new ArrayList(full).toString(),
+ full.toString());
+ }
+
+ /**
+ * lastIndexOf returns the index for the given object
+ */
+ public void testLastIndexOf1() {
+ CopyOnWriteArrayList full = populatedArray(3);
+ full.add(one);
+ full.add(three);
+ assertEquals(3, full.lastIndexOf(one));
+ assertEquals(-1, full.lastIndexOf(six));
+ }
+
+ /**
+ * lastIndexOf returns the index from the given starting point
+ */
+ public void testLastIndexOf2() {
+ CopyOnWriteArrayList full = populatedArray(3);
+ full.add(one);
+ full.add(three);
+ assertEquals(3, full.lastIndexOf(one, 4));
+ assertEquals(-1, full.lastIndexOf(three, 3));
+ }
+
+ /**
+ * listIterator traverses all elements
+ */
+ public void testListIterator1() {
+ CopyOnWriteArrayList full = populatedArray(SIZE);
+ ListIterator i = full.listIterator();
+ int j;
+ for (j = 0; i.hasNext(); j++)
+ assertEquals(j, i.next());
+ assertEquals(SIZE, j);
+ }
+
+ /**
+ * listIterator only returns those elements after the given index
+ */
+ public void testListIterator2() {
+ CopyOnWriteArrayList full = populatedArray(3);
+ ListIterator i = full.listIterator(1);
+ int j;
+ for (j = 0; i.hasNext(); j++)
+ assertEquals(j+1, i.next());
+ assertEquals(2, j);
+ }
+
+ /**
+ * remove(int) removes and returns the object at the given index
+ */
+ public void testRemove_int() {
+ int SIZE = 3;
+ for (int i = 0; i < SIZE; i++) {
+ CopyOnWriteArrayList full = populatedArray(SIZE);
+ assertEquals(i, full.remove(i));
+ assertEquals(SIZE - 1, full.size());
+ assertFalse(full.contains(new Integer(i)));
+ }
+ }
+
+ /**
+ * remove(Object) removes the object if found and returns true
+ */
+ public void testRemove_Object() {
+ int SIZE = 3;
+ for (int i = 0; i < SIZE; i++) {
+ CopyOnWriteArrayList full = populatedArray(SIZE);
+ assertFalse(full.remove(new Integer(-42)));
+ assertTrue(full.remove(new Integer(i)));
+ assertEquals(SIZE - 1, full.size());
+ assertFalse(full.contains(new Integer(i)));
+ }
+ CopyOnWriteArrayList x = new CopyOnWriteArrayList(Arrays.asList(4, 5, 6));
+ assertTrue(x.remove(new Integer(6)));
+ assertEquals(x, Arrays.asList(4, 5));
+ assertTrue(x.remove(new Integer(4)));
+ assertEquals(x, Arrays.asList(5));
+ assertTrue(x.remove(new Integer(5)));
+ assertEquals(x, Arrays.asList());
+ assertFalse(x.remove(new Integer(5)));
+ }
+
+ /**
+ * removeAll removes all elements from the given collection
+ */
+ public void testRemoveAll() {
+ CopyOnWriteArrayList full = populatedArray(3);
+ Vector v = new Vector();
+ v.add(one);
+ v.add(two);
+ full.removeAll(v);
+ assertEquals(1, full.size());
+ }
+
+ /**
+ * set changes the element at the given index
+ */
+ public void testSet() {
+ CopyOnWriteArrayList full = populatedArray(3);
+ assertEquals(2, full.set(2, four));
+ assertEquals(4, full.get(2));
+ }
+
+ /**
+ * size returns the number of elements
+ */
+ public void testSize() {
+ CopyOnWriteArrayList empty = new CopyOnWriteArrayList();
+ CopyOnWriteArrayList full = populatedArray(SIZE);
+ assertEquals(SIZE, full.size());
+ assertEquals(0, empty.size());
+ }
+
+ /**
+ * toArray() returns an Object array containing all elements from
+ * the list in insertion order
+ */
+ public void testToArray() {
+ Object[] a = new CopyOnWriteArrayList().toArray();
+ assertTrue(Arrays.equals(new Object[0], a));
+ assertSame(Object[].class, a.getClass());
+
+ Integer[] elements = new Integer[SIZE];
+ for (int i = 0; i < SIZE; i++)
+ elements[i] = i;
+ Collections.shuffle(Arrays.asList(elements));
+ Collection<Integer> full = populatedArray(elements);
+
+ assertTrue(Arrays.equals(elements, full.toArray()));
+ assertSame(Object[].class, full.toArray().getClass());
+ }
+
+ /**
+ * toArray(Integer array) returns an Integer array containing all
+ * elements from the list in insertion order
+ */
+ public void testToArray2() {
+ Collection empty = new CopyOnWriteArrayList();
+ Integer[] a;
+
+ a = new Integer[0];
+ assertSame(a, empty.toArray(a));
+
+ a = new Integer[SIZE/2];
+ Arrays.fill(a, 42);
+ assertSame(a, empty.toArray(a));
+ assertNull(a[0]);
+ for (int i = 1; i < a.length; i++)
+ assertEquals(42, (int) a[i]);
+
+ Integer[] elements = new Integer[SIZE];
+ for (int i = 0; i < SIZE; i++)
+ elements[i] = i;
+ Collections.shuffle(Arrays.asList(elements));
+ Collection<Integer> full = populatedArray(elements);
+
+ Arrays.fill(a, 42);
+ assertTrue(Arrays.equals(elements, full.toArray(a)));
+ for (int i = 0; i < a.length; i++)
+ assertEquals(42, (int) a[i]);
+ assertSame(Integer[].class, full.toArray(a).getClass());
+
+ a = new Integer[SIZE];
+ Arrays.fill(a, 42);
+ assertSame(a, full.toArray(a));
+ assertTrue(Arrays.equals(elements, a));
+
+ a = new Integer[2*SIZE];
+ Arrays.fill(a, 42);
+ assertSame(a, full.toArray(a));
+ assertTrue(Arrays.equals(elements, Arrays.copyOf(a, SIZE)));
+ assertNull(a[SIZE]);
+ for (int i = SIZE + 1; i < a.length; i++)
+ assertEquals(42, (int) a[i]);
+ }
+
+ /**
+ * sublists contains elements at indexes offset from their base
+ */
+ public void testSubList() {
+ CopyOnWriteArrayList a = populatedArray(10);
+ assertTrue(a.subList(1,1).isEmpty());
+ for (int j = 0; j < 9; ++j) {
+ for (int i = j ; i < 10; ++i) {
+ List b = a.subList(j,i);
+ for (int k = j; k < i; ++k) {
+ assertEquals(new Integer(k), b.get(k-j));
+ }
+ }
+ }
+
+ List s = a.subList(2, 5);
+ assertEquals(3, s.size());
+ s.set(2, m1);
+ assertEquals(a.get(4), m1);
+ s.clear();
+ assertEquals(7, a.size());
+ }
+
+ // Exception tests
+
+ /**
+ * toArray throws an ArrayStoreException when the given array
+ * can not store the objects inside the list
+ */
+ public void testToArray_ArrayStoreException() {
+ try {
+ CopyOnWriteArrayList c = new CopyOnWriteArrayList();
+ c.add("zfasdfsdf");
+ c.add("asdadasd");
+ c.toArray(new Long[5]);
+ shouldThrow();
+ } catch (ArrayStoreException success) {}
+ }
+
+ /**
+ * get throws an IndexOutOfBoundsException on a negative index
+ */
+ public void testGet1_IndexOutOfBoundsException() {
+ try {
+ CopyOnWriteArrayList c = new CopyOnWriteArrayList();
+ c.get(-1);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
+
+ /**
+ * get throws an IndexOutOfBoundsException on a too high index
+ */
+ public void testGet2_IndexOutOfBoundsException() {
+ try {
+ CopyOnWriteArrayList c = new CopyOnWriteArrayList();
+ c.add("asdasd");
+ c.add("asdad");
+ c.get(100);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
+
+ /**
+ * set throws an IndexOutOfBoundsException on a negative index
+ */
+ public void testSet1_IndexOutOfBoundsException() {
+ try {
+ CopyOnWriteArrayList c = new CopyOnWriteArrayList();
+ c.set(-1,"qwerty");
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
+
+ /**
+ * set throws an IndexOutOfBoundsException on a too high index
+ */
+ public void testSet2() {
+ try {
+ CopyOnWriteArrayList c = new CopyOnWriteArrayList();
+ c.add("asdasd");
+ c.add("asdad");
+ c.set(100, "qwerty");
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
+
+ /**
+ * add throws an IndexOutOfBoundsException on a negative index
+ */
+ public void testAdd1_IndexOutOfBoundsException() {
+ try {
+ CopyOnWriteArrayList c = new CopyOnWriteArrayList();
+ c.add(-1,"qwerty");
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
+
+ /**
+ * add throws an IndexOutOfBoundsException on a too high index
+ */
+ public void testAdd2_IndexOutOfBoundsException() {
+ try {
+ CopyOnWriteArrayList c = new CopyOnWriteArrayList();
+ c.add("asdasd");
+ c.add("asdasdasd");
+ c.add(100, "qwerty");
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
+
+ /**
+ * remove throws an IndexOutOfBoundsException on a negative index
+ */
+ public void testRemove1_IndexOutOfBounds() {
+ try {
+ CopyOnWriteArrayList c = new CopyOnWriteArrayList();
+ c.remove(-1);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
+
+ /**
+ * remove throws an IndexOutOfBoundsException on a too high index
+ */
+ public void testRemove2_IndexOutOfBounds() {
+ try {
+ CopyOnWriteArrayList c = new CopyOnWriteArrayList();
+ c.add("asdasd");
+ c.add("adasdasd");
+ c.remove(100);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
+
+ /**
+ * addAll throws an IndexOutOfBoundsException on a negative index
+ */
+ public void testAddAll1_IndexOutOfBoundsException() {
+ try {
+ CopyOnWriteArrayList c = new CopyOnWriteArrayList();
+ c.addAll(-1,new LinkedList());
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
+
+ /**
+ * addAll throws an IndexOutOfBoundsException on a too high index
+ */
+ public void testAddAll2_IndexOutOfBoundsException() {
+ try {
+ CopyOnWriteArrayList c = new CopyOnWriteArrayList();
+ c.add("asdasd");
+ c.add("asdasdasd");
+ c.addAll(100, new LinkedList());
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
+
+ /**
+ * listIterator throws an IndexOutOfBoundsException on a negative index
+ */
+ public void testListIterator1_IndexOutOfBoundsException() {
+ try {
+ CopyOnWriteArrayList c = new CopyOnWriteArrayList();
+ c.listIterator(-1);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
+
+ /**
+ * listIterator throws an IndexOutOfBoundsException on a too high index
+ */
+ public void testListIterator2_IndexOutOfBoundsException() {
+ try {
+ CopyOnWriteArrayList c = new CopyOnWriteArrayList();
+ c.add("adasd");
+ c.add("asdasdas");
+ c.listIterator(100);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
+
+ /**
+ * subList throws an IndexOutOfBoundsException on a negative index
+ */
+ public void testSubList1_IndexOutOfBoundsException() {
+ try {
+ CopyOnWriteArrayList c = new CopyOnWriteArrayList();
+ c.subList(-1,100);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
+
+ /**
+ * subList throws an IndexOutOfBoundsException on a too high index
+ */
+ public void testSubList2_IndexOutOfBoundsException() {
+ try {
+ CopyOnWriteArrayList c = new CopyOnWriteArrayList();
+ c.add("asdasd");
+ c.subList(1,100);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
+
+ /**
+ * subList throws IndexOutOfBoundsException when the second index
+ * is lower then the first
+ */
+ public void testSubList3_IndexOutOfBoundsException() {
+ try {
+ CopyOnWriteArrayList c = new CopyOnWriteArrayList();
+ c.subList(3,1);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
+
+ /**
+ * a deserialized serialized list is equal
+ */
+ public void testSerialization() throws Exception {
+ List x = populatedArray(SIZE);
+ List y = serialClone(x);
+
+ assertNotSame(x, y);
+ assertEquals(x.size(), y.size());
+ assertEquals(x.toString(), y.toString());
+ assertTrue(Arrays.equals(x.toArray(), y.toArray()));
+ assertEquals(x, y);
+ assertEquals(y, x);
+ while (!x.isEmpty()) {
+ assertFalse(y.isEmpty());
+ assertEquals(x.remove(0), y.remove(0));
+ }
+ assertTrue(y.isEmpty());
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/CopyOnWriteArraySetTest.java b/jsr166-tests/src/test/java/jsr166/CopyOnWriteArraySetTest.java
new file mode 100644
index 0000000..feb283f
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/CopyOnWriteArraySetTest.java
@@ -0,0 +1,359 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.Vector;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+public class CopyOnWriteArraySetTest extends JSR166TestCase {
+
+ static CopyOnWriteArraySet<Integer> populatedSet(int n) {
+ CopyOnWriteArraySet<Integer> a = new CopyOnWriteArraySet<Integer>();
+ assertTrue(a.isEmpty());
+ for (int i = 0; i < n; i++)
+ a.add(i);
+ assertFalse(a.isEmpty());
+ assertEquals(n, a.size());
+ return a;
+ }
+
+ static CopyOnWriteArraySet populatedSet(Integer[] elements) {
+ CopyOnWriteArraySet<Integer> a = new CopyOnWriteArraySet<Integer>();
+ assertTrue(a.isEmpty());
+ for (int i = 0; i < elements.length; i++)
+ a.add(elements[i]);
+ assertFalse(a.isEmpty());
+ assertEquals(elements.length, a.size());
+ return a;
+ }
+
+ /**
+ * Default-constructed set is empty
+ */
+ public void testConstructor() {
+ CopyOnWriteArraySet a = new CopyOnWriteArraySet();
+ assertTrue(a.isEmpty());
+ }
+
+ /**
+ * Collection-constructed set holds all of its elements
+ */
+ public void testConstructor3() {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
+ CopyOnWriteArraySet a = new CopyOnWriteArraySet(Arrays.asList(ints));
+ for (int i = 0; i < SIZE; ++i)
+ assertTrue(a.contains(ints[i]));
+ }
+
+ /**
+ * addAll adds each element from the given collection
+ */
+ public void testAddAll() {
+ CopyOnWriteArraySet full = populatedSet(3);
+ Vector v = new Vector();
+ v.add(three);
+ v.add(four);
+ v.add(five);
+ full.addAll(v);
+ assertEquals(6, full.size());
+ }
+
+ /**
+ * addAll adds each element from the given collection that did not
+ * already exist in the set
+ */
+ public void testAddAll2() {
+ CopyOnWriteArraySet full = populatedSet(3);
+ Vector v = new Vector();
+ v.add(three);
+ v.add(four);
+ v.add(one); // will not add this element
+ full.addAll(v);
+ assertEquals(5, full.size());
+ }
+
+ /**
+ * add will not add the element if it already exists in the set
+ */
+ public void testAdd2() {
+ CopyOnWriteArraySet full = populatedSet(3);
+ full.add(one);
+ assertEquals(3, full.size());
+ }
+
+ /**
+ * add adds the element when it does not exist in the set
+ */
+ public void testAdd3() {
+ CopyOnWriteArraySet full = populatedSet(3);
+ full.add(three);
+ assertTrue(full.contains(three));
+ }
+
+ /**
+ * clear removes all elements from the set
+ */
+ public void testClear() {
+ CopyOnWriteArraySet full = populatedSet(3);
+ full.clear();
+ assertEquals(0, full.size());
+ }
+
+ /**
+ * contains returns true for added elements
+ */
+ public void testContains() {
+ CopyOnWriteArraySet full = populatedSet(3);
+ assertTrue(full.contains(one));
+ assertFalse(full.contains(five));
+ }
+
+ /**
+ * Sets with equal elements are equal
+ */
+ public void testEquals() {
+ CopyOnWriteArraySet a = populatedSet(3);
+ CopyOnWriteArraySet b = populatedSet(3);
+ assertTrue(a.equals(b));
+ assertTrue(b.equals(a));
+ assertEquals(a.hashCode(), b.hashCode());
+ a.add(m1);
+ assertFalse(a.equals(b));
+ assertFalse(b.equals(a));
+ b.add(m1);
+ assertTrue(a.equals(b));
+ assertTrue(b.equals(a));
+ assertEquals(a.hashCode(), b.hashCode());
+ }
+
+ /**
+ * containsAll returns true for collections with subset of elements
+ */
+ public void testContainsAll() {
+ CopyOnWriteArraySet full = populatedSet(3);
+ Vector v = new Vector();
+ v.add(one);
+ v.add(two);
+ assertTrue(full.containsAll(v));
+ v.add(six);
+ assertFalse(full.containsAll(v));
+ }
+
+ /**
+ * isEmpty is true when empty, else false
+ */
+ public void testIsEmpty() {
+ CopyOnWriteArraySet empty = new CopyOnWriteArraySet();
+ CopyOnWriteArraySet full = populatedSet(3);
+ assertTrue(empty.isEmpty());
+ assertFalse(full.isEmpty());
+ }
+
+ /**
+ * iterator() returns an iterator containing the elements of the
+ * set in insertion order
+ */
+ public void testIterator() {
+ Collection empty = new CopyOnWriteArraySet();
+ assertFalse(empty.iterator().hasNext());
+ try {
+ empty.iterator().next();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+
+ Integer[] elements = new Integer[SIZE];
+ for (int i = 0; i < SIZE; i++)
+ elements[i] = i;
+ Collections.shuffle(Arrays.asList(elements));
+ Collection<Integer> full = populatedSet(elements);
+
+ Iterator it = full.iterator();
+ for (int j = 0; j < SIZE; j++) {
+ assertTrue(it.hasNext());
+ assertEquals(elements[j], it.next());
+ }
+ assertFalse(it.hasNext());
+ try {
+ it.next();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * iterator remove is unsupported
+ */
+ public void testIteratorRemove() {
+ CopyOnWriteArraySet full = populatedSet(3);
+ Iterator it = full.iterator();
+ it.next();
+ try {
+ it.remove();
+ shouldThrow();
+ } catch (UnsupportedOperationException success) {}
+ }
+
+ /**
+ * toString holds toString of elements
+ */
+ public void testToString() {
+ assertEquals("[]", new CopyOnWriteArraySet().toString());
+ CopyOnWriteArraySet full = populatedSet(3);
+ String s = full.toString();
+ for (int i = 0; i < 3; ++i)
+ assertTrue(s.contains(String.valueOf(i)));
+ assertEquals(new ArrayList(full).toString(),
+ full.toString());
+ }
+
+ /**
+ * removeAll removes all elements from the given collection
+ */
+ public void testRemoveAll() {
+ CopyOnWriteArraySet full = populatedSet(3);
+ Vector v = new Vector();
+ v.add(one);
+ v.add(two);
+ full.removeAll(v);
+ assertEquals(1, full.size());
+ }
+
+ /**
+ * remove removes an element
+ */
+ public void testRemove() {
+ CopyOnWriteArraySet full = populatedSet(3);
+ full.remove(one);
+ assertFalse(full.contains(one));
+ assertEquals(2, full.size());
+ }
+
+ /**
+ * size returns the number of elements
+ */
+ public void testSize() {
+ CopyOnWriteArraySet empty = new CopyOnWriteArraySet();
+ CopyOnWriteArraySet full = populatedSet(3);
+ assertEquals(3, full.size());
+ assertEquals(0, empty.size());
+ }
+
+ /**
+ * toArray() returns an Object array containing all elements from
+ * the set in insertion order
+ */
+ public void testToArray() {
+ Object[] a = new CopyOnWriteArraySet().toArray();
+ assertTrue(Arrays.equals(new Object[0], a));
+ assertSame(Object[].class, a.getClass());
+
+ Integer[] elements = new Integer[SIZE];
+ for (int i = 0; i < SIZE; i++)
+ elements[i] = i;
+ Collections.shuffle(Arrays.asList(elements));
+ Collection<Integer> full = populatedSet(elements);
+
+ assertTrue(Arrays.equals(elements, full.toArray()));
+ assertSame(Object[].class, full.toArray().getClass());
+ }
+
+ /**
+ * toArray(Integer array) returns an Integer array containing all
+ * elements from the set in insertion order
+ */
+ public void testToArray2() {
+ Collection empty = new CopyOnWriteArraySet();
+ Integer[] a;
+
+ a = new Integer[0];
+ assertSame(a, empty.toArray(a));
+
+ a = new Integer[SIZE/2];
+ Arrays.fill(a, 42);
+ assertSame(a, empty.toArray(a));
+ assertNull(a[0]);
+ for (int i = 1; i < a.length; i++)
+ assertEquals(42, (int) a[i]);
+
+ Integer[] elements = new Integer[SIZE];
+ for (int i = 0; i < SIZE; i++)
+ elements[i] = i;
+ Collections.shuffle(Arrays.asList(elements));
+ Collection<Integer> full = populatedSet(elements);
+
+ Arrays.fill(a, 42);
+ assertTrue(Arrays.equals(elements, full.toArray(a)));
+ for (int i = 0; i < a.length; i++)
+ assertEquals(42, (int) a[i]);
+ assertSame(Integer[].class, full.toArray(a).getClass());
+
+ a = new Integer[SIZE];
+ Arrays.fill(a, 42);
+ assertSame(a, full.toArray(a));
+ assertTrue(Arrays.equals(elements, a));
+
+ a = new Integer[2*SIZE];
+ Arrays.fill(a, 42);
+ assertSame(a, full.toArray(a));
+ assertTrue(Arrays.equals(elements, Arrays.copyOf(a, SIZE)));
+ assertNull(a[SIZE]);
+ for (int i = SIZE + 1; i < a.length; i++)
+ assertEquals(42, (int) a[i]);
+ }
+
+ /**
+ * toArray throws an ArrayStoreException when the given array can
+ * not store the objects inside the set
+ */
+ public void testToArray_ArrayStoreException() {
+ try {
+ CopyOnWriteArraySet c = new CopyOnWriteArraySet();
+ c.add("zfasdfsdf");
+ c.add("asdadasd");
+ c.toArray(new Long[5]);
+ shouldThrow();
+ } catch (ArrayStoreException success) {}
+ }
+
+ /**
+ * A deserialized serialized set is equal
+ */
+ public void testSerialization() throws Exception {
+ Set x = populatedSet(SIZE);
+ Set y = serialClone(x);
+
+ assertNotSame(y, x);
+ assertEquals(x.size(), y.size());
+ assertEquals(x.toString(), y.toString());
+ assertTrue(Arrays.equals(x.toArray(), y.toArray()));
+ assertEquals(x, y);
+ assertEquals(y, x);
+ }
+
+ /**
+ * addAll is idempotent
+ */
+ public void testAddAll_idempotent() throws Exception {
+ Set x = populatedSet(SIZE);
+ Set y = new CopyOnWriteArraySet(x);
+ y.addAll(x);
+ assertEquals(x, y);
+ assertEquals(y, x);
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/CountDownLatchTest.java b/jsr166-tests/src/test/java/jsr166/CountDownLatchTest.java
new file mode 100644
index 0000000..bc2aecf
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/CountDownLatchTest.java
@@ -0,0 +1,190 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.*;
+import java.util.concurrent.CountDownLatch;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+public class CountDownLatchTest extends JSR166TestCase {
+
+ /**
+ * negative constructor argument throws IAE
+ */
+ public void testConstructor() {
+ try {
+ new CountDownLatch(-1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * getCount returns initial count and decreases after countDown
+ */
+ public void testGetCount() {
+ final CountDownLatch l = new CountDownLatch(2);
+ assertEquals(2, l.getCount());
+ l.countDown();
+ assertEquals(1, l.getCount());
+ }
+
+ /**
+ * countDown decrements count when positive and has no effect when zero
+ */
+ public void testCountDown() {
+ final CountDownLatch l = new CountDownLatch(1);
+ assertEquals(1, l.getCount());
+ l.countDown();
+ assertEquals(0, l.getCount());
+ l.countDown();
+ assertEquals(0, l.getCount());
+ }
+
+ /**
+ * await returns after countDown to zero, but not before
+ */
+ public void testAwait() {
+ final CountDownLatch l = new CountDownLatch(2);
+ final CountDownLatch pleaseCountDown = new CountDownLatch(1);
+
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertEquals(2, l.getCount());
+ pleaseCountDown.countDown();
+ l.await();
+ assertEquals(0, l.getCount());
+ }});
+
+ await(pleaseCountDown);
+ assertEquals(2, l.getCount());
+ l.countDown();
+ assertEquals(1, l.getCount());
+ assertThreadStaysAlive(t);
+ l.countDown();
+ assertEquals(0, l.getCount());
+ awaitTermination(t);
+ }
+
+ /**
+ * timed await returns after countDown to zero
+ */
+ public void testTimedAwait() {
+ final CountDownLatch l = new CountDownLatch(2);
+ final CountDownLatch pleaseCountDown = new CountDownLatch(1);
+
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertEquals(2, l.getCount());
+ pleaseCountDown.countDown();
+ assertTrue(l.await(LONG_DELAY_MS, MILLISECONDS));
+ assertEquals(0, l.getCount());
+ }});
+
+ await(pleaseCountDown);
+ assertEquals(2, l.getCount());
+ l.countDown();
+ assertEquals(1, l.getCount());
+ assertThreadStaysAlive(t);
+ l.countDown();
+ assertEquals(0, l.getCount());
+ awaitTermination(t);
+ }
+
+ /**
+ * await throws IE if interrupted before counted down
+ */
+ public void testAwait_Interruptible() {
+ final CountDownLatch l = new CountDownLatch(1);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ Thread.currentThread().interrupt();
+ try {
+ l.await();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ l.await();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ assertEquals(1, l.getCount());
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * timed await throws IE if interrupted before counted down
+ */
+ public void testTimedAwait_Interruptible() {
+ final CountDownLatch l = new CountDownLatch(1);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ Thread.currentThread().interrupt();
+ try {
+ l.await(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ l.await(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ assertEquals(1, l.getCount());
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * timed await times out if not counted down before timeout
+ */
+ public void testAwaitTimeout() throws InterruptedException {
+ final CountDownLatch l = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertEquals(1, l.getCount());
+ assertFalse(l.await(timeoutMillis(), MILLISECONDS));
+ assertEquals(1, l.getCount());
+ }});
+
+ awaitTermination(t);
+ assertEquals(1, l.getCount());
+ }
+
+ /**
+ * toString indicates current count
+ */
+ public void testToString() {
+ CountDownLatch s = new CountDownLatch(2);
+ assertTrue(s.toString().contains("Count = 2"));
+ s.countDown();
+ assertTrue(s.toString().contains("Count = 1"));
+ s.countDown();
+ assertTrue(s.toString().contains("Count = 0"));
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/CountedCompleterTest.java b/jsr166-tests/src/test/java/jsr166/CountedCompleterTest.java
new file mode 100644
index 0000000..2f8665b
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/CountedCompleterTest.java
@@ -0,0 +1,1821 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package jsr166;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.ForkJoinTask;
+import java.util.concurrent.CountedCompleter;
+import java.util.concurrent.ForkJoinWorkerThread;
+import java.util.concurrent.RecursiveAction;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
+import java.util.concurrent.atomic.AtomicReference;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import java.util.HashSet;
+import junit.framework.*;
+
+public class CountedCompleterTest extends JSR166TestCase {
+
+ // Runs with "mainPool" use > 1 thread. singletonPool tests use 1
+ static final int mainPoolSize =
+ Math.max(2, Runtime.getRuntime().availableProcessors());
+
+ private static ForkJoinPool mainPool() {
+ return new ForkJoinPool(mainPoolSize);
+ }
+
+ private static ForkJoinPool singletonPool() {
+ return new ForkJoinPool(1);
+ }
+
+ private static ForkJoinPool asyncSingletonPool() {
+ return new ForkJoinPool(1,
+ ForkJoinPool.defaultForkJoinWorkerThreadFactory,
+ null, true);
+ }
+
+ private void testInvokeOnPool(ForkJoinPool pool, ForkJoinTask a) {
+ try {
+ assertFalse(a.isDone());
+ assertFalse(a.isCompletedNormally());
+ assertFalse(a.isCompletedAbnormally());
+ assertFalse(a.isCancelled());
+ assertNull(a.getException());
+ assertNull(a.getRawResult());
+
+ assertNull(pool.invoke(a));
+
+ assertTrue(a.isDone());
+ assertTrue(a.isCompletedNormally());
+ assertFalse(a.isCompletedAbnormally());
+ assertFalse(a.isCancelled());
+ assertNull(a.getException());
+ assertNull(a.getRawResult());
+ } finally {
+ joinPool(pool);
+ }
+ }
+
+ void checkNotDone(CountedCompleter a) {
+ assertFalse(a.isDone());
+ assertFalse(a.isCompletedNormally());
+ assertFalse(a.isCompletedAbnormally());
+ assertFalse(a.isCancelled());
+ assertNull(a.getException());
+ assertNull(a.getRawResult());
+
+ try {
+ a.get(0L, SECONDS);
+ shouldThrow();
+ } catch (TimeoutException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ void checkCompletedNormally(CountedCompleter<?> a) {
+ assertTrue(a.isDone());
+ assertFalse(a.isCancelled());
+ assertTrue(a.isCompletedNormally());
+ assertFalse(a.isCompletedAbnormally());
+ assertNull(a.getException());
+ assertNull(a.getRawResult());
+
+ {
+ Thread.currentThread().interrupt();
+ long t0 = System.nanoTime();
+ assertNull(a.join());
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
+ Thread.interrupted();
+ }
+
+ {
+ Thread.currentThread().interrupt();
+ long t0 = System.nanoTime();
+ a.quietlyJoin(); // should be no-op
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
+ Thread.interrupted();
+ }
+
+ assertFalse(a.cancel(false));
+ assertFalse(a.cancel(true));
+ try {
+ assertNull(a.get());
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ try {
+ assertNull(a.get(5L, SECONDS));
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ void checkCancelled(CountedCompleter a) {
+ assertTrue(a.isDone());
+ assertTrue(a.isCancelled());
+ assertFalse(a.isCompletedNormally());
+ assertTrue(a.isCompletedAbnormally());
+ assertTrue(a.getException() instanceof CancellationException);
+ assertNull(a.getRawResult());
+ assertTrue(a.cancel(false));
+ assertTrue(a.cancel(true));
+
+ try {
+ Thread.currentThread().interrupt();
+ a.join();
+ shouldThrow();
+ } catch (CancellationException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ Thread.interrupted();
+
+ {
+ long t0 = System.nanoTime();
+ a.quietlyJoin(); // should be no-op
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
+ }
+
+ try {
+ a.get();
+ shouldThrow();
+ } catch (CancellationException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+
+ try {
+ a.get(5L, SECONDS);
+ shouldThrow();
+ } catch (CancellationException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ void checkCompletedAbnormally(CountedCompleter a, Throwable t) {
+ assertTrue(a.isDone());
+ assertFalse(a.isCancelled());
+ assertFalse(a.isCompletedNormally());
+ assertTrue(a.isCompletedAbnormally());
+ assertSame(t.getClass(), a.getException().getClass());
+ assertNull(a.getRawResult());
+ assertFalse(a.cancel(false));
+ assertFalse(a.cancel(true));
+
+ try {
+ Thread.currentThread().interrupt();
+ a.join();
+ shouldThrow();
+ } catch (Throwable expected) {
+ assertSame(t.getClass(), expected.getClass());
+ }
+ Thread.interrupted();
+
+ {
+ long t0 = System.nanoTime();
+ a.quietlyJoin(); // should be no-op
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
+ }
+
+ try {
+ a.get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertSame(t.getClass(), success.getCause().getClass());
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+
+ try {
+ a.get(5L, SECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertSame(t.getClass(), success.getCause().getClass());
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+
+ try {
+ a.invoke();
+ shouldThrow();
+ } catch (Throwable ex) {
+ assertSame(t, ex);
+ }
+ }
+
+ public static final class FJException extends RuntimeException {
+ FJException() { super(); }
+ }
+
+ abstract class CheckedCC extends CountedCompleter<Object> {
+ final AtomicInteger computeN = new AtomicInteger(0);
+ final AtomicInteger onCompletionN = new AtomicInteger(0);
+ final AtomicInteger onExceptionalCompletionN = new AtomicInteger(0);
+ final AtomicInteger setRawResultN = new AtomicInteger(0);
+ final AtomicReference<Object> rawResult = new AtomicReference<Object>(null);
+ int computeN() { return computeN.get(); }
+ int onCompletionN() { return onCompletionN.get(); }
+ int onExceptionalCompletionN() { return onExceptionalCompletionN.get(); }
+ int setRawResultN() { return setRawResultN.get(); }
+
+ CheckedCC() { super(); }
+ CheckedCC(CountedCompleter p) { super(p); }
+ CheckedCC(CountedCompleter p, int n) { super(p, n); }
+ abstract void realCompute();
+ public final void compute() {
+ computeN.incrementAndGet();
+ realCompute();
+ }
+ public void onCompletion(CountedCompleter caller) {
+ onCompletionN.incrementAndGet();
+ super.onCompletion(caller);
+ }
+ public boolean onExceptionalCompletion(Throwable ex,
+ CountedCompleter caller) {
+ onExceptionalCompletionN.incrementAndGet();
+ assertNotNull(ex);
+ assertTrue(isCompletedAbnormally());
+ assertTrue(super.onExceptionalCompletion(ex, caller));
+ return true;
+ }
+ protected void setRawResult(Object t) {
+ setRawResultN.incrementAndGet();
+ rawResult.set(t);
+ super.setRawResult(t);
+ }
+ void checkIncomplete() {
+ assertEquals(0, computeN());
+ assertEquals(0, onCompletionN());
+ assertEquals(0, onExceptionalCompletionN());
+ assertEquals(0, setRawResultN());
+ checkNotDone(this);
+ }
+ void checkCompletes(Object rawResult) {
+ checkIncomplete();
+ int pendingCount = getPendingCount();
+ complete(rawResult);
+ assertEquals(pendingCount, getPendingCount());
+ assertEquals(0, computeN());
+ assertEquals(1, onCompletionN());
+ assertEquals(0, onExceptionalCompletionN());
+ assertEquals(1, setRawResultN());
+ assertSame(rawResult, this.rawResult.get());
+ checkCompletedNormally(this);
+ }
+ void checkCompletesExceptionally(Throwable ex) {
+ checkIncomplete();
+ completeExceptionally(ex);
+ checkCompletedExceptionally(ex);
+ }
+ void checkCompletedExceptionally(Throwable ex) {
+ assertEquals(0, computeN());
+ assertEquals(0, onCompletionN());
+ assertEquals(1, onExceptionalCompletionN());
+ assertEquals(0, setRawResultN());
+ assertNull(this.rawResult.get());
+ checkCompletedAbnormally(this, ex);
+ }
+ }
+
+ final class NoopCC extends CheckedCC {
+ NoopCC() { super(); }
+ NoopCC(CountedCompleter p) { super(p); }
+ protected void realCompute() {}
+ }
+
+ /**
+ * A newly constructed CountedCompleter is not completed;
+ * complete() causes completion. pendingCount is ignored.
+ */
+ public void testComplete() {
+ for (Object x : new Object[] { Boolean.TRUE, null }) {
+ for (int pendingCount : new int[] { 0, 42 }) {
+ testComplete(new NoopCC(), x, pendingCount);
+ testComplete(new NoopCC(new NoopCC()), x, pendingCount);
+ }
+ }
+ }
+ void testComplete(NoopCC cc, Object x, int pendingCount) {
+ cc.setPendingCount(pendingCount);
+ cc.checkCompletes(x);
+ }
+
+ /**
+ * completeExceptionally completes exceptionally
+ */
+ public void testCompleteExceptionally() {
+ new NoopCC()
+ .checkCompletesExceptionally(new FJException());
+ new NoopCC(new NoopCC())
+ .checkCompletesExceptionally(new FJException());
+ }
+
+ /**
+ * completeExceptionally(null) throws NullPointerException
+ */
+ public void testCompleteExceptionally_null() {
+ try {
+ new NoopCC()
+ .checkCompletesExceptionally(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * setPendingCount sets the reported pending count
+ */
+ public void testSetPendingCount() {
+ NoopCC a = new NoopCC();
+ assertEquals(0, a.getPendingCount());
+ a.setPendingCount(1);
+ assertEquals(1, a.getPendingCount());
+ a.setPendingCount(27);
+ assertEquals(27, a.getPendingCount());
+ }
+
+ /**
+ * addToPendingCount adds to the reported pending count
+ */
+ public void testAddToPendingCount() {
+ NoopCC a = new NoopCC();
+ assertEquals(0, a.getPendingCount());
+ a.addToPendingCount(1);
+ assertEquals(1, a.getPendingCount());
+ a.addToPendingCount(27);
+ assertEquals(28, a.getPendingCount());
+ }
+
+ /**
+ * decrementPendingCountUnlessZero decrements reported pending
+ * count unless zero
+ */
+ public void testDecrementPendingCount() {
+ NoopCC a = new NoopCC();
+ assertEquals(0, a.getPendingCount());
+ a.addToPendingCount(1);
+ assertEquals(1, a.getPendingCount());
+ a.decrementPendingCountUnlessZero();
+ assertEquals(0, a.getPendingCount());
+ a.decrementPendingCountUnlessZero();
+ assertEquals(0, a.getPendingCount());
+ }
+
+ /**
+ * compareAndSetPendingCount compares and sets the reported
+ * pending count
+ */
+ public void testCompareAndSetPendingCount() {
+ NoopCC a = new NoopCC();
+ assertEquals(0, a.getPendingCount());
+ assertTrue(a.compareAndSetPendingCount(0, 1));
+ assertEquals(1, a.getPendingCount());
+ assertTrue(a.compareAndSetPendingCount(1, 2));
+ assertEquals(2, a.getPendingCount());
+ assertFalse(a.compareAndSetPendingCount(1, 3));
+ assertEquals(2, a.getPendingCount());
+ }
+
+ /**
+ * getCompleter returns parent or null if at root
+ */
+ public void testGetCompleter() {
+ NoopCC a = new NoopCC();
+ assertNull(a.getCompleter());
+ CountedCompleter b = new NoopCC(a);
+ assertSame(a, b.getCompleter());
+ CountedCompleter c = new NoopCC(b);
+ assertSame(b, c.getCompleter());
+ }
+
+ /**
+ * getRoot returns self if no parent, else parent's root
+ */
+ public void testGetRoot() {
+ NoopCC a = new NoopCC();
+ NoopCC b = new NoopCC(a);
+ NoopCC c = new NoopCC(b);
+ assertSame(a, a.getRoot());
+ assertSame(a, b.getRoot());
+ assertSame(a, c.getRoot());
+ }
+
+ /**
+ * tryComplete decrements pending count unless zero, in which case
+ * causes completion
+ */
+ public void testTryComplete() {
+ NoopCC a = new NoopCC();
+ assertEquals(0, a.getPendingCount());
+ int n = 3;
+ a.setPendingCount(n);
+ for (; n > 0; n--) {
+ assertEquals(n, a.getPendingCount());
+ a.tryComplete();
+ a.checkIncomplete();
+ assertEquals(n - 1, a.getPendingCount());
+ }
+ a.tryComplete();
+ assertEquals(0, a.computeN());
+ assertEquals(1, a.onCompletionN());
+ assertEquals(0, a.onExceptionalCompletionN());
+ assertEquals(0, a.setRawResultN());
+ checkCompletedNormally(a);
+ }
+
+ /**
+ * propagateCompletion decrements pending count unless zero, in
+ * which case causes completion, without invoking onCompletion
+ */
+ public void testPropagateCompletion() {
+ NoopCC a = new NoopCC();
+ assertEquals(0, a.getPendingCount());
+ int n = 3;
+ a.setPendingCount(n);
+ for (; n > 0; n--) {
+ assertEquals(n, a.getPendingCount());
+ a.propagateCompletion();
+ a.checkIncomplete();
+ assertEquals(n - 1, a.getPendingCount());
+ }
+ a.propagateCompletion();
+ assertEquals(0, a.computeN());
+ assertEquals(0, a.onCompletionN());
+ assertEquals(0, a.onExceptionalCompletionN());
+ assertEquals(0, a.setRawResultN());
+ checkCompletedNormally(a);
+ }
+
+ /**
+ * firstComplete returns this if pending count is zero else null
+ */
+ public void testFirstComplete() {
+ NoopCC a = new NoopCC();
+ a.setPendingCount(1);
+ assertNull(a.firstComplete());
+ a.checkIncomplete();
+ assertSame(a, a.firstComplete());
+ a.checkIncomplete();
+ }
+
+ /**
+ * firstComplete.nextComplete returns parent if pending count is
+ * zero else null
+ */
+ public void testNextComplete() {
+ NoopCC a = new NoopCC();
+ NoopCC b = new NoopCC(a);
+ a.setPendingCount(1);
+ b.setPendingCount(1);
+ assertNull(b.firstComplete());
+ assertSame(b, b.firstComplete());
+ assertNull(b.nextComplete());
+ a.checkIncomplete();
+ b.checkIncomplete();
+ assertSame(a, b.nextComplete());
+ assertSame(a, b.nextComplete());
+ a.checkIncomplete();
+ b.checkIncomplete();
+ assertNull(a.nextComplete());
+ b.checkIncomplete();
+ checkCompletedNormally(a);
+ }
+
+ /**
+ * quietlyCompleteRoot completes root task
+ */
+ public void testQuietlyCompleteRoot() {
+ NoopCC a = new NoopCC();
+ NoopCC b = new NoopCC(a);
+ NoopCC c = new NoopCC(b);
+ a.setPendingCount(1);
+ b.setPendingCount(1);
+ c.setPendingCount(1);
+ c.quietlyCompleteRoot();
+ assertTrue(a.isDone());
+ assertFalse(b.isDone());
+ assertFalse(c.isDone());
+ }
+
+ // Invocation tests use some interdependent task classes
+ // to better test propagation etc
+
+
+ // Version of Fibonacci with different classes for left vs right forks
+ abstract class CCF extends CheckedCC {
+ int number;
+ int rnumber;
+
+ public CCF(CountedCompleter parent, int n) {
+ super(parent, 1);
+ this.number = n;
+ }
+
+ protected final void realCompute() {
+ CCF f = this;
+ int n = number;
+ while (n >= 2) {
+ new RCCF(f, n - 2).fork();
+ f = new LCCF(f, --n);
+ }
+ f.complete(null);
+ }
+ }
+
+ final class LCCF extends CCF {
+ public LCCF(int n) { this(null, n); }
+ public LCCF(CountedCompleter parent, int n) {
+ super(parent, n);
+ }
+ public final void onCompletion(CountedCompleter caller) {
+ super.onCompletion(caller);
+ CCF p = (CCF)getCompleter();
+ int n = number + rnumber;
+ if (p != null)
+ p.number = n;
+ else
+ number = n;
+ }
+ }
+ final class RCCF extends CCF {
+ public RCCF(CountedCompleter parent, int n) {
+ super(parent, n);
+ }
+ public final void onCompletion(CountedCompleter caller) {
+ super.onCompletion(caller);
+ CCF p = (CCF)getCompleter();
+ int n = number + rnumber;
+ if (p != null)
+ p.rnumber = n;
+ else
+ number = n;
+ }
+ }
+
+ // Version of CCF with forced failure in left completions
+ abstract class FailingCCF extends CheckedCC {
+ int number;
+ int rnumber;
+
+ public FailingCCF(CountedCompleter parent, int n) {
+ super(parent, 1);
+ this.number = n;
+ }
+
+ protected final void realCompute() {
+ FailingCCF f = this;
+ int n = number;
+ while (n >= 2) {
+ new RFCCF(f, n - 2).fork();
+ f = new LFCCF(f, --n);
+ }
+ f.complete(null);
+ }
+ }
+
+ final class LFCCF extends FailingCCF {
+ public LFCCF(int n) { this(null, n); }
+ public LFCCF(CountedCompleter parent, int n) {
+ super(parent, n);
+ }
+ public final void onCompletion(CountedCompleter caller) {
+ super.onCompletion(caller);
+ FailingCCF p = (FailingCCF)getCompleter();
+ int n = number + rnumber;
+ if (p != null)
+ p.number = n;
+ else
+ number = n;
+ }
+ }
+ final class RFCCF extends FailingCCF {
+ public RFCCF(CountedCompleter parent, int n) {
+ super(parent, n);
+ }
+ public final void onCompletion(CountedCompleter caller) {
+ super.onCompletion(caller);
+ completeExceptionally(new FJException());
+ }
+ }
+
+ /**
+ * invoke returns when task completes normally.
+ * isCompletedAbnormally and isCancelled return false for normally
+ * completed tasks; getRawResult returns null.
+ */
+ public void testInvoke() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ assertNull(f.invoke());
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * quietlyInvoke task returns when task completes normally.
+ * isCompletedAbnormally and isCancelled return false for normally
+ * completed tasks
+ */
+ public void testQuietlyInvoke() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ f.quietlyInvoke();
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * join of a forked task returns when task completes
+ */
+ public void testForkJoin() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ assertSame(f, f.fork());
+ assertNull(f.join());
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * get of a forked task returns when task completes
+ */
+ public void testForkGet() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ CCF f = new LCCF(8);
+ assertSame(f, f.fork());
+ assertNull(f.get());
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * timed get of a forked task returns when task completes
+ */
+ public void testForkTimedGet() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ CCF f = new LCCF(8);
+ assertSame(f, f.fork());
+ assertNull(f.get(LONG_DELAY_MS, MILLISECONDS));
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * timed get with null time unit throws NPE
+ */
+ public void testForkTimedGetNPE() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ CCF f = new LCCF(8);
+ assertSame(f, f.fork());
+ try {
+ f.get(5L, null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * quietlyJoin of a forked task returns when task completes
+ */
+ public void testForkQuietlyJoin() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ assertSame(f, f.fork());
+ f.quietlyJoin();
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * helpQuiesce returns when tasks are complete.
+ * getQueuedTaskCount returns 0 when quiescent
+ */
+ public void testForkHelpQuiesce() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ assertSame(f, f.fork());
+ helpQuiesce();
+ assertEquals(21, f.number);
+ assertEquals(0, getQueuedTaskCount());
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invoke task throws exception when task completes abnormally
+ */
+ public void testAbnormalInvoke() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingCCF f = new LFCCF(8);
+ try {
+ f.invoke();
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * quietlyInvoke task returns when task completes abnormally
+ */
+ public void testAbnormalQuietlyInvoke() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingCCF f = new LFCCF(8);
+ f.quietlyInvoke();
+ assertTrue(f.getException() instanceof FJException);
+ checkCompletedAbnormally(f, f.getException());
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * join of a forked task throws exception when task completes abnormally
+ */
+ public void testAbnormalForkJoin() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingCCF f = new LFCCF(8);
+ assertSame(f, f.fork());
+ try {
+ f.join();
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * get of a forked task throws exception when task completes abnormally
+ */
+ public void testAbnormalForkGet() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ FailingCCF f = new LFCCF(8);
+ assertSame(f, f.fork());
+ try {
+ f.get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ Throwable cause = success.getCause();
+ assertTrue(cause instanceof FJException);
+ checkCompletedAbnormally(f, cause);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * timed get of a forked task throws exception when task completes abnormally
+ */
+ public void testAbnormalForkTimedGet() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ FailingCCF f = new LFCCF(8);
+ assertSame(f, f.fork());
+ try {
+ f.get(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ Throwable cause = success.getCause();
+ assertTrue(cause instanceof FJException);
+ checkCompletedAbnormally(f, cause);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * quietlyJoin of a forked task returns when task completes abnormally
+ */
+ public void testAbnormalForkQuietlyJoin() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingCCF f = new LFCCF(8);
+ assertSame(f, f.fork());
+ f.quietlyJoin();
+ assertTrue(f.getException() instanceof FJException);
+ checkCompletedAbnormally(f, f.getException());
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invoke task throws exception when task cancelled
+ */
+ public void testCancelledInvoke() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ assertTrue(f.cancel(true));
+ try {
+ f.invoke();
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * join of a forked task throws exception when task cancelled
+ */
+ public void testCancelledForkJoin() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ try {
+ f.join();
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * get of a forked task throws exception when task cancelled
+ */
+ public void testCancelledForkGet() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ CCF f = new LCCF(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ try {
+ f.get();
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * timed get of a forked task throws exception when task cancelled
+ */
+ public void testCancelledForkTimedGet() throws Exception {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ CCF f = new LCCF(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ try {
+ f.get(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * quietlyJoin of a forked task returns when task cancelled
+ */
+ public void testCancelledForkQuietlyJoin() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ f.quietlyJoin();
+ checkCancelled(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * getPool of executing task returns its pool
+ */
+ public void testGetPool() {
+ final ForkJoinPool mainPool = mainPool();
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ assertSame(mainPool, getPool());
+ }};
+ testInvokeOnPool(mainPool, a);
+ }
+
+ /**
+ * getPool of non-FJ task returns null
+ */
+ public void testGetPool2() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ assertNull(getPool());
+ }};
+ assertNull(a.invoke());
+ }
+
+ /**
+ * inForkJoinPool of executing task returns true
+ */
+ public void testInForkJoinPool() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ assertTrue(inForkJoinPool());
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * inForkJoinPool of non-FJ task returns false
+ */
+ public void testInForkJoinPool2() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ assertFalse(inForkJoinPool());
+ }};
+ assertNull(a.invoke());
+ }
+
+ /**
+ * setRawResult(null) succeeds
+ */
+ public void testSetRawResult() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ setRawResult(null);
+ assertNull(getRawResult());
+ }};
+ assertNull(a.invoke());
+ }
+
+ /**
+ * invoke task throws exception after invoking completeExceptionally
+ */
+ public void testCompleteExceptionally2() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF n = new LCCF(8);
+ CCF f = new LCCF(n, 8);
+ FJException ex = new FJException();
+ f.completeExceptionally(ex);
+ f.checkCompletedExceptionally(ex);
+ n.checkCompletedExceptionally(ex);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(t1, t2) invokes all task arguments
+ */
+ public void testInvokeAll2() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ CCF g = new LCCF(9);
+ invokeAll(f, g);
+ assertEquals(21, f.number);
+ assertEquals(34, g.number);
+ checkCompletedNormally(f);
+ checkCompletedNormally(g);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with 1 argument invokes task
+ */
+ public void testInvokeAll1() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ invokeAll(f);
+ checkCompletedNormally(f);
+ assertEquals(21, f.number);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with > 2 argument invokes tasks
+ */
+ public void testInvokeAll3() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ CCF g = new LCCF(9);
+ CCF h = new LCCF(7);
+ invokeAll(f, g, h);
+ assertEquals(21, f.number);
+ assertEquals(34, g.number);
+ assertEquals(13, h.number);
+ checkCompletedNormally(f);
+ checkCompletedNormally(g);
+ checkCompletedNormally(h);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(collection) invokes all tasks in the collection
+ */
+ public void testInvokeAllCollection() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ CCF g = new LCCF(9);
+ CCF h = new LCCF(7);
+ HashSet set = new HashSet();
+ set.add(f);
+ set.add(g);
+ set.add(h);
+ invokeAll(set);
+ assertEquals(21, f.number);
+ assertEquals(34, g.number);
+ assertEquals(13, h.number);
+ checkCompletedNormally(f);
+ checkCompletedNormally(g);
+ checkCompletedNormally(h);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with any null task throws NPE
+ */
+ public void testInvokeAllNPE() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ CCF g = new LCCF(9);
+ CCF h = null;
+ try {
+ invokeAll(f, g, h);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(t1, t2) throw exception if any task does
+ */
+ public void testAbnormalInvokeAll2() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ FailingCCF g = new LFCCF(9);
+ try {
+ invokeAll(f, g);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(g, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with 1 argument throws exception if task does
+ */
+ public void testAbnormalInvokeAll1() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingCCF g = new LFCCF(9);
+ try {
+ invokeAll(g);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(g, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with > 2 argument throws exception if any task does
+ */
+ public void testAbnormalInvokeAll3() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ FailingCCF g = new LFCCF(9);
+ CCF h = new LCCF(7);
+ try {
+ invokeAll(f, g, h);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(g, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(collection) throws exception if any task does
+ */
+ public void testAbnormalInvokeAllCollection() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingCCF f = new LFCCF(8);
+ CCF g = new LCCF(9);
+ CCF h = new LCCF(7);
+ HashSet set = new HashSet();
+ set.add(f);
+ set.add(g);
+ set.add(h);
+ try {
+ invokeAll(set);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * tryUnfork returns true for most recent unexecuted task,
+ * and suppresses execution
+ */
+ public void testTryUnfork() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF g = new LCCF(9);
+ assertSame(g, g.fork());
+ CCF f = new LCCF(8);
+ assertSame(f, f.fork());
+ assertTrue(f.tryUnfork());
+ helpQuiesce();
+ checkNotDone(f);
+ checkCompletedNormally(g);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * getSurplusQueuedTaskCount returns > 0 when
+ * there are more tasks than threads
+ */
+ public void testGetSurplusQueuedTaskCount() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF h = new LCCF(7);
+ assertSame(h, h.fork());
+ CCF g = new LCCF(9);
+ assertSame(g, g.fork());
+ CCF f = new LCCF(8);
+ assertSame(f, f.fork());
+ assertTrue(getSurplusQueuedTaskCount() > 0);
+ helpQuiesce();
+ assertEquals(0, getSurplusQueuedTaskCount());
+ checkCompletedNormally(f);
+ checkCompletedNormally(g);
+ checkCompletedNormally(h);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * peekNextLocalTask returns most recent unexecuted task.
+ */
+ public void testPeekNextLocalTask() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF g = new LCCF(9);
+ assertSame(g, g.fork());
+ CCF f = new LCCF(8);
+ assertSame(f, f.fork());
+ assertSame(f, peekNextLocalTask());
+ assertNull(f.join());
+ checkCompletedNormally(f);
+ helpQuiesce();
+ checkCompletedNormally(g);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * pollNextLocalTask returns most recent unexecuted task without
+ * executing it
+ */
+ public void testPollNextLocalTask() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF g = new LCCF(9);
+ assertSame(g, g.fork());
+ CCF f = new LCCF(8);
+ assertSame(f, f.fork());
+ assertSame(f, pollNextLocalTask());
+ helpQuiesce();
+ checkNotDone(f);
+ assertEquals(34, g.number);
+ checkCompletedNormally(g);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * pollTask returns an unexecuted task without executing it
+ */
+ public void testPollTask() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF g = new LCCF(9);
+ assertSame(g, g.fork());
+ CCF f = new LCCF(8);
+ assertSame(f, f.fork());
+ assertSame(f, pollTask());
+ helpQuiesce();
+ checkNotDone(f);
+ checkCompletedNormally(g);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * peekNextLocalTask returns least recent unexecuted task in async mode
+ */
+ public void testPeekNextLocalTaskAsync() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF g = new LCCF(9);
+ assertSame(g, g.fork());
+ CCF f = new LCCF(8);
+ assertSame(f, f.fork());
+ assertSame(g, peekNextLocalTask());
+ assertNull(f.join());
+ helpQuiesce();
+ checkCompletedNormally(f);
+ assertEquals(34, g.number);
+ checkCompletedNormally(g);
+ }};
+ testInvokeOnPool(asyncSingletonPool(), a);
+ }
+
+ /**
+ * pollNextLocalTask returns least recent unexecuted task without
+ * executing it, in async mode
+ */
+ public void testPollNextLocalTaskAsync() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF g = new LCCF(9);
+ assertSame(g, g.fork());
+ CCF f = new LCCF(8);
+ assertSame(f, f.fork());
+ assertSame(g, pollNextLocalTask());
+ helpQuiesce();
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ checkNotDone(g);
+ }};
+ testInvokeOnPool(asyncSingletonPool(), a);
+ }
+
+ /**
+ * pollTask returns an unexecuted task without executing it, in
+ * async mode
+ */
+ public void testPollTaskAsync() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF g = new LCCF(9);
+ assertSame(g, g.fork());
+ CCF f = new LCCF(8);
+ assertSame(f, f.fork());
+ assertSame(g, pollTask());
+ helpQuiesce();
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ checkNotDone(g);
+ }};
+ testInvokeOnPool(asyncSingletonPool(), a);
+ }
+
+ // versions for singleton pools
+
+ /**
+ * invoke returns when task completes normally.
+ * isCompletedAbnormally and isCancelled return false for normally
+ * completed tasks; getRawResult returns null.
+ */
+ public void testInvokeSingleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ assertNull(f.invoke());
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * quietlyInvoke task returns when task completes normally.
+ * isCompletedAbnormally and isCancelled return false for normally
+ * completed tasks
+ */
+ public void testQuietlyInvokeSingleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ f.quietlyInvoke();
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * join of a forked task returns when task completes
+ */
+ public void testForkJoinSingleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ assertSame(f, f.fork());
+ assertNull(f.join());
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * get of a forked task returns when task completes
+ */
+ public void testForkGetSingleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ CCF f = new LCCF(8);
+ assertSame(f, f.fork());
+ assertNull(f.get());
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * timed get of a forked task returns when task completes
+ */
+ public void testForkTimedGetSingleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ CCF f = new LCCF(8);
+ assertSame(f, f.fork());
+ assertNull(f.get(LONG_DELAY_MS, MILLISECONDS));
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * timed get with null time unit throws NPE
+ */
+ public void testForkTimedGetNPESingleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ CCF f = new LCCF(8);
+ assertSame(f, f.fork());
+ try {
+ f.get(5L, null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * quietlyJoin of a forked task returns when task completes
+ */
+ public void testForkQuietlyJoinSingleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ assertSame(f, f.fork());
+ f.quietlyJoin();
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * helpQuiesce returns when tasks are complete.
+ * getQueuedTaskCount returns 0 when quiescent
+ */
+ public void testForkHelpQuiesceSingleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ assertSame(f, f.fork());
+ helpQuiesce();
+ assertEquals(0, getQueuedTaskCount());
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * invoke task throws exception when task completes abnormally
+ */
+ public void testAbnormalInvokeSingleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingCCF f = new LFCCF(8);
+ try {
+ f.invoke();
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * quietlyInvoke task returns when task completes abnormally
+ */
+ public void testAbnormalQuietlyInvokeSingleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingCCF f = new LFCCF(8);
+ f.quietlyInvoke();
+ assertTrue(f.getException() instanceof FJException);
+ checkCompletedAbnormally(f, f.getException());
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * join of a forked task throws exception when task completes abnormally
+ */
+ public void testAbnormalForkJoinSingleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingCCF f = new LFCCF(8);
+ assertSame(f, f.fork());
+ try {
+ f.join();
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * get of a forked task throws exception when task completes abnormally
+ */
+ public void testAbnormalForkGetSingleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ FailingCCF f = new LFCCF(8);
+ assertSame(f, f.fork());
+ try {
+ f.get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ Throwable cause = success.getCause();
+ assertTrue(cause instanceof FJException);
+ checkCompletedAbnormally(f, cause);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * timed get of a forked task throws exception when task completes abnormally
+ */
+ public void testAbnormalForkTimedGetSingleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ FailingCCF f = new LFCCF(8);
+ assertSame(f, f.fork());
+ try {
+ f.get(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ Throwable cause = success.getCause();
+ assertTrue(cause instanceof FJException);
+ checkCompletedAbnormally(f, cause);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * quietlyJoin of a forked task returns when task completes abnormally
+ */
+ public void testAbnormalForkQuietlyJoinSingleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingCCF f = new LFCCF(8);
+ assertSame(f, f.fork());
+ f.quietlyJoin();
+ assertTrue(f.getException() instanceof FJException);
+ checkCompletedAbnormally(f, f.getException());
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * invoke task throws exception when task cancelled
+ */
+ public void testCancelledInvokeSingleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ assertTrue(f.cancel(true));
+ try {
+ f.invoke();
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * join of a forked task throws exception when task cancelled
+ */
+ public void testCancelledForkJoinSingleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ try {
+ f.join();
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * get of a forked task throws exception when task cancelled
+ */
+ public void testCancelledForkGetSingleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ CCF f = new LCCF(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ try {
+ f.get();
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * timed get of a forked task throws exception when task cancelled
+ */
+ public void testCancelledForkTimedGetSingleton() throws Exception {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ CCF f = new LCCF(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ try {
+ f.get(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * quietlyJoin of a forked task returns when task cancelled
+ */
+ public void testCancelledForkQuietlyJoinSingleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ f.quietlyJoin();
+ checkCancelled(f);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * invoke task throws exception after invoking completeExceptionally
+ */
+ public void testCompleteExceptionallySingleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF n = new LCCF(8);
+ CCF f = new LCCF(n, 8);
+ FJException ex = new FJException();
+ f.completeExceptionally(ex);
+ f.checkCompletedExceptionally(ex);
+ n.checkCompletedExceptionally(ex);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * invokeAll(t1, t2) invokes all task arguments
+ */
+ public void testInvokeAll2Singleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ CCF g = new LCCF(9);
+ invokeAll(f, g);
+ assertEquals(21, f.number);
+ assertEquals(34, g.number);
+ checkCompletedNormally(f);
+ checkCompletedNormally(g);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with 1 argument invokes task
+ */
+ public void testInvokeAll1Singleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ invokeAll(f);
+ checkCompletedNormally(f);
+ assertEquals(21, f.number);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with > 2 argument invokes tasks
+ */
+ public void testInvokeAll3Singleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ CCF g = new LCCF(9);
+ CCF h = new LCCF(7);
+ invokeAll(f, g, h);
+ assertEquals(21, f.number);
+ assertEquals(34, g.number);
+ assertEquals(13, h.number);
+ checkCompletedNormally(f);
+ checkCompletedNormally(g);
+ checkCompletedNormally(h);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * invokeAll(collection) invokes all tasks in the collection
+ */
+ public void testInvokeAllCollectionSingleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ CCF g = new LCCF(9);
+ CCF h = new LCCF(7);
+ HashSet set = new HashSet();
+ set.add(f);
+ set.add(g);
+ set.add(h);
+ invokeAll(set);
+ assertEquals(21, f.number);
+ assertEquals(34, g.number);
+ assertEquals(13, h.number);
+ checkCompletedNormally(f);
+ checkCompletedNormally(g);
+ checkCompletedNormally(h);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with any null task throws NPE
+ */
+ public void testInvokeAllNPESingleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ CCF g = new LCCF(9);
+ CCF h = null;
+ try {
+ invokeAll(f, g, h);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * invokeAll(t1, t2) throw exception if any task does
+ */
+ public void testAbnormalInvokeAll2Singleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ FailingCCF g = new LFCCF(9);
+ try {
+ invokeAll(f, g);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(g, success);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with 1 argument throws exception if task does
+ */
+ public void testAbnormalInvokeAll1Singleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingCCF g = new LFCCF(9);
+ try {
+ invokeAll(g);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(g, success);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with > 2 argument throws exception if any task does
+ */
+ public void testAbnormalInvokeAll3Singleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ CCF f = new LCCF(8);
+ FailingCCF g = new LFCCF(9);
+ CCF h = new LCCF(7);
+ try {
+ invokeAll(f, g, h);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(g, success);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * invokeAll(collection) throws exception if any task does
+ */
+ public void testAbnormalInvokeAllCollectionSingleton() {
+ ForkJoinTask a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingCCF f = new LFCCF(8);
+ CCF g = new LCCF(9);
+ CCF h = new LCCF(7);
+ HashSet set = new HashSet();
+ set.add(f);
+ set.add(g);
+ set.add(h);
+ try {
+ invokeAll(set);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/CyclicBarrierTest.java b/jsr166-tests/src/test/java/jsr166/CyclicBarrierTest.java
new file mode 100644
index 0000000..3239030
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/CyclicBarrierTest.java
@@ -0,0 +1,458 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.*;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+public class CyclicBarrierTest extends JSR166TestCase {
+
+ private volatile int countAction;
+ private class MyAction implements Runnable {
+ public void run() { ++countAction; }
+ }
+
+ /**
+ * Spin-waits till the number of waiters == numberOfWaiters.
+ */
+ void awaitNumberWaiting(CyclicBarrier barrier, int numberOfWaiters) {
+ long startTime = System.nanoTime();
+ while (barrier.getNumberWaiting() != numberOfWaiters) {
+ if (millisElapsedSince(startTime) > LONG_DELAY_MS)
+ fail("timed out");
+ Thread.yield();
+ }
+ }
+
+ /**
+ * Creating with negative parties throws IAE
+ */
+ public void testConstructor1() {
+ try {
+ new CyclicBarrier(-1, (Runnable)null);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Creating with negative parties and no action throws IAE
+ */
+ public void testConstructor2() {
+ try {
+ new CyclicBarrier(-1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * getParties returns the number of parties given in constructor
+ */
+ public void testGetParties() {
+ CyclicBarrier b = new CyclicBarrier(2);
+ assertEquals(2, b.getParties());
+ assertEquals(0, b.getNumberWaiting());
+ }
+
+ /**
+ * A 1-party barrier triggers after single await
+ */
+ public void testSingleParty() throws Exception {
+ CyclicBarrier b = new CyclicBarrier(1);
+ assertEquals(1, b.getParties());
+ assertEquals(0, b.getNumberWaiting());
+ b.await();
+ b.await();
+ assertEquals(0, b.getNumberWaiting());
+ }
+
+ /**
+ * The supplied barrier action is run at barrier
+ */
+ public void testBarrierAction() throws Exception {
+ countAction = 0;
+ CyclicBarrier b = new CyclicBarrier(1, new MyAction());
+ assertEquals(1, b.getParties());
+ assertEquals(0, b.getNumberWaiting());
+ b.await();
+ b.await();
+ assertEquals(0, b.getNumberWaiting());
+ assertEquals(2, countAction);
+ }
+
+ /**
+ * A 2-party/thread barrier triggers after both threads invoke await
+ */
+ public void testTwoParties() throws Exception {
+ final CyclicBarrier b = new CyclicBarrier(2);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws Exception {
+ b.await();
+ b.await();
+ b.await();
+ b.await();
+ }});
+
+ b.await();
+ b.await();
+ b.await();
+ b.await();
+ awaitTermination(t);
+ }
+
+ /**
+ * An interruption in one party causes others waiting in await to
+ * throw BrokenBarrierException
+ */
+ public void testAwait1_Interrupted_BrokenBarrier() {
+ final CyclicBarrier c = new CyclicBarrier(3);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(2);
+ Thread t1 = new ThreadShouldThrow(InterruptedException.class) {
+ public void realRun() throws Exception {
+ pleaseInterrupt.countDown();
+ c.await();
+ }};
+ Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) {
+ public void realRun() throws Exception {
+ pleaseInterrupt.countDown();
+ c.await();
+ }};
+
+ t1.start();
+ t2.start();
+ await(pleaseInterrupt);
+ t1.interrupt();
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * An interruption in one party causes others waiting in timed await to
+ * throw BrokenBarrierException
+ */
+ public void testAwait2_Interrupted_BrokenBarrier() throws Exception {
+ final CyclicBarrier c = new CyclicBarrier(3);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(2);
+ Thread t1 = new ThreadShouldThrow(InterruptedException.class) {
+ public void realRun() throws Exception {
+ pleaseInterrupt.countDown();
+ c.await(LONG_DELAY_MS, MILLISECONDS);
+ }};
+ Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) {
+ public void realRun() throws Exception {
+ pleaseInterrupt.countDown();
+ c.await(LONG_DELAY_MS, MILLISECONDS);
+ }};
+
+ t1.start();
+ t2.start();
+ await(pleaseInterrupt);
+ t1.interrupt();
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * A timeout in timed await throws TimeoutException
+ */
+ public void testAwait3_TimeoutException() throws InterruptedException {
+ final CyclicBarrier c = new CyclicBarrier(2);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws Exception {
+ long startTime = System.nanoTime();
+ try {
+ c.await(timeoutMillis(), MILLISECONDS);
+ shouldThrow();
+ } catch (TimeoutException success) {}
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ }});
+
+ awaitTermination(t);
+ }
+
+ /**
+ * A timeout in one party causes others waiting in timed await to
+ * throw BrokenBarrierException
+ */
+ public void testAwait4_Timeout_BrokenBarrier() throws InterruptedException {
+ final CyclicBarrier c = new CyclicBarrier(3);
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws Exception {
+ try {
+ c.await(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (BrokenBarrierException success) {}
+ }});
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws Exception {
+ awaitNumberWaiting(c, 1);
+ long startTime = System.nanoTime();
+ try {
+ c.await(timeoutMillis(), MILLISECONDS);
+ shouldThrow();
+ } catch (TimeoutException success) {}
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ }});
+
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * A timeout in one party causes others waiting in await to
+ * throw BrokenBarrierException
+ */
+ public void testAwait5_Timeout_BrokenBarrier() throws InterruptedException {
+ final CyclicBarrier c = new CyclicBarrier(3);
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws Exception {
+ try {
+ c.await();
+ shouldThrow();
+ } catch (BrokenBarrierException success) {}
+ }});
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws Exception {
+ awaitNumberWaiting(c, 1);
+ long startTime = System.nanoTime();
+ try {
+ c.await(timeoutMillis(), MILLISECONDS);
+ shouldThrow();
+ } catch (TimeoutException success) {}
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ }});
+
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * A reset of an active barrier causes waiting threads to throw
+ * BrokenBarrierException
+ */
+ public void testReset_BrokenBarrier() throws InterruptedException {
+ final CyclicBarrier c = new CyclicBarrier(3);
+ final CountDownLatch pleaseReset = new CountDownLatch(2);
+ Thread t1 = new ThreadShouldThrow(BrokenBarrierException.class) {
+ public void realRun() throws Exception {
+ pleaseReset.countDown();
+ c.await();
+ }};
+ Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) {
+ public void realRun() throws Exception {
+ pleaseReset.countDown();
+ c.await();
+ }};
+
+ t1.start();
+ t2.start();
+ await(pleaseReset);
+
+ awaitNumberWaiting(c, 2);
+ c.reset();
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * A reset before threads enter barrier does not throw
+ * BrokenBarrierException
+ */
+ public void testReset_NoBrokenBarrier() throws Exception {
+ final CyclicBarrier c = new CyclicBarrier(3);
+ c.reset();
+
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws Exception {
+ c.await();
+ }});
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws Exception {
+ c.await();
+ }});
+
+ c.await();
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * All threads block while a barrier is broken.
+ */
+ public void testReset_Leakage() throws InterruptedException {
+ final CyclicBarrier c = new CyclicBarrier(2);
+ final AtomicBoolean done = new AtomicBoolean();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ while (!done.get()) {
+ try {
+ while (c.isBroken())
+ c.reset();
+
+ c.await();
+ shouldThrow();
+ }
+ catch (BrokenBarrierException ok) {}
+ catch (InterruptedException ok) {}
+ }}});
+
+ for (int i = 0; i < 4; i++) {
+ delay(timeoutMillis());
+ t.interrupt();
+ }
+ done.set(true);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * Reset of a non-broken barrier does not break barrier
+ */
+ public void testResetWithoutBreakage() throws Exception {
+ final CyclicBarrier barrier = new CyclicBarrier(3);
+ for (int i = 0; i < 3; i++) {
+ final CyclicBarrier start = new CyclicBarrier(3);
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws Exception {
+ start.await();
+ barrier.await();
+ }});
+
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws Exception {
+ start.await();
+ barrier.await();
+ }});
+
+ start.await();
+ barrier.await();
+ awaitTermination(t1);
+ awaitTermination(t2);
+ assertFalse(barrier.isBroken());
+ assertEquals(0, barrier.getNumberWaiting());
+ if (i == 1) barrier.reset();
+ assertFalse(barrier.isBroken());
+ assertEquals(0, barrier.getNumberWaiting());
+ }
+ }
+
+ /**
+ * Reset of a barrier after interruption reinitializes it.
+ */
+ public void testResetAfterInterrupt() throws Exception {
+ final CyclicBarrier barrier = new CyclicBarrier(3);
+ for (int i = 0; i < 2; i++) {
+ final CyclicBarrier start = new CyclicBarrier(3);
+ Thread t1 = new ThreadShouldThrow(InterruptedException.class) {
+ public void realRun() throws Exception {
+ start.await();
+ barrier.await();
+ }};
+
+ Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) {
+ public void realRun() throws Exception {
+ start.await();
+ barrier.await();
+ }};
+
+ t1.start();
+ t2.start();
+ start.await();
+ t1.interrupt();
+ awaitTermination(t1);
+ awaitTermination(t2);
+ assertTrue(barrier.isBroken());
+ assertEquals(0, barrier.getNumberWaiting());
+ barrier.reset();
+ assertFalse(barrier.isBroken());
+ assertEquals(0, barrier.getNumberWaiting());
+ }
+ }
+
+ /**
+ * Reset of a barrier after timeout reinitializes it.
+ */
+ public void testResetAfterTimeout() throws Exception {
+ final CyclicBarrier barrier = new CyclicBarrier(3);
+ for (int i = 0; i < 2; i++) {
+ assertEquals(0, barrier.getNumberWaiting());
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws Exception {
+ try {
+ barrier.await();
+ shouldThrow();
+ } catch (BrokenBarrierException success) {}
+ }});
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws Exception {
+ awaitNumberWaiting(barrier, 1);
+ long startTime = System.nanoTime();
+ try {
+ barrier.await(timeoutMillis(), MILLISECONDS);
+ shouldThrow();
+ } catch (TimeoutException success) {}
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ }});
+
+ awaitTermination(t1);
+ awaitTermination(t2);
+ assertEquals(0, barrier.getNumberWaiting());
+ assertTrue(barrier.isBroken());
+ assertEquals(0, barrier.getNumberWaiting());
+ barrier.reset();
+ assertFalse(barrier.isBroken());
+ assertEquals(0, barrier.getNumberWaiting());
+ }
+ }
+
+ /**
+ * Reset of a barrier after a failed command reinitializes it.
+ */
+ public void testResetAfterCommandException() throws Exception {
+ final CyclicBarrier barrier =
+ new CyclicBarrier(3, new Runnable() {
+ public void run() {
+ throw new NullPointerException(); }});
+ for (int i = 0; i < 2; i++) {
+ final CyclicBarrier start = new CyclicBarrier(3);
+ Thread t1 = new ThreadShouldThrow(BrokenBarrierException.class) {
+ public void realRun() throws Exception {
+ start.await();
+ barrier.await();
+ }};
+
+ Thread t2 = new ThreadShouldThrow(BrokenBarrierException.class) {
+ public void realRun() throws Exception {
+ start.await();
+ barrier.await();
+ }};
+
+ t1.start();
+ t2.start();
+ start.await();
+ awaitNumberWaiting(barrier, 2);
+ try {
+ barrier.await();
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ awaitTermination(t1);
+ awaitTermination(t2);
+ assertTrue(barrier.isBroken());
+ assertEquals(0, barrier.getNumberWaiting());
+ barrier.reset();
+ assertFalse(barrier.isBroken());
+ assertEquals(0, barrier.getNumberWaiting());
+ }
+ }
+}
diff --git a/jsr166-tests/src/test/java/jsr166/DelayQueueTest.java b/jsr166-tests/src/test/java/jsr166/DelayQueueTest.java
new file mode 100644
index 0000000..5d48c18
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/DelayQueueTest.java
@@ -0,0 +1,767 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Delayed;
+import java.util.concurrent.DelayQueue;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+public class DelayQueueTest extends JSR166TestCase {
+
+ public static class Generic extends BlockingQueueTest {
+ protected BlockingQueue emptyCollection() {
+ return new DelayQueue();
+ }
+ protected PDelay makeElement(int i) {
+ return new PDelay(i);
+ }
+ }
+
+ private static final int NOCAP = Integer.MAX_VALUE;
+
+ /**
+ * A delayed implementation for testing.
+ * Most tests use Pseudodelays, where delays are all elapsed
+ * (so, no blocking solely for delays) but are still ordered
+ */
+ static class PDelay implements Delayed {
+ int pseudodelay;
+ PDelay(int i) { pseudodelay = i; }
+ public int compareTo(PDelay other) {
+ int a = this.pseudodelay;
+ int b = other.pseudodelay;
+ return (a < b) ? -1 : (a > b) ? 1 : 0;
+ }
+ public int compareTo(Delayed y) {
+ return compareTo((PDelay)y);
+ }
+ public boolean equals(Object other) {
+ return (other instanceof PDelay) &&
+ this.pseudodelay == ((PDelay)other).pseudodelay;
+ }
+ // suppress [overrides] javac warning
+ public int hashCode() { return pseudodelay; }
+ public long getDelay(TimeUnit ignore) {
+ return Integer.MIN_VALUE + pseudodelay;
+ }
+ public String toString() {
+ return String.valueOf(pseudodelay);
+ }
+ }
+
+ /**
+ * Delayed implementation that actually delays
+ */
+ static class NanoDelay implements Delayed {
+ long trigger;
+ NanoDelay(long i) {
+ trigger = System.nanoTime() + i;
+ }
+ public int compareTo(NanoDelay y) {
+ long i = trigger;
+ long j = y.trigger;
+ if (i < j) return -1;
+ if (i > j) return 1;
+ return 0;
+ }
+
+ public int compareTo(Delayed y) {
+ return compareTo((NanoDelay)y);
+ }
+
+ public boolean equals(Object other) {
+ return equals((NanoDelay)other);
+ }
+ public boolean equals(NanoDelay other) {
+ return other.trigger == trigger;
+ }
+
+ // suppress [overrides] javac warning
+ public int hashCode() { return (int) trigger; }
+
+ public long getDelay(TimeUnit unit) {
+ long n = trigger - System.nanoTime();
+ return unit.convert(n, TimeUnit.NANOSECONDS);
+ }
+
+ public long getTriggerTime() {
+ return trigger;
+ }
+
+ public String toString() {
+ return String.valueOf(trigger);
+ }
+ }
+
+ /**
+ * Returns a new queue of given size containing consecutive
+ * PDelays 0 ... n.
+ */
+ private DelayQueue<PDelay> populatedQueue(int n) {
+ DelayQueue<PDelay> q = new DelayQueue<PDelay>();
+ assertTrue(q.isEmpty());
+ for (int i = n-1; i >= 0; i-=2)
+ assertTrue(q.offer(new PDelay(i)));
+ for (int i = (n & 1); i < n; i+=2)
+ assertTrue(q.offer(new PDelay(i)));
+ assertFalse(q.isEmpty());
+ assertEquals(NOCAP, q.remainingCapacity());
+ assertEquals(n, q.size());
+ return q;
+ }
+
+ /**
+ * A new queue has unbounded capacity
+ */
+ public void testConstructor1() {
+ assertEquals(NOCAP, new DelayQueue().remainingCapacity());
+ }
+
+ /**
+ * Initializing from null Collection throws NPE
+ */
+ public void testConstructor3() {
+ try {
+ DelayQueue q = new DelayQueue(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing from Collection of null elements throws NPE
+ */
+ public void testConstructor4() {
+ try {
+ PDelay[] ints = new PDelay[SIZE];
+ DelayQueue q = new DelayQueue(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing from Collection with some null elements throws NPE
+ */
+ public void testConstructor5() {
+ try {
+ PDelay[] ints = new PDelay[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new PDelay(i);
+ DelayQueue q = new DelayQueue(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Queue contains all elements of collection used to initialize
+ */
+ public void testConstructor6() {
+ PDelay[] ints = new PDelay[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new PDelay(i);
+ DelayQueue q = new DelayQueue(Arrays.asList(ints));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(ints[i], q.poll());
+ }
+
+ /**
+ * isEmpty is true before add, false after
+ */
+ public void testEmpty() {
+ DelayQueue q = new DelayQueue();
+ assertTrue(q.isEmpty());
+ assertEquals(NOCAP, q.remainingCapacity());
+ q.add(new PDelay(1));
+ assertFalse(q.isEmpty());
+ q.add(new PDelay(2));
+ q.remove();
+ q.remove();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * remainingCapacity does not change when elements added or removed,
+ * but size does
+ */
+ public void testRemainingCapacity() {
+ DelayQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(NOCAP, q.remainingCapacity());
+ assertEquals(SIZE-i, q.size());
+ q.remove();
+ }
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(NOCAP, q.remainingCapacity());
+ assertEquals(i, q.size());
+ q.add(new PDelay(i));
+ }
+ }
+
+ /**
+ * offer non-null succeeds
+ */
+ public void testOffer() {
+ DelayQueue q = new DelayQueue();
+ assertTrue(q.offer(new PDelay(0)));
+ assertTrue(q.offer(new PDelay(1)));
+ }
+
+ /**
+ * add succeeds
+ */
+ public void testAdd() {
+ DelayQueue q = new DelayQueue();
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.size());
+ assertTrue(q.add(new PDelay(i)));
+ }
+ }
+
+ /**
+ * addAll(this) throws IAE
+ */
+ public void testAddAllSelf() {
+ try {
+ DelayQueue q = populatedQueue(SIZE);
+ q.addAll(q);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * addAll of a collection with any null elements throws NPE after
+ * possibly adding some elements
+ */
+ public void testAddAll3() {
+ try {
+ DelayQueue q = new DelayQueue();
+ PDelay[] ints = new PDelay[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new PDelay(i);
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Queue contains all elements of successful addAll
+ */
+ public void testAddAll5() {
+ PDelay[] empty = new PDelay[0];
+ PDelay[] ints = new PDelay[SIZE];
+ for (int i = SIZE-1; i >= 0; --i)
+ ints[i] = new PDelay(i);
+ DelayQueue q = new DelayQueue();
+ assertFalse(q.addAll(Arrays.asList(empty)));
+ assertTrue(q.addAll(Arrays.asList(ints)));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(ints[i], q.poll());
+ }
+
+ /**
+ * all elements successfully put are contained
+ */
+ public void testPut() {
+ DelayQueue q = new DelayQueue();
+ for (int i = 0; i < SIZE; ++i) {
+ PDelay I = new PDelay(i);
+ q.put(I);
+ assertTrue(q.contains(I));
+ }
+ assertEquals(SIZE, q.size());
+ }
+
+ /**
+ * put doesn't block waiting for take
+ */
+ public void testPutWithTake() throws InterruptedException {
+ final DelayQueue q = new DelayQueue();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ q.put(new PDelay(0));
+ q.put(new PDelay(0));
+ q.put(new PDelay(0));
+ q.put(new PDelay(0));
+ }});
+
+ awaitTermination(t);
+ assertEquals(4, q.size());
+ }
+
+ /**
+ * timed offer does not time out
+ */
+ public void testTimedOffer() throws InterruptedException {
+ final DelayQueue q = new DelayQueue();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ q.put(new PDelay(0));
+ q.put(new PDelay(0));
+ assertTrue(q.offer(new PDelay(0), SHORT_DELAY_MS, MILLISECONDS));
+ assertTrue(q.offer(new PDelay(0), LONG_DELAY_MS, MILLISECONDS));
+ }});
+
+ awaitTermination(t);
+ }
+
+ /**
+ * take retrieves elements in priority order
+ */
+ public void testTake() throws InterruptedException {
+ DelayQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(new PDelay(i), ((PDelay)q.take()));
+ }
+ }
+
+ /**
+ * Take removes existing elements until empty, then blocks interruptibly
+ */
+ public void testBlockingTake() throws InterruptedException {
+ final DelayQueue q = populatedQueue(SIZE);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(new PDelay(i), ((PDelay)q.take()));
+ }
+
+ Thread.currentThread().interrupt();
+ try {
+ q.take();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ q.take();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * poll succeeds unless empty
+ */
+ public void testPoll() {
+ DelayQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(new PDelay(i), ((PDelay)q.poll()));
+ }
+ assertNull(q.poll());
+ }
+
+ /**
+ * timed poll with zero timeout succeeds when non-empty, else times out
+ */
+ public void testTimedPoll0() throws InterruptedException {
+ DelayQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(new PDelay(i), ((PDelay)q.poll(0, MILLISECONDS)));
+ }
+ assertNull(q.poll(0, MILLISECONDS));
+ }
+
+ /**
+ * timed poll with nonzero timeout succeeds when non-empty, else times out
+ */
+ public void testTimedPoll() throws InterruptedException {
+ DelayQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ long startTime = System.nanoTime();
+ assertEquals(new PDelay(i), ((PDelay)q.poll(LONG_DELAY_MS, MILLISECONDS)));
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ }
+ long startTime = System.nanoTime();
+ assertNull(q.poll(timeoutMillis(), MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ checkEmpty(q);
+ }
+
+ /**
+ * Interrupted timed poll throws InterruptedException instead of
+ * returning timeout status
+ */
+ public void testInterruptedTimedPoll() throws InterruptedException {
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ DelayQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(new PDelay(i), ((PDelay)q.poll(SHORT_DELAY_MS, MILLISECONDS)));
+ }
+
+ Thread.currentThread().interrupt();
+ try {
+ q.poll(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ q.poll(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * peek returns next element, or null if empty
+ */
+ public void testPeek() {
+ DelayQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(new PDelay(i), ((PDelay)q.peek()));
+ assertEquals(new PDelay(i), ((PDelay)q.poll()));
+ if (q.isEmpty())
+ assertNull(q.peek());
+ else
+ assertFalse(new PDelay(i).equals(q.peek()));
+ }
+ assertNull(q.peek());
+ }
+
+ /**
+ * element returns next element, or throws NSEE if empty
+ */
+ public void testElement() {
+ DelayQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(new PDelay(i), ((PDelay)q.element()));
+ q.poll();
+ }
+ try {
+ q.element();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * remove removes next element, or throws NSEE if empty
+ */
+ public void testRemove() {
+ DelayQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(new PDelay(i), ((PDelay)q.remove()));
+ }
+ try {
+ q.remove();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * contains(x) reports true when elements added but not yet removed
+ */
+ public void testContains() {
+ DelayQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.contains(new PDelay(i)));
+ q.poll();
+ assertFalse(q.contains(new PDelay(i)));
+ }
+ }
+
+ /**
+ * clear removes all elements
+ */
+ public void testClear() {
+ DelayQueue q = populatedQueue(SIZE);
+ q.clear();
+ assertTrue(q.isEmpty());
+ assertEquals(0, q.size());
+ assertEquals(NOCAP, q.remainingCapacity());
+ PDelay x = new PDelay(1);
+ q.add(x);
+ assertFalse(q.isEmpty());
+ assertTrue(q.contains(x));
+ q.clear();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * containsAll(c) is true when c contains a subset of elements
+ */
+ public void testContainsAll() {
+ DelayQueue q = populatedQueue(SIZE);
+ DelayQueue p = new DelayQueue();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.containsAll(p));
+ assertFalse(p.containsAll(q));
+ p.add(new PDelay(i));
+ }
+ assertTrue(p.containsAll(q));
+ }
+
+ /**
+ * retainAll(c) retains only those elements of c and reports true if changed
+ */
+ public void testRetainAll() {
+ DelayQueue q = populatedQueue(SIZE);
+ DelayQueue p = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ boolean changed = q.retainAll(p);
+ if (i == 0)
+ assertFalse(changed);
+ else
+ assertTrue(changed);
+
+ assertTrue(q.containsAll(p));
+ assertEquals(SIZE-i, q.size());
+ p.remove();
+ }
+ }
+
+ /**
+ * removeAll(c) removes only those elements of c and reports true if changed
+ */
+ public void testRemoveAll() {
+ for (int i = 1; i < SIZE; ++i) {
+ DelayQueue q = populatedQueue(SIZE);
+ DelayQueue p = populatedQueue(i);
+ assertTrue(q.removeAll(p));
+ assertEquals(SIZE-i, q.size());
+ for (int j = 0; j < i; ++j) {
+ PDelay I = (PDelay)(p.remove());
+ assertFalse(q.contains(I));
+ }
+ }
+ }
+
+ /**
+ * toArray contains all elements
+ */
+ public void testToArray() throws InterruptedException {
+ DelayQueue q = populatedQueue(SIZE);
+ Object[] o = q.toArray();
+ Arrays.sort(o);
+ for (int i = 0; i < o.length; i++)
+ assertSame(o[i], q.take());
+ }
+
+ /**
+ * toArray(a) contains all elements
+ */
+ public void testToArray2() {
+ DelayQueue<PDelay> q = populatedQueue(SIZE);
+ PDelay[] ints = new PDelay[SIZE];
+ PDelay[] array = q.toArray(ints);
+ assertSame(ints, array);
+ Arrays.sort(ints);
+ for (int i = 0; i < ints.length; i++)
+ assertSame(ints[i], q.remove());
+ }
+
+ /**
+ * toArray(incompatible array type) throws ArrayStoreException
+ */
+ public void testToArray1_BadArg() {
+ DelayQueue q = populatedQueue(SIZE);
+ try {
+ q.toArray(new String[10]);
+ shouldThrow();
+ } catch (ArrayStoreException success) {}
+ }
+
+ /**
+ * iterator iterates through all elements
+ */
+ public void testIterator() {
+ DelayQueue q = populatedQueue(SIZE);
+ int i = 0;
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ assertTrue(q.contains(it.next()));
+ ++i;
+ }
+ assertEquals(i, SIZE);
+ }
+
+ /**
+ * iterator.remove removes current element
+ */
+ public void testIteratorRemove() {
+ final DelayQueue q = new DelayQueue();
+ q.add(new PDelay(2));
+ q.add(new PDelay(1));
+ q.add(new PDelay(3));
+ Iterator it = q.iterator();
+ it.next();
+ it.remove();
+ it = q.iterator();
+ assertEquals(new PDelay(2), it.next());
+ assertEquals(new PDelay(3), it.next());
+ assertFalse(it.hasNext());
+ }
+
+ /**
+ * toString contains toStrings of elements
+ */
+ public void testToString() {
+ DelayQueue q = populatedQueue(SIZE);
+ String s = q.toString();
+ for (Object e : q)
+ assertTrue(s.contains(e.toString()));
+ }
+
+ /**
+ * timed poll transfers elements across Executor tasks
+ */
+ public void testPollInExecutor() {
+ final DelayQueue q = new DelayQueue();
+ final CheckedBarrier threadsStarted = new CheckedBarrier(2);
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertNull(q.poll());
+ threadsStarted.await();
+ assertNotNull(q.poll(LONG_DELAY_MS, MILLISECONDS));
+ checkEmpty(q);
+ }});
+
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ q.put(new PDelay(1));
+ }});
+
+ joinPool(executor);
+ }
+
+ /**
+ * Delayed actions do not occur until their delay elapses
+ */
+ public void testDelay() throws InterruptedException {
+ DelayQueue<NanoDelay> q = new DelayQueue<NanoDelay>();
+ for (int i = 0; i < SIZE; ++i)
+ q.add(new NanoDelay(1000000L * (SIZE - i)));
+
+ long last = 0;
+ for (int i = 0; i < SIZE; ++i) {
+ NanoDelay e = q.take();
+ long tt = e.getTriggerTime();
+ assertTrue(System.nanoTime() - tt >= 0);
+ if (i != 0)
+ assertTrue(tt >= last);
+ last = tt;
+ }
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * peek of a non-empty queue returns non-null even if not expired
+ */
+ public void testPeekDelayed() {
+ DelayQueue q = new DelayQueue();
+ q.add(new NanoDelay(Long.MAX_VALUE));
+ assertNotNull(q.peek());
+ }
+
+ /**
+ * poll of a non-empty queue returns null if no expired elements.
+ */
+ public void testPollDelayed() {
+ DelayQueue q = new DelayQueue();
+ q.add(new NanoDelay(Long.MAX_VALUE));
+ assertNull(q.poll());
+ }
+
+ /**
+ * timed poll of a non-empty queue returns null if no expired elements.
+ */
+ public void testTimedPollDelayed() throws InterruptedException {
+ DelayQueue q = new DelayQueue();
+ q.add(new NanoDelay(LONG_DELAY_MS * 1000000L));
+ assertNull(q.poll(timeoutMillis(), MILLISECONDS));
+ }
+
+ /**
+ * drainTo(c) empties queue into another collection c
+ */
+ public void testDrainTo() {
+ DelayQueue q = new DelayQueue();
+ PDelay[] elems = new PDelay[SIZE];
+ for (int i = 0; i < SIZE; ++i) {
+ elems[i] = new PDelay(i);
+ q.add(elems[i]);
+ }
+ ArrayList l = new ArrayList();
+ q.drainTo(l);
+ assertEquals(0, q.size());
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(elems[i], l.get(i));
+ q.add(elems[0]);
+ q.add(elems[1]);
+ assertFalse(q.isEmpty());
+ assertTrue(q.contains(elems[0]));
+ assertTrue(q.contains(elems[1]));
+ l.clear();
+ q.drainTo(l);
+ assertEquals(0, q.size());
+ assertEquals(2, l.size());
+ for (int i = 0; i < 2; ++i)
+ assertEquals(elems[i], l.get(i));
+ }
+
+ /**
+ * drainTo empties queue
+ */
+ public void testDrainToWithActivePut() throws InterruptedException {
+ final DelayQueue q = populatedQueue(SIZE);
+ Thread t = new Thread(new CheckedRunnable() {
+ public void realRun() {
+ q.put(new PDelay(SIZE+1));
+ }});
+
+ t.start();
+ ArrayList l = new ArrayList();
+ q.drainTo(l);
+ assertTrue(l.size() >= SIZE);
+ t.join();
+ assertTrue(q.size() + l.size() >= SIZE);
+ }
+
+ /**
+ * drainTo(c, n) empties first min(n, size) elements of queue into c
+ */
+ public void testDrainToN() {
+ for (int i = 0; i < SIZE + 2; ++i) {
+ DelayQueue q = populatedQueue(SIZE);
+ ArrayList l = new ArrayList();
+ q.drainTo(l, i);
+ int k = (i < SIZE) ? i : SIZE;
+ assertEquals(SIZE-k, q.size());
+ assertEquals(k, l.size());
+ }
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/EntryTest.java b/jsr166-tests/src/test/java/jsr166/EntryTest.java
new file mode 100644
index 0000000..4387a53
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/EntryTest.java
@@ -0,0 +1,123 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.*;
+
+public class EntryTest extends JSR166TestCase {
+
+ static final String k1 = "1";
+ static final String v1 = "a";
+ static final String k2 = "2";
+ static final String v2 = "b";
+
+ /**
+ * A new SimpleEntry(k, v) holds k, v.
+ */
+ public void testConstructor1() {
+ Map.Entry e = new AbstractMap.SimpleEntry(k1, v1);
+ assertEquals(k1, e.getKey());
+ assertEquals(v1, e.getValue());
+ }
+
+ /**
+ * A new SimpleImmutableEntry(k, v) holds k, v.
+ */
+ public void testConstructor2() {
+ Map.Entry s = new AbstractMap.SimpleImmutableEntry(k1, v1);
+ assertEquals(k1, s.getKey());
+ assertEquals(v1, s.getValue());
+ }
+
+ /**
+ * A new SimpleEntry(entry(k, v)) holds k, v.
+ */
+ public void testConstructor3() {
+ Map.Entry e2 = new AbstractMap.SimpleEntry(k1, v1);
+ Map.Entry e = new AbstractMap.SimpleEntry(e2);
+ assertEquals(k1, e.getKey());
+ assertEquals(v1, e.getValue());
+ }
+
+ /**
+ * A new SimpleImmutableEntry(entry(k, v)) holds k, v.
+ */
+ public void testConstructor4() {
+ Map.Entry s2 = new AbstractMap.SimpleImmutableEntry(k1, v1);
+ Map.Entry s = new AbstractMap.SimpleImmutableEntry(s2);
+ assertEquals(k1, s.getKey());
+ assertEquals(v1, s.getValue());
+ }
+
+ /**
+ * Entries with same key-value pairs are equal and have same
+ * hashcodes
+ */
+ public void testEquals() {
+ Map.Entry e2 = new AbstractMap.SimpleEntry(k1, v1);
+ Map.Entry e = new AbstractMap.SimpleEntry(e2);
+ Map.Entry s2 = new AbstractMap.SimpleImmutableEntry(k1, v1);
+ Map.Entry s = new AbstractMap.SimpleImmutableEntry(s2);
+ assertEquals(e2, e);
+ assertEquals(e2.hashCode(), e.hashCode());
+ assertEquals(s2, s);
+ assertEquals(s2.hashCode(), s.hashCode());
+ assertEquals(e2, s2);
+ assertEquals(e2.hashCode(), s2.hashCode());
+ assertEquals(e, s);
+ assertEquals(e.hashCode(), s.hashCode());
+ }
+
+ /**
+ * Entries with different key-value pairs are not equal
+ */
+ public void testNotEquals() {
+ Map.Entry e2 = new AbstractMap.SimpleEntry(k1, v1);
+ Map.Entry e = new AbstractMap.SimpleEntry(k2, v1);
+ assertFalse(e2.equals(e));
+ e = new AbstractMap.SimpleEntry(k1, v2);
+ assertFalse(e2.equals(e));
+ e = new AbstractMap.SimpleEntry(k2, v2);
+ assertFalse(e2.equals(e));
+
+ Map.Entry s2 = new AbstractMap.SimpleImmutableEntry(k1, v1);
+ Map.Entry s = new AbstractMap.SimpleImmutableEntry(k2, v1);
+ assertFalse(s2.equals(s));
+ s = new AbstractMap.SimpleImmutableEntry(k1, v2);
+ assertFalse(s2.equals(s));
+ s = new AbstractMap.SimpleImmutableEntry(k2, v2);
+ assertFalse(s2.equals(s));
+ }
+
+ /**
+ * getValue returns last setValue for SimpleEntry
+ */
+ public void testSetValue1() {
+ Map.Entry e2 = new AbstractMap.SimpleEntry(k1, v1);
+ Map.Entry e = new AbstractMap.SimpleEntry(e2);
+ assertEquals(k1, e.getKey());
+ assertEquals(v1, e.getValue());
+ e.setValue(k2);
+ assertEquals(k2, e.getValue());
+ assertFalse(e2.equals(e));
+ }
+
+ /**
+ * setValue for SimpleImmutableEntry throws UnsupportedOperationException
+ */
+ public void testSetValue2() {
+ Map.Entry s2 = new AbstractMap.SimpleImmutableEntry(k1, v1);
+ Map.Entry s = new AbstractMap.SimpleImmutableEntry(s2);
+ assertEquals(k1, s.getKey());
+ assertEquals(v1, s.getValue());
+ try {
+ s.setValue(k2);
+ shouldThrow();
+ } catch (UnsupportedOperationException success) {}
+ }
+}
diff --git a/jsr166-tests/src/test/java/jsr166/ExchangerTest.java b/jsr166-tests/src/test/java/jsr166/ExchangerTest.java
new file mode 100644
index 0000000..b0f325e
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/ExchangerTest.java
@@ -0,0 +1,146 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.*;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Exchanger;
+import java.util.concurrent.TimeoutException;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+public class ExchangerTest extends JSR166TestCase {
+
+ /**
+ * exchange exchanges objects across two threads
+ */
+ public void testExchange() {
+ final Exchanger e = new Exchanger();
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertSame(one, e.exchange(two));
+ assertSame(two, e.exchange(one));
+ }});
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertSame(two, e.exchange(one));
+ assertSame(one, e.exchange(two));
+ }});
+
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * timed exchange exchanges objects across two threads
+ */
+ public void testTimedExchange() {
+ final Exchanger e = new Exchanger();
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws Exception {
+ assertSame(one, e.exchange(two, LONG_DELAY_MS, MILLISECONDS));
+ assertSame(two, e.exchange(one, LONG_DELAY_MS, MILLISECONDS));
+ }});
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws Exception {
+ assertSame(two, e.exchange(one, LONG_DELAY_MS, MILLISECONDS));
+ assertSame(one, e.exchange(two, LONG_DELAY_MS, MILLISECONDS));
+ }});
+
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * interrupt during wait for exchange throws IE
+ */
+ public void testExchange_InterruptedException() {
+ final Exchanger e = new Exchanger();
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ e.exchange(one);
+ }});
+
+ await(threadStarted);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * interrupt during wait for timed exchange throws IE
+ */
+ public void testTimedExchange_InterruptedException() {
+ final Exchanger e = new Exchanger();
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws Exception {
+ threadStarted.countDown();
+ e.exchange(null, LONG_DELAY_MS, MILLISECONDS);
+ }});
+
+ await(threadStarted);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * timeout during wait for timed exchange throws TimeoutException
+ */
+ public void testExchange_TimeoutException() {
+ final Exchanger e = new Exchanger();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws Exception {
+ long startTime = System.nanoTime();
+ try {
+ e.exchange(null, timeoutMillis(), MILLISECONDS);
+ shouldThrow();
+ } catch (TimeoutException success) {}
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ }});
+
+ awaitTermination(t);
+ }
+
+ /**
+ * If one exchanging thread is interrupted, another succeeds.
+ */
+ public void testReplacementAfterExchange() {
+ final Exchanger e = new Exchanger();
+ final CountDownLatch exchanged = new CountDownLatch(2);
+ final CountDownLatch interrupted = new CountDownLatch(1);
+ Thread t1 = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertSame(two, e.exchange(one));
+ exchanged.countDown();
+ e.exchange(two);
+ }});
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertSame(one, e.exchange(two));
+ exchanged.countDown();
+ interrupted.await();
+ assertSame(three, e.exchange(one));
+ }});
+ Thread t3 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ interrupted.await();
+ assertSame(one, e.exchange(three));
+ }});
+
+ await(exchanged);
+ t1.interrupt();
+ awaitTermination(t1);
+ interrupted.countDown();
+ awaitTermination(t2);
+ awaitTermination(t3);
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/ExecutorCompletionServiceTest.java b/jsr166-tests/src/test/java/jsr166/ExecutorCompletionServiceTest.java
new file mode 100644
index 0000000..eced0ba
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/ExecutorCompletionServiceTest.java
@@ -0,0 +1,221 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.*;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorCompletionService;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.RunnableFuture;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.security.*;
+
+public class ExecutorCompletionServiceTest extends JSR166TestCase {
+
+ /**
+ * Creating a new ECS with null Executor throw NPE
+ */
+ public void testConstructorNPE() {
+ try {
+ ExecutorCompletionService ecs = new ExecutorCompletionService(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Creating a new ECS with null queue throw NPE
+ */
+ public void testConstructorNPE2() {
+ try {
+ ExecutorService e = Executors.newCachedThreadPool();
+ ExecutorCompletionService ecs = new ExecutorCompletionService(e, null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Submitting a null callable throws NPE
+ */
+ public void testSubmitNPE() {
+ ExecutorService e = Executors.newCachedThreadPool();
+ ExecutorCompletionService ecs = new ExecutorCompletionService(e);
+ try {
+ Callable c = null;
+ ecs.submit(c);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * Submitting a null runnable throws NPE
+ */
+ public void testSubmitNPE2() {
+ ExecutorService e = Executors.newCachedThreadPool();
+ ExecutorCompletionService ecs = new ExecutorCompletionService(e);
+ try {
+ Runnable r = null;
+ ecs.submit(r, Boolean.TRUE);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * A taken submitted task is completed
+ */
+ public void testTake() throws InterruptedException {
+ ExecutorService e = Executors.newCachedThreadPool();
+ ExecutorCompletionService ecs = new ExecutorCompletionService(e);
+ try {
+ Callable c = new StringTask();
+ ecs.submit(c);
+ Future f = ecs.take();
+ assertTrue(f.isDone());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * Take returns the same future object returned by submit
+ */
+ public void testTake2() throws InterruptedException {
+ ExecutorService e = Executors.newCachedThreadPool();
+ ExecutorCompletionService ecs = new ExecutorCompletionService(e);
+ try {
+ Callable c = new StringTask();
+ Future f1 = ecs.submit(c);
+ Future f2 = ecs.take();
+ assertSame(f1, f2);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * If poll returns non-null, the returned task is completed
+ */
+ public void testPoll1() throws Exception {
+ ExecutorService e = Executors.newCachedThreadPool();
+ ExecutorCompletionService ecs = new ExecutorCompletionService(e);
+ try {
+ assertNull(ecs.poll());
+ Callable c = new StringTask();
+ ecs.submit(c);
+
+ long startTime = System.nanoTime();
+ Future f;
+ while ((f = ecs.poll()) == null) {
+ if (millisElapsedSince(startTime) > LONG_DELAY_MS)
+ fail("timed out");
+ Thread.yield();
+ }
+ assertTrue(f.isDone());
+ assertSame(TEST_STRING, f.get());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * If timed poll returns non-null, the returned task is completed
+ */
+ public void testPoll2() throws InterruptedException {
+ ExecutorService e = Executors.newCachedThreadPool();
+ ExecutorCompletionService ecs = new ExecutorCompletionService(e);
+ try {
+ assertNull(ecs.poll());
+ Callable c = new StringTask();
+ ecs.submit(c);
+ Future f = ecs.poll(SHORT_DELAY_MS, MILLISECONDS);
+ if (f != null)
+ assertTrue(f.isDone());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * Submitting to underlying AES that overrides newTaskFor(Callable)
+ * returns and eventually runs Future returned by newTaskFor.
+ */
+ public void testNewTaskForCallable() throws InterruptedException {
+ final AtomicBoolean done = new AtomicBoolean(false);
+ class MyCallableFuture<V> extends FutureTask<V> {
+ MyCallableFuture(Callable<V> c) { super(c); }
+ protected void done() { done.set(true); }
+ }
+ ExecutorService e = new ThreadPoolExecutor(
+ 1, 1, 30L, TimeUnit.SECONDS,
+ new ArrayBlockingQueue<Runnable>(1)) {
+ protected <T> RunnableFuture<T> newTaskFor(Callable<T> c) {
+ return new MyCallableFuture<T>(c);
+ }};
+ ExecutorCompletionService<String> ecs =
+ new ExecutorCompletionService<String>(e);
+ try {
+ assertNull(ecs.poll());
+ Callable<String> c = new StringTask();
+ Future f1 = ecs.submit(c);
+ assertTrue("submit must return MyCallableFuture",
+ f1 instanceof MyCallableFuture);
+ Future f2 = ecs.take();
+ assertSame("submit and take must return same objects", f1, f2);
+ assertTrue("completed task must have set done", done.get());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * Submitting to underlying AES that overrides newTaskFor(Runnable,T)
+ * returns and eventually runs Future returned by newTaskFor.
+ */
+ public void testNewTaskForRunnable() throws InterruptedException {
+ final AtomicBoolean done = new AtomicBoolean(false);
+ class MyRunnableFuture<V> extends FutureTask<V> {
+ MyRunnableFuture(Runnable t, V r) { super(t, r); }
+ protected void done() { done.set(true); }
+ }
+ ExecutorService e = new ThreadPoolExecutor(
+ 1, 1, 30L, TimeUnit.SECONDS,
+ new ArrayBlockingQueue<Runnable>(1)) {
+ protected <T> RunnableFuture<T> newTaskFor(Runnable t, T r) {
+ return new MyRunnableFuture<T>(t, r);
+ }};
+ ExecutorCompletionService<String> ecs =
+ new ExecutorCompletionService<String>(e);
+ try {
+ assertNull(ecs.poll());
+ Runnable r = new NoOpRunnable();
+ Future f1 = ecs.submit(r, null);
+ assertTrue("submit must return MyRunnableFuture",
+ f1 instanceof MyRunnableFuture);
+ Future f2 = ecs.take();
+ assertSame("submit and take must return same objects", f1, f2);
+ assertTrue("completed task must have set done", done.get());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/ExecutorsTest.java b/jsr166-tests/src/test/java/jsr166/ExecutorsTest.java
new file mode 100644
index 0000000..18c0975
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/ExecutorsTest.java
@@ -0,0 +1,585 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.*;
+import java.util.concurrent.*;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import java.security.*;
+
+public class ExecutorsTest extends JSR166TestCase {
+
+ /**
+ * A newCachedThreadPool can execute runnables
+ */
+ public void testNewCachedThreadPool1() {
+ ExecutorService e = Executors.newCachedThreadPool();
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ joinPool(e);
+ }
+
+ /**
+ * A newCachedThreadPool with given ThreadFactory can execute runnables
+ */
+ public void testNewCachedThreadPool2() {
+ ExecutorService e = Executors.newCachedThreadPool(new SimpleThreadFactory());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ joinPool(e);
+ }
+
+ /**
+ * A newCachedThreadPool with null ThreadFactory throws NPE
+ */
+ public void testNewCachedThreadPool3() {
+ try {
+ ExecutorService e = Executors.newCachedThreadPool(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * A new SingleThreadExecutor can execute runnables
+ */
+ public void testNewSingleThreadExecutor1() {
+ ExecutorService e = Executors.newSingleThreadExecutor();
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ joinPool(e);
+ }
+
+ /**
+ * A new SingleThreadExecutor with given ThreadFactory can execute runnables
+ */
+ public void testNewSingleThreadExecutor2() {
+ ExecutorService e = Executors.newSingleThreadExecutor(new SimpleThreadFactory());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ joinPool(e);
+ }
+
+ /**
+ * A new SingleThreadExecutor with null ThreadFactory throws NPE
+ */
+ public void testNewSingleThreadExecutor3() {
+ try {
+ ExecutorService e = Executors.newSingleThreadExecutor(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * A new SingleThreadExecutor cannot be casted to concrete implementation
+ */
+ public void testCastNewSingleThreadExecutor() {
+ ExecutorService e = Executors.newSingleThreadExecutor();
+ try {
+ ThreadPoolExecutor tpe = (ThreadPoolExecutor)e;
+ shouldThrow();
+ } catch (ClassCastException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * A new newFixedThreadPool can execute runnables
+ */
+ public void testNewFixedThreadPool1() {
+ ExecutorService e = Executors.newFixedThreadPool(2);
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ joinPool(e);
+ }
+
+ /**
+ * A new newFixedThreadPool with given ThreadFactory can execute runnables
+ */
+ public void testNewFixedThreadPool2() {
+ ExecutorService e = Executors.newFixedThreadPool(2, new SimpleThreadFactory());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ joinPool(e);
+ }
+
+ /**
+ * A new newFixedThreadPool with null ThreadFactory throws NPE
+ */
+ public void testNewFixedThreadPool3() {
+ try {
+ ExecutorService e = Executors.newFixedThreadPool(2, null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * A new newFixedThreadPool with 0 threads throws IAE
+ */
+ public void testNewFixedThreadPool4() {
+ try {
+ ExecutorService e = Executors.newFixedThreadPool(0);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * An unconfigurable newFixedThreadPool can execute runnables
+ */
+ public void testUnconfigurableExecutorService() {
+ ExecutorService e = Executors.unconfigurableExecutorService(Executors.newFixedThreadPool(2));
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ e.execute(new NoOpRunnable());
+ joinPool(e);
+ }
+
+ /**
+ * unconfigurableExecutorService(null) throws NPE
+ */
+ public void testUnconfigurableExecutorServiceNPE() {
+ try {
+ ExecutorService e = Executors.unconfigurableExecutorService(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * unconfigurableScheduledExecutorService(null) throws NPE
+ */
+ public void testUnconfigurableScheduledExecutorServiceNPE() {
+ try {
+ ExecutorService e = Executors.unconfigurableScheduledExecutorService(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * a newSingleThreadScheduledExecutor successfully runs delayed task
+ */
+ public void testNewSingleThreadScheduledExecutor() throws Exception {
+ ScheduledExecutorService p = Executors.newSingleThreadScheduledExecutor();
+ try {
+ final CountDownLatch proceed = new CountDownLatch(1);
+ final Runnable task = new CheckedRunnable() {
+ public void realRun() {
+ await(proceed);
+ }};
+ long startTime = System.nanoTime();
+ Future f = p.schedule(Executors.callable(task, Boolean.TRUE),
+ timeoutMillis(), MILLISECONDS);
+ assertFalse(f.isDone());
+ proceed.countDown();
+ assertSame(Boolean.TRUE, f.get(LONG_DELAY_MS, MILLISECONDS));
+ assertSame(Boolean.TRUE, f.get());
+ assertTrue(f.isDone());
+ assertFalse(f.isCancelled());
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * a newScheduledThreadPool successfully runs delayed task
+ */
+ public void testNewScheduledThreadPool() throws Exception {
+ ScheduledExecutorService p = Executors.newScheduledThreadPool(2);
+ try {
+ final CountDownLatch proceed = new CountDownLatch(1);
+ final Runnable task = new CheckedRunnable() {
+ public void realRun() {
+ await(proceed);
+ }};
+ long startTime = System.nanoTime();
+ Future f = p.schedule(Executors.callable(task, Boolean.TRUE),
+ timeoutMillis(), MILLISECONDS);
+ assertFalse(f.isDone());
+ proceed.countDown();
+ assertSame(Boolean.TRUE, f.get(LONG_DELAY_MS, MILLISECONDS));
+ assertSame(Boolean.TRUE, f.get());
+ assertTrue(f.isDone());
+ assertFalse(f.isCancelled());
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * an unconfigurable newScheduledThreadPool successfully runs delayed task
+ */
+ public void testUnconfigurableScheduledExecutorService() throws Exception {
+ ScheduledExecutorService p =
+ Executors.unconfigurableScheduledExecutorService
+ (Executors.newScheduledThreadPool(2));
+ try {
+ final CountDownLatch proceed = new CountDownLatch(1);
+ final Runnable task = new CheckedRunnable() {
+ public void realRun() {
+ await(proceed);
+ }};
+ long startTime = System.nanoTime();
+ Future f = p.schedule(Executors.callable(task, Boolean.TRUE),
+ timeoutMillis(), MILLISECONDS);
+ assertFalse(f.isDone());
+ proceed.countDown();
+ assertSame(Boolean.TRUE, f.get(LONG_DELAY_MS, MILLISECONDS));
+ assertSame(Boolean.TRUE, f.get());
+ assertTrue(f.isDone());
+ assertFalse(f.isCancelled());
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * Future.get on submitted tasks will time out if they compute too long.
+ */
+ public void testTimedCallable() throws Exception {
+ final ExecutorService[] executors = {
+ Executors.newSingleThreadExecutor(),
+ Executors.newCachedThreadPool(),
+ Executors.newFixedThreadPool(2),
+ Executors.newScheduledThreadPool(2),
+ };
+
+ final Runnable sleeper = new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ delay(LONG_DELAY_MS);
+ }};
+
+ List<Thread> threads = new ArrayList<Thread>();
+ for (final ExecutorService executor : executors) {
+ threads.add(newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ long startTime = System.nanoTime();
+ Future future = executor.submit(sleeper);
+ assertFutureTimesOut(future);
+ }}));
+ }
+ for (Thread thread : threads)
+ awaitTermination(thread);
+ for (ExecutorService executor : executors)
+ joinPool(executor);
+ }
+
+ /**
+ * ThreadPoolExecutor using defaultThreadFactory has
+ * specified group, priority, daemon status, and name
+ */
+ public void testDefaultThreadFactory() throws Exception {
+ final ThreadGroup egroup = Thread.currentThread().getThreadGroup();
+ final CountDownLatch done = new CountDownLatch(1);
+ Runnable r = new CheckedRunnable() {
+ public void realRun() {
+ try {
+ Thread current = Thread.currentThread();
+ assertTrue(!current.isDaemon());
+ assertTrue(current.getPriority() <= Thread.NORM_PRIORITY);
+ ThreadGroup g = current.getThreadGroup();
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ assertTrue(g == s.getThreadGroup());
+ else
+ assertTrue(g == egroup);
+ String name = current.getName();
+ assertTrue(name.endsWith("thread-1"));
+ } catch (SecurityException ok) {
+ // Also pass if not allowed to change setting
+ }
+ done.countDown();
+ }};
+ ExecutorService e = Executors.newSingleThreadExecutor(Executors.defaultThreadFactory());
+
+ e.execute(r);
+ await(done);
+
+ try {
+ e.shutdown();
+ } catch (SecurityException ok) {
+ }
+
+ joinPool(e);
+ }
+
+ /**
+ * ThreadPoolExecutor using privilegedThreadFactory has
+ * specified group, priority, daemon status, name,
+ * access control context and context class loader
+ */
+ public void testPrivilegedThreadFactory() throws Exception {
+ final CountDownLatch done = new CountDownLatch(1);
+ Runnable r = new CheckedRunnable() {
+ public void realRun() throws Exception {
+ final ThreadGroup egroup = Thread.currentThread().getThreadGroup();
+ final ClassLoader thisccl = Thread.currentThread().getContextClassLoader();
+ // final AccessControlContext thisacc = AccessController.getContext(); // Android removed
+ Runnable r = new CheckedRunnable() {
+ public void realRun() {
+ Thread current = Thread.currentThread();
+ assertTrue(!current.isDaemon());
+ assertTrue(current.getPriority() <= Thread.NORM_PRIORITY);
+ ThreadGroup g = current.getThreadGroup();
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ assertTrue(g == s.getThreadGroup());
+ else
+ assertTrue(g == egroup);
+ String name = current.getName();
+ assertTrue(name.endsWith("thread-1"));
+ assertSame(thisccl, current.getContextClassLoader());
+ // assertEquals(thisacc, AccessController.getContext()); // Android removed
+ done.countDown();
+ }};
+ ExecutorService e = Executors.newSingleThreadExecutor(Executors.privilegedThreadFactory());
+ e.execute(r);
+ await(done);
+ e.shutdown();
+ joinPool(e);
+ }};
+
+ runWithPermissions(r,
+ new RuntimePermission("getClassLoader"),
+ new RuntimePermission("setContextClassLoader"),
+ new RuntimePermission("modifyThread"));
+ }
+
+ boolean haveCCLPermissions() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ try {
+ sm.checkPermission(new RuntimePermission("setContextClassLoader"));
+ sm.checkPermission(new RuntimePermission("getClassLoader"));
+ } catch (AccessControlException e) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void checkCCL() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(new RuntimePermission("setContextClassLoader"));
+ sm.checkPermission(new RuntimePermission("getClassLoader"));
+ }
+ }
+
+ class CheckCCL implements Callable<Object> {
+ public Object call() {
+ checkCCL();
+ return null;
+ }
+ }
+
+ /**
+ * Without class loader permissions, creating
+ * privilegedCallableUsingCurrentClassLoader throws ACE
+ */
+ public void testCreatePrivilegedCallableUsingCCLWithNoPrivs() {
+ Runnable r = new CheckedRunnable() {
+ public void realRun() throws Exception {
+ if (System.getSecurityManager() == null)
+ return;
+ try {
+ Executors.privilegedCallableUsingCurrentClassLoader(new NoOpCallable());
+ shouldThrow();
+ } catch (AccessControlException success) {}
+ }};
+
+ runWithoutPermissions(r);
+ }
+
+ /**
+ * With class loader permissions, calling
+ * privilegedCallableUsingCurrentClassLoader does not throw ACE
+ */
+ public void testPrivilegedCallableUsingCCLWithPrivs() throws Exception {
+ Runnable r = new CheckedRunnable() {
+ public void realRun() throws Exception {
+ Executors.privilegedCallableUsingCurrentClassLoader
+ (new NoOpCallable())
+ .call();
+ }};
+
+ runWithPermissions(r,
+ new RuntimePermission("getClassLoader"),
+ new RuntimePermission("setContextClassLoader"));
+ }
+
+ /**
+ * Without permissions, calling privilegedCallable throws ACE
+ */
+ public void testPrivilegedCallableWithNoPrivs() throws Exception {
+ // Avoid classloader-related SecurityExceptions in swingui.TestRunner
+ Executors.privilegedCallable(new CheckCCL());
+
+ Runnable r = new CheckedRunnable() {
+ public void realRun() throws Exception {
+ if (System.getSecurityManager() == null)
+ return;
+ Callable task = Executors.privilegedCallable(new CheckCCL());
+ try {
+ task.call();
+ shouldThrow();
+ } catch (AccessControlException success) {}
+ }};
+
+ runWithoutPermissions(r);
+
+ // It seems rather difficult to test that the
+ // AccessControlContext of the privilegedCallable is used
+ // instead of its caller. Below is a failed attempt to do
+ // that, which does not work because the AccessController
+ // cannot capture the internal state of the current Policy.
+ // It would be much more work to differentiate based on,
+ // e.g. CodeSource.
+
+// final AccessControlContext[] noprivAcc = new AccessControlContext[1];
+// final Callable[] task = new Callable[1];
+
+// runWithPermissions
+// (new CheckedRunnable() {
+// public void realRun() {
+// if (System.getSecurityManager() == null)
+// return;
+// noprivAcc[0] = AccessController.getContext();
+// task[0] = Executors.privilegedCallable(new CheckCCL());
+// try {
+// AccessController.doPrivileged(new PrivilegedAction<Void>() {
+// public Void run() {
+// checkCCL();
+// return null;
+// }}, noprivAcc[0]);
+// shouldThrow();
+// } catch (AccessControlException success) {}
+// }});
+
+// runWithPermissions
+// (new CheckedRunnable() {
+// public void realRun() throws Exception {
+// if (System.getSecurityManager() == null)
+// return;
+// // Verify that we have an underprivileged ACC
+// try {
+// AccessController.doPrivileged(new PrivilegedAction<Void>() {
+// public Void run() {
+// checkCCL();
+// return null;
+// }}, noprivAcc[0]);
+// shouldThrow();
+// } catch (AccessControlException success) {}
+
+// try {
+// task[0].call();
+// shouldThrow();
+// } catch (AccessControlException success) {}
+// }},
+// new RuntimePermission("getClassLoader"),
+// new RuntimePermission("setContextClassLoader"));
+ }
+
+ /**
+ * With permissions, calling privilegedCallable succeeds
+ */
+ public void testPrivilegedCallableWithPrivs() throws Exception {
+ Runnable r = new CheckedRunnable() {
+ public void realRun() throws Exception {
+ Executors.privilegedCallable(new CheckCCL()).call();
+ }};
+
+ runWithPermissions(r,
+ new RuntimePermission("getClassLoader"),
+ new RuntimePermission("setContextClassLoader"));
+ }
+
+ /**
+ * callable(Runnable) returns null when called
+ */
+ public void testCallable1() throws Exception {
+ Callable c = Executors.callable(new NoOpRunnable());
+ assertNull(c.call());
+ }
+
+ /**
+ * callable(Runnable, result) returns result when called
+ */
+ public void testCallable2() throws Exception {
+ Callable c = Executors.callable(new NoOpRunnable(), one);
+ assertSame(one, c.call());
+ }
+
+ /**
+ * callable(PrivilegedAction) returns its result when called
+ */
+ public void testCallable3() throws Exception {
+ Callable c = Executors.callable(new PrivilegedAction() {
+ public Object run() { return one; }});
+ assertSame(one, c.call());
+ }
+
+ /**
+ * callable(PrivilegedExceptionAction) returns its result when called
+ */
+ public void testCallable4() throws Exception {
+ Callable c = Executors.callable(new PrivilegedExceptionAction() {
+ public Object run() { return one; }});
+ assertSame(one, c.call());
+ }
+
+ /**
+ * callable(null Runnable) throws NPE
+ */
+ public void testCallableNPE1() {
+ try {
+ Callable c = Executors.callable((Runnable) null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * callable(null, result) throws NPE
+ */
+ public void testCallableNPE2() {
+ try {
+ Callable c = Executors.callable((Runnable) null, one);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * callable(null PrivilegedAction) throws NPE
+ */
+ public void testCallableNPE3() {
+ try {
+ Callable c = Executors.callable((PrivilegedAction) null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * callable(null PrivilegedExceptionAction) throws NPE
+ */
+ public void testCallableNPE4() {
+ try {
+ Callable c = Executors.callable((PrivilegedExceptionAction) null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/ForkJoinPoolTest.java b/jsr166-tests/src/test/java/jsr166/ForkJoinPoolTest.java
new file mode 100644
index 0000000..8416198
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/ForkJoinPoolTest.java
@@ -0,0 +1,996 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.AbstractExecutorService;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.ForkJoinTask;
+import java.util.concurrent.ForkJoinWorkerThread;
+import java.util.concurrent.RecursiveTask;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.ReentrantLock;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import java.security.AccessControlException;
+import java.security.Policy;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+
+public class ForkJoinPoolTest extends JSR166TestCase {
+
+ /*
+ * Testing coverage notes:
+ *
+ * 1. shutdown and related methods are tested via super.joinPool.
+ *
+ * 2. newTaskFor and adapters are tested in submit/invoke tests
+ *
+ * 3. We cannot portably test monitoring methods such as
+ * getStealCount() since they rely ultimately on random task
+ * stealing that may cause tasks not to be stolen/propagated
+ * across threads, especially on uniprocessors.
+ *
+ * 4. There are no independently testable ForkJoinWorkerThread
+ * methods, but they are covered here and in task tests.
+ */
+
+ // Some classes to test extension and factory methods
+
+ static class MyHandler implements Thread.UncaughtExceptionHandler {
+ volatile int catches = 0;
+ public void uncaughtException(Thread t, Throwable e) {
+ ++catches;
+ }
+ }
+
+ // to test handlers
+ static class FailingFJWSubclass extends ForkJoinWorkerThread {
+ public FailingFJWSubclass(ForkJoinPool p) { super(p) ; }
+ protected void onStart() { super.onStart(); throw new Error(); }
+ }
+
+ static class FailingThreadFactory
+ implements ForkJoinPool.ForkJoinWorkerThreadFactory {
+ volatile int calls = 0;
+ public ForkJoinWorkerThread newThread(ForkJoinPool p) {
+ if (++calls > 1) return null;
+ return new FailingFJWSubclass(p);
+ }
+ }
+
+ static class SubFJP extends ForkJoinPool { // to expose protected
+ SubFJP() { super(1); }
+ public int drainTasksTo(Collection<? super ForkJoinTask<?>> c) {
+ return super.drainTasksTo(c);
+ }
+ public ForkJoinTask<?> pollSubmission() {
+ return super.pollSubmission();
+ }
+ }
+
+ static class ManagedLocker implements ForkJoinPool.ManagedBlocker {
+ final ReentrantLock lock;
+ boolean hasLock = false;
+ ManagedLocker(ReentrantLock lock) { this.lock = lock; }
+ public boolean block() {
+ if (!hasLock)
+ lock.lock();
+ return true;
+ }
+ public boolean isReleasable() {
+ return hasLock || (hasLock = lock.tryLock());
+ }
+ }
+
+ // A simple recursive task for testing
+ static final class FibTask extends RecursiveTask<Integer> {
+ final int number;
+ FibTask(int n) { number = n; }
+ public Integer compute() {
+ int n = number;
+ if (n <= 1)
+ return n;
+ FibTask f1 = new FibTask(n - 1);
+ f1.fork();
+ return (new FibTask(n - 2)).compute() + f1.join();
+ }
+ }
+
+ // A failing task for testing
+ static final class FailingTask extends ForkJoinTask<Void> {
+ public final Void getRawResult() { return null; }
+ protected final void setRawResult(Void mustBeNull) { }
+ protected final boolean exec() { throw new Error(); }
+ FailingTask() {}
+ }
+
+ // Fib needlessly using locking to test ManagedBlockers
+ static final class LockingFibTask extends RecursiveTask<Integer> {
+ final int number;
+ final ManagedLocker locker;
+ final ReentrantLock lock;
+ LockingFibTask(int n, ManagedLocker locker, ReentrantLock lock) {
+ number = n;
+ this.locker = locker;
+ this.lock = lock;
+ }
+ public Integer compute() {
+ int n;
+ LockingFibTask f1 = null;
+ LockingFibTask f2 = null;
+ locker.block();
+ n = number;
+ if (n > 1) {
+ f1 = new LockingFibTask(n - 1, locker, lock);
+ f2 = new LockingFibTask(n - 2, locker, lock);
+ }
+ lock.unlock();
+ if (n <= 1)
+ return n;
+ else {
+ f1.fork();
+ return f2.compute() + f1.join();
+ }
+ }
+ }
+
+ /**
+ * Successfully constructed pool reports default factory,
+ * parallelism and async mode policies, no active threads or
+ * tasks, and quiescent running state.
+ */
+ public void testDefaultInitialState() {
+ ForkJoinPool p = new ForkJoinPool(1);
+ try {
+ assertSame(ForkJoinPool.defaultForkJoinWorkerThreadFactory,
+ p.getFactory());
+ assertFalse(p.getAsyncMode());
+ assertEquals(0, p.getActiveThreadCount());
+ assertEquals(0, p.getStealCount());
+ assertEquals(0, p.getQueuedTaskCount());
+ assertEquals(0, p.getQueuedSubmissionCount());
+ assertFalse(p.hasQueuedSubmissions());
+ assertFalse(p.isShutdown());
+ assertFalse(p.isTerminating());
+ assertFalse(p.isTerminated());
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * Constructor throws if size argument is less than zero
+ */
+ public void testConstructor1() {
+ try {
+ new ForkJoinPool(-1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if factory argument is null
+ */
+ public void testConstructor2() {
+ try {
+ new ForkJoinPool(1, null, null, false);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * getParallelism returns size set in constructor
+ */
+ public void testGetParallelism() {
+ ForkJoinPool p = new ForkJoinPool(1);
+ try {
+ assertEquals(1, p.getParallelism());
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * getPoolSize returns number of started workers.
+ */
+ public void testGetPoolSize() {
+ ForkJoinPool p = new ForkJoinPool(1);
+ try {
+ assertEquals(0, p.getActiveThreadCount());
+ Future<String> future = p.submit(new StringTask());
+ assertEquals(1, p.getPoolSize());
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * awaitTermination on a non-shutdown pool times out
+ */
+ public void testAwaitTermination_timesOut() throws InterruptedException {
+ ForkJoinPool p = new ForkJoinPool(1);
+ assertFalse(p.isTerminated());
+ assertFalse(p.awaitTermination(Long.MIN_VALUE, NANOSECONDS));
+ assertFalse(p.awaitTermination(Long.MIN_VALUE, MILLISECONDS));
+ assertFalse(p.awaitTermination(-1L, NANOSECONDS));
+ assertFalse(p.awaitTermination(-1L, MILLISECONDS));
+ assertFalse(p.awaitTermination(0L, NANOSECONDS));
+ assertFalse(p.awaitTermination(0L, MILLISECONDS));
+ long timeoutNanos = 999999L;
+ long startTime = System.nanoTime();
+ assertFalse(p.awaitTermination(timeoutNanos, NANOSECONDS));
+ assertTrue(System.nanoTime() - startTime >= timeoutNanos);
+ assertFalse(p.isTerminated());
+ startTime = System.nanoTime();
+ long timeoutMillis = timeoutMillis();
+ assertFalse(p.awaitTermination(timeoutMillis, MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
+ assertFalse(p.isTerminated());
+ p.shutdown();
+ assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
+ }
+
+ /**
+ * setUncaughtExceptionHandler changes handler for uncaught exceptions.
+ *
+ * Additionally tests: Overriding ForkJoinWorkerThread.onStart
+ * performs its defined action
+ */
+ public void testSetUncaughtExceptionHandler() throws InterruptedException {
+ final CountDownLatch uehInvoked = new CountDownLatch(1);
+ final Thread.UncaughtExceptionHandler eh =
+ new Thread.UncaughtExceptionHandler() {
+ public void uncaughtException(Thread t, Throwable e) {
+ uehInvoked.countDown();
+ }};
+ ForkJoinPool p = new ForkJoinPool(1, new FailingThreadFactory(),
+ eh, false);
+ try {
+ assertSame(eh, p.getUncaughtExceptionHandler());
+ try {
+ p.execute(new FibTask(8));
+ assertTrue(uehInvoked.await(MEDIUM_DELAY_MS, MILLISECONDS));
+ } catch (RejectedExecutionException ok) {
+ }
+ } finally {
+ p.shutdownNow(); // failure might have prevented processing task
+ joinPool(p);
+ }
+ }
+
+ /**
+ * After invoking a single task, isQuiescent eventually becomes
+ * true, at which time queues are empty, threads are not active,
+ * the task has completed successfully, and construction
+ * parameters continue to hold
+ */
+ public void testIsQuiescent() throws Exception {
+ ForkJoinPool p = new ForkJoinPool(2);
+ try {
+ assertTrue(p.isQuiescent());
+ long startTime = System.nanoTime();
+ FibTask f = new FibTask(20);
+ p.invoke(f);
+ assertSame(ForkJoinPool.defaultForkJoinWorkerThreadFactory,
+ p.getFactory());
+ while (! p.isQuiescent()) {
+ if (millisElapsedSince(startTime) > LONG_DELAY_MS)
+ throw new AssertionFailedError("timed out");
+ assertFalse(p.getAsyncMode());
+ assertFalse(p.isShutdown());
+ assertFalse(p.isTerminating());
+ assertFalse(p.isTerminated());
+ Thread.yield();
+ }
+
+ assertTrue(p.isQuiescent());
+ assertFalse(p.getAsyncMode());
+ assertEquals(0, p.getActiveThreadCount());
+ assertEquals(0, p.getQueuedTaskCount());
+ assertEquals(0, p.getQueuedSubmissionCount());
+ assertFalse(p.hasQueuedSubmissions());
+ assertFalse(p.isShutdown());
+ assertFalse(p.isTerminating());
+ assertFalse(p.isTerminated());
+ assertTrue(f.isDone());
+ assertEquals(6765, (int) f.get());
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * Completed submit(ForkJoinTask) returns result
+ */
+ public void testSubmitForkJoinTask() throws Throwable {
+ ForkJoinPool p = new ForkJoinPool(1);
+ try {
+ ForkJoinTask<Integer> f = p.submit(new FibTask(8));
+ assertEquals(21, (int) f.get());
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * A task submitted after shutdown is rejected
+ */
+ public void testSubmitAfterShutdown() {
+ ForkJoinPool p = new ForkJoinPool(1);
+ try {
+ p.shutdown();
+ assertTrue(p.isShutdown());
+ try {
+ ForkJoinTask<Integer> f = p.submit(new FibTask(8));
+ shouldThrow();
+ } catch (RejectedExecutionException success) {}
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * Pool maintains parallelism when using ManagedBlocker
+ */
+ public void testBlockingForkJoinTask() throws Throwable {
+ ForkJoinPool p = new ForkJoinPool(4);
+ try {
+ ReentrantLock lock = new ReentrantLock();
+ ManagedLocker locker = new ManagedLocker(lock);
+ ForkJoinTask<Integer> f = new LockingFibTask(20, locker, lock);
+ p.execute(f);
+ assertEquals(6765, (int) f.get());
+ } finally {
+ p.shutdownNow(); // don't wait out shutdown
+ }
+ }
+
+ /**
+ * pollSubmission returns unexecuted submitted task, if present
+ */
+ public void testPollSubmission() {
+ final CountDownLatch done = new CountDownLatch(1);
+ SubFJP p = new SubFJP();
+ try {
+ ForkJoinTask a = p.submit(awaiter(done));
+ ForkJoinTask b = p.submit(awaiter(done));
+ ForkJoinTask c = p.submit(awaiter(done));
+ ForkJoinTask r = p.pollSubmission();
+ assertTrue(r == a || r == b || r == c);
+ assertFalse(r.isDone());
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * drainTasksTo transfers unexecuted submitted tasks, if present
+ */
+ public void testDrainTasksTo() {
+ final CountDownLatch done = new CountDownLatch(1);
+ SubFJP p = new SubFJP();
+ try {
+ ForkJoinTask a = p.submit(awaiter(done));
+ ForkJoinTask b = p.submit(awaiter(done));
+ ForkJoinTask c = p.submit(awaiter(done));
+ ArrayList<ForkJoinTask> al = new ArrayList();
+ p.drainTasksTo(al);
+ assertTrue(al.size() > 0);
+ for (ForkJoinTask r : al) {
+ assertTrue(r == a || r == b || r == c);
+ assertFalse(r.isDone());
+ }
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ // FJ Versions of AbstractExecutorService tests
+
+ /**
+ * execute(runnable) runs it to completion
+ */
+ public void testExecuteRunnable() throws Throwable {
+ ExecutorService e = new ForkJoinPool(1);
+ try {
+ final AtomicBoolean done = new AtomicBoolean(false);
+ CheckedRunnable task = new CheckedRunnable() {
+ public void realRun() {
+ done.set(true);
+ }};
+ Future<?> future = e.submit(task);
+ assertNull(future.get());
+ assertNull(future.get(0, MILLISECONDS));
+ assertTrue(done.get());
+ assertTrue(future.isDone());
+ assertFalse(future.isCancelled());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * Completed submit(callable) returns result
+ */
+ public void testSubmitCallable() throws Throwable {
+ ExecutorService e = new ForkJoinPool(1);
+ try {
+ Future<String> future = e.submit(new StringTask());
+ assertSame(TEST_STRING, future.get());
+ assertTrue(future.isDone());
+ assertFalse(future.isCancelled());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * Completed submit(runnable) returns successfully
+ */
+ public void testSubmitRunnable() throws Throwable {
+ ExecutorService e = new ForkJoinPool(1);
+ try {
+ Future<?> future = e.submit(new NoOpRunnable());
+ assertNull(future.get());
+ assertTrue(future.isDone());
+ assertFalse(future.isCancelled());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * Completed submit(runnable, result) returns result
+ */
+ public void testSubmitRunnable2() throws Throwable {
+ ExecutorService e = new ForkJoinPool(1);
+ try {
+ Future<String> future = e.submit(new NoOpRunnable(), TEST_STRING);
+ assertSame(TEST_STRING, future.get());
+ assertTrue(future.isDone());
+ assertFalse(future.isCancelled());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * A submitted privileged action runs to completion
+ */
+ public void testSubmitPrivilegedAction() throws Exception {
+ final Callable callable = Executors.callable(new PrivilegedAction() {
+ public Object run() { return TEST_STRING; }});
+ Runnable r = new CheckedRunnable() {
+ public void realRun() throws Exception {
+ ExecutorService e = new ForkJoinPool(1);
+ try {
+ Future future = e.submit(callable);
+ assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
+ }
+ }};
+
+ runWithPermissions(r, new RuntimePermission("modifyThread"));
+ }
+
+ /**
+ * A submitted privileged exception action runs to completion
+ */
+ public void testSubmitPrivilegedExceptionAction() throws Exception {
+ final Callable callable =
+ Executors.callable(new PrivilegedExceptionAction() {
+ public Object run() { return TEST_STRING; }});
+ Runnable r = new CheckedRunnable() {
+ public void realRun() throws Exception {
+ ExecutorService e = new ForkJoinPool(1);
+ try {
+ Future future = e.submit(callable);
+ assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
+ }
+ }};
+
+ runWithPermissions(r, new RuntimePermission("modifyThread"));
+ }
+
+ /**
+ * A submitted failed privileged exception action reports exception
+ */
+ public void testSubmitFailedPrivilegedExceptionAction() throws Exception {
+ final Callable callable =
+ Executors.callable(new PrivilegedExceptionAction() {
+ public Object run() { throw new IndexOutOfBoundsException(); }});
+ Runnable r = new CheckedRunnable() {
+ public void realRun() throws Exception {
+ ExecutorService e = new ForkJoinPool(1);
+ try {
+ Future future = e.submit(callable);
+ try {
+ future.get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof IndexOutOfBoundsException);
+ }
+ } finally {
+ joinPool(e);
+ }
+ }};
+
+ runWithPermissions(r, new RuntimePermission("modifyThread"));
+ }
+
+ /**
+ * execute(null runnable) throws NullPointerException
+ */
+ public void testExecuteNullRunnable() {
+ ExecutorService e = new ForkJoinPool(1);
+ try {
+ Future<?> future = e.submit((Runnable) null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * submit(null callable) throws NullPointerException
+ */
+ public void testSubmitNullCallable() {
+ ExecutorService e = new ForkJoinPool(1);
+ try {
+ Future<String> future = e.submit((Callable) null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * submit(callable).get() throws InterruptedException if interrupted
+ */
+ public void testInterruptedSubmit() throws InterruptedException {
+ final CountDownLatch submitted = new CountDownLatch(1);
+ final CountDownLatch quittingTime = new CountDownLatch(1);
+ final ExecutorService p = new ForkJoinPool(1);
+ final Callable<Void> awaiter = new CheckedCallable<Void>() {
+ public Void realCall() throws InterruptedException {
+ assertTrue(quittingTime.await(MEDIUM_DELAY_MS, MILLISECONDS));
+ return null;
+ }};
+ try {
+ Thread t = new Thread(new CheckedInterruptedRunnable() {
+ public void realRun() throws Exception {
+ Future<Void> future = p.submit(awaiter);
+ submitted.countDown();
+ future.get();
+ }});
+ t.start();
+ assertTrue(submitted.await(MEDIUM_DELAY_MS, MILLISECONDS));
+ t.interrupt();
+ t.join();
+ } finally {
+ quittingTime.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * get of submit(callable) throws ExecutionException if callable
+ * throws exception
+ */
+ public void testSubmitEE() throws Throwable {
+ ForkJoinPool p = new ForkJoinPool(1);
+ try {
+ p.submit(new Callable() {
+ public Object call() { throw new ArithmeticException(); }})
+ .get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof ArithmeticException);
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * invokeAny(null) throws NullPointerException
+ */
+ public void testInvokeAny1() throws Throwable {
+ ExecutorService e = new ForkJoinPool(1);
+ try {
+ e.invokeAny(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(empty collection) throws IllegalArgumentException
+ */
+ public void testInvokeAny2() throws Throwable {
+ ExecutorService e = new ForkJoinPool(1);
+ try {
+ e.invokeAny(new ArrayList<Callable<String>>());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(c) throws NullPointerException if c has a single null element
+ */
+ public void testInvokeAny3() throws Throwable {
+ ExecutorService e = new ForkJoinPool(1);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(null);
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(c) throws NullPointerException if c has null elements
+ */
+ public void testInvokeAny4() throws Throwable {
+ CountDownLatch latch = new CountDownLatch(1);
+ ExecutorService e = new ForkJoinPool(1);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(latchAwaitingStringTask(latch));
+ l.add(null);
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ latch.countDown();
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(c) throws ExecutionException if no task in c completes
+ */
+ public void testInvokeAny5() throws Throwable {
+ ExecutorService e = new ForkJoinPool(1);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(c) returns result of some task in c if at least one completes
+ */
+ public void testInvokeAny6() throws Throwable {
+ ExecutorService e = new ForkJoinPool(1);
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(new StringTask());
+ String result = e.invokeAny(l);
+ assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAll(null) throws NullPointerException
+ */
+ public void testInvokeAll1() throws Throwable {
+ ExecutorService e = new ForkJoinPool(1);
+ try {
+ e.invokeAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAll(empty collection) returns empty collection
+ */
+ public void testInvokeAll2() throws InterruptedException {
+ ExecutorService e = new ForkJoinPool(1);
+ try {
+ List<Future<String>> r
+ = e.invokeAll(new ArrayList<Callable<String>>());
+ assertTrue(r.isEmpty());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAll(c) throws NullPointerException if c has null elements
+ */
+ public void testInvokeAll3() throws InterruptedException {
+ ExecutorService e = new ForkJoinPool(1);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(null);
+ try {
+ e.invokeAll(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * get of returned element of invokeAll(c) throws
+ * ExecutionException on failed task
+ */
+ public void testInvokeAll4() throws Throwable {
+ ExecutorService e = new ForkJoinPool(1);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ List<Future<String>> futures = e.invokeAll(l);
+ assertEquals(1, futures.size());
+ try {
+ futures.get(0).get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAll(c) returns results of all completed tasks in c
+ */
+ public void testInvokeAll5() throws Throwable {
+ ExecutorService e = new ForkJoinPool(1);
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(new StringTask());
+ List<Future<String>> futures = e.invokeAll(l);
+ assertEquals(2, futures.size());
+ for (Future<String> future : futures)
+ assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(null) throws NullPointerException
+ */
+ public void testTimedInvokeAny1() throws Throwable {
+ ExecutorService e = new ForkJoinPool(1);
+ try {
+ e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(null time unit) throws NullPointerException
+ */
+ public void testTimedInvokeAnyNullTimeUnit() throws Throwable {
+ ExecutorService e = new ForkJoinPool(1);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(empty collection) throws IllegalArgumentException
+ */
+ public void testTimedInvokeAny2() throws Throwable {
+ ExecutorService e = new ForkJoinPool(1);
+ try {
+ e.invokeAny(new ArrayList<Callable<String>>(),
+ MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(c) throws NullPointerException if c has null elements
+ */
+ public void testTimedInvokeAny3() throws Throwable {
+ CountDownLatch latch = new CountDownLatch(1);
+ ExecutorService e = new ForkJoinPool(1);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(latchAwaitingStringTask(latch));
+ l.add(null);
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ latch.countDown();
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(c) throws ExecutionException if no task completes
+ */
+ public void testTimedInvokeAny4() throws Throwable {
+ ExecutorService e = new ForkJoinPool(1);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(c) returns result of some task in c
+ */
+ public void testTimedInvokeAny5() throws Throwable {
+ ExecutorService e = new ForkJoinPool(1);
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(new StringTask());
+ String result = e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(null) throws NullPointerException
+ */
+ public void testTimedInvokeAll1() throws Throwable {
+ ExecutorService e = new ForkJoinPool(1);
+ try {
+ e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(null time unit) throws NullPointerException
+ */
+ public void testTimedInvokeAllNullTimeUnit() throws Throwable {
+ ExecutorService e = new ForkJoinPool(1);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ try {
+ e.invokeAll(l, MEDIUM_DELAY_MS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(empty collection) returns empty collection
+ */
+ public void testTimedInvokeAll2() throws InterruptedException {
+ ExecutorService e = new ForkJoinPool(1);
+ try {
+ List<Future<String>> r
+ = e.invokeAll(new ArrayList<Callable<String>>(),
+ MEDIUM_DELAY_MS, MILLISECONDS);
+ assertTrue(r.isEmpty());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(c) throws NullPointerException if c has null elements
+ */
+ public void testTimedInvokeAll3() throws InterruptedException {
+ ExecutorService e = new ForkJoinPool(1);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(null);
+ try {
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * get of returned element of invokeAll(c) throws exception on failed task
+ */
+ public void testTimedInvokeAll4() throws Throwable {
+ ExecutorService e = new ForkJoinPool(1);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ List<Future<String>> futures
+ = e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ assertEquals(1, futures.size());
+ try {
+ futures.get(0).get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(c) returns results of all completed tasks in c
+ */
+ public void testTimedInvokeAll5() throws Throwable {
+ ExecutorService e = new ForkJoinPool(1);
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(new StringTask());
+ List<Future<String>> futures
+ = e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ assertEquals(2, futures.size());
+ for (Future<String> future : futures)
+ assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/ForkJoinTaskTest.java b/jsr166-tests/src/test/java/jsr166/ForkJoinTaskTest.java
new file mode 100644
index 0000000..080fd9c
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/ForkJoinTaskTest.java
@@ -0,0 +1,1605 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package jsr166;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.ForkJoinTask;
+import java.util.concurrent.ForkJoinWorkerThread;
+import java.util.concurrent.RecursiveAction;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import java.util.HashSet;
+import junit.framework.*;
+
+public class ForkJoinTaskTest extends JSR166TestCase {
+
+ // Runs with "mainPool" use > 1 thread. singletonPool tests use 1
+ static final int mainPoolSize =
+ Math.max(2, Runtime.getRuntime().availableProcessors());
+
+ private static ForkJoinPool mainPool() {
+ return new ForkJoinPool(mainPoolSize);
+ }
+
+ private static ForkJoinPool singletonPool() {
+ return new ForkJoinPool(1);
+ }
+
+ private static ForkJoinPool asyncSingletonPool() {
+ return new ForkJoinPool(1,
+ ForkJoinPool.defaultForkJoinWorkerThreadFactory,
+ null, true);
+ }
+
+ private void testInvokeOnPool(ForkJoinPool pool, RecursiveAction a) {
+ try {
+ assertFalse(a.isDone());
+ assertFalse(a.isCompletedNormally());
+ assertFalse(a.isCompletedAbnormally());
+ assertFalse(a.isCancelled());
+ assertNull(a.getException());
+ assertNull(a.getRawResult());
+
+ assertNull(pool.invoke(a));
+
+ assertTrue(a.isDone());
+ assertTrue(a.isCompletedNormally());
+ assertFalse(a.isCompletedAbnormally());
+ assertFalse(a.isCancelled());
+ assertNull(a.getException());
+ assertNull(a.getRawResult());
+ } finally {
+ joinPool(pool);
+ }
+ }
+
+ void checkNotDone(ForkJoinTask a) {
+ assertFalse(a.isDone());
+ assertFalse(a.isCompletedNormally());
+ assertFalse(a.isCompletedAbnormally());
+ assertFalse(a.isCancelled());
+ assertNull(a.getException());
+ assertNull(a.getRawResult());
+
+ try {
+ a.get(0L, SECONDS);
+ shouldThrow();
+ } catch (TimeoutException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ <T> void checkCompletedNormally(ForkJoinTask<T> a) {
+ checkCompletedNormally(a, null);
+ }
+
+ <T> void checkCompletedNormally(ForkJoinTask<T> a, T expected) {
+ assertTrue(a.isDone());
+ assertFalse(a.isCancelled());
+ assertTrue(a.isCompletedNormally());
+ assertFalse(a.isCompletedAbnormally());
+ assertNull(a.getException());
+ assertSame(expected, a.getRawResult());
+
+ {
+ Thread.currentThread().interrupt();
+ long t0 = System.nanoTime();
+ assertSame(expected, a.join());
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
+ Thread.interrupted();
+ }
+
+ {
+ Thread.currentThread().interrupt();
+ long t0 = System.nanoTime();
+ a.quietlyJoin(); // should be no-op
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
+ Thread.interrupted();
+ }
+
+ assertFalse(a.cancel(false));
+ assertFalse(a.cancel(true));
+ try {
+ assertSame(expected, a.get());
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ try {
+ assertSame(expected, a.get(5L, SECONDS));
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ void checkCancelled(ForkJoinTask a) {
+ assertTrue(a.isDone());
+ assertTrue(a.isCancelled());
+ assertFalse(a.isCompletedNormally());
+ assertTrue(a.isCompletedAbnormally());
+ assertTrue(a.getException() instanceof CancellationException);
+ assertNull(a.getRawResult());
+ assertTrue(a.cancel(false));
+ assertTrue(a.cancel(true));
+
+ try {
+ Thread.currentThread().interrupt();
+ a.join();
+ shouldThrow();
+ } catch (CancellationException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ Thread.interrupted();
+
+ {
+ long t0 = System.nanoTime();
+ a.quietlyJoin(); // should be no-op
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
+ }
+
+ try {
+ a.get();
+ shouldThrow();
+ } catch (CancellationException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+
+ try {
+ a.get(5L, SECONDS);
+ shouldThrow();
+ } catch (CancellationException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ void checkCompletedAbnormally(ForkJoinTask a, Throwable t) {
+ assertTrue(a.isDone());
+ assertFalse(a.isCancelled());
+ assertFalse(a.isCompletedNormally());
+ assertTrue(a.isCompletedAbnormally());
+ assertSame(t.getClass(), a.getException().getClass());
+ assertNull(a.getRawResult());
+ assertFalse(a.cancel(false));
+ assertFalse(a.cancel(true));
+
+ try {
+ Thread.currentThread().interrupt();
+ a.join();
+ shouldThrow();
+ } catch (Throwable expected) {
+ assertSame(t.getClass(), expected.getClass());
+ }
+ Thread.interrupted();
+
+ {
+ long t0 = System.nanoTime();
+ a.quietlyJoin(); // should be no-op
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
+ }
+
+ try {
+ a.get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertSame(t.getClass(), success.getCause().getClass());
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+
+ try {
+ a.get(5L, SECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertSame(t.getClass(), success.getCause().getClass());
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ /*
+ * Testing coverage notes:
+ *
+ * To test extension methods and overrides, most tests use
+ * BinaryAsyncAction extension class that processes joins
+ * differently than supplied Recursive forms.
+ */
+
+ public static final class FJException extends RuntimeException {
+ FJException() { super(); }
+ }
+
+ abstract static class BinaryAsyncAction extends ForkJoinTask<Void> {
+ private volatile int controlState;
+
+ static final AtomicIntegerFieldUpdater<BinaryAsyncAction> controlStateUpdater =
+ AtomicIntegerFieldUpdater.newUpdater(BinaryAsyncAction.class,
+ "controlState");
+
+ private BinaryAsyncAction parent;
+
+ private BinaryAsyncAction sibling;
+
+ protected BinaryAsyncAction() {
+ }
+
+ public final Void getRawResult() { return null; }
+ protected final void setRawResult(Void mustBeNull) { }
+
+ public final void linkSubtasks(BinaryAsyncAction x, BinaryAsyncAction y) {
+ x.parent = y.parent = this;
+ x.sibling = y;
+ y.sibling = x;
+ }
+
+ protected void onComplete(BinaryAsyncAction x, BinaryAsyncAction y) {
+ }
+
+ protected boolean onException() {
+ return true;
+ }
+
+ public void linkAndForkSubtasks(BinaryAsyncAction x, BinaryAsyncAction y) {
+ linkSubtasks(x, y);
+ y.fork();
+ x.fork();
+ }
+
+ private void completeThis() {
+ super.complete(null);
+ }
+
+ private void completeThisExceptionally(Throwable ex) {
+ super.completeExceptionally(ex);
+ }
+
+ public final void complete() {
+ BinaryAsyncAction a = this;
+ for (;;) {
+ BinaryAsyncAction s = a.sibling;
+ BinaryAsyncAction p = a.parent;
+ a.sibling = null;
+ a.parent = null;
+ a.completeThis();
+ if (p == null || p.compareAndSetControlState(0, 1))
+ break;
+ try {
+ p.onComplete(a, s);
+ } catch (Throwable rex) {
+ p.completeExceptionally(rex);
+ return;
+ }
+ a = p;
+ }
+ }
+
+ public final void completeExceptionally(Throwable ex) {
+ BinaryAsyncAction a = this;
+ while (!a.isCompletedAbnormally()) {
+ a.completeThisExceptionally(ex);
+ BinaryAsyncAction s = a.sibling;
+ if (s != null)
+ s.cancel(false);
+ if (!a.onException() || (a = a.parent) == null)
+ break;
+ }
+ }
+
+ public final BinaryAsyncAction getParent() {
+ return parent;
+ }
+
+ public BinaryAsyncAction getSibling() {
+ return sibling;
+ }
+
+ public void reinitialize() {
+ parent = sibling = null;
+ super.reinitialize();
+ }
+
+ protected final int getControlState() {
+ return controlState;
+ }
+
+ protected final boolean compareAndSetControlState(int expect,
+ int update) {
+ return controlStateUpdater.compareAndSet(this, expect, update);
+ }
+
+ protected final void setControlState(int value) {
+ controlState = value;
+ }
+
+ protected final void incrementControlState() {
+ controlStateUpdater.incrementAndGet(this);
+ }
+
+ protected final void decrementControlState() {
+ controlStateUpdater.decrementAndGet(this);
+ }
+
+ }
+
+ static final class AsyncFib extends BinaryAsyncAction {
+ int number;
+ public AsyncFib(int n) {
+ this.number = n;
+ }
+
+ public final boolean exec() {
+ AsyncFib f = this;
+ int n = f.number;
+ if (n > 1) {
+ while (n > 1) {
+ AsyncFib p = f;
+ AsyncFib r = new AsyncFib(n - 2);
+ f = new AsyncFib(--n);
+ p.linkSubtasks(r, f);
+ r.fork();
+ }
+ f.number = n;
+ }
+ f.complete();
+ return false;
+ }
+
+ protected void onComplete(BinaryAsyncAction x, BinaryAsyncAction y) {
+ number = ((AsyncFib)x).number + ((AsyncFib)y).number;
+ }
+ }
+
+ static final class FailingAsyncFib extends BinaryAsyncAction {
+ int number;
+ public FailingAsyncFib(int n) {
+ this.number = n;
+ }
+
+ public final boolean exec() {
+ FailingAsyncFib f = this;
+ int n = f.number;
+ if (n > 1) {
+ while (n > 1) {
+ FailingAsyncFib p = f;
+ FailingAsyncFib r = new FailingAsyncFib(n - 2);
+ f = new FailingAsyncFib(--n);
+ p.linkSubtasks(r, f);
+ r.fork();
+ }
+ f.number = n;
+ }
+ f.complete();
+ return false;
+ }
+
+ protected void onComplete(BinaryAsyncAction x, BinaryAsyncAction y) {
+ completeExceptionally(new FJException());
+ }
+ }
+
+ /**
+ * invoke returns when task completes normally.
+ * isCompletedAbnormally and isCancelled return false for normally
+ * completed tasks; getRawResult returns null.
+ */
+ public void testInvoke() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ assertNull(f.invoke());
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * quietlyInvoke task returns when task completes normally.
+ * isCompletedAbnormally and isCancelled return false for normally
+ * completed tasks
+ */
+ public void testQuietlyInvoke() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ f.quietlyInvoke();
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * join of a forked task returns when task completes
+ */
+ public void testForkJoin() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ assertSame(f, f.fork());
+ assertNull(f.join());
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * get of a forked task returns when task completes
+ */
+ public void testForkGet() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ AsyncFib f = new AsyncFib(8);
+ assertSame(f, f.fork());
+ assertNull(f.get());
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * timed get of a forked task returns when task completes
+ */
+ public void testForkTimedGet() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ AsyncFib f = new AsyncFib(8);
+ assertSame(f, f.fork());
+ assertNull(f.get(LONG_DELAY_MS, MILLISECONDS));
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * timed get with null time unit throws NPE
+ */
+ public void testForkTimedGetNPE() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ AsyncFib f = new AsyncFib(8);
+ assertSame(f, f.fork());
+ try {
+ f.get(5L, null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * quietlyJoin of a forked task returns when task completes
+ */
+ public void testForkQuietlyJoin() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ assertSame(f, f.fork());
+ f.quietlyJoin();
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * helpQuiesce returns when tasks are complete.
+ * getQueuedTaskCount returns 0 when quiescent
+ */
+ public void testForkHelpQuiesce() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ assertSame(f, f.fork());
+ helpQuiesce();
+ assertEquals(21, f.number);
+ assertEquals(0, getQueuedTaskCount());
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invoke task throws exception when task completes abnormally
+ */
+ public void testAbnormalInvoke() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingAsyncFib f = new FailingAsyncFib(8);
+ try {
+ f.invoke();
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * quietlyInvoke task returns when task completes abnormally
+ */
+ public void testAbnormalQuietlyInvoke() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingAsyncFib f = new FailingAsyncFib(8);
+ f.quietlyInvoke();
+ assertTrue(f.getException() instanceof FJException);
+ checkCompletedAbnormally(f, f.getException());
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * join of a forked task throws exception when task completes abnormally
+ */
+ public void testAbnormalForkJoin() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingAsyncFib f = new FailingAsyncFib(8);
+ assertSame(f, f.fork());
+ try {
+ f.join();
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * get of a forked task throws exception when task completes abnormally
+ */
+ public void testAbnormalForkGet() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ FailingAsyncFib f = new FailingAsyncFib(8);
+ assertSame(f, f.fork());
+ try {
+ f.get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ Throwable cause = success.getCause();
+ assertTrue(cause instanceof FJException);
+ checkCompletedAbnormally(f, cause);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * timed get of a forked task throws exception when task completes abnormally
+ */
+ public void testAbnormalForkTimedGet() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ FailingAsyncFib f = new FailingAsyncFib(8);
+ assertSame(f, f.fork());
+ try {
+ f.get(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ Throwable cause = success.getCause();
+ assertTrue(cause instanceof FJException);
+ checkCompletedAbnormally(f, cause);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * quietlyJoin of a forked task returns when task completes abnormally
+ */
+ public void testAbnormalForkQuietlyJoin() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingAsyncFib f = new FailingAsyncFib(8);
+ assertSame(f, f.fork());
+ f.quietlyJoin();
+ assertTrue(f.getException() instanceof FJException);
+ checkCompletedAbnormally(f, f.getException());
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invoke task throws exception when task cancelled
+ */
+ public void testCancelledInvoke() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ assertTrue(f.cancel(true));
+ try {
+ f.invoke();
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * join of a forked task throws exception when task cancelled
+ */
+ public void testCancelledForkJoin() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ try {
+ f.join();
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * get of a forked task throws exception when task cancelled
+ */
+ public void testCancelledForkGet() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ AsyncFib f = new AsyncFib(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ try {
+ f.get();
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * timed get of a forked task throws exception when task cancelled
+ */
+ public void testCancelledForkTimedGet() throws Exception {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ AsyncFib f = new AsyncFib(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ try {
+ f.get(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * quietlyJoin of a forked task returns when task cancelled
+ */
+ public void testCancelledForkQuietlyJoin() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ f.quietlyJoin();
+ checkCancelled(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * getPool of executing task returns its pool
+ */
+ public void testGetPool() {
+ final ForkJoinPool mainPool = mainPool();
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ assertSame(mainPool, getPool());
+ }};
+ testInvokeOnPool(mainPool, a);
+ }
+
+ /**
+ * getPool of non-FJ task returns null
+ */
+ public void testGetPool2() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ assertNull(getPool());
+ }};
+ assertNull(a.invoke());
+ }
+
+ /**
+ * inForkJoinPool of executing task returns true
+ */
+ public void testInForkJoinPool() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ assertTrue(inForkJoinPool());
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * inForkJoinPool of non-FJ task returns false
+ */
+ public void testInForkJoinPool2() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ assertFalse(inForkJoinPool());
+ }};
+ assertNull(a.invoke());
+ }
+
+ /**
+ * setRawResult(null) succeeds
+ */
+ public void testSetRawResult() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ setRawResult(null);
+ assertNull(getRawResult());
+ }};
+ assertNull(a.invoke());
+ }
+
+ /**
+ * invoke task throws exception after invoking completeExceptionally
+ */
+ public void testCompleteExceptionally() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ f.completeExceptionally(new FJException());
+ try {
+ f.invoke();
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(t1, t2) invokes all task arguments
+ */
+ public void testInvokeAll2() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ AsyncFib g = new AsyncFib(9);
+ invokeAll(f, g);
+ assertEquals(21, f.number);
+ assertEquals(34, g.number);
+ checkCompletedNormally(f);
+ checkCompletedNormally(g);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with 1 argument invokes task
+ */
+ public void testInvokeAll1() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ invokeAll(f);
+ checkCompletedNormally(f);
+ assertEquals(21, f.number);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with > 2 argument invokes tasks
+ */
+ public void testInvokeAll3() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ AsyncFib g = new AsyncFib(9);
+ AsyncFib h = new AsyncFib(7);
+ invokeAll(f, g, h);
+ assertEquals(21, f.number);
+ assertEquals(34, g.number);
+ assertEquals(13, h.number);
+ checkCompletedNormally(f);
+ checkCompletedNormally(g);
+ checkCompletedNormally(h);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(collection) invokes all tasks in the collection
+ */
+ public void testInvokeAllCollection() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ AsyncFib g = new AsyncFib(9);
+ AsyncFib h = new AsyncFib(7);
+ HashSet set = new HashSet();
+ set.add(f);
+ set.add(g);
+ set.add(h);
+ invokeAll(set);
+ assertEquals(21, f.number);
+ assertEquals(34, g.number);
+ assertEquals(13, h.number);
+ checkCompletedNormally(f);
+ checkCompletedNormally(g);
+ checkCompletedNormally(h);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with any null task throws NPE
+ */
+ public void testInvokeAllNPE() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ AsyncFib g = new AsyncFib(9);
+ AsyncFib h = null;
+ try {
+ invokeAll(f, g, h);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(t1, t2) throw exception if any task does
+ */
+ public void testAbnormalInvokeAll2() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ FailingAsyncFib g = new FailingAsyncFib(9);
+ try {
+ invokeAll(f, g);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(g, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with 1 argument throws exception if task does
+ */
+ public void testAbnormalInvokeAll1() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingAsyncFib g = new FailingAsyncFib(9);
+ try {
+ invokeAll(g);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(g, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with > 2 argument throws exception if any task does
+ */
+ public void testAbnormalInvokeAll3() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ FailingAsyncFib g = new FailingAsyncFib(9);
+ AsyncFib h = new AsyncFib(7);
+ try {
+ invokeAll(f, g, h);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(g, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(collection) throws exception if any task does
+ */
+ public void testAbnormalInvokeAllCollection() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingAsyncFib f = new FailingAsyncFib(8);
+ AsyncFib g = new AsyncFib(9);
+ AsyncFib h = new AsyncFib(7);
+ HashSet set = new HashSet();
+ set.add(f);
+ set.add(g);
+ set.add(h);
+ try {
+ invokeAll(set);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * tryUnfork returns true for most recent unexecuted task,
+ * and suppresses execution
+ */
+ public void testTryUnfork() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib g = new AsyncFib(9);
+ assertSame(g, g.fork());
+ AsyncFib f = new AsyncFib(8);
+ assertSame(f, f.fork());
+ assertTrue(f.tryUnfork());
+ helpQuiesce();
+ checkNotDone(f);
+ checkCompletedNormally(g);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * getSurplusQueuedTaskCount returns > 0 when
+ * there are more tasks than threads
+ */
+ public void testGetSurplusQueuedTaskCount() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib h = new AsyncFib(7);
+ assertSame(h, h.fork());
+ AsyncFib g = new AsyncFib(9);
+ assertSame(g, g.fork());
+ AsyncFib f = new AsyncFib(8);
+ assertSame(f, f.fork());
+ assertTrue(getSurplusQueuedTaskCount() > 0);
+ helpQuiesce();
+ assertEquals(0, getSurplusQueuedTaskCount());
+ checkCompletedNormally(f);
+ checkCompletedNormally(g);
+ checkCompletedNormally(h);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * peekNextLocalTask returns most recent unexecuted task.
+ */
+ public void testPeekNextLocalTask() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib g = new AsyncFib(9);
+ assertSame(g, g.fork());
+ AsyncFib f = new AsyncFib(8);
+ assertSame(f, f.fork());
+ assertSame(f, peekNextLocalTask());
+ assertNull(f.join());
+ checkCompletedNormally(f);
+ helpQuiesce();
+ checkCompletedNormally(g);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * pollNextLocalTask returns most recent unexecuted task without
+ * executing it
+ */
+ public void testPollNextLocalTask() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib g = new AsyncFib(9);
+ assertSame(g, g.fork());
+ AsyncFib f = new AsyncFib(8);
+ assertSame(f, f.fork());
+ assertSame(f, pollNextLocalTask());
+ helpQuiesce();
+ checkNotDone(f);
+ assertEquals(34, g.number);
+ checkCompletedNormally(g);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * pollTask returns an unexecuted task without executing it
+ */
+ public void testPollTask() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib g = new AsyncFib(9);
+ assertSame(g, g.fork());
+ AsyncFib f = new AsyncFib(8);
+ assertSame(f, f.fork());
+ assertSame(f, pollTask());
+ helpQuiesce();
+ checkNotDone(f);
+ checkCompletedNormally(g);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * peekNextLocalTask returns least recent unexecuted task in async mode
+ */
+ public void testPeekNextLocalTaskAsync() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib g = new AsyncFib(9);
+ assertSame(g, g.fork());
+ AsyncFib f = new AsyncFib(8);
+ assertSame(f, f.fork());
+ assertSame(g, peekNextLocalTask());
+ assertNull(f.join());
+ helpQuiesce();
+ checkCompletedNormally(f);
+ assertEquals(34, g.number);
+ checkCompletedNormally(g);
+ }};
+ testInvokeOnPool(asyncSingletonPool(), a);
+ }
+
+ /**
+ * pollNextLocalTask returns least recent unexecuted task without
+ * executing it, in async mode
+ */
+ public void testPollNextLocalTaskAsync() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib g = new AsyncFib(9);
+ assertSame(g, g.fork());
+ AsyncFib f = new AsyncFib(8);
+ assertSame(f, f.fork());
+ assertSame(g, pollNextLocalTask());
+ helpQuiesce();
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ checkNotDone(g);
+ }};
+ testInvokeOnPool(asyncSingletonPool(), a);
+ }
+
+ /**
+ * pollTask returns an unexecuted task without executing it, in
+ * async mode
+ */
+ public void testPollTaskAsync() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib g = new AsyncFib(9);
+ assertSame(g, g.fork());
+ AsyncFib f = new AsyncFib(8);
+ assertSame(f, f.fork());
+ assertSame(g, pollTask());
+ helpQuiesce();
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ checkNotDone(g);
+ }};
+ testInvokeOnPool(asyncSingletonPool(), a);
+ }
+
+ // versions for singleton pools
+
+ /**
+ * invoke returns when task completes normally.
+ * isCompletedAbnormally and isCancelled return false for normally
+ * completed tasks; getRawResult returns null.
+ */
+ public void testInvokeSingleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ assertNull(f.invoke());
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * quietlyInvoke task returns when task completes normally.
+ * isCompletedAbnormally and isCancelled return false for normally
+ * completed tasks
+ */
+ public void testQuietlyInvokeSingleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ f.quietlyInvoke();
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * join of a forked task returns when task completes
+ */
+ public void testForkJoinSingleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ assertSame(f, f.fork());
+ assertNull(f.join());
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * get of a forked task returns when task completes
+ */
+ public void testForkGetSingleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ AsyncFib f = new AsyncFib(8);
+ assertSame(f, f.fork());
+ assertNull(f.get());
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * timed get of a forked task returns when task completes
+ */
+ public void testForkTimedGetSingleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ AsyncFib f = new AsyncFib(8);
+ assertSame(f, f.fork());
+ assertNull(f.get(LONG_DELAY_MS, MILLISECONDS));
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * timed get with null time unit throws NPE
+ */
+ public void testForkTimedGetNPESingleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ AsyncFib f = new AsyncFib(8);
+ assertSame(f, f.fork());
+ try {
+ f.get(5L, null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * quietlyJoin of a forked task returns when task completes
+ */
+ public void testForkQuietlyJoinSingleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ assertSame(f, f.fork());
+ f.quietlyJoin();
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * helpQuiesce returns when tasks are complete.
+ * getQueuedTaskCount returns 0 when quiescent
+ */
+ public void testForkHelpQuiesceSingleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ assertSame(f, f.fork());
+ helpQuiesce();
+ assertEquals(0, getQueuedTaskCount());
+ assertEquals(21, f.number);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * invoke task throws exception when task completes abnormally
+ */
+ public void testAbnormalInvokeSingleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingAsyncFib f = new FailingAsyncFib(8);
+ try {
+ f.invoke();
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * quietlyInvoke task returns when task completes abnormally
+ */
+ public void testAbnormalQuietlyInvokeSingleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingAsyncFib f = new FailingAsyncFib(8);
+ f.quietlyInvoke();
+ assertTrue(f.getException() instanceof FJException);
+ checkCompletedAbnormally(f, f.getException());
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * join of a forked task throws exception when task completes abnormally
+ */
+ public void testAbnormalForkJoinSingleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingAsyncFib f = new FailingAsyncFib(8);
+ assertSame(f, f.fork());
+ try {
+ f.join();
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * get of a forked task throws exception when task completes abnormally
+ */
+ public void testAbnormalForkGetSingleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ FailingAsyncFib f = new FailingAsyncFib(8);
+ assertSame(f, f.fork());
+ try {
+ f.get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ Throwable cause = success.getCause();
+ assertTrue(cause instanceof FJException);
+ checkCompletedAbnormally(f, cause);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * timed get of a forked task throws exception when task completes abnormally
+ */
+ public void testAbnormalForkTimedGetSingleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ FailingAsyncFib f = new FailingAsyncFib(8);
+ assertSame(f, f.fork());
+ try {
+ f.get(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ Throwable cause = success.getCause();
+ assertTrue(cause instanceof FJException);
+ checkCompletedAbnormally(f, cause);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * quietlyJoin of a forked task returns when task completes abnormally
+ */
+ public void testAbnormalForkQuietlyJoinSingleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingAsyncFib f = new FailingAsyncFib(8);
+ assertSame(f, f.fork());
+ f.quietlyJoin();
+ assertTrue(f.getException() instanceof FJException);
+ checkCompletedAbnormally(f, f.getException());
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * invoke task throws exception when task cancelled
+ */
+ public void testCancelledInvokeSingleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ assertTrue(f.cancel(true));
+ try {
+ f.invoke();
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * join of a forked task throws exception when task cancelled
+ */
+ public void testCancelledForkJoinSingleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ try {
+ f.join();
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * get of a forked task throws exception when task cancelled
+ */
+ public void testCancelledForkGetSingleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ AsyncFib f = new AsyncFib(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ try {
+ f.get();
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * timed get of a forked task throws exception when task cancelled
+ */
+ public void testCancelledForkTimedGetSingleton() throws Exception {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ AsyncFib f = new AsyncFib(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ try {
+ f.get(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * quietlyJoin of a forked task returns when task cancelled
+ */
+ public void testCancelledForkQuietlyJoinSingleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ f.quietlyJoin();
+ checkCancelled(f);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * invoke task throws exception after invoking completeExceptionally
+ */
+ public void testCompleteExceptionallySingleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ f.completeExceptionally(new FJException());
+ try {
+ f.invoke();
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * invokeAll(t1, t2) invokes all task arguments
+ */
+ public void testInvokeAll2Singleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ AsyncFib g = new AsyncFib(9);
+ invokeAll(f, g);
+ assertEquals(21, f.number);
+ assertEquals(34, g.number);
+ checkCompletedNormally(f);
+ checkCompletedNormally(g);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with 1 argument invokes task
+ */
+ public void testInvokeAll1Singleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ invokeAll(f);
+ checkCompletedNormally(f);
+ assertEquals(21, f.number);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with > 2 argument invokes tasks
+ */
+ public void testInvokeAll3Singleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ AsyncFib g = new AsyncFib(9);
+ AsyncFib h = new AsyncFib(7);
+ invokeAll(f, g, h);
+ assertEquals(21, f.number);
+ assertEquals(34, g.number);
+ assertEquals(13, h.number);
+ checkCompletedNormally(f);
+ checkCompletedNormally(g);
+ checkCompletedNormally(h);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * invokeAll(collection) invokes all tasks in the collection
+ */
+ public void testInvokeAllCollectionSingleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ AsyncFib g = new AsyncFib(9);
+ AsyncFib h = new AsyncFib(7);
+ HashSet set = new HashSet();
+ set.add(f);
+ set.add(g);
+ set.add(h);
+ invokeAll(set);
+ assertEquals(21, f.number);
+ assertEquals(34, g.number);
+ assertEquals(13, h.number);
+ checkCompletedNormally(f);
+ checkCompletedNormally(g);
+ checkCompletedNormally(h);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with any null task throws NPE
+ */
+ public void testInvokeAllNPESingleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ AsyncFib g = new AsyncFib(9);
+ AsyncFib h = null;
+ try {
+ invokeAll(f, g, h);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * invokeAll(t1, t2) throw exception if any task does
+ */
+ public void testAbnormalInvokeAll2Singleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ FailingAsyncFib g = new FailingAsyncFib(9);
+ try {
+ invokeAll(f, g);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(g, success);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with 1 argument throws exception if task does
+ */
+ public void testAbnormalInvokeAll1Singleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingAsyncFib g = new FailingAsyncFib(9);
+ try {
+ invokeAll(g);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(g, success);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with > 2 argument throws exception if any task does
+ */
+ public void testAbnormalInvokeAll3Singleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ AsyncFib f = new AsyncFib(8);
+ FailingAsyncFib g = new FailingAsyncFib(9);
+ AsyncFib h = new AsyncFib(7);
+ try {
+ invokeAll(f, g, h);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(g, success);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * invokeAll(collection) throws exception if any task does
+ */
+ public void testAbnormalInvokeAllCollectionSingleton() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingAsyncFib f = new FailingAsyncFib(8);
+ AsyncFib g = new AsyncFib(9);
+ AsyncFib h = new AsyncFib(7);
+ HashSet set = new HashSet();
+ set.add(f);
+ set.add(g);
+ set.add(h);
+ try {
+ invokeAll(set);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/FutureTaskTest.java b/jsr166-tests/src/test/java/jsr166/FutureTaskTest.java
new file mode 100644
index 0000000..baab79e
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/FutureTaskTest.java
@@ -0,0 +1,799 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import java.util.*;
+
+public class FutureTaskTest extends JSR166TestCase {
+
+ void checkIsDone(Future<?> f) {
+ assertTrue(f.isDone());
+ assertFalse(f.cancel(false));
+ assertFalse(f.cancel(true));
+ if (f instanceof PublicFutureTask) {
+ PublicFutureTask pf = (PublicFutureTask) f;
+ assertEquals(1, pf.doneCount());
+ assertFalse(pf.runAndReset());
+ assertEquals(1, pf.doneCount());
+ Object r = null; Object exInfo = null;
+ try {
+ r = f.get();
+ } catch (CancellationException t) {
+ exInfo = CancellationException.class;
+ } catch (ExecutionException t) {
+ exInfo = t.getCause();
+ } catch (Throwable t) {
+ threadUnexpectedException(t);
+ }
+
+ // Check that run and runAndReset have no effect.
+ int savedRunCount = pf.runCount();
+ pf.run();
+ pf.runAndReset();
+ assertEquals(savedRunCount, pf.runCount());
+ try {
+ assertSame(r, f.get());
+ } catch (CancellationException t) {
+ assertSame(exInfo, CancellationException.class);
+ } catch (ExecutionException t) {
+ assertSame(exInfo, t.getCause());
+ } catch (Throwable t) {
+ threadUnexpectedException(t);
+ }
+ assertTrue(f.isDone());
+ }
+ }
+
+ void checkNotDone(Future<?> f) {
+ assertFalse(f.isDone());
+ assertFalse(f.isCancelled());
+ if (f instanceof PublicFutureTask) {
+ PublicFutureTask pf = (PublicFutureTask) f;
+ assertEquals(0, pf.doneCount());
+ assertEquals(0, pf.setCount());
+ assertEquals(0, pf.setExceptionCount());
+ }
+ }
+
+ void checkIsRunning(Future<?> f) {
+ checkNotDone(f);
+ if (f instanceof FutureTask) {
+ FutureTask ft = (FutureTask<?>) f;
+ // Check that run methods do nothing
+ ft.run();
+ if (f instanceof PublicFutureTask) {
+ PublicFutureTask pf = (PublicFutureTask) f;
+ int savedRunCount = pf.runCount();
+ pf.run();
+ assertFalse(pf.runAndReset());
+ assertEquals(savedRunCount, pf.runCount());
+ }
+ checkNotDone(f);
+ }
+ }
+
+ <T> void checkCompletedNormally(Future<T> f, T expected) {
+ checkIsDone(f);
+ assertFalse(f.isCancelled());
+
+ try {
+ assertSame(expected, f.get());
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ try {
+ assertSame(expected, f.get(5L, SECONDS));
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ void checkCancelled(Future<?> f) {
+ checkIsDone(f);
+ assertTrue(f.isCancelled());
+
+ try {
+ f.get();
+ shouldThrow();
+ } catch (CancellationException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+
+ try {
+ f.get(5L, SECONDS);
+ shouldThrow();
+ } catch (CancellationException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ void tryToConfuseDoneTask(PublicFutureTask pf) {
+ pf.set(new Object());
+ pf.setException(new Error());
+ for (boolean mayInterruptIfRunning : new boolean[] { true, false }) {
+ pf.cancel(true);
+ }
+ }
+
+ void checkCompletedAbnormally(Future<?> f, Throwable t) {
+ checkIsDone(f);
+ assertFalse(f.isCancelled());
+
+ try {
+ f.get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertSame(t, success.getCause());
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+
+ try {
+ f.get(5L, SECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertSame(t, success.getCause());
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ /**
+ * Subclass to expose protected methods
+ */
+ static class PublicFutureTask extends FutureTask {
+ private final AtomicInteger runCount;
+ private final AtomicInteger doneCount = new AtomicInteger(0);
+ private final AtomicInteger runAndResetCount = new AtomicInteger(0);
+ private final AtomicInteger setCount = new AtomicInteger(0);
+ private final AtomicInteger setExceptionCount = new AtomicInteger(0);
+ public int runCount() { return runCount.get(); }
+ public int doneCount() { return doneCount.get(); }
+ public int runAndResetCount() { return runAndResetCount.get(); }
+ public int setCount() { return setCount.get(); }
+ public int setExceptionCount() { return setExceptionCount.get(); }
+
+ PublicFutureTask(Runnable runnable) {
+ this(runnable, seven);
+ }
+ PublicFutureTask(Runnable runnable, Object result) {
+ this(runnable, result, new AtomicInteger(0));
+ }
+ private PublicFutureTask(final Runnable runnable, Object result,
+ final AtomicInteger runCount) {
+ super(new Runnable() {
+ public void run() {
+ runCount.getAndIncrement();
+ runnable.run();
+ }}, result);
+ this.runCount = runCount;
+ }
+ PublicFutureTask(Callable callable) {
+ this(callable, new AtomicInteger(0));
+ }
+ private PublicFutureTask(final Callable callable,
+ final AtomicInteger runCount) {
+ super(new Callable() {
+ public Object call() throws Exception {
+ runCount.getAndIncrement();
+ return callable.call();
+ }});
+ this.runCount = runCount;
+ }
+ @Override public void done() {
+ assertTrue(isDone());
+ doneCount.incrementAndGet();
+ super.done();
+ }
+ @Override public boolean runAndReset() {
+ runAndResetCount.incrementAndGet();
+ return super.runAndReset();
+ }
+ @Override public void set(Object x) {
+ setCount.incrementAndGet();
+ super.set(x);
+ }
+ @Override public void setException(Throwable t) {
+ setExceptionCount.incrementAndGet();
+ super.setException(t);
+ }
+ }
+
+ class Counter extends CheckedRunnable {
+ final AtomicInteger count = new AtomicInteger(0);
+ public int get() { return count.get(); }
+ public void realRun() {
+ count.getAndIncrement();
+ }
+ }
+
+ /**
+ * creating a future with a null callable throws NullPointerException
+ */
+ public void testConstructor() {
+ try {
+ new FutureTask(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * creating a future with null runnable throws NullPointerException
+ */
+ public void testConstructor2() {
+ try {
+ new FutureTask(null, Boolean.TRUE);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * isDone is true when a task completes
+ */
+ public void testIsDone() {
+ PublicFutureTask task = new PublicFutureTask(new NoOpCallable());
+ assertFalse(task.isDone());
+ task.run();
+ assertTrue(task.isDone());
+ checkCompletedNormally(task, Boolean.TRUE);
+ assertEquals(1, task.runCount());
+ }
+
+ /**
+ * runAndReset of a non-cancelled task succeeds
+ */
+ public void testRunAndReset() {
+ PublicFutureTask task = new PublicFutureTask(new NoOpCallable());
+ for (int i = 0; i < 3; i++) {
+ assertTrue(task.runAndReset());
+ checkNotDone(task);
+ assertEquals(i+1, task.runCount());
+ assertEquals(i+1, task.runAndResetCount());
+ assertEquals(0, task.setCount());
+ assertEquals(0, task.setExceptionCount());
+ }
+ }
+
+ /**
+ * runAndReset after cancellation fails
+ */
+ public void testRunAndResetAfterCancel() {
+ for (boolean mayInterruptIfRunning : new boolean[] { true, false }) {
+ PublicFutureTask task = new PublicFutureTask(new NoOpCallable());
+ assertTrue(task.cancel(mayInterruptIfRunning));
+ for (int i = 0; i < 3; i++) {
+ assertFalse(task.runAndReset());
+ assertEquals(0, task.runCount());
+ assertEquals(i+1, task.runAndResetCount());
+ assertEquals(0, task.setCount());
+ assertEquals(0, task.setExceptionCount());
+ }
+ tryToConfuseDoneTask(task);
+ checkCancelled(task);
+ }
+ }
+
+ /**
+ * setting value causes get to return it
+ */
+ public void testSet() throws Exception {
+ PublicFutureTask task = new PublicFutureTask(new NoOpCallable());
+ task.set(one);
+ for (int i = 0; i < 3; i++) {
+ assertSame(one, task.get());
+ assertSame(one, task.get(LONG_DELAY_MS, MILLISECONDS));
+ assertEquals(1, task.setCount());
+ }
+ tryToConfuseDoneTask(task);
+ checkCompletedNormally(task, one);
+ assertEquals(0, task.runCount());
+ }
+
+ /**
+ * setException causes get to throw ExecutionException
+ */
+ public void testSetException_get() throws Exception {
+ Exception nse = new NoSuchElementException();
+ PublicFutureTask task = new PublicFutureTask(new NoOpCallable());
+ task.setException(nse);
+
+ try {
+ task.get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertSame(nse, success.getCause());
+ checkCompletedAbnormally(task, nse);
+ }
+
+ try {
+ task.get(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertSame(nse, success.getCause());
+ checkCompletedAbnormally(task, nse);
+ }
+
+ assertEquals(1, task.setExceptionCount());
+ assertEquals(0, task.setCount());
+ tryToConfuseDoneTask(task);
+ checkCompletedAbnormally(task, nse);
+ assertEquals(0, task.runCount());
+ }
+
+ /**
+ * cancel(false) before run succeeds
+ */
+ public void testCancelBeforeRun() {
+ PublicFutureTask task = new PublicFutureTask(new NoOpCallable());
+ assertTrue(task.cancel(false));
+ task.run();
+ assertEquals(0, task.runCount());
+ assertEquals(0, task.setCount());
+ assertEquals(0, task.setExceptionCount());
+ assertTrue(task.isCancelled());
+ assertTrue(task.isDone());
+ tryToConfuseDoneTask(task);
+ assertEquals(0, task.runCount());
+ checkCancelled(task);
+ }
+
+ /**
+ * cancel(true) before run succeeds
+ */
+ public void testCancelBeforeRun2() {
+ PublicFutureTask task = new PublicFutureTask(new NoOpCallable());
+ assertTrue(task.cancel(true));
+ task.run();
+ assertEquals(0, task.runCount());
+ assertEquals(0, task.setCount());
+ assertEquals(0, task.setExceptionCount());
+ assertTrue(task.isCancelled());
+ assertTrue(task.isDone());
+ tryToConfuseDoneTask(task);
+ assertEquals(0, task.runCount());
+ checkCancelled(task);
+ }
+
+ /**
+ * cancel(false) of a completed task fails
+ */
+ public void testCancelAfterRun() {
+ PublicFutureTask task = new PublicFutureTask(new NoOpCallable());
+ task.run();
+ assertFalse(task.cancel(false));
+ assertEquals(1, task.runCount());
+ assertEquals(1, task.setCount());
+ assertEquals(0, task.setExceptionCount());
+ tryToConfuseDoneTask(task);
+ checkCompletedNormally(task, Boolean.TRUE);
+ assertEquals(1, task.runCount());
+ }
+
+ /**
+ * cancel(true) of a completed task fails
+ */
+ public void testCancelAfterRun2() {
+ PublicFutureTask task = new PublicFutureTask(new NoOpCallable());
+ task.run();
+ assertFalse(task.cancel(true));
+ assertEquals(1, task.runCount());
+ assertEquals(1, task.setCount());
+ assertEquals(0, task.setExceptionCount());
+ tryToConfuseDoneTask(task);
+ checkCompletedNormally(task, Boolean.TRUE);
+ assertEquals(1, task.runCount());
+ }
+
+ /**
+ * cancel(true) interrupts a running task that subsequently succeeds
+ */
+ public void testCancelInterrupt() {
+ final CountDownLatch pleaseCancel = new CountDownLatch(1);
+ final PublicFutureTask task =
+ new PublicFutureTask(new CheckedRunnable() {
+ public void realRun() {
+ pleaseCancel.countDown();
+ try {
+ delay(LONG_DELAY_MS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ }});
+
+ Thread t = newStartedThread(task);
+ await(pleaseCancel);
+ assertTrue(task.cancel(true));
+ assertTrue(task.isCancelled());
+ assertTrue(task.isDone());
+ awaitTermination(t);
+ assertEquals(1, task.runCount());
+ assertEquals(1, task.setCount());
+ assertEquals(0, task.setExceptionCount());
+ tryToConfuseDoneTask(task);
+ checkCancelled(task);
+ }
+
+ /**
+ * cancel(true) tries to interrupt a running task, but
+ * Thread.interrupt throws (simulating a restrictive security
+ * manager)
+ */
+ public void testCancelInterrupt_ThrowsSecurityException() {
+ final CountDownLatch pleaseCancel = new CountDownLatch(1);
+ final CountDownLatch cancelled = new CountDownLatch(1);
+ final PublicFutureTask task =
+ new PublicFutureTask(new CheckedRunnable() {
+ public void realRun() {
+ pleaseCancel.countDown();
+ await(cancelled);
+ assertFalse(Thread.interrupted());
+ }});
+
+ final Thread t = new Thread(task) {
+ // Simulate a restrictive security manager.
+ @Override public void interrupt() {
+ throw new SecurityException();
+ }};
+ t.setDaemon(true);
+ t.start();
+
+ await(pleaseCancel);
+ try {
+ task.cancel(true);
+ shouldThrow();
+ } catch (SecurityException expected) {}
+
+ // We failed to deliver the interrupt, but the world retains
+ // its sanity, as if we had done task.cancel(false)
+ assertTrue(task.isCancelled());
+ assertTrue(task.isDone());
+ assertEquals(1, task.runCount());
+ assertEquals(1, task.doneCount());
+ assertEquals(0, task.setCount());
+ assertEquals(0, task.setExceptionCount());
+ cancelled.countDown();
+ awaitTermination(t);
+ assertEquals(1, task.setCount());
+ assertEquals(0, task.setExceptionCount());
+ tryToConfuseDoneTask(task);
+ checkCancelled(task);
+ }
+
+ /**
+ * cancel(true) interrupts a running task that subsequently throws
+ */
+ public void testCancelInterrupt_taskFails() {
+ final CountDownLatch pleaseCancel = new CountDownLatch(1);
+ final PublicFutureTask task =
+ new PublicFutureTask(new Runnable() {
+ public void run() {
+ try {
+ pleaseCancel.countDown();
+ delay(LONG_DELAY_MS);
+ threadShouldThrow();
+ } catch (InterruptedException success) {
+ } catch (Throwable t) { threadUnexpectedException(t); }
+ throw new RuntimeException();
+ }});
+
+ Thread t = newStartedThread(task);
+ await(pleaseCancel);
+ assertTrue(task.cancel(true));
+ assertTrue(task.isCancelled());
+ awaitTermination(t);
+ assertEquals(1, task.runCount());
+ assertEquals(0, task.setCount());
+ assertEquals(1, task.setExceptionCount());
+ tryToConfuseDoneTask(task);
+ checkCancelled(task);
+ }
+
+ /**
+ * cancel(false) does not interrupt a running task
+ */
+ public void testCancelNoInterrupt() {
+ final CountDownLatch pleaseCancel = new CountDownLatch(1);
+ final CountDownLatch cancelled = new CountDownLatch(1);
+ final PublicFutureTask task =
+ new PublicFutureTask(new CheckedCallable<Boolean>() {
+ public Boolean realCall() {
+ pleaseCancel.countDown();
+ await(cancelled);
+ assertFalse(Thread.interrupted());
+ return Boolean.TRUE;
+ }});
+
+ Thread t = newStartedThread(task);
+ await(pleaseCancel);
+ assertTrue(task.cancel(false));
+ assertTrue(task.isCancelled());
+ cancelled.countDown();
+ awaitTermination(t);
+ assertEquals(1, task.runCount());
+ assertEquals(1, task.setCount());
+ assertEquals(0, task.setExceptionCount());
+ tryToConfuseDoneTask(task);
+ checkCancelled(task);
+ }
+
+ /**
+ * run in one thread causes get in another thread to retrieve value
+ */
+ public void testGetRun() {
+ final CountDownLatch pleaseRun = new CountDownLatch(2);
+
+ final PublicFutureTask task =
+ new PublicFutureTask(new CheckedCallable<Object>() {
+ public Object realCall() {
+ return two;
+ }});
+
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws Exception {
+ pleaseRun.countDown();
+ assertSame(two, task.get());
+ }});
+
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws Exception {
+ pleaseRun.countDown();
+ assertSame(two, task.get(2*LONG_DELAY_MS, MILLISECONDS));
+ }});
+
+ await(pleaseRun);
+ checkNotDone(task);
+ assertTrue(t1.isAlive());
+ assertTrue(t2.isAlive());
+ task.run();
+ checkCompletedNormally(task, two);
+ assertEquals(1, task.runCount());
+ assertEquals(1, task.setCount());
+ assertEquals(0, task.setExceptionCount());
+ awaitTermination(t1);
+ awaitTermination(t2);
+ tryToConfuseDoneTask(task);
+ checkCompletedNormally(task, two);
+ }
+
+ /**
+ * set in one thread causes get in another thread to retrieve value
+ */
+ public void testGetSet() {
+ final CountDownLatch pleaseSet = new CountDownLatch(2);
+
+ final PublicFutureTask task =
+ new PublicFutureTask(new CheckedCallable<Object>() {
+ public Object realCall() throws InterruptedException {
+ return two;
+ }});
+
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws Exception {
+ pleaseSet.countDown();
+ assertSame(two, task.get());
+ }});
+
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws Exception {
+ pleaseSet.countDown();
+ assertSame(two, task.get(2*LONG_DELAY_MS, MILLISECONDS));
+ }});
+
+ await(pleaseSet);
+ checkNotDone(task);
+ assertTrue(t1.isAlive());
+ assertTrue(t2.isAlive());
+ task.set(two);
+ assertEquals(0, task.runCount());
+ assertEquals(1, task.setCount());
+ assertEquals(0, task.setExceptionCount());
+ tryToConfuseDoneTask(task);
+ checkCompletedNormally(task, two);
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * Cancelling a task causes timed get in another thread to throw
+ * CancellationException
+ */
+ public void testTimedGet_Cancellation() {
+ testTimedGet_Cancellation(false);
+ }
+ public void testTimedGet_Cancellation_interrupt() {
+ testTimedGet_Cancellation(true);
+ }
+ public void testTimedGet_Cancellation(final boolean mayInterruptIfRunning) {
+ final CountDownLatch pleaseCancel = new CountDownLatch(3);
+ final CountDownLatch cancelled = new CountDownLatch(1);
+ final Callable<Object> callable =
+ new CheckedCallable<Object>() {
+ public Object realCall() throws InterruptedException {
+ pleaseCancel.countDown();
+ if (mayInterruptIfRunning) {
+ try {
+ delay(2*LONG_DELAY_MS);
+ } catch (InterruptedException success) {}
+ } else {
+ await(cancelled);
+ }
+ return two;
+ }};
+ final PublicFutureTask task = new PublicFutureTask(callable);
+
+ Thread t1 = new ThreadShouldThrow(CancellationException.class) {
+ public void realRun() throws Exception {
+ pleaseCancel.countDown();
+ task.get();
+ }};
+ Thread t2 = new ThreadShouldThrow(CancellationException.class) {
+ public void realRun() throws Exception {
+ pleaseCancel.countDown();
+ task.get(2*LONG_DELAY_MS, MILLISECONDS);
+ }};
+ t1.start();
+ t2.start();
+ Thread t3 = newStartedThread(task);
+ await(pleaseCancel);
+ checkIsRunning(task);
+ task.cancel(mayInterruptIfRunning);
+ checkCancelled(task);
+ awaitTermination(t1);
+ awaitTermination(t2);
+ cancelled.countDown();
+ awaitTermination(t3);
+ assertEquals(1, task.runCount());
+ assertEquals(1, task.setCount());
+ assertEquals(0, task.setExceptionCount());
+ tryToConfuseDoneTask(task);
+ checkCancelled(task);
+ }
+
+ /**
+ * A runtime exception in task causes get to throw ExecutionException
+ */
+ public void testGet_ExecutionException() throws InterruptedException {
+ final ArithmeticException e = new ArithmeticException();
+ final PublicFutureTask task = new PublicFutureTask(new Callable() {
+ public Object call() {
+ throw e;
+ }});
+
+ task.run();
+ assertEquals(1, task.runCount());
+ assertEquals(0, task.setCount());
+ assertEquals(1, task.setExceptionCount());
+ try {
+ task.get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertSame(e, success.getCause());
+ tryToConfuseDoneTask(task);
+ checkCompletedAbnormally(task, success.getCause());
+ }
+ }
+
+ /**
+ * A runtime exception in task causes timed get to throw ExecutionException
+ */
+ public void testTimedGet_ExecutionException2() throws Exception {
+ final ArithmeticException e = new ArithmeticException();
+ final PublicFutureTask task = new PublicFutureTask(new Callable() {
+ public Object call() {
+ throw e;
+ }});
+
+ task.run();
+ try {
+ task.get(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertSame(e, success.getCause());
+ tryToConfuseDoneTask(task);
+ checkCompletedAbnormally(task, success.getCause());
+ }
+ }
+
+ /**
+ * get is interruptible
+ */
+ public void testGet_interruptible() {
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ final FutureTask task = new FutureTask(new NoOpCallable());
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws Exception {
+ Thread.currentThread().interrupt();
+ try {
+ task.get();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ task.get();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ t.interrupt();
+ awaitTermination(t);
+ checkNotDone(task);
+ }
+
+ /**
+ * timed get is interruptible
+ */
+ public void testTimedGet_interruptible() {
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ final FutureTask task = new FutureTask(new NoOpCallable());
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws Exception {
+ Thread.currentThread().interrupt();
+ try {
+ task.get(2*LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ task.get(2*LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ t.interrupt();
+ awaitTermination(t);
+ checkNotDone(task);
+ }
+
+ /**
+ * A timed out timed get throws TimeoutException
+ */
+ public void testGet_TimeoutException() throws Exception {
+ FutureTask task = new FutureTask(new NoOpCallable());
+ long startTime = System.nanoTime();
+ try {
+ task.get(timeoutMillis(), MILLISECONDS);
+ shouldThrow();
+ } catch (TimeoutException success) {
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ }
+ }
+
+ /**
+ * timed get with null TimeUnit throws NullPointerException
+ */
+ public void testGet_NullTimeUnit() throws Exception {
+ FutureTask task = new FutureTask(new NoOpCallable());
+ long[] timeouts = { Long.MIN_VALUE, 0L, Long.MAX_VALUE };
+
+ for (long timeout : timeouts) {
+ try {
+ task.get(timeout, null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ task.run();
+
+ for (long timeout : timeouts) {
+ try {
+ task.get(timeout, null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/JSR166TestCase.java b/jsr166-tests/src/test/java/jsr166/JSR166TestCase.java
new file mode 100644
index 0000000..d9bf255
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/JSR166TestCase.java
@@ -0,0 +1,1140 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.PropertyPermission;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.Policy;
+import java.security.ProtectionDomain;
+import java.security.SecurityPermission;
+
+/**
+ * Base class for JSR166 Junit TCK tests. Defines some constants,
+ * utility methods and classes, as well as a simple framework for
+ * helping to make sure that assertions failing in generated threads
+ * cause the associated test that generated them to itself fail (which
+ * JUnit does not otherwise arrange). The rules for creating such
+ * tests are:
+ *
+ * <ol>
+ *
+ * <li> All assertions in code running in generated threads must use
+ * the forms {@link #threadFail}, {@link #threadAssertTrue}, {@link
+ * #threadAssertEquals}, or {@link #threadAssertNull}, (not
+ * {@code fail}, {@code assertTrue}, etc.) It is OK (but not
+ * particularly recommended) for other code to use these forms too.
+ * Only the most typically used JUnit assertion methods are defined
+ * this way, but enough to live with.</li>
+ *
+ * <li> If you override {@link #setUp} or {@link #tearDown}, make sure
+ * to invoke {@code super.setUp} and {@code super.tearDown} within
+ * them. These methods are used to clear and check for thread
+ * assertion failures.</li>
+ *
+ * <li>All delays and timeouts must use one of the constants {@code
+ * SHORT_DELAY_MS}, {@code SMALL_DELAY_MS}, {@code MEDIUM_DELAY_MS},
+ * {@code LONG_DELAY_MS}. The idea here is that a SHORT is always
+ * discriminable from zero time, and always allows enough time for the
+ * small amounts of computation (creating a thread, calling a few
+ * methods, etc) needed to reach a timeout point. Similarly, a SMALL
+ * is always discriminable as larger than SHORT and smaller than
+ * MEDIUM. And so on. These constants are set to conservative values,
+ * but even so, if there is ever any doubt, they can all be increased
+ * in one spot to rerun tests on slower platforms.</li>
+ *
+ * <li> All threads generated must be joined inside each test case
+ * method (or {@code fail} to do so) before returning from the
+ * method. The {@code joinPool} method can be used to do this when
+ * using Executors.</li>
+ *
+ * </ol>
+ *
+ * <p><b>Other notes</b>
+ * <ul>
+ *
+ * <li> Usually, there is one testcase method per JSR166 method
+ * covering "normal" operation, and then as many exception-testing
+ * methods as there are exceptions the method can throw. Sometimes
+ * there are multiple tests per JSR166 method when the different
+ * "normal" behaviors differ significantly. And sometimes testcases
+ * cover multiple methods when they cannot be tested in
+ * isolation.</li>
+ *
+ * <li> The documentation style for testcases is to provide as javadoc
+ * a simple sentence or two describing the property that the testcase
+ * method purports to test. The javadocs do not say anything about how
+ * the property is tested. To find out, read the code.</li>
+ *
+ * <li> These tests are "conformance tests", and do not attempt to
+ * test throughput, latency, scalability or other performance factors
+ * (see the separate "jtreg" tests for a set intended to check these
+ * for the most central aspects of functionality.) So, most tests use
+ * the smallest sensible numbers of threads, collection sizes, etc
+ * needed to check basic conformance.</li>
+ *
+ * <li>The test classes currently do not declare inclusion in
+ * any particular package to simplify things for people integrating
+ * them in TCK test suites.</li>
+ *
+ * <li> As a convenience, the {@code main} of this class (JSR166TestCase)
+ * runs all JSR166 unit tests.</li>
+ *
+ * </ul>
+ */
+public class JSR166TestCase extends TestCase {
+
+ protected static final boolean expensiveTests = false;
+
+ public static long SHORT_DELAY_MS;
+ public static long SMALL_DELAY_MS;
+ public static long MEDIUM_DELAY_MS;
+ public static long LONG_DELAY_MS;
+
+
+ /**
+ * Returns the shortest timed delay. This could
+ * be reimplemented to use for example a Property.
+ */
+ protected long getShortDelay() {
+ return 50;
+ }
+
+ /**
+ * Sets delays as multiples of SHORT_DELAY.
+ */
+ protected void setDelays() {
+ SHORT_DELAY_MS = getShortDelay();
+ SMALL_DELAY_MS = SHORT_DELAY_MS * 5;
+ MEDIUM_DELAY_MS = SHORT_DELAY_MS * 10;
+ LONG_DELAY_MS = SHORT_DELAY_MS * 200;
+ }
+
+ /**
+ * Returns a timeout in milliseconds to be used in tests that
+ * verify that operations block or time out.
+ */
+ long timeoutMillis() {
+ return SHORT_DELAY_MS / 4;
+ }
+
+ /**
+ * Returns a new Date instance representing a time delayMillis
+ * milliseconds in the future.
+ */
+ Date delayedDate(long delayMillis) {
+ return new Date(System.currentTimeMillis() + delayMillis);
+ }
+
+ /**
+ * The first exception encountered if any threadAssertXXX method fails.
+ */
+ private final AtomicReference<Throwable> threadFailure
+ = new AtomicReference<Throwable>(null);
+
+ /**
+ * Records an exception so that it can be rethrown later in the test
+ * harness thread, triggering a test case failure. Only the first
+ * failure is recorded; subsequent calls to this method from within
+ * the same test have no effect.
+ */
+ public void threadRecordFailure(Throwable t) {
+ threadFailure.compareAndSet(null, t);
+ }
+
+ public void setUp() {
+ setDelays();
+ }
+
+ /**
+ * Extra checks that get done for all test cases.
+ *
+ * Triggers test case failure if any thread assertions have failed,
+ * by rethrowing, in the test harness thread, any exception recorded
+ * earlier by threadRecordFailure.
+ *
+ * Triggers test case failure if interrupt status is set in the main thread.
+ */
+ public void tearDown() throws Exception {
+ Throwable t = threadFailure.getAndSet(null);
+ if (t != null) {
+ if (t instanceof Error)
+ throw (Error) t;
+ else if (t instanceof RuntimeException)
+ throw (RuntimeException) t;
+ else if (t instanceof Exception)
+ throw (Exception) t;
+ else {
+ AssertionFailedError afe =
+ new AssertionFailedError(t.toString());
+ afe.initCause(t);
+ throw afe;
+ }
+ }
+
+ if (Thread.interrupted())
+ throw new AssertionFailedError("interrupt status set in main thread");
+
+ checkForkJoinPoolThreadLeaks();
+ }
+
+ /**
+ * Find missing try { ... } finally { joinPool(e); }
+ */
+ void checkForkJoinPoolThreadLeaks() throws InterruptedException {
+ Thread[] survivors = new Thread[5];
+ int count = Thread.enumerate(survivors);
+ for (int i = 0; i < count; i++) {
+ Thread thread = survivors[i];
+ String name = thread.getName();
+ if (name.startsWith("ForkJoinPool-")) {
+ // give thread some time to terminate
+ thread.join(LONG_DELAY_MS);
+ if (!thread.isAlive()) continue;
+ thread.stop();
+ throw new AssertionFailedError
+ (String.format("Found leaked ForkJoinPool thread test=%s thread=%s%n",
+ toString(), name));
+ }
+ }
+ }
+
+ /**
+ * Just like fail(reason), but additionally recording (using
+ * threadRecordFailure) any AssertionFailedError thrown, so that
+ * the current testcase will fail.
+ */
+ public void threadFail(String reason) {
+ try {
+ fail(reason);
+ } catch (AssertionFailedError t) {
+ threadRecordFailure(t);
+ fail(reason);
+ }
+ }
+
+ /**
+ * Just like assertTrue(b), but additionally recording (using
+ * threadRecordFailure) any AssertionFailedError thrown, so that
+ * the current testcase will fail.
+ */
+ public void threadAssertTrue(boolean b) {
+ try {
+ assertTrue(b);
+ } catch (AssertionFailedError t) {
+ threadRecordFailure(t);
+ throw t;
+ }
+ }
+
+ /**
+ * Just like assertFalse(b), but additionally recording (using
+ * threadRecordFailure) any AssertionFailedError thrown, so that
+ * the current testcase will fail.
+ */
+ public void threadAssertFalse(boolean b) {
+ try {
+ assertFalse(b);
+ } catch (AssertionFailedError t) {
+ threadRecordFailure(t);
+ throw t;
+ }
+ }
+
+ /**
+ * Just like assertNull(x), but additionally recording (using
+ * threadRecordFailure) any AssertionFailedError thrown, so that
+ * the current testcase will fail.
+ */
+ public void threadAssertNull(Object x) {
+ try {
+ assertNull(x);
+ } catch (AssertionFailedError t) {
+ threadRecordFailure(t);
+ throw t;
+ }
+ }
+
+ /**
+ * Just like assertEquals(x, y), but additionally recording (using
+ * threadRecordFailure) any AssertionFailedError thrown, so that
+ * the current testcase will fail.
+ */
+ public void threadAssertEquals(long x, long y) {
+ try {
+ assertEquals(x, y);
+ } catch (AssertionFailedError t) {
+ threadRecordFailure(t);
+ throw t;
+ }
+ }
+
+ /**
+ * Just like assertEquals(x, y), but additionally recording (using
+ * threadRecordFailure) any AssertionFailedError thrown, so that
+ * the current testcase will fail.
+ */
+ public void threadAssertEquals(Object x, Object y) {
+ try {
+ assertEquals(x, y);
+ } catch (AssertionFailedError t) {
+ threadRecordFailure(t);
+ throw t;
+ } catch (Throwable t) {
+ threadUnexpectedException(t);
+ }
+ }
+
+ /**
+ * Just like assertSame(x, y), but additionally recording (using
+ * threadRecordFailure) any AssertionFailedError thrown, so that
+ * the current testcase will fail.
+ */
+ public void threadAssertSame(Object x, Object y) {
+ try {
+ assertSame(x, y);
+ } catch (AssertionFailedError t) {
+ threadRecordFailure(t);
+ throw t;
+ }
+ }
+
+ /**
+ * Calls threadFail with message "should throw exception".
+ */
+ public void threadShouldThrow() {
+ threadFail("should throw exception");
+ }
+
+ /**
+ * Calls threadFail with message "should throw" + exceptionName.
+ */
+ public void threadShouldThrow(String exceptionName) {
+ threadFail("should throw " + exceptionName);
+ }
+
+ /**
+ * Records the given exception using {@link #threadRecordFailure},
+ * then rethrows the exception, wrapping it in an
+ * AssertionFailedError if necessary.
+ */
+ public void threadUnexpectedException(Throwable t) {
+ threadRecordFailure(t);
+ t.printStackTrace();
+ if (t instanceof RuntimeException)
+ throw (RuntimeException) t;
+ else if (t instanceof Error)
+ throw (Error) t;
+ else {
+ AssertionFailedError afe =
+ new AssertionFailedError("unexpected exception: " + t);
+ afe.initCause(t);
+ throw afe;
+ }
+ }
+
+ /**
+ * Delays, via Thread.sleep, for the given millisecond delay, but
+ * if the sleep is shorter than specified, may re-sleep or yield
+ * until time elapses.
+ */
+ static void delay(long millis) throws InterruptedException {
+ long startTime = System.nanoTime();
+ long ns = millis * 1000 * 1000;
+ for (;;) {
+ if (millis > 0L)
+ Thread.sleep(millis);
+ else // too short to sleep
+ Thread.yield();
+ long d = ns - (System.nanoTime() - startTime);
+ if (d > 0L)
+ millis = d / (1000 * 1000);
+ else
+ break;
+ }
+ }
+
+ /**
+ * Waits out termination of a thread pool or fails doing so.
+ */
+ void joinPool(ExecutorService exec) {
+ try {
+ exec.shutdown();
+ assertTrue("ExecutorService did not terminate in a timely manner",
+ exec.awaitTermination(2 * LONG_DELAY_MS, MILLISECONDS));
+ } catch (SecurityException ok) {
+ // Allowed in case test doesn't have privs
+ } catch (InterruptedException ie) {
+ fail("Unexpected InterruptedException");
+ }
+ }
+
+ /**
+ * Checks that thread does not terminate within the default
+ * millisecond delay of {@code timeoutMillis()}.
+ */
+ void assertThreadStaysAlive(Thread thread) {
+ assertThreadStaysAlive(thread, timeoutMillis());
+ }
+
+ /**
+ * Checks that thread does not terminate within the given millisecond delay.
+ */
+ void assertThreadStaysAlive(Thread thread, long millis) {
+ try {
+ // No need to optimize the failing case via Thread.join.
+ delay(millis);
+ assertTrue(thread.isAlive());
+ } catch (InterruptedException ie) {
+ fail("Unexpected InterruptedException");
+ }
+ }
+
+ /**
+ * Checks that the threads do not terminate within the default
+ * millisecond delay of {@code timeoutMillis()}.
+ */
+ void assertThreadsStayAlive(Thread... threads) {
+ assertThreadsStayAlive(timeoutMillis(), threads);
+ }
+
+ /**
+ * Checks that the threads do not terminate within the given millisecond delay.
+ */
+ void assertThreadsStayAlive(long millis, Thread... threads) {
+ try {
+ // No need to optimize the failing case via Thread.join.
+ delay(millis);
+ for (Thread thread : threads)
+ assertTrue(thread.isAlive());
+ } catch (InterruptedException ie) {
+ fail("Unexpected InterruptedException");
+ }
+ }
+
+ /**
+ * Checks that future.get times out, with the default timeout of
+ * {@code timeoutMillis()}.
+ */
+ void assertFutureTimesOut(Future future) {
+ assertFutureTimesOut(future, timeoutMillis());
+ }
+
+ /**
+ * Checks that future.get times out, with the given millisecond timeout.
+ */
+ void assertFutureTimesOut(Future future, long timeoutMillis) {
+ long startTime = System.nanoTime();
+ try {
+ future.get(timeoutMillis, MILLISECONDS);
+ shouldThrow();
+ } catch (TimeoutException success) {
+ } catch (Exception e) {
+ threadUnexpectedException(e);
+ } finally { future.cancel(true); }
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
+ }
+
+ /**
+ * Fails with message "should throw exception".
+ */
+ public void shouldThrow() {
+ fail("Should throw exception");
+ }
+
+ /**
+ * Fails with message "should throw " + exceptionName.
+ */
+ public void shouldThrow(String exceptionName) {
+ fail("Should throw " + exceptionName);
+ }
+
+ /**
+ * The number of elements to place in collections, arrays, etc.
+ */
+ public static final int SIZE = 20;
+
+ // Some convenient Integer constants
+
+ public static final Integer zero = new Integer(0);
+ public static final Integer one = new Integer(1);
+ public static final Integer two = new Integer(2);
+ public static final Integer three = new Integer(3);
+ public static final Integer four = new Integer(4);
+ public static final Integer five = new Integer(5);
+ public static final Integer six = new Integer(6);
+ public static final Integer seven = new Integer(7);
+ public static final Integer eight = new Integer(8);
+ public static final Integer nine = new Integer(9);
+ public static final Integer m1 = new Integer(-1);
+ public static final Integer m2 = new Integer(-2);
+ public static final Integer m3 = new Integer(-3);
+ public static final Integer m4 = new Integer(-4);
+ public static final Integer m5 = new Integer(-5);
+ public static final Integer m6 = new Integer(-6);
+ public static final Integer m10 = new Integer(-10);
+
+
+ /**
+ * android-changed
+ * Android does not use a SecurityManager. This will simply execute
+ * the runnable ingoring permisions.
+ */
+ public void runWithPermissions(Runnable r, Permission... permissions) {
+ r.run();
+ }
+
+ /**
+ * android-changed
+ * Android does not use a SecurityManager. This will simply execute
+ * the runnable ingoring permisions.
+ */
+ public void runWithSecurityManagerWithPermissions(Runnable r,
+ Permission... permissions) {
+ r.run();
+ }
+
+ /**
+ * Runs a runnable without any permissions.
+ */
+ public void runWithoutPermissions(Runnable r) {
+ runWithPermissions(r);
+ }
+
+ /**
+ * A security policy where new permissions can be dynamically added
+ * or all cleared.
+ */
+ public static class AdjustablePolicy extends java.security.Policy {
+ Permissions perms = new Permissions();
+ AdjustablePolicy(Permission... permissions) {
+ for (Permission permission : permissions)
+ perms.add(permission);
+ }
+ void addPermission(Permission perm) { perms.add(perm); }
+ void clearPermissions() { perms = new Permissions(); }
+ public PermissionCollection getPermissions(CodeSource cs) {
+ return perms;
+ }
+ public PermissionCollection getPermissions(ProtectionDomain pd) {
+ return perms;
+ }
+ public boolean implies(ProtectionDomain pd, Permission p) {
+ return perms.implies(p);
+ }
+ public void refresh() {}
+ public String toString() {
+ List<Permission> ps = new ArrayList<Permission>();
+ for (Enumeration<Permission> e = perms.elements(); e.hasMoreElements();)
+ ps.add(e.nextElement());
+ return "AdjustablePolicy with permissions " + ps;
+ }
+ }
+
+ /**
+ * Returns a policy containing all the permissions we ever need.
+ */
+ public static Policy permissivePolicy() {
+ return new AdjustablePolicy
+ // Permissions j.u.c. needs directly
+ (new RuntimePermission("modifyThread"),
+ new RuntimePermission("getClassLoader"),
+ new RuntimePermission("setContextClassLoader"),
+ // Permissions needed to change permissions!
+ new SecurityPermission("getPolicy"),
+ new SecurityPermission("setPolicy"),
+ new RuntimePermission("setSecurityManager"),
+ // Permissions needed by the junit test harness
+ new RuntimePermission("accessDeclaredMembers"),
+ new PropertyPermission("*", "read"),
+ new java.io.FilePermission("<<ALL FILES>>", "read"));
+ }
+
+ /**
+ * Sleeps until the given time has elapsed.
+ * Throws AssertionFailedError if interrupted.
+ */
+ void sleep(long millis) {
+ try {
+ delay(millis);
+ } catch (InterruptedException ie) {
+ AssertionFailedError afe =
+ new AssertionFailedError("Unexpected InterruptedException");
+ afe.initCause(ie);
+ throw afe;
+ }
+ }
+
+ /**
+ * Spin-waits up to the specified number of milliseconds for the given
+ * thread to enter a wait state: BLOCKED, WAITING, or TIMED_WAITING.
+ */
+ void waitForThreadToEnterWaitState(Thread thread, long timeoutMillis) {
+ long startTime = System.nanoTime();
+ for (;;) {
+ Thread.State s = thread.getState();
+ if (s == Thread.State.BLOCKED ||
+ s == Thread.State.WAITING ||
+ s == Thread.State.TIMED_WAITING)
+ return;
+ else if (s == Thread.State.TERMINATED)
+ fail("Unexpected thread termination");
+ else if (millisElapsedSince(startTime) > timeoutMillis) {
+ threadAssertTrue(thread.isAlive());
+ return;
+ }
+ Thread.yield();
+ }
+ }
+
+ /**
+ * Waits up to LONG_DELAY_MS for the given thread to enter a wait
+ * state: BLOCKED, WAITING, or TIMED_WAITING.
+ */
+ void waitForThreadToEnterWaitState(Thread thread) {
+ waitForThreadToEnterWaitState(thread, LONG_DELAY_MS);
+ }
+
+ /**
+ * Returns the number of milliseconds since time given by
+ * startNanoTime, which must have been previously returned from a
+ * call to {@link System.nanoTime()}.
+ */
+ long millisElapsedSince(long startNanoTime) {
+ return NANOSECONDS.toMillis(System.nanoTime() - startNanoTime);
+ }
+
+ /**
+ * Returns a new started daemon Thread running the given runnable.
+ */
+ Thread newStartedThread(Runnable runnable) {
+ Thread t = new Thread(runnable);
+ t.setDaemon(true);
+ t.start();
+ return t;
+ }
+
+ /**
+ * Waits for the specified time (in milliseconds) for the thread
+ * to terminate (using {@link Thread#join(long)}), else interrupts
+ * the thread (in the hope that it may terminate later) and fails.
+ */
+ void awaitTermination(Thread t, long timeoutMillis) {
+ try {
+ t.join(timeoutMillis);
+ } catch (InterruptedException ie) {
+ threadUnexpectedException(ie);
+ } finally {
+ if (t.getState() != Thread.State.TERMINATED) {
+ t.interrupt();
+ fail("Test timed out");
+ }
+ }
+ }
+
+ /**
+ * Waits for LONG_DELAY_MS milliseconds for the thread to
+ * terminate (using {@link Thread#join(long)}), else interrupts
+ * the thread (in the hope that it may terminate later) and fails.
+ */
+ void awaitTermination(Thread t) {
+ awaitTermination(t, LONG_DELAY_MS);
+ }
+
+ // Some convenient Runnable classes
+
+ public abstract class CheckedRunnable implements Runnable {
+ protected abstract void realRun() throws Throwable;
+
+ public final void run() {
+ try {
+ realRun();
+ } catch (Throwable t) {
+ threadUnexpectedException(t);
+ }
+ }
+ }
+
+ public abstract class RunnableShouldThrow implements Runnable {
+ protected abstract void realRun() throws Throwable;
+
+ final Class<?> exceptionClass;
+
+ <T extends Throwable> RunnableShouldThrow(Class<T> exceptionClass) {
+ this.exceptionClass = exceptionClass;
+ }
+
+ public final void run() {
+ try {
+ realRun();
+ threadShouldThrow(exceptionClass.getSimpleName());
+ } catch (Throwable t) {
+ if (! exceptionClass.isInstance(t))
+ threadUnexpectedException(t);
+ }
+ }
+ }
+
+ public abstract class ThreadShouldThrow extends Thread {
+ protected abstract void realRun() throws Throwable;
+
+ final Class<?> exceptionClass;
+
+ <T extends Throwable> ThreadShouldThrow(Class<T> exceptionClass) {
+ this.exceptionClass = exceptionClass;
+ }
+
+ public final void run() {
+ try {
+ realRun();
+ threadShouldThrow(exceptionClass.getSimpleName());
+ } catch (Throwable t) {
+ if (! exceptionClass.isInstance(t))
+ threadUnexpectedException(t);
+ }
+ }
+ }
+
+ public abstract class CheckedInterruptedRunnable implements Runnable {
+ protected abstract void realRun() throws Throwable;
+
+ public final void run() {
+ try {
+ realRun();
+ threadShouldThrow("InterruptedException");
+ } catch (InterruptedException success) {
+ threadAssertFalse(Thread.interrupted());
+ } catch (Throwable t) {
+ threadUnexpectedException(t);
+ }
+ }
+ }
+
+ public abstract class CheckedCallable<T> implements Callable<T> {
+ protected abstract T realCall() throws Throwable;
+
+ public final T call() {
+ try {
+ return realCall();
+ } catch (Throwable t) {
+ threadUnexpectedException(t);
+ return null;
+ }
+ }
+ }
+
+ public abstract class CheckedInterruptedCallable<T>
+ implements Callable<T> {
+ protected abstract T realCall() throws Throwable;
+
+ public final T call() {
+ try {
+ T result = realCall();
+ threadShouldThrow("InterruptedException");
+ return result;
+ } catch (InterruptedException success) {
+ threadAssertFalse(Thread.interrupted());
+ } catch (Throwable t) {
+ threadUnexpectedException(t);
+ }
+ return null;
+ }
+ }
+
+ public static class NoOpRunnable implements Runnable {
+ public void run() {}
+ }
+
+ public static class NoOpCallable implements Callable {
+ public Object call() { return Boolean.TRUE; }
+ }
+
+ public static final String TEST_STRING = "a test string";
+
+ public static class StringTask implements Callable<String> {
+ public String call() { return TEST_STRING; }
+ }
+
+ public Callable<String> latchAwaitingStringTask(final CountDownLatch latch) {
+ return new CheckedCallable<String>() {
+ protected String realCall() {
+ try {
+ latch.await();
+ } catch (InterruptedException quittingTime) {}
+ return TEST_STRING;
+ }};
+ }
+
+ public Runnable awaiter(final CountDownLatch latch) {
+ return new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ await(latch);
+ }};
+ }
+
+ public void await(CountDownLatch latch) {
+ try {
+ assertTrue(latch.await(LONG_DELAY_MS, MILLISECONDS));
+ } catch (Throwable t) {
+ threadUnexpectedException(t);
+ }
+ }
+
+ public void await(Semaphore semaphore) {
+ try {
+ assertTrue(semaphore.tryAcquire(LONG_DELAY_MS, MILLISECONDS));
+ } catch (Throwable t) {
+ threadUnexpectedException(t);
+ }
+ }
+
+// /**
+// * Spin-waits up to LONG_DELAY_MS until flag becomes true.
+// */
+// public void await(AtomicBoolean flag) {
+// await(flag, LONG_DELAY_MS);
+// }
+
+// /**
+// * Spin-waits up to the specified timeout until flag becomes true.
+// */
+// public void await(AtomicBoolean flag, long timeoutMillis) {
+// long startTime = System.nanoTime();
+// while (!flag.get()) {
+// if (millisElapsedSince(startTime) > timeoutMillis)
+// throw new AssertionFailedError("timed out");
+// Thread.yield();
+// }
+// }
+
+ public static class NPETask implements Callable<String> {
+ public String call() { throw new NullPointerException(); }
+ }
+
+ public static class CallableOne implements Callable<Integer> {
+ public Integer call() { return one; }
+ }
+
+ public class ShortRunnable extends CheckedRunnable {
+ protected void realRun() throws Throwable {
+ delay(SHORT_DELAY_MS);
+ }
+ }
+
+ public class ShortInterruptedRunnable extends CheckedInterruptedRunnable {
+ protected void realRun() throws InterruptedException {
+ delay(SHORT_DELAY_MS);
+ }
+ }
+
+ public class SmallRunnable extends CheckedRunnable {
+ protected void realRun() throws Throwable {
+ delay(SMALL_DELAY_MS);
+ }
+ }
+
+ public class SmallPossiblyInterruptedRunnable extends CheckedRunnable {
+ protected void realRun() {
+ try {
+ delay(SMALL_DELAY_MS);
+ } catch (InterruptedException ok) {}
+ }
+ }
+
+ public class SmallCallable extends CheckedCallable {
+ protected Object realCall() throws InterruptedException {
+ delay(SMALL_DELAY_MS);
+ return Boolean.TRUE;
+ }
+ }
+
+ public class MediumRunnable extends CheckedRunnable {
+ protected void realRun() throws Throwable {
+ delay(MEDIUM_DELAY_MS);
+ }
+ }
+
+ public class MediumInterruptedRunnable extends CheckedInterruptedRunnable {
+ protected void realRun() throws InterruptedException {
+ delay(MEDIUM_DELAY_MS);
+ }
+ }
+
+ public Runnable possiblyInterruptedRunnable(final long timeoutMillis) {
+ return new CheckedRunnable() {
+ protected void realRun() {
+ try {
+ delay(timeoutMillis);
+ } catch (InterruptedException ok) {}
+ }};
+ }
+
+ public class MediumPossiblyInterruptedRunnable extends CheckedRunnable {
+ protected void realRun() {
+ try {
+ delay(MEDIUM_DELAY_MS);
+ } catch (InterruptedException ok) {}
+ }
+ }
+
+ public class LongPossiblyInterruptedRunnable extends CheckedRunnable {
+ protected void realRun() {
+ try {
+ delay(LONG_DELAY_MS);
+ } catch (InterruptedException ok) {}
+ }
+ }
+
+ /**
+ * For use as ThreadFactory in constructors
+ */
+ public static class SimpleThreadFactory implements ThreadFactory {
+ public Thread newThread(Runnable r) {
+ return new Thread(r);
+ }
+ }
+
+ public interface TrackedRunnable extends Runnable {
+ boolean isDone();
+ }
+
+ public static TrackedRunnable trackedRunnable(final long timeoutMillis) {
+ return new TrackedRunnable() {
+ private volatile boolean done = false;
+ public boolean isDone() { return done; }
+ public void run() {
+ try {
+ delay(timeoutMillis);
+ done = true;
+ } catch (InterruptedException ok) {}
+ }
+ };
+ }
+
+ public static class TrackedShortRunnable implements Runnable {
+ public volatile boolean done = false;
+ public void run() {
+ try {
+ delay(SHORT_DELAY_MS);
+ done = true;
+ } catch (InterruptedException ok) {}
+ }
+ }
+
+ public static class TrackedSmallRunnable implements Runnable {
+ public volatile boolean done = false;
+ public void run() {
+ try {
+ delay(SMALL_DELAY_MS);
+ done = true;
+ } catch (InterruptedException ok) {}
+ }
+ }
+
+ public static class TrackedMediumRunnable implements Runnable {
+ public volatile boolean done = false;
+ public void run() {
+ try {
+ delay(MEDIUM_DELAY_MS);
+ done = true;
+ } catch (InterruptedException ok) {}
+ }
+ }
+
+ public static class TrackedLongRunnable implements Runnable {
+ public volatile boolean done = false;
+ public void run() {
+ try {
+ delay(LONG_DELAY_MS);
+ done = true;
+ } catch (InterruptedException ok) {}
+ }
+ }
+
+ public static class TrackedNoOpRunnable implements Runnable {
+ public volatile boolean done = false;
+ public void run() {
+ done = true;
+ }
+ }
+
+ public static class TrackedCallable implements Callable {
+ public volatile boolean done = false;
+ public Object call() {
+ try {
+ delay(SMALL_DELAY_MS);
+ done = true;
+ } catch (InterruptedException ok) {}
+ return Boolean.TRUE;
+ }
+ }
+
+ /**
+ * Analog of CheckedRunnable for RecursiveAction
+ */
+ public abstract class CheckedRecursiveAction extends RecursiveAction {
+ protected abstract void realCompute() throws Throwable;
+
+ @Override protected final void compute() {
+ try {
+ realCompute();
+ } catch (Throwable t) {
+ threadUnexpectedException(t);
+ }
+ }
+ }
+
+ /**
+ * Analog of CheckedCallable for RecursiveTask
+ */
+ public abstract class CheckedRecursiveTask<T> extends RecursiveTask<T> {
+ protected abstract T realCompute() throws Throwable;
+
+ @Override protected final T compute() {
+ try {
+ return realCompute();
+ } catch (Throwable t) {
+ threadUnexpectedException(t);
+ return null;
+ }
+ }
+ }
+
+ /**
+ * For use as RejectedExecutionHandler in constructors
+ */
+ public static class NoOpREHandler implements RejectedExecutionHandler {
+ public void rejectedExecution(Runnable r,
+ ThreadPoolExecutor executor) {}
+ }
+
+ /**
+ * A CyclicBarrier that uses timed await and fails with
+ * AssertionFailedErrors instead of throwing checked exceptions.
+ */
+ public class CheckedBarrier extends CyclicBarrier {
+ public CheckedBarrier(int parties) { super(parties); }
+
+ public int await() {
+ try {
+ return super.await(2 * LONG_DELAY_MS, MILLISECONDS);
+ } catch (TimeoutException e) {
+ throw new AssertionFailedError("timed out");
+ } catch (Exception e) {
+ AssertionFailedError afe =
+ new AssertionFailedError("Unexpected exception: " + e);
+ afe.initCause(e);
+ throw afe;
+ }
+ }
+ }
+
+ void checkEmpty(BlockingQueue q) {
+ try {
+ assertTrue(q.isEmpty());
+ assertEquals(0, q.size());
+ assertNull(q.peek());
+ assertNull(q.poll());
+ assertNull(q.poll(0, MILLISECONDS));
+ assertEquals(q.toString(), "[]");
+ assertTrue(Arrays.equals(q.toArray(), new Object[0]));
+ assertFalse(q.iterator().hasNext());
+ try {
+ q.element();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ try {
+ q.iterator().next();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ try {
+ q.remove();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ } catch (InterruptedException ie) {
+ threadUnexpectedException(ie);
+ }
+ }
+
+ void assertSerialEquals(Object x, Object y) {
+ assertTrue(Arrays.equals(serialBytes(x), serialBytes(y)));
+ }
+
+ void assertNotSerialEquals(Object x, Object y) {
+ assertFalse(Arrays.equals(serialBytes(x), serialBytes(y)));
+ }
+
+ byte[] serialBytes(Object o) {
+ try {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(bos);
+ oos.writeObject(o);
+ oos.flush();
+ oos.close();
+ return bos.toByteArray();
+ } catch (Throwable t) {
+ threadUnexpectedException(t);
+ return new byte[0];
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ <T> T serialClone(T o) {
+ try {
+ ObjectInputStream ois = new ObjectInputStream
+ (new ByteArrayInputStream(serialBytes(o)));
+ T clone = (T) ois.readObject();
+ assertSame(o.getClass(), clone.getClass());
+ return clone;
+ } catch (Throwable t) {
+ threadUnexpectedException(t);
+ return null;
+ }
+ }
+
+ public void assertThrows(Class<? extends Throwable> expectedExceptionClass,
+ Runnable... throwingActions) {
+ for (Runnable throwingAction : throwingActions) {
+ boolean threw = false;
+ try { throwingAction.run(); }
+ catch (Throwable t) {
+ threw = true;
+ if (!expectedExceptionClass.isInstance(t)) {
+ AssertionFailedError afe =
+ new AssertionFailedError
+ ("Expected " + expectedExceptionClass.getName() +
+ ", got " + t.getClass().getName());
+ afe.initCause(t);
+ threadUnexpectedException(afe);
+ }
+ }
+ if (!threw)
+ shouldThrow(expectedExceptionClass.getName());
+ }
+ }
+}
diff --git a/jsr166-tests/src/test/java/jsr166/LinkedBlockingDequeTest.java b/jsr166-tests/src/test/java/jsr166/LinkedBlockingDequeTest.java
new file mode 100644
index 0000000..638a7ac
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/LinkedBlockingDequeTest.java
@@ -0,0 +1,1769 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+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;
+import java.util.concurrent.LinkedBlockingDeque;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+public class LinkedBlockingDequeTest extends JSR166TestCase {
+
+ public static class Unbounded extends BlockingQueueTest {
+ protected BlockingQueue emptyCollection() {
+ return new LinkedBlockingDeque();
+ }
+ }
+
+ public static class Bounded extends BlockingQueueTest {
+ protected BlockingQueue emptyCollection() {
+ return new LinkedBlockingDeque(SIZE);
+ }
+ }
+
+ /**
+ * Returns a new deque of given size containing consecutive
+ * Integers 0 ... n.
+ */
+ private LinkedBlockingDeque<Integer> populatedDeque(int n) {
+ LinkedBlockingDeque<Integer> q =
+ new LinkedBlockingDeque<Integer>(n);
+ assertTrue(q.isEmpty());
+ for (int i = 0; i < n; i++)
+ assertTrue(q.offer(new Integer(i)));
+ assertFalse(q.isEmpty());
+ assertEquals(0, q.remainingCapacity());
+ assertEquals(n, q.size());
+ return q;
+ }
+
+ /**
+ * isEmpty is true before add, false after
+ */
+ public void testEmpty() {
+ LinkedBlockingDeque q = new LinkedBlockingDeque();
+ assertTrue(q.isEmpty());
+ q.add(new Integer(1));
+ assertFalse(q.isEmpty());
+ q.add(new Integer(2));
+ q.removeFirst();
+ q.removeFirst();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * size changes when elements added and removed
+ */
+ public void testSize() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(SIZE-i, q.size());
+ q.removeFirst();
+ }
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.size());
+ q.add(new Integer(i));
+ }
+ }
+
+ /**
+ * offerFirst(null) throws NullPointerException
+ */
+ public void testOfferFirstNull() {
+ LinkedBlockingDeque q = new LinkedBlockingDeque();
+ try {
+ q.offerFirst(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * offerLast(null) throws NullPointerException
+ */
+ public void testOfferLastNull() {
+ LinkedBlockingDeque q = new LinkedBlockingDeque();
+ try {
+ q.offerLast(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * OfferFirst succeeds
+ */
+ public void testOfferFirst() {
+ LinkedBlockingDeque q = new LinkedBlockingDeque();
+ assertTrue(q.offerFirst(new Integer(0)));
+ assertTrue(q.offerFirst(new Integer(1)));
+ }
+
+ /**
+ * OfferLast succeeds
+ */
+ public void testOfferLast() {
+ LinkedBlockingDeque q = new LinkedBlockingDeque();
+ assertTrue(q.offerLast(new Integer(0)));
+ assertTrue(q.offerLast(new Integer(1)));
+ }
+
+ /**
+ * pollFirst succeeds unless empty
+ */
+ public void testPollFirst() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.pollFirst());
+ }
+ assertNull(q.pollFirst());
+ }
+
+ /**
+ * pollLast succeeds unless empty
+ */
+ public void testPollLast() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = SIZE-1; i >= 0; --i) {
+ assertEquals(i, q.pollLast());
+ }
+ assertNull(q.pollLast());
+ }
+
+ /**
+ * peekFirst returns next element, or null if empty
+ */
+ public void testPeekFirst() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.peekFirst());
+ assertEquals(i, q.pollFirst());
+ assertTrue(q.peekFirst() == null ||
+ !q.peekFirst().equals(i));
+ }
+ assertNull(q.peekFirst());
+ }
+
+ /**
+ * peek returns next element, or null if empty
+ */
+ public void testPeek() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.peek());
+ assertEquals(i, q.pollFirst());
+ assertTrue(q.peek() == null ||
+ !q.peek().equals(i));
+ }
+ assertNull(q.peek());
+ }
+
+ /**
+ * peekLast returns next element, or null if empty
+ */
+ public void testPeekLast() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = SIZE-1; i >= 0; --i) {
+ assertEquals(i, q.peekLast());
+ assertEquals(i, q.pollLast());
+ assertTrue(q.peekLast() == null ||
+ !q.peekLast().equals(i));
+ }
+ assertNull(q.peekLast());
+ }
+
+ /**
+ * getFirst() returns first element, or throws NSEE if empty
+ */
+ public void testFirstElement() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.getFirst());
+ assertEquals(i, q.pollFirst());
+ }
+ try {
+ q.getFirst();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ assertNull(q.peekFirst());
+ }
+
+ /**
+ * getLast() returns last element, or throws NSEE if empty
+ */
+ public void testLastElement() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = SIZE-1; i >= 0; --i) {
+ assertEquals(i, q.getLast());
+ assertEquals(i, q.pollLast());
+ }
+ try {
+ q.getLast();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ assertNull(q.peekLast());
+ }
+
+ /**
+ * removeFirst() removes first element, or throws NSEE if empty
+ */
+ public void testRemoveFirst() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.removeFirst());
+ }
+ try {
+ q.removeFirst();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ assertNull(q.peekFirst());
+ }
+
+ /**
+ * removeLast() removes last element, or throws NSEE if empty
+ */
+ public void testRemoveLast() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = SIZE - 1; i >= 0; --i) {
+ assertEquals(i, q.removeLast());
+ }
+ try {
+ q.removeLast();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ assertNull(q.peekLast());
+ }
+
+ /**
+ * remove removes next element, or throws NSEE if empty
+ */
+ public void testRemove() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.remove());
+ }
+ try {
+ q.remove();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * removeFirstOccurrence(x) removes x and returns true if present
+ */
+ public void testRemoveFirstOccurrence() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 1; i < SIZE; i+=2) {
+ assertTrue(q.removeFirstOccurrence(new Integer(i)));
+ }
+ for (int i = 0; i < SIZE; i+=2) {
+ assertTrue(q.removeFirstOccurrence(new Integer(i)));
+ assertFalse(q.removeFirstOccurrence(new Integer(i+1)));
+ }
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * removeLastOccurrence(x) removes x and returns true if present
+ */
+ public void testRemoveLastOccurrence() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 1; i < SIZE; i+=2) {
+ assertTrue(q.removeLastOccurrence(new Integer(i)));
+ }
+ for (int i = 0; i < SIZE; i+=2) {
+ assertTrue(q.removeLastOccurrence(new Integer(i)));
+ assertFalse(q.removeLastOccurrence(new Integer(i+1)));
+ }
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * peekFirst returns element inserted with addFirst
+ */
+ public void testAddFirst() {
+ LinkedBlockingDeque q = populatedDeque(3);
+ q.pollLast();
+ q.addFirst(four);
+ assertSame(four, q.peekFirst());
+ }
+
+ /**
+ * peekLast returns element inserted with addLast
+ */
+ public void testAddLast() {
+ LinkedBlockingDeque q = populatedDeque(3);
+ q.pollLast();
+ q.addLast(four);
+ assertSame(four, q.peekLast());
+ }
+
+ /**
+ * A new deque has the indicated capacity, or Integer.MAX_VALUE if
+ * none given
+ */
+ public void testConstructor1() {
+ assertEquals(SIZE, new LinkedBlockingDeque(SIZE).remainingCapacity());
+ assertEquals(Integer.MAX_VALUE, new LinkedBlockingDeque().remainingCapacity());
+ }
+
+ /**
+ * Constructor throws IllegalArgumentException if capacity argument nonpositive
+ */
+ public void testConstructor2() {
+ try {
+ new LinkedBlockingDeque(0);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Initializing from null Collection throws NullPointerException
+ */
+ public void testConstructor3() {
+ try {
+ new LinkedBlockingDeque(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing from Collection of null elements throws NullPointerException
+ */
+ public void testConstructor4() {
+ Collection<Integer> elements = Arrays.asList(new Integer[SIZE]);
+ try {
+ new LinkedBlockingDeque(elements);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing from Collection with some null elements throws
+ * NullPointerException
+ */
+ public void testConstructor5() {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = i;
+ Collection<Integer> elements = Arrays.asList(ints);
+ try {
+ new LinkedBlockingDeque(elements);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Deque contains all elements of collection used to initialize
+ */
+ public void testConstructor6() {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = i;
+ LinkedBlockingDeque q = new LinkedBlockingDeque(Arrays.asList(ints));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(ints[i], q.poll());
+ }
+
+ /**
+ * Deque transitions from empty to full when elements added
+ */
+ public void testEmptyFull() {
+ LinkedBlockingDeque q = new LinkedBlockingDeque(2);
+ assertTrue(q.isEmpty());
+ assertEquals("should have room for 2", 2, q.remainingCapacity());
+ q.add(one);
+ assertFalse(q.isEmpty());
+ q.add(two);
+ assertFalse(q.isEmpty());
+ assertEquals(0, q.remainingCapacity());
+ assertFalse(q.offer(three));
+ }
+
+ /**
+ * remainingCapacity decreases on add, increases on remove
+ */
+ public void testRemainingCapacity() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.remainingCapacity());
+ assertEquals(SIZE-i, q.size());
+ q.remove();
+ }
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(SIZE-i, q.remainingCapacity());
+ assertEquals(i, q.size());
+ q.add(new Integer(i));
+ }
+ }
+
+ /**
+ * push(null) throws NPE
+ */
+ public void testPushNull() {
+ try {
+ LinkedBlockingDeque q = new LinkedBlockingDeque(1);
+ q.push(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * push succeeds if not full; throws ISE if full
+ */
+ public void testPush() {
+ try {
+ LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ Integer I = new Integer(i);
+ q.push(I);
+ assertEquals(I, q.peek());
+ }
+ assertEquals(0, q.remainingCapacity());
+ q.push(new Integer(SIZE));
+ shouldThrow();
+ } catch (IllegalStateException success) {}
+ }
+
+ /**
+ * peekFirst returns element inserted with push
+ */
+ public void testPushWithPeek() {
+ LinkedBlockingDeque q = populatedDeque(3);
+ q.pollLast();
+ q.push(four);
+ assertSame(four, q.peekFirst());
+ }
+
+ /**
+ * pop removes next element, or throws NSEE if empty
+ */
+ public void testPop() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.pop());
+ }
+ try {
+ q.pop();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * Offer succeeds if not full; fails if full
+ */
+ public void testOffer() {
+ LinkedBlockingDeque q = new LinkedBlockingDeque(1);
+ assertTrue(q.offer(zero));
+ assertFalse(q.offer(one));
+ }
+
+ /**
+ * add succeeds if not full; throws ISE if full
+ */
+ public void testAdd() {
+ LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i)
+ assertTrue(q.add(new Integer(i)));
+ assertEquals(0, q.remainingCapacity());
+ try {
+ q.add(new Integer(SIZE));
+ shouldThrow();
+ } catch (IllegalStateException success) {}
+ }
+
+ /**
+ * addAll(this) throws IAE
+ */
+ public void testAddAllSelf() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ try {
+ q.addAll(q);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * addAll of a collection with any null elements throws NPE after
+ * possibly adding some elements
+ */
+ public void testAddAll3() {
+ LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE);
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
+ Collection<Integer> elements = Arrays.asList(ints);
+ try {
+ q.addAll(elements);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll throws IllegalStateException if not enough room
+ */
+ public void testAddAll4() {
+ LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE - 1);
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(i);
+ Collection<Integer> elements = Arrays.asList(ints);
+ try {
+ q.addAll(elements);
+ shouldThrow();
+ } catch (IllegalStateException success) {}
+ }
+
+ /**
+ * Deque contains all elements, in traversal order, of successful addAll
+ */
+ public void testAddAll5() {
+ Integer[] empty = new Integer[0];
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(i);
+ LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE);
+ assertFalse(q.addAll(Arrays.asList(empty)));
+ assertTrue(q.addAll(Arrays.asList(ints)));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(ints[i], q.poll());
+ }
+
+ /**
+ * all elements successfully put are contained
+ */
+ public void testPut() throws InterruptedException {
+ LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ Integer I = new Integer(i);
+ q.put(I);
+ assertTrue(q.contains(I));
+ }
+ assertEquals(0, q.remainingCapacity());
+ }
+
+ /**
+ * put blocks interruptibly if full
+ */
+ public void testBlockingPut() throws InterruptedException {
+ final LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ for (int i = 0; i < SIZE; ++i)
+ q.put(i);
+ assertEquals(SIZE, q.size());
+ assertEquals(0, q.remainingCapacity());
+
+ Thread.currentThread().interrupt();
+ try {
+ q.put(99);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ q.put(99);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ assertEquals(SIZE, q.size());
+ assertEquals(0, q.remainingCapacity());
+ }
+
+ /**
+ * put blocks interruptibly waiting for take when full
+ */
+ public void testPutWithTake() throws InterruptedException {
+ final int capacity = 2;
+ final LinkedBlockingDeque q = new LinkedBlockingDeque(capacity);
+ final CountDownLatch pleaseTake = new CountDownLatch(1);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ for (int i = 0; i < capacity; i++)
+ q.put(i);
+ pleaseTake.countDown();
+ q.put(86);
+
+ pleaseInterrupt.countDown();
+ try {
+ q.put(99);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseTake);
+ assertEquals(0, q.remainingCapacity());
+ assertEquals(0, q.take());
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ assertEquals(0, q.remainingCapacity());
+ }
+
+ /**
+ * timed offer times out if full and elements not taken
+ */
+ public void testTimedOffer() throws InterruptedException {
+ final LinkedBlockingDeque q = new LinkedBlockingDeque(2);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ q.put(new Object());
+ q.put(new Object());
+ long startTime = System.nanoTime();
+ assertFalse(q.offer(new Object(), timeoutMillis(), MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ pleaseInterrupt.countDown();
+ try {
+ q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * take retrieves elements in FIFO order
+ */
+ public void testTake() throws InterruptedException {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.take());
+ }
+ }
+
+ /**
+ * take removes existing elements until empty, then blocks interruptibly
+ */
+ public void testBlockingTake() throws InterruptedException {
+ final LinkedBlockingDeque q = populatedDeque(SIZE);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.take());
+ }
+
+ Thread.currentThread().interrupt();
+ try {
+ q.take();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ q.take();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * poll succeeds unless empty
+ */
+ public void testPoll() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.poll());
+ }
+ assertNull(q.poll());
+ }
+
+ /**
+ * timed poll with zero timeout succeeds when non-empty, else times out
+ */
+ public void testTimedPoll0() throws InterruptedException {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.poll(0, MILLISECONDS));
+ }
+ assertNull(q.poll(0, MILLISECONDS));
+ }
+
+ /**
+ * timed poll with nonzero timeout succeeds when non-empty, else times out
+ */
+ public void testTimedPoll() throws InterruptedException {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ long startTime = System.nanoTime();
+ assertEquals(i, q.poll(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ }
+ long startTime = System.nanoTime();
+ assertNull(q.poll(timeoutMillis(), MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ checkEmpty(q);
+ }
+
+ /**
+ * Interrupted timed poll throws InterruptedException instead of
+ * returning timeout status
+ */
+ public void testInterruptedTimedPoll() throws InterruptedException {
+ final BlockingQueue<Integer> q = populatedDeque(SIZE);
+ final CountDownLatch aboutToWait = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ for (int i = 0; i < SIZE; ++i) {
+ long t0 = System.nanoTime();
+ assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
+ }
+ long t0 = System.nanoTime();
+ aboutToWait.countDown();
+ try {
+ q.poll(MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {
+ assertTrue(millisElapsedSince(t0) < MEDIUM_DELAY_MS);
+ }
+ }});
+
+ aboutToWait.await();
+ waitForThreadToEnterWaitState(t, SMALL_DELAY_MS);
+ t.interrupt();
+ awaitTermination(t, MEDIUM_DELAY_MS);
+ checkEmpty(q);
+ }
+
+ /**
+ * putFirst(null) throws NPE
+ */
+ public void testPutFirstNull() throws InterruptedException {
+ LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE);
+ try {
+ q.putFirst(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * all elements successfully putFirst are contained
+ */
+ public void testPutFirst() throws InterruptedException {
+ LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ Integer I = new Integer(i);
+ q.putFirst(I);
+ assertTrue(q.contains(I));
+ }
+ assertEquals(0, q.remainingCapacity());
+ }
+
+ /**
+ * putFirst blocks interruptibly if full
+ */
+ public void testBlockingPutFirst() throws InterruptedException {
+ final LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ for (int i = 0; i < SIZE; ++i)
+ q.putFirst(i);
+ assertEquals(SIZE, q.size());
+ assertEquals(0, q.remainingCapacity());
+
+ Thread.currentThread().interrupt();
+ try {
+ q.putFirst(99);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ q.putFirst(99);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ assertEquals(SIZE, q.size());
+ assertEquals(0, q.remainingCapacity());
+ }
+
+ /**
+ * putFirst blocks interruptibly waiting for take when full
+ */
+ public void testPutFirstWithTake() throws InterruptedException {
+ final int capacity = 2;
+ final LinkedBlockingDeque q = new LinkedBlockingDeque(capacity);
+ final CountDownLatch pleaseTake = new CountDownLatch(1);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ for (int i = 0; i < capacity; i++)
+ q.putFirst(i);
+ pleaseTake.countDown();
+ q.putFirst(86);
+
+ pleaseInterrupt.countDown();
+ try {
+ q.putFirst(99);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseTake);
+ assertEquals(0, q.remainingCapacity());
+ assertEquals(capacity - 1, q.take());
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ assertEquals(0, q.remainingCapacity());
+ }
+
+ /**
+ * timed offerFirst times out if full and elements not taken
+ */
+ public void testTimedOfferFirst() throws InterruptedException {
+ final LinkedBlockingDeque q = new LinkedBlockingDeque(2);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ q.putFirst(new Object());
+ q.putFirst(new Object());
+ long startTime = System.nanoTime();
+ assertFalse(q.offerFirst(new Object(), timeoutMillis(), MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ pleaseInterrupt.countDown();
+ try {
+ q.offerFirst(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * take retrieves elements in FIFO order
+ */
+ public void testTakeFirst() throws InterruptedException {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.takeFirst());
+ }
+ }
+
+ /**
+ * takeFirst() blocks interruptibly when empty
+ */
+ public void testTakeFirstFromEmptyBlocksInterruptibly() {
+ final BlockingDeque q = new LinkedBlockingDeque();
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ threadStarted.countDown();
+ try {
+ q.takeFirst();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(threadStarted);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * takeFirst() throws InterruptedException immediately if interrupted
+ * before waiting
+ */
+ public void testTakeFirstFromEmptyAfterInterrupt() {
+ final BlockingDeque q = new LinkedBlockingDeque();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ Thread.currentThread().interrupt();
+ try {
+ q.takeFirst();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ awaitTermination(t);
+ }
+
+ /**
+ * takeLast() blocks interruptibly when empty
+ */
+ public void testTakeLastFromEmptyBlocksInterruptibly() {
+ final BlockingDeque q = new LinkedBlockingDeque();
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ threadStarted.countDown();
+ try {
+ q.takeLast();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(threadStarted);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * takeLast() throws InterruptedException immediately if interrupted
+ * before waiting
+ */
+ public void testTakeLastFromEmptyAfterInterrupt() {
+ final BlockingDeque q = new LinkedBlockingDeque();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ Thread.currentThread().interrupt();
+ try {
+ q.takeLast();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ awaitTermination(t);
+ }
+
+ /**
+ * takeFirst removes existing elements until empty, then blocks interruptibly
+ */
+ public void testBlockingTakeFirst() throws InterruptedException {
+ final LinkedBlockingDeque q = populatedDeque(SIZE);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.takeFirst());
+ }
+
+ Thread.currentThread().interrupt();
+ try {
+ q.takeFirst();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ q.takeFirst();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * timed pollFirst with zero timeout succeeds when non-empty, else times out
+ */
+ public void testTimedPollFirst0() throws InterruptedException {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.pollFirst(0, MILLISECONDS));
+ }
+ assertNull(q.pollFirst(0, MILLISECONDS));
+ }
+
+ /**
+ * timed pollFirst with nonzero timeout succeeds when non-empty, else times out
+ */
+ public void testTimedPollFirst() throws InterruptedException {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ long startTime = System.nanoTime();
+ assertEquals(i, q.pollFirst(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ }
+ long startTime = System.nanoTime();
+ assertNull(q.pollFirst(timeoutMillis(), MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ checkEmpty(q);
+ }
+
+ /**
+ * Interrupted timed pollFirst throws InterruptedException instead of
+ * returning timeout status
+ */
+ public void testInterruptedTimedPollFirst() throws InterruptedException {
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.pollFirst(LONG_DELAY_MS, MILLISECONDS));
+ }
+
+ Thread.currentThread().interrupt();
+ try {
+ q.pollFirst(SMALL_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ q.pollFirst(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * timed pollFirst before a delayed offerFirst fails; after offerFirst succeeds;
+ * on interruption throws
+ */
+ public void testTimedPollFirstWithOfferFirst() throws InterruptedException {
+ final LinkedBlockingDeque q = new LinkedBlockingDeque(2);
+ final CheckedBarrier barrier = new CheckedBarrier(2);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ long startTime = System.nanoTime();
+ assertNull(q.pollFirst(timeoutMillis(), MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+
+ barrier.await();
+
+ assertSame(zero, q.pollFirst(LONG_DELAY_MS, MILLISECONDS));
+
+ Thread.currentThread().interrupt();
+ try {
+ q.pollFirst(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+
+ barrier.await();
+ try {
+ q.pollFirst(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ }});
+
+ barrier.await();
+ long startTime = System.nanoTime();
+ assertTrue(q.offerFirst(zero, LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ barrier.await();
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * putLast(null) throws NPE
+ */
+ public void testPutLastNull() throws InterruptedException {
+ LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE);
+ try {
+ q.putLast(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * all elements successfully putLast are contained
+ */
+ public void testPutLast() throws InterruptedException {
+ LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ Integer I = new Integer(i);
+ q.putLast(I);
+ assertTrue(q.contains(I));
+ }
+ assertEquals(0, q.remainingCapacity());
+ }
+
+ /**
+ * putLast blocks interruptibly if full
+ */
+ public void testBlockingPutLast() throws InterruptedException {
+ final LinkedBlockingDeque q = new LinkedBlockingDeque(SIZE);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ for (int i = 0; i < SIZE; ++i)
+ q.putLast(i);
+ assertEquals(SIZE, q.size());
+ assertEquals(0, q.remainingCapacity());
+
+ Thread.currentThread().interrupt();
+ try {
+ q.putLast(99);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ q.putLast(99);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ assertEquals(SIZE, q.size());
+ assertEquals(0, q.remainingCapacity());
+ }
+
+ /**
+ * putLast blocks interruptibly waiting for take when full
+ */
+ public void testPutLastWithTake() throws InterruptedException {
+ final int capacity = 2;
+ final LinkedBlockingDeque q = new LinkedBlockingDeque(capacity);
+ final CountDownLatch pleaseTake = new CountDownLatch(1);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ for (int i = 0; i < capacity; i++)
+ q.putLast(i);
+ pleaseTake.countDown();
+ q.putLast(86);
+
+ pleaseInterrupt.countDown();
+ try {
+ q.putLast(99);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseTake);
+ assertEquals(0, q.remainingCapacity());
+ assertEquals(0, q.take());
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ assertEquals(0, q.remainingCapacity());
+ }
+
+ /**
+ * timed offerLast times out if full and elements not taken
+ */
+ public void testTimedOfferLast() throws InterruptedException {
+ final LinkedBlockingDeque q = new LinkedBlockingDeque(2);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ q.putLast(new Object());
+ q.putLast(new Object());
+ long startTime = System.nanoTime();
+ assertFalse(q.offerLast(new Object(), timeoutMillis(), MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ pleaseInterrupt.countDown();
+ try {
+ q.offerLast(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * takeLast retrieves elements in FIFO order
+ */
+ public void testTakeLast() throws InterruptedException {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(SIZE-i-1, q.takeLast());
+ }
+ }
+
+ /**
+ * takeLast removes existing elements until empty, then blocks interruptibly
+ */
+ public void testBlockingTakeLast() throws InterruptedException {
+ final LinkedBlockingDeque q = populatedDeque(SIZE);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(SIZE-i-1, q.takeLast());
+ }
+
+ Thread.currentThread().interrupt();
+ try {
+ q.takeLast();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ q.takeLast();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * timed pollLast with zero timeout succeeds when non-empty, else times out
+ */
+ public void testTimedPollLast0() throws InterruptedException {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(SIZE-i-1, q.pollLast(0, MILLISECONDS));
+ }
+ assertNull(q.pollLast(0, MILLISECONDS));
+ }
+
+ /**
+ * timed pollLast with nonzero timeout succeeds when non-empty, else times out
+ */
+ public void testTimedPollLast() throws InterruptedException {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ long startTime = System.nanoTime();
+ assertEquals(SIZE-i-1, q.pollLast(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ }
+ long startTime = System.nanoTime();
+ assertNull(q.pollLast(timeoutMillis(), MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ checkEmpty(q);
+ }
+
+ /**
+ * Interrupted timed pollLast throws InterruptedException instead of
+ * returning timeout status
+ */
+ public void testInterruptedTimedPollLast() throws InterruptedException {
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(SIZE-i-1, q.pollLast(LONG_DELAY_MS, MILLISECONDS));
+ }
+
+ Thread.currentThread().interrupt();
+ try {
+ q.pollLast(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ q.pollLast(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * timed poll before a delayed offerLast fails; after offerLast succeeds;
+ * on interruption throws
+ */
+ public void testTimedPollWithOfferLast() throws InterruptedException {
+ final LinkedBlockingDeque q = new LinkedBlockingDeque(2);
+ final CheckedBarrier barrier = new CheckedBarrier(2);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ long startTime = System.nanoTime();
+ assertNull(q.poll(timeoutMillis(), MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+
+ barrier.await();
+
+ assertSame(zero, q.poll(LONG_DELAY_MS, MILLISECONDS));
+
+ Thread.currentThread().interrupt();
+ try {
+ q.poll(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ barrier.await();
+ try {
+ q.poll(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ barrier.await();
+ long startTime = System.nanoTime();
+ assertTrue(q.offerLast(zero, LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+
+ barrier.await();
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * element returns next element, or throws NSEE if empty
+ */
+ public void testElement() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.element());
+ q.poll();
+ }
+ try {
+ q.element();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * contains(x) reports true when elements added but not yet removed
+ */
+ public void testContains() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.contains(new Integer(i)));
+ q.poll();
+ assertFalse(q.contains(new Integer(i)));
+ }
+ }
+
+ /**
+ * clear removes all elements
+ */
+ public void testClear() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ q.clear();
+ assertTrue(q.isEmpty());
+ assertEquals(0, q.size());
+ assertEquals(SIZE, q.remainingCapacity());
+ q.add(one);
+ assertFalse(q.isEmpty());
+ assertTrue(q.contains(one));
+ q.clear();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * containsAll(c) is true when c contains a subset of elements
+ */
+ public void testContainsAll() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ LinkedBlockingDeque p = new LinkedBlockingDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.containsAll(p));
+ assertFalse(p.containsAll(q));
+ p.add(new Integer(i));
+ }
+ assertTrue(p.containsAll(q));
+ }
+
+ /**
+ * retainAll(c) retains only those elements of c and reports true if changed
+ */
+ public void testRetainAll() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ LinkedBlockingDeque p = populatedDeque(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ boolean changed = q.retainAll(p);
+ if (i == 0)
+ assertFalse(changed);
+ else
+ assertTrue(changed);
+
+ assertTrue(q.containsAll(p));
+ assertEquals(SIZE-i, q.size());
+ p.remove();
+ }
+ }
+
+ /**
+ * removeAll(c) removes only those elements of c and reports true if changed
+ */
+ public void testRemoveAll() {
+ for (int i = 1; i < SIZE; ++i) {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ LinkedBlockingDeque p = populatedDeque(i);
+ assertTrue(q.removeAll(p));
+ assertEquals(SIZE-i, q.size());
+ for (int j = 0; j < i; ++j) {
+ Integer I = (Integer)(p.remove());
+ assertFalse(q.contains(I));
+ }
+ }
+ }
+
+ /**
+ * toArray contains all elements in FIFO order
+ */
+ public void testToArray() throws InterruptedException {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ Object[] o = q.toArray();
+ for (int i = 0; i < o.length; i++)
+ assertSame(o[i], q.poll());
+ }
+
+ /**
+ * toArray(a) contains all elements in FIFO order
+ */
+ public void testToArray2() {
+ LinkedBlockingDeque<Integer> q = populatedDeque(SIZE);
+ Integer[] ints = new Integer[SIZE];
+ Integer[] array = q.toArray(ints);
+ assertSame(ints, array);
+ for (int i = 0; i < ints.length; i++)
+ assertSame(ints[i], q.remove());
+ }
+
+ /**
+ * toArray(incompatible array type) throws ArrayStoreException
+ */
+ public void testToArray1_BadArg() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ try {
+ q.toArray(new String[10]);
+ shouldThrow();
+ } catch (ArrayStoreException success) {}
+ }
+
+ /**
+ * iterator iterates through all elements
+ */
+ public void testIterator() throws InterruptedException {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ assertEquals(it.next(), q.take());
+ }
+ }
+
+ /**
+ * iterator.remove removes current element
+ */
+ public void testIteratorRemove() {
+ final LinkedBlockingDeque q = new LinkedBlockingDeque(3);
+ q.add(two);
+ q.add(one);
+ q.add(three);
+
+ Iterator it = q.iterator();
+ it.next();
+ it.remove();
+
+ it = q.iterator();
+ assertSame(it.next(), one);
+ assertSame(it.next(), three);
+ assertFalse(it.hasNext());
+ }
+
+ /**
+ * iterator ordering is FIFO
+ */
+ public void testIteratorOrdering() {
+ final LinkedBlockingDeque q = new LinkedBlockingDeque(3);
+ q.add(one);
+ q.add(two);
+ q.add(three);
+ assertEquals(0, q.remainingCapacity());
+ int k = 0;
+ for (Iterator it = q.iterator(); it.hasNext();) {
+ assertEquals(++k, it.next());
+ }
+ assertEquals(3, k);
+ }
+
+ /**
+ * Modifications do not cause iterators to fail
+ */
+ public void testWeaklyConsistentIteration() {
+ final LinkedBlockingDeque q = new LinkedBlockingDeque(3);
+ q.add(one);
+ q.add(two);
+ q.add(three);
+ for (Iterator it = q.iterator(); it.hasNext();) {
+ q.remove();
+ it.next();
+ }
+ assertEquals(0, q.size());
+ }
+
+ /**
+ * Descending iterator iterates through all elements
+ */
+ public void testDescendingIterator() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ int i = 0;
+ Iterator it = q.descendingIterator();
+ while (it.hasNext()) {
+ assertTrue(q.contains(it.next()));
+ ++i;
+ }
+ assertEquals(i, SIZE);
+ assertFalse(it.hasNext());
+ try {
+ it.next();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * Descending iterator ordering is reverse FIFO
+ */
+ public void testDescendingIteratorOrdering() {
+ final LinkedBlockingDeque q = new LinkedBlockingDeque();
+ for (int iters = 0; iters < 100; ++iters) {
+ q.add(new Integer(3));
+ q.add(new Integer(2));
+ q.add(new Integer(1));
+ int k = 0;
+ for (Iterator it = q.descendingIterator(); it.hasNext();) {
+ assertEquals(++k, it.next());
+ }
+
+ assertEquals(3, k);
+ q.remove();
+ q.remove();
+ q.remove();
+ }
+ }
+
+ /**
+ * descendingIterator.remove removes current element
+ */
+ public void testDescendingIteratorRemove() {
+ final LinkedBlockingDeque q = new LinkedBlockingDeque();
+ for (int iters = 0; iters < 100; ++iters) {
+ q.add(new Integer(3));
+ q.add(new Integer(2));
+ q.add(new Integer(1));
+ Iterator it = q.descendingIterator();
+ assertEquals(it.next(), new Integer(1));
+ it.remove();
+ assertEquals(it.next(), new Integer(2));
+ it = q.descendingIterator();
+ assertEquals(it.next(), new Integer(2));
+ assertEquals(it.next(), new Integer(3));
+ it.remove();
+ assertFalse(it.hasNext());
+ q.remove();
+ }
+ }
+
+ /**
+ * toString contains toStrings of elements
+ */
+ public void testToString() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ String s = q.toString();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(s.contains(String.valueOf(i)));
+ }
+ }
+
+ /**
+ * offer transfers elements across Executor tasks
+ */
+ public void testOfferInExecutor() {
+ final LinkedBlockingDeque q = new LinkedBlockingDeque(2);
+ q.add(one);
+ q.add(two);
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+ final CheckedBarrier threadsStarted = new CheckedBarrier(2);
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(q.offer(three));
+ threadsStarted.await();
+ assertTrue(q.offer(three, LONG_DELAY_MS, MILLISECONDS));
+ assertEquals(0, q.remainingCapacity());
+ }});
+
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ assertSame(one, q.take());
+ }});
+
+ joinPool(executor);
+ }
+
+ /**
+ * timed poll retrieves elements across Executor threads
+ */
+ public void testPollInExecutor() {
+ final LinkedBlockingDeque q = new LinkedBlockingDeque(2);
+ final CheckedBarrier threadsStarted = new CheckedBarrier(2);
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertNull(q.poll());
+ threadsStarted.await();
+ assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS));
+ checkEmpty(q);
+ }});
+
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ q.put(one);
+ }});
+
+ joinPool(executor);
+ }
+
+ /**
+ * A deserialized serialized deque has same elements in same order
+ */
+ public void testSerialization() throws Exception {
+ Queue x = populatedDeque(SIZE);
+ Queue y = serialClone(x);
+
+ assertNotSame(y, x);
+ assertEquals(x.size(), y.size());
+ assertEquals(x.toString(), y.toString());
+ assertTrue(Arrays.equals(x.toArray(), y.toArray()));
+ while (!x.isEmpty()) {
+ assertFalse(y.isEmpty());
+ assertEquals(x.remove(), y.remove());
+ }
+ assertTrue(y.isEmpty());
+ }
+
+ /**
+ * drainTo(c) empties deque into another collection c
+ */
+ public void testDrainTo() {
+ LinkedBlockingDeque q = populatedDeque(SIZE);
+ ArrayList l = new ArrayList();
+ q.drainTo(l);
+ assertEquals(0, q.size());
+ assertEquals(SIZE, l.size());
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(l.get(i), new Integer(i));
+ q.add(zero);
+ q.add(one);
+ assertFalse(q.isEmpty());
+ assertTrue(q.contains(zero));
+ assertTrue(q.contains(one));
+ l.clear();
+ q.drainTo(l);
+ assertEquals(0, q.size());
+ assertEquals(2, l.size());
+ for (int i = 0; i < 2; ++i)
+ assertEquals(l.get(i), new Integer(i));
+ }
+
+ /**
+ * drainTo empties full deque, unblocking a waiting put.
+ */
+ public void testDrainToWithActivePut() throws InterruptedException {
+ final LinkedBlockingDeque q = populatedDeque(SIZE);
+ Thread t = new Thread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ q.put(new Integer(SIZE+1));
+ }});
+
+ t.start();
+ ArrayList l = new ArrayList();
+ q.drainTo(l);
+ assertTrue(l.size() >= SIZE);
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(l.get(i), new Integer(i));
+ t.join();
+ assertTrue(q.size() + l.size() >= SIZE);
+ }
+
+ /**
+ * drainTo(c, n) empties first min(n, size) elements of queue into c
+ */
+ public void testDrainToN() {
+ LinkedBlockingDeque q = new LinkedBlockingDeque();
+ for (int i = 0; i < SIZE + 2; ++i) {
+ for (int j = 0; j < SIZE; j++)
+ assertTrue(q.offer(new Integer(j)));
+ ArrayList l = new ArrayList();
+ q.drainTo(l, i);
+ int k = (i < SIZE) ? i : SIZE;
+ assertEquals(k, l.size());
+ assertEquals(SIZE-k, q.size());
+ for (int j = 0; j < k; ++j)
+ assertEquals(l.get(j), new Integer(j));
+ while (q.poll() != null) ;
+ }
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/LinkedBlockingQueueTest.java b/jsr166-tests/src/test/java/jsr166/LinkedBlockingQueueTest.java
new file mode 100644
index 0000000..5628040
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/LinkedBlockingQueueTest.java
@@ -0,0 +1,824 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+public class LinkedBlockingQueueTest extends JSR166TestCase {
+
+ public static class Unbounded extends BlockingQueueTest {
+ protected BlockingQueue emptyCollection() {
+ return new LinkedBlockingQueue();
+ }
+ }
+
+ public static class Bounded extends BlockingQueueTest {
+ protected BlockingQueue emptyCollection() {
+ return new LinkedBlockingQueue(SIZE);
+ }
+ }
+
+ /**
+ * Returns a new queue of given size containing consecutive
+ * Integers 0 ... n.
+ */
+ private LinkedBlockingQueue<Integer> populatedQueue(int n) {
+ LinkedBlockingQueue<Integer> q =
+ new LinkedBlockingQueue<Integer>(n);
+ assertTrue(q.isEmpty());
+ for (int i = 0; i < n; i++)
+ assertTrue(q.offer(new Integer(i)));
+ assertFalse(q.isEmpty());
+ assertEquals(0, q.remainingCapacity());
+ assertEquals(n, q.size());
+ return q;
+ }
+
+ /**
+ * A new queue has the indicated capacity, or Integer.MAX_VALUE if
+ * none given
+ */
+ public void testConstructor1() {
+ assertEquals(SIZE, new LinkedBlockingQueue(SIZE).remainingCapacity());
+ assertEquals(Integer.MAX_VALUE, new LinkedBlockingQueue().remainingCapacity());
+ }
+
+ /**
+ * Constructor throws IllegalArgumentException if capacity argument nonpositive
+ */
+ public void testConstructor2() {
+ try {
+ new LinkedBlockingQueue(0);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Initializing from null Collection throws NullPointerException
+ */
+ public void testConstructor3() {
+ try {
+ new LinkedBlockingQueue(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing from Collection of null elements throws NullPointerException
+ */
+ public void testConstructor4() {
+ Collection<Integer> elements = Arrays.asList(new Integer[SIZE]);
+ try {
+ new LinkedBlockingQueue(elements);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing from Collection with some null elements throws
+ * NullPointerException
+ */
+ public void testConstructor5() {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
+ Collection<Integer> elements = Arrays.asList(ints);
+ try {
+ new LinkedBlockingQueue(elements);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Queue contains all elements of collection used to initialize
+ */
+ public void testConstructor6() {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(i);
+ LinkedBlockingQueue q = new LinkedBlockingQueue(Arrays.asList(ints));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(ints[i], q.poll());
+ }
+
+ /**
+ * Queue transitions from empty to full when elements added
+ */
+ public void testEmptyFull() {
+ LinkedBlockingQueue q = new LinkedBlockingQueue(2);
+ assertTrue(q.isEmpty());
+ assertEquals("should have room for 2", 2, q.remainingCapacity());
+ q.add(one);
+ assertFalse(q.isEmpty());
+ q.add(two);
+ assertFalse(q.isEmpty());
+ assertEquals(0, q.remainingCapacity());
+ assertFalse(q.offer(three));
+ }
+
+ /**
+ * remainingCapacity decreases on add, increases on remove
+ */
+ public void testRemainingCapacity() {
+ LinkedBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.remainingCapacity());
+ assertEquals(SIZE-i, q.size());
+ q.remove();
+ }
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(SIZE-i, q.remainingCapacity());
+ assertEquals(i, q.size());
+ q.add(new Integer(i));
+ }
+ }
+
+ /**
+ * Offer succeeds if not full; fails if full
+ */
+ public void testOffer() {
+ LinkedBlockingQueue q = new LinkedBlockingQueue(1);
+ assertTrue(q.offer(zero));
+ assertFalse(q.offer(one));
+ }
+
+ /**
+ * add succeeds if not full; throws IllegalStateException if full
+ */
+ public void testAdd() {
+ LinkedBlockingQueue q = new LinkedBlockingQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i)
+ assertTrue(q.add(new Integer(i)));
+ assertEquals(0, q.remainingCapacity());
+ try {
+ q.add(new Integer(SIZE));
+ shouldThrow();
+ } catch (IllegalStateException success) {}
+ }
+
+ /**
+ * addAll(this) throws IllegalArgumentException
+ */
+ public void testAddAllSelf() {
+ LinkedBlockingQueue q = populatedQueue(SIZE);
+ try {
+ q.addAll(q);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * addAll of a collection with any null elements throws NPE after
+ * possibly adding some elements
+ */
+ public void testAddAll3() {
+ LinkedBlockingQueue q = new LinkedBlockingQueue(SIZE);
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
+ Collection<Integer> elements = Arrays.asList(ints);
+ try {
+ q.addAll(elements);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll throws IllegalStateException if not enough room
+ */
+ public void testAddAll4() {
+ LinkedBlockingQueue q = new LinkedBlockingQueue(SIZE - 1);
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(i);
+ Collection<Integer> elements = Arrays.asList(ints);
+ try {
+ q.addAll(elements);
+ shouldThrow();
+ } catch (IllegalStateException success) {}
+ }
+
+ /**
+ * Queue contains all elements, in traversal order, of successful addAll
+ */
+ public void testAddAll5() {
+ Integer[] empty = new Integer[0];
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(i);
+ LinkedBlockingQueue q = new LinkedBlockingQueue(SIZE);
+ assertFalse(q.addAll(Arrays.asList(empty)));
+ assertTrue(q.addAll(Arrays.asList(ints)));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(ints[i], q.poll());
+ }
+
+ /**
+ * all elements successfully put are contained
+ */
+ public void testPut() throws InterruptedException {
+ LinkedBlockingQueue q = new LinkedBlockingQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ Integer I = new Integer(i);
+ q.put(I);
+ assertTrue(q.contains(I));
+ }
+ assertEquals(0, q.remainingCapacity());
+ }
+
+ /**
+ * put blocks interruptibly if full
+ */
+ public void testBlockingPut() throws InterruptedException {
+ final LinkedBlockingQueue q = new LinkedBlockingQueue(SIZE);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ for (int i = 0; i < SIZE; ++i)
+ q.put(i);
+ assertEquals(SIZE, q.size());
+ assertEquals(0, q.remainingCapacity());
+
+ Thread.currentThread().interrupt();
+ try {
+ q.put(99);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ q.put(99);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ assertEquals(SIZE, q.size());
+ assertEquals(0, q.remainingCapacity());
+ }
+
+ /**
+ * put blocks interruptibly waiting for take when full
+ */
+ public void testPutWithTake() throws InterruptedException {
+ final int capacity = 2;
+ final LinkedBlockingQueue q = new LinkedBlockingQueue(2);
+ final CountDownLatch pleaseTake = new CountDownLatch(1);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ for (int i = 0; i < capacity; i++)
+ q.put(i);
+ pleaseTake.countDown();
+ q.put(86);
+
+ pleaseInterrupt.countDown();
+ try {
+ q.put(99);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseTake);
+ assertEquals(0, q.remainingCapacity());
+ assertEquals(0, q.take());
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ assertEquals(0, q.remainingCapacity());
+ }
+
+ /**
+ * timed offer times out if full and elements not taken
+ */
+ public void testTimedOffer() {
+ final LinkedBlockingQueue q = new LinkedBlockingQueue(2);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ q.put(new Object());
+ q.put(new Object());
+ long startTime = System.nanoTime();
+ assertFalse(q.offer(new Object(), timeoutMillis(), MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ pleaseInterrupt.countDown();
+ try {
+ q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * take retrieves elements in FIFO order
+ */
+ public void testTake() throws InterruptedException {
+ LinkedBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.take());
+ }
+ }
+
+ /**
+ * Take removes existing elements until empty, then blocks interruptibly
+ */
+ public void testBlockingTake() throws InterruptedException {
+ final BlockingQueue q = populatedQueue(SIZE);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.take());
+ }
+
+ Thread.currentThread().interrupt();
+ try {
+ q.take();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ q.take();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * poll succeeds unless empty
+ */
+ public void testPoll() {
+ LinkedBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.poll());
+ }
+ assertNull(q.poll());
+ }
+
+ /**
+ * timed poll with zero timeout succeeds when non-empty, else times out
+ */
+ public void testTimedPoll0() throws InterruptedException {
+ LinkedBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.poll(0, MILLISECONDS));
+ }
+ assertNull(q.poll(0, MILLISECONDS));
+ }
+
+ /**
+ * timed poll with nonzero timeout succeeds when non-empty, else times out
+ */
+ public void testTimedPoll() throws InterruptedException {
+ LinkedBlockingQueue<Integer> q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ long startTime = System.nanoTime();
+ assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ }
+ long startTime = System.nanoTime();
+ assertNull(q.poll(timeoutMillis(), MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ checkEmpty(q);
+ }
+
+ /**
+ * Interrupted timed poll throws InterruptedException instead of
+ * returning timeout status
+ */
+ public void testInterruptedTimedPoll() throws InterruptedException {
+ final BlockingQueue<Integer> q = populatedQueue(SIZE);
+ final CountDownLatch aboutToWait = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ for (int i = 0; i < SIZE; ++i) {
+ long t0 = System.nanoTime();
+ assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
+ }
+ long t0 = System.nanoTime();
+ aboutToWait.countDown();
+ try {
+ q.poll(MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {
+ assertTrue(millisElapsedSince(t0) < MEDIUM_DELAY_MS);
+ }
+ }});
+
+ aboutToWait.await();
+ waitForThreadToEnterWaitState(t, SMALL_DELAY_MS);
+ t.interrupt();
+ awaitTermination(t, MEDIUM_DELAY_MS);
+ checkEmpty(q);
+ }
+
+ /**
+ * peek returns next element, or null if empty
+ */
+ public void testPeek() {
+ LinkedBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.peek());
+ assertEquals(i, q.poll());
+ assertTrue(q.peek() == null ||
+ !q.peek().equals(i));
+ }
+ assertNull(q.peek());
+ }
+
+ /**
+ * element returns next element, or throws NSEE if empty
+ */
+ public void testElement() {
+ LinkedBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.element());
+ assertEquals(i, q.poll());
+ }
+ try {
+ q.element();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * remove removes next element, or throws NSEE if empty
+ */
+ public void testRemove() {
+ LinkedBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.remove());
+ }
+ try {
+ q.remove();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * An add following remove(x) succeeds
+ */
+ public void testRemoveElementAndAdd() throws InterruptedException {
+ LinkedBlockingQueue q = new LinkedBlockingQueue();
+ assertTrue(q.add(new Integer(1)));
+ assertTrue(q.add(new Integer(2)));
+ assertTrue(q.remove(new Integer(1)));
+ assertTrue(q.remove(new Integer(2)));
+ assertTrue(q.add(new Integer(3)));
+ assertNotNull(q.take());
+ }
+
+ /**
+ * contains(x) reports true when elements added but not yet removed
+ */
+ public void testContains() {
+ LinkedBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.contains(new Integer(i)));
+ q.poll();
+ assertFalse(q.contains(new Integer(i)));
+ }
+ }
+
+ /**
+ * clear removes all elements
+ */
+ public void testClear() {
+ LinkedBlockingQueue q = populatedQueue(SIZE);
+ q.clear();
+ assertTrue(q.isEmpty());
+ assertEquals(0, q.size());
+ assertEquals(SIZE, q.remainingCapacity());
+ q.add(one);
+ assertFalse(q.isEmpty());
+ assertTrue(q.contains(one));
+ q.clear();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * containsAll(c) is true when c contains a subset of elements
+ */
+ public void testContainsAll() {
+ LinkedBlockingQueue q = populatedQueue(SIZE);
+ LinkedBlockingQueue p = new LinkedBlockingQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.containsAll(p));
+ assertFalse(p.containsAll(q));
+ p.add(new Integer(i));
+ }
+ assertTrue(p.containsAll(q));
+ }
+
+ /**
+ * retainAll(c) retains only those elements of c and reports true if changed
+ */
+ public void testRetainAll() {
+ LinkedBlockingQueue q = populatedQueue(SIZE);
+ LinkedBlockingQueue p = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ boolean changed = q.retainAll(p);
+ if (i == 0)
+ assertFalse(changed);
+ else
+ assertTrue(changed);
+
+ assertTrue(q.containsAll(p));
+ assertEquals(SIZE-i, q.size());
+ p.remove();
+ }
+ }
+
+ /**
+ * removeAll(c) removes only those elements of c and reports true if changed
+ */
+ public void testRemoveAll() {
+ for (int i = 1; i < SIZE; ++i) {
+ LinkedBlockingQueue q = populatedQueue(SIZE);
+ LinkedBlockingQueue p = populatedQueue(i);
+ assertTrue(q.removeAll(p));
+ assertEquals(SIZE-i, q.size());
+ for (int j = 0; j < i; ++j) {
+ Integer I = (Integer)(p.remove());
+ assertFalse(q.contains(I));
+ }
+ }
+ }
+
+ /**
+ * toArray contains all elements in FIFO order
+ */
+ public void testToArray() {
+ LinkedBlockingQueue q = populatedQueue(SIZE);
+ Object[] o = q.toArray();
+ for (int i = 0; i < o.length; i++)
+ assertSame(o[i], q.poll());
+ }
+
+ /**
+ * toArray(a) contains all elements in FIFO order
+ */
+ public void testToArray2() throws InterruptedException {
+ LinkedBlockingQueue<Integer> q = populatedQueue(SIZE);
+ Integer[] ints = new Integer[SIZE];
+ Integer[] array = q.toArray(ints);
+ assertSame(ints, array);
+ for (int i = 0; i < ints.length; i++)
+ assertSame(ints[i], q.poll());
+ }
+
+ /**
+ * toArray(incompatible array type) throws ArrayStoreException
+ */
+ public void testToArray1_BadArg() {
+ LinkedBlockingQueue q = populatedQueue(SIZE);
+ try {
+ q.toArray(new String[10]);
+ shouldThrow();
+ } catch (ArrayStoreException success) {}
+ }
+
+ /**
+ * iterator iterates through all elements
+ */
+ public void testIterator() throws InterruptedException {
+ LinkedBlockingQueue q = populatedQueue(SIZE);
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ assertEquals(it.next(), q.take());
+ }
+ }
+
+ /**
+ * iterator.remove removes current element
+ */
+ public void testIteratorRemove() {
+ final LinkedBlockingQueue q = new LinkedBlockingQueue(3);
+ q.add(two);
+ q.add(one);
+ q.add(three);
+
+ Iterator it = q.iterator();
+ it.next();
+ it.remove();
+
+ it = q.iterator();
+ assertSame(it.next(), one);
+ assertSame(it.next(), three);
+ assertFalse(it.hasNext());
+ }
+
+ /**
+ * iterator ordering is FIFO
+ */
+ public void testIteratorOrdering() {
+ final LinkedBlockingQueue q = new LinkedBlockingQueue(3);
+ q.add(one);
+ q.add(two);
+ q.add(three);
+ assertEquals(0, q.remainingCapacity());
+ int k = 0;
+ for (Iterator it = q.iterator(); it.hasNext();) {
+ assertEquals(++k, it.next());
+ }
+ assertEquals(3, k);
+ }
+
+ /**
+ * Modifications do not cause iterators to fail
+ */
+ public void testWeaklyConsistentIteration() {
+ final LinkedBlockingQueue q = new LinkedBlockingQueue(3);
+ q.add(one);
+ q.add(two);
+ q.add(three);
+ for (Iterator it = q.iterator(); it.hasNext();) {
+ q.remove();
+ it.next();
+ }
+ assertEquals(0, q.size());
+ }
+
+ /**
+ * toString contains toStrings of elements
+ */
+ public void testToString() {
+ LinkedBlockingQueue q = populatedQueue(SIZE);
+ String s = q.toString();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(s.contains(String.valueOf(i)));
+ }
+ }
+
+ /**
+ * offer transfers elements across Executor tasks
+ */
+ public void testOfferInExecutor() {
+ final LinkedBlockingQueue q = new LinkedBlockingQueue(2);
+ q.add(one);
+ q.add(two);
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+ final CheckedBarrier threadsStarted = new CheckedBarrier(2);
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(q.offer(three));
+ threadsStarted.await();
+ assertTrue(q.offer(three, LONG_DELAY_MS, MILLISECONDS));
+ assertEquals(0, q.remainingCapacity());
+ }});
+
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ assertSame(one, q.take());
+ }});
+
+ joinPool(executor);
+ }
+
+ /**
+ * timed poll retrieves elements across Executor threads
+ */
+ public void testPollInExecutor() {
+ final LinkedBlockingQueue q = new LinkedBlockingQueue(2);
+ final CheckedBarrier threadsStarted = new CheckedBarrier(2);
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertNull(q.poll());
+ threadsStarted.await();
+ assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS));
+ checkEmpty(q);
+ }});
+
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ q.put(one);
+ }});
+
+ joinPool(executor);
+ }
+
+ /**
+ * A deserialized serialized queue has same elements in same order
+ */
+ public void testSerialization() throws Exception {
+ Queue x = populatedQueue(SIZE);
+ Queue y = serialClone(x);
+
+ assertNotSame(x, y);
+ assertEquals(x.size(), y.size());
+ assertEquals(x.toString(), y.toString());
+ assertTrue(Arrays.equals(x.toArray(), y.toArray()));
+ while (!x.isEmpty()) {
+ assertFalse(y.isEmpty());
+ assertEquals(x.remove(), y.remove());
+ }
+ assertTrue(y.isEmpty());
+ }
+
+ /**
+ * drainTo(c) empties queue into another collection c
+ */
+ public void testDrainTo() {
+ LinkedBlockingQueue q = populatedQueue(SIZE);
+ ArrayList l = new ArrayList();
+ q.drainTo(l);
+ assertEquals(0, q.size());
+ assertEquals(SIZE, l.size());
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(l.get(i), new Integer(i));
+ q.add(zero);
+ q.add(one);
+ assertFalse(q.isEmpty());
+ assertTrue(q.contains(zero));
+ assertTrue(q.contains(one));
+ l.clear();
+ q.drainTo(l);
+ assertEquals(0, q.size());
+ assertEquals(2, l.size());
+ for (int i = 0; i < 2; ++i)
+ assertEquals(l.get(i), new Integer(i));
+ }
+
+ /**
+ * drainTo empties full queue, unblocking a waiting put.
+ */
+ public void testDrainToWithActivePut() throws InterruptedException {
+ final LinkedBlockingQueue q = populatedQueue(SIZE);
+ Thread t = new Thread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ q.put(new Integer(SIZE+1));
+ }});
+
+ t.start();
+ ArrayList l = new ArrayList();
+ q.drainTo(l);
+ assertTrue(l.size() >= SIZE);
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(l.get(i), new Integer(i));
+ t.join();
+ assertTrue(q.size() + l.size() >= SIZE);
+ }
+
+ /**
+ * drainTo(c, n) empties first min(n, size) elements of queue into c
+ */
+ public void testDrainToN() {
+ LinkedBlockingQueue q = new LinkedBlockingQueue();
+ for (int i = 0; i < SIZE + 2; ++i) {
+ for (int j = 0; j < SIZE; j++)
+ assertTrue(q.offer(new Integer(j)));
+ ArrayList l = new ArrayList();
+ q.drainTo(l, i);
+ int k = (i < SIZE) ? i : SIZE;
+ assertEquals(k, l.size());
+ assertEquals(SIZE-k, q.size());
+ for (int j = 0; j < k; ++j)
+ assertEquals(l.get(j), new Integer(j));
+ while (q.poll() != null) ;
+ }
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/LinkedListTest.java b/jsr166-tests/src/test/java/jsr166/LinkedListTest.java
new file mode 100644
index 0000000..5b09100
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/LinkedListTest.java
@@ -0,0 +1,627 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.NoSuchElementException;
+
+public class LinkedListTest extends JSR166TestCase {
+
+ /**
+ * Returns a new queue of given size containing consecutive
+ * Integers 0 ... n.
+ */
+ private LinkedList<Integer> populatedQueue(int n) {
+ LinkedList<Integer> q = new LinkedList<Integer>();
+ assertTrue(q.isEmpty());
+ for (int i = 0; i < n; ++i)
+ assertTrue(q.offer(new Integer(i)));
+ assertFalse(q.isEmpty());
+ assertEquals(n, q.size());
+ return q;
+ }
+
+ /**
+ * new queue is empty
+ */
+ public void testConstructor1() {
+ assertEquals(0, new LinkedList().size());
+ }
+
+ /**
+ * Initializing from null Collection throws NPE
+ */
+ public void testConstructor3() {
+ try {
+ LinkedList q = new LinkedList((Collection)null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Queue contains all elements of collection used to initialize
+ */
+ public void testConstructor6() {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = i;
+ LinkedList q = new LinkedList(Arrays.asList(ints));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(ints[i], q.poll());
+ }
+
+ /**
+ * isEmpty is true before add, false after
+ */
+ public void testEmpty() {
+ LinkedList q = new LinkedList();
+ assertTrue(q.isEmpty());
+ q.add(new Integer(1));
+ assertFalse(q.isEmpty());
+ q.add(new Integer(2));
+ q.remove();
+ q.remove();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * size changes when elements added and removed
+ */
+ public void testSize() {
+ LinkedList q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(SIZE-i, q.size());
+ q.remove();
+ }
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.size());
+ q.add(new Integer(i));
+ }
+ }
+
+ /**
+ * offer(null) succeeds
+ */
+ public void testOfferNull() {
+ LinkedList q = new LinkedList();
+ q.offer(null);
+ }
+
+ /**
+ * Offer succeeds
+ */
+ public void testOffer() {
+ LinkedList q = new LinkedList();
+ assertTrue(q.offer(new Integer(0)));
+ assertTrue(q.offer(new Integer(1)));
+ }
+
+ /**
+ * add succeeds
+ */
+ public void testAdd() {
+ LinkedList q = new LinkedList();
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.size());
+ assertTrue(q.add(new Integer(i)));
+ }
+ }
+
+ /**
+ * addAll(null) throws NPE
+ */
+ public void testAddAll1() {
+ try {
+ LinkedList q = new LinkedList();
+ q.addAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Queue contains all elements, in traversal order, of successful addAll
+ */
+ public void testAddAll5() {
+ Integer[] empty = new Integer[0];
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = i;
+ LinkedList q = new LinkedList();
+ assertFalse(q.addAll(Arrays.asList(empty)));
+ assertTrue(q.addAll(Arrays.asList(ints)));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(ints[i], q.poll());
+ }
+
+ /**
+ * addAll with too large an index throws IOOBE
+ */
+ public void testAddAll2_IndexOutOfBoundsException() {
+ LinkedList l = new LinkedList();
+ l.add(new Object());
+ LinkedList m = new LinkedList();
+ m.add(new Object());
+ try {
+ l.addAll(4,m);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
+
+ /**
+ * addAll with negative index throws IOOBE
+ */
+ public void testAddAll4_BadIndex() {
+ LinkedList l = new LinkedList();
+ l.add(new Object());
+ LinkedList m = new LinkedList();
+ m.add(new Object());
+ try {
+ l.addAll(-1,m);
+ shouldThrow();
+ } catch (IndexOutOfBoundsException success) {}
+ }
+
+ /**
+ * poll succeeds unless empty
+ */
+ public void testPoll() {
+ LinkedList q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.poll());
+ }
+ assertNull(q.poll());
+ }
+
+ /**
+ * peek returns next element, or null if empty
+ */
+ public void testPeek() {
+ LinkedList q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.peek());
+ assertEquals(i, q.poll());
+ assertTrue(q.peek() == null ||
+ !q.peek().equals(i));
+ }
+ assertNull(q.peek());
+ }
+
+ /**
+ * element returns next element, or throws NSEE if empty
+ */
+ public void testElement() {
+ LinkedList q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.element());
+ assertEquals(i, q.poll());
+ }
+ try {
+ q.element();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * remove removes next element, or throws NSEE if empty
+ */
+ public void testRemove() {
+ LinkedList q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.remove());
+ }
+ try {
+ q.remove();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * remove(x) removes x and returns true if present
+ */
+ public void testRemoveElement() {
+ LinkedList q = populatedQueue(SIZE);
+ for (int i = 1; i < SIZE; i+=2) {
+ assertTrue(q.contains(i));
+ assertTrue(q.remove((Integer)i));
+ assertFalse(q.contains(i));
+ assertTrue(q.contains(i-1));
+ }
+ for (int i = 0; i < SIZE; i+=2) {
+ assertTrue(q.contains(i));
+ assertTrue(q.remove((Integer)i));
+ assertFalse(q.contains(i));
+ assertFalse(q.remove((Integer)(i+1)));
+ assertFalse(q.contains(i+1));
+ }
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * contains(x) reports true when elements added but not yet removed
+ */
+ public void testContains() {
+ LinkedList q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.contains(new Integer(i)));
+ q.poll();
+ assertFalse(q.contains(new Integer(i)));
+ }
+ }
+
+ /**
+ * clear removes all elements
+ */
+ public void testClear() {
+ LinkedList q = populatedQueue(SIZE);
+ q.clear();
+ assertTrue(q.isEmpty());
+ assertEquals(0, q.size());
+ assertTrue(q.add(new Integer(1)));
+ assertFalse(q.isEmpty());
+ q.clear();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * containsAll(c) is true when c contains a subset of elements
+ */
+ public void testContainsAll() {
+ LinkedList q = populatedQueue(SIZE);
+ LinkedList p = new LinkedList();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.containsAll(p));
+ assertFalse(p.containsAll(q));
+ assertTrue(p.add(new Integer(i)));
+ }
+ assertTrue(p.containsAll(q));
+ }
+
+ /**
+ * retainAll(c) retains only those elements of c and reports true if changed
+ */
+ public void testRetainAll() {
+ LinkedList q = populatedQueue(SIZE);
+ LinkedList p = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ boolean changed = q.retainAll(p);
+ if (i == 0)
+ assertFalse(changed);
+ else
+ assertTrue(changed);
+
+ assertTrue(q.containsAll(p));
+ assertEquals(SIZE-i, q.size());
+ p.remove();
+ }
+ }
+
+ /**
+ * removeAll(c) removes only those elements of c and reports true if changed
+ */
+ public void testRemoveAll() {
+ for (int i = 1; i < SIZE; ++i) {
+ LinkedList q = populatedQueue(SIZE);
+ LinkedList p = populatedQueue(i);
+ assertTrue(q.removeAll(p));
+ assertEquals(SIZE-i, q.size());
+ for (int j = 0; j < i; ++j) {
+ Integer I = (Integer)(p.remove());
+ assertFalse(q.contains(I));
+ }
+ }
+ }
+
+ /**
+ * toArray contains all elements in FIFO order
+ */
+ public void testToArray() {
+ LinkedList q = populatedQueue(SIZE);
+ Object[] o = q.toArray();
+ for (int i = 0; i < o.length; i++)
+ assertSame(o[i], q.poll());
+ }
+
+ /**
+ * toArray(a) contains all elements in FIFO order
+ */
+ public void testToArray2() {
+ LinkedList<Integer> q = populatedQueue(SIZE);
+ Integer[] ints = new Integer[SIZE];
+ Integer[] array = q.toArray(ints);
+ assertSame(ints, array);
+ for (int i = 0; i < ints.length; i++)
+ assertSame(ints[i], q.poll());
+ }
+
+ /**
+ * toArray(null) throws NullPointerException
+ */
+ public void testToArray_NullArg() {
+ LinkedList l = new LinkedList();
+ l.add(new Object());
+ try {
+ l.toArray(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * toArray(incompatible array type) throws ArrayStoreException
+ */
+ public void testToArray1_BadArg() {
+ LinkedList l = new LinkedList();
+ l.add(new Integer(5));
+ try {
+ l.toArray(new String[10]);
+ shouldThrow();
+ } catch (ArrayStoreException success) {}
+ }
+
+ /**
+ * iterator iterates through all elements
+ */
+ public void testIterator() {
+ LinkedList q = populatedQueue(SIZE);
+ int i = 0;
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ assertTrue(q.contains(it.next()));
+ ++i;
+ }
+ assertEquals(i, SIZE);
+ }
+
+ /**
+ * iterator ordering is FIFO
+ */
+ public void testIteratorOrdering() {
+ final LinkedList q = new LinkedList();
+ q.add(new Integer(1));
+ q.add(new Integer(2));
+ q.add(new Integer(3));
+ int k = 0;
+ for (Iterator it = q.iterator(); it.hasNext();) {
+ assertEquals(++k, it.next());
+ }
+
+ assertEquals(3, k);
+ }
+
+ /**
+ * iterator.remove removes current element
+ */
+ public void testIteratorRemove() {
+ final LinkedList q = new LinkedList();
+ q.add(new Integer(1));
+ q.add(new Integer(2));
+ q.add(new Integer(3));
+ Iterator it = q.iterator();
+ assertEquals(1, it.next());
+ it.remove();
+ it = q.iterator();
+ assertEquals(2, it.next());
+ assertEquals(3, it.next());
+ assertFalse(it.hasNext());
+ }
+
+ /**
+ * Descending iterator iterates through all elements
+ */
+ public void testDescendingIterator() {
+ LinkedList q = populatedQueue(SIZE);
+ int i = 0;
+ Iterator it = q.descendingIterator();
+ while (it.hasNext()) {
+ assertTrue(q.contains(it.next()));
+ ++i;
+ }
+ assertEquals(i, SIZE);
+ assertFalse(it.hasNext());
+ try {
+ it.next();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * Descending iterator ordering is reverse FIFO
+ */
+ public void testDescendingIteratorOrdering() {
+ final LinkedList q = new LinkedList();
+ q.add(new Integer(3));
+ q.add(new Integer(2));
+ q.add(new Integer(1));
+ int k = 0;
+ for (Iterator it = q.descendingIterator(); it.hasNext();) {
+ assertEquals(++k, it.next());
+ }
+
+ assertEquals(3, k);
+ }
+
+ /**
+ * descendingIterator.remove removes current element
+ */
+ public void testDescendingIteratorRemove() {
+ final LinkedList q = new LinkedList();
+ q.add(three);
+ q.add(two);
+ q.add(one);
+ Iterator it = q.descendingIterator();
+ it.next();
+ it.remove();
+ it = q.descendingIterator();
+ assertSame(it.next(), two);
+ assertSame(it.next(), three);
+ assertFalse(it.hasNext());
+ }
+
+ /**
+ * toString contains toStrings of elements
+ */
+ public void testToString() {
+ LinkedList q = populatedQueue(SIZE);
+ String s = q.toString();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(s.contains(String.valueOf(i)));
+ }
+ }
+
+ /**
+ * peek returns element inserted with addFirst
+ */
+ public void testAddFirst() {
+ LinkedList q = populatedQueue(3);
+ q.addFirst(four);
+ assertSame(four, q.peek());
+ }
+
+ /**
+ * peekFirst returns element inserted with push
+ */
+ public void testPush() {
+ LinkedList q = populatedQueue(3);
+ q.push(four);
+ assertSame(four, q.peekFirst());
+ }
+
+ /**
+ * pop removes next element, or throws NSEE if empty
+ */
+ public void testPop() {
+ LinkedList q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.pop());
+ }
+ try {
+ q.pop();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * OfferFirst succeeds
+ */
+ public void testOfferFirst() {
+ LinkedList q = new LinkedList();
+ assertTrue(q.offerFirst(new Integer(0)));
+ assertTrue(q.offerFirst(new Integer(1)));
+ }
+
+ /**
+ * OfferLast succeeds
+ */
+ public void testOfferLast() {
+ LinkedList q = new LinkedList();
+ assertTrue(q.offerLast(new Integer(0)));
+ assertTrue(q.offerLast(new Integer(1)));
+ }
+
+ /**
+ * pollLast succeeds unless empty
+ */
+ public void testPollLast() {
+ LinkedList q = populatedQueue(SIZE);
+ for (int i = SIZE-1; i >= 0; --i) {
+ assertEquals(i, q.pollLast());
+ }
+ assertNull(q.pollLast());
+ }
+
+ /**
+ * peekFirst returns next element, or null if empty
+ */
+ public void testPeekFirst() {
+ LinkedList q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.peekFirst());
+ assertEquals(i, q.pollFirst());
+ assertTrue(q.peekFirst() == null ||
+ !q.peekFirst().equals(i));
+ }
+ assertNull(q.peekFirst());
+ }
+
+ /**
+ * peekLast returns next element, or null if empty
+ */
+ public void testPeekLast() {
+ LinkedList q = populatedQueue(SIZE);
+ for (int i = SIZE-1; i >= 0; --i) {
+ assertEquals(i, q.peekLast());
+ assertEquals(i, q.pollLast());
+ assertTrue(q.peekLast() == null ||
+ !q.peekLast().equals(i));
+ }
+ assertNull(q.peekLast());
+ }
+
+ public void testFirstElement() {
+ LinkedList q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.getFirst());
+ assertEquals(i, q.pollFirst());
+ }
+ try {
+ q.getFirst();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * getLast returns next element, or throws NSEE if empty
+ */
+ public void testLastElement() {
+ LinkedList q = populatedQueue(SIZE);
+ for (int i = SIZE-1; i >= 0; --i) {
+ assertEquals(i, q.getLast());
+ assertEquals(i, q.pollLast());
+ }
+ try {
+ q.getLast();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ assertNull(q.peekLast());
+ }
+
+ /**
+ * removeFirstOccurrence(x) removes x and returns true if present
+ */
+ public void testRemoveFirstOccurrence() {
+ LinkedList q = populatedQueue(SIZE);
+ for (int i = 1; i < SIZE; i+=2) {
+ assertTrue(q.removeFirstOccurrence(new Integer(i)));
+ }
+ for (int i = 0; i < SIZE; i+=2) {
+ assertTrue(q.removeFirstOccurrence(new Integer(i)));
+ assertFalse(q.removeFirstOccurrence(new Integer(i+1)));
+ }
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * removeLastOccurrence(x) removes x and returns true if present
+ */
+ public void testRemoveLastOccurrence() {
+ LinkedList q = populatedQueue(SIZE);
+ for (int i = 1; i < SIZE; i+=2) {
+ assertTrue(q.removeLastOccurrence(new Integer(i)));
+ }
+ for (int i = 0; i < SIZE; i+=2) {
+ assertTrue(q.removeLastOccurrence(new Integer(i)));
+ assertFalse(q.removeLastOccurrence(new Integer(i+1)));
+ }
+ assertTrue(q.isEmpty());
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/LinkedTransferQueueTest.java b/jsr166-tests/src/test/java/jsr166/LinkedTransferQueueTest.java
new file mode 100644
index 0000000..a14f303
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/LinkedTransferQueueTest.java
@@ -0,0 +1,1009 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include John Vint
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedTransferQueue;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+@SuppressWarnings({"unchecked", "rawtypes"})
+public class LinkedTransferQueueTest extends JSR166TestCase {
+
+ public static class Generic extends BlockingQueueTest {
+ protected BlockingQueue emptyCollection() {
+ return new LinkedTransferQueue();
+ }
+ }
+
+ /**
+ * Constructor builds new queue with size being zero and empty
+ * being true
+ */
+ public void testConstructor1() {
+ assertEquals(0, new LinkedTransferQueue().size());
+ assertTrue(new LinkedTransferQueue().isEmpty());
+ }
+
+ /**
+ * Initializing constructor with null collection throws
+ * NullPointerException
+ */
+ public void testConstructor2() {
+ try {
+ new LinkedTransferQueue(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing from Collection of null elements throws
+ * NullPointerException
+ */
+ public void testConstructor3() {
+ Collection<Integer> elements = Arrays.asList(new Integer[SIZE]);
+ try {
+ new LinkedTransferQueue(elements);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing constructor with a collection containing some null elements
+ * throws NullPointerException
+ */
+ public void testConstructor4() {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = i;
+ Collection<Integer> elements = Arrays.asList(ints);
+ try {
+ new LinkedTransferQueue(elements);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Queue contains all elements of the collection it is initialized by
+ */
+ public void testConstructor5() {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i) {
+ ints[i] = i;
+ }
+ List intList = Arrays.asList(ints);
+ LinkedTransferQueue q
+ = new LinkedTransferQueue(intList);
+ assertEquals(q.size(), intList.size());
+ assertEquals(q.toString(), intList.toString());
+ assertTrue(Arrays.equals(q.toArray(),
+ intList.toArray()));
+ assertTrue(Arrays.equals(q.toArray(new Object[0]),
+ intList.toArray(new Object[0])));
+ assertTrue(Arrays.equals(q.toArray(new Object[SIZE]),
+ intList.toArray(new Object[SIZE])));
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(ints[i], q.poll());
+ }
+ }
+
+ /**
+ * remainingCapacity() always returns Integer.MAX_VALUE
+ */
+ public void testRemainingCapacity() {
+ LinkedTransferQueue<Integer> q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
+ assertEquals(SIZE - i, q.size());
+ q.remove();
+ }
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
+ assertEquals(i, q.size());
+ q.add(i);
+ }
+ }
+
+ /**
+ * addAll(this) throws IllegalArgumentException
+ */
+ public void testAddAllSelf() {
+ try {
+ LinkedTransferQueue q = populatedQueue(SIZE);
+ q.addAll(q);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * addAll of a collection with any null elements throws
+ * NullPointerException after possibly adding some elements
+ */
+ public void testAddAll3() {
+ try {
+ LinkedTransferQueue q = new LinkedTransferQueue();
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE - 1; ++i) {
+ ints[i] = i;
+ }
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Queue contains all elements, in traversal order, of successful addAll
+ */
+ public void testAddAll5() {
+ Integer[] empty = new Integer[0];
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i) {
+ ints[i] = i;
+ }
+ LinkedTransferQueue q = new LinkedTransferQueue();
+ assertFalse(q.addAll(Arrays.asList(empty)));
+ assertTrue(q.addAll(Arrays.asList(ints)));
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(ints[i], q.poll());
+ }
+ }
+
+ /**
+ * all elements successfully put are contained
+ */
+ public void testPut() {
+ LinkedTransferQueue<Integer> q = new LinkedTransferQueue<Integer>();
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.size());
+ q.put(i);
+ assertTrue(q.contains(i));
+ }
+ }
+
+ /**
+ * take retrieves elements in FIFO order
+ */
+ public void testTake() throws InterruptedException {
+ LinkedTransferQueue<Integer> q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, (int) q.take());
+ }
+ }
+
+ /**
+ * take removes existing elements until empty, then blocks interruptibly
+ */
+ public void testBlockingTake() throws InterruptedException {
+ final BlockingQueue q = populatedQueue(SIZE);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.take());
+ }
+
+ Thread.currentThread().interrupt();
+ try {
+ q.take();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ q.take();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * poll succeeds unless empty
+ */
+ public void testPoll() throws InterruptedException {
+ LinkedTransferQueue<Integer> q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, (int) q.poll());
+ }
+ assertNull(q.poll());
+ checkEmpty(q);
+ }
+
+ /**
+ * timed poll with zero timeout succeeds when non-empty, else times out
+ */
+ public void testTimedPoll0() throws InterruptedException {
+ LinkedTransferQueue<Integer> q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, (int) q.poll(0, MILLISECONDS));
+ }
+ assertNull(q.poll(0, MILLISECONDS));
+ checkEmpty(q);
+ }
+
+ /**
+ * timed poll with nonzero timeout succeeds when non-empty, else times out
+ */
+ public void testTimedPoll() throws InterruptedException {
+ LinkedTransferQueue<Integer> q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ long startTime = System.nanoTime();
+ assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ }
+ long startTime = System.nanoTime();
+ assertNull(q.poll(timeoutMillis(), MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ checkEmpty(q);
+ }
+
+ /**
+ * Interrupted timed poll throws InterruptedException instead of
+ * returning timeout status
+ */
+ public void testInterruptedTimedPoll() throws InterruptedException {
+ final BlockingQueue<Integer> q = populatedQueue(SIZE);
+ final CountDownLatch aboutToWait = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ for (int i = 0; i < SIZE; ++i) {
+ long t0 = System.nanoTime();
+ assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
+ }
+ long t0 = System.nanoTime();
+ aboutToWait.countDown();
+ try {
+ q.poll(MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {
+ assertTrue(millisElapsedSince(t0) < MEDIUM_DELAY_MS);
+ }
+ }});
+
+ aboutToWait.await();
+ waitForThreadToEnterWaitState(t, SMALL_DELAY_MS);
+ t.interrupt();
+ awaitTermination(t, MEDIUM_DELAY_MS);
+ checkEmpty(q);
+ }
+
+ /**
+ * timed poll after thread interrupted throws InterruptedException
+ * instead of returning timeout status
+ */
+ public void testTimedPollAfterInterrupt() throws InterruptedException {
+ final BlockingQueue<Integer> q = populatedQueue(SIZE);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ Thread.currentThread().interrupt();
+ for (int i = 0; i < SIZE; ++i) {
+ long t0 = System.nanoTime();
+ assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
+ }
+ try {
+ q.poll(MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ }});
+
+ awaitTermination(t, MEDIUM_DELAY_MS);
+ checkEmpty(q);
+ }
+
+ /**
+ * peek returns next element, or null if empty
+ */
+ public void testPeek() throws InterruptedException {
+ LinkedTransferQueue<Integer> q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, (int) q.peek());
+ assertEquals(i, (int) q.poll());
+ assertTrue(q.peek() == null ||
+ i != (int) q.peek());
+ }
+ assertNull(q.peek());
+ checkEmpty(q);
+ }
+
+ /**
+ * element returns next element, or throws NoSuchElementException if empty
+ */
+ public void testElement() throws InterruptedException {
+ LinkedTransferQueue<Integer> q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, (int) q.element());
+ assertEquals(i, (int) q.poll());
+ }
+ try {
+ q.element();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ checkEmpty(q);
+ }
+
+ /**
+ * remove removes next element, or throws NoSuchElementException if empty
+ */
+ public void testRemove() throws InterruptedException {
+ LinkedTransferQueue<Integer> q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, (int) q.remove());
+ }
+ try {
+ q.remove();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ checkEmpty(q);
+ }
+
+ /**
+ * An add following remove(x) succeeds
+ */
+ public void testRemoveElementAndAdd() throws InterruptedException {
+ LinkedTransferQueue q = new LinkedTransferQueue();
+ assertTrue(q.add(one));
+ assertTrue(q.add(two));
+ assertTrue(q.remove(one));
+ assertTrue(q.remove(two));
+ assertTrue(q.add(three));
+ assertSame(q.take(), three);
+ }
+
+ /**
+ * contains(x) reports true when elements added but not yet removed
+ */
+ public void testContains() {
+ LinkedTransferQueue<Integer> q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.contains(i));
+ assertEquals(i, (int) q.poll());
+ assertFalse(q.contains(i));
+ }
+ }
+
+ /**
+ * clear removes all elements
+ */
+ public void testClear() throws InterruptedException {
+ LinkedTransferQueue q = populatedQueue(SIZE);
+ q.clear();
+ checkEmpty(q);
+ assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
+ q.add(one);
+ assertFalse(q.isEmpty());
+ assertEquals(1, q.size());
+ assertTrue(q.contains(one));
+ q.clear();
+ checkEmpty(q);
+ }
+
+ /**
+ * containsAll(c) is true when c contains a subset of elements
+ */
+ public void testContainsAll() {
+ LinkedTransferQueue<Integer> q = populatedQueue(SIZE);
+ LinkedTransferQueue<Integer> p = new LinkedTransferQueue<Integer>();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.containsAll(p));
+ assertFalse(p.containsAll(q));
+ p.add(i);
+ }
+ assertTrue(p.containsAll(q));
+ }
+
+ /**
+ * retainAll(c) retains only those elements of c and reports true
+ * if changed
+ */
+ public void testRetainAll() {
+ LinkedTransferQueue q = populatedQueue(SIZE);
+ LinkedTransferQueue p = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ boolean changed = q.retainAll(p);
+ if (i == 0) {
+ assertFalse(changed);
+ } else {
+ assertTrue(changed);
+ }
+ assertTrue(q.containsAll(p));
+ assertEquals(SIZE - i, q.size());
+ p.remove();
+ }
+ }
+
+ /**
+ * removeAll(c) removes only those elements of c and reports true
+ * if changed
+ */
+ public void testRemoveAll() {
+ for (int i = 1; i < SIZE; ++i) {
+ LinkedTransferQueue q = populatedQueue(SIZE);
+ LinkedTransferQueue p = populatedQueue(i);
+ assertTrue(q.removeAll(p));
+ assertEquals(SIZE - i, q.size());
+ for (int j = 0; j < i; ++j) {
+ assertFalse(q.contains(p.remove()));
+ }
+ }
+ }
+
+ /**
+ * toArray() contains all elements in FIFO order
+ */
+ public void testToArray() {
+ LinkedTransferQueue q = populatedQueue(SIZE);
+ Object[] o = q.toArray();
+ for (int i = 0; i < o.length; i++) {
+ assertSame(o[i], q.poll());
+ }
+ }
+
+ /**
+ * toArray(a) contains all elements in FIFO order
+ */
+ public void testToArray2() {
+ LinkedTransferQueue<Integer> q = populatedQueue(SIZE);
+ Integer[] ints = new Integer[SIZE];
+ Integer[] array = q.toArray(ints);
+ assertSame(ints, array);
+ for (int i = 0; i < ints.length; i++) {
+ assertSame(ints[i], q.poll());
+ }
+ }
+
+ /**
+ * toArray(incompatible array type) throws ArrayStoreException
+ */
+ public void testToArray1_BadArg() {
+ LinkedTransferQueue q = populatedQueue(SIZE);
+ try {
+ q.toArray(new String[10]);
+ shouldThrow();
+ } catch (ArrayStoreException success) {}
+ }
+
+ /**
+ * iterator iterates through all elements
+ */
+ public void testIterator() throws InterruptedException {
+ LinkedTransferQueue q = populatedQueue(SIZE);
+ Iterator it = q.iterator();
+ int i = 0;
+ while (it.hasNext()) {
+ assertEquals(it.next(), i++);
+ }
+ assertEquals(i, SIZE);
+ }
+
+ /**
+ * iterator.remove() removes current element
+ */
+ public void testIteratorRemove() {
+ final LinkedTransferQueue q = new LinkedTransferQueue();
+ q.add(two);
+ q.add(one);
+ q.add(three);
+
+ Iterator it = q.iterator();
+ it.next();
+ it.remove();
+
+ it = q.iterator();
+ assertSame(it.next(), one);
+ assertSame(it.next(), three);
+ assertFalse(it.hasNext());
+ }
+
+ /**
+ * iterator ordering is FIFO
+ */
+ public void testIteratorOrdering() {
+ final LinkedTransferQueue<Integer> q
+ = new LinkedTransferQueue<Integer>();
+ assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
+ q.add(one);
+ q.add(two);
+ q.add(three);
+ assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
+ int k = 0;
+ for (Integer n : q) {
+ assertEquals(++k, (int) n);
+ }
+ assertEquals(3, k);
+ }
+
+ /**
+ * Modifications do not cause iterators to fail
+ */
+ public void testWeaklyConsistentIteration() {
+ final LinkedTransferQueue q = new LinkedTransferQueue();
+ q.add(one);
+ q.add(two);
+ q.add(three);
+ for (Iterator it = q.iterator(); it.hasNext();) {
+ q.remove();
+ it.next();
+ }
+ assertEquals(0, q.size());
+ }
+
+ /**
+ * toString contains toStrings of elements
+ */
+ public void testToString() {
+ LinkedTransferQueue q = populatedQueue(SIZE);
+ String s = q.toString();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(s.contains(String.valueOf(i)));
+ }
+ }
+
+ /**
+ * offer transfers elements across Executor tasks
+ */
+ public void testOfferInExecutor() {
+ final LinkedTransferQueue q = new LinkedTransferQueue();
+ final CheckedBarrier threadsStarted = new CheckedBarrier(2);
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ assertTrue(q.offer(one, LONG_DELAY_MS, MILLISECONDS));
+ }});
+
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ assertSame(one, q.take());
+ checkEmpty(q);
+ }});
+
+ joinPool(executor);
+ }
+
+ /**
+ * timed poll retrieves elements across Executor threads
+ */
+ public void testPollInExecutor() {
+ final LinkedTransferQueue q = new LinkedTransferQueue();
+ final CheckedBarrier threadsStarted = new CheckedBarrier(2);
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertNull(q.poll());
+ threadsStarted.await();
+ assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS));
+ checkEmpty(q);
+ }});
+
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ q.put(one);
+ }});
+
+ joinPool(executor);
+ }
+
+ /**
+ * A deserialized serialized queue has same elements in same order
+ */
+ public void testSerialization() throws Exception {
+ Queue x = populatedQueue(SIZE);
+ Queue y = serialClone(x);
+
+ assertNotSame(y, x);
+ assertEquals(x.size(), y.size());
+ assertEquals(x.toString(), y.toString());
+ assertTrue(Arrays.equals(x.toArray(), y.toArray()));
+ while (!x.isEmpty()) {
+ assertFalse(y.isEmpty());
+ assertEquals(x.remove(), y.remove());
+ }
+ assertTrue(y.isEmpty());
+ }
+
+ /**
+ * drainTo(c) empties queue into another collection c
+ */
+ public void testDrainTo() {
+ LinkedTransferQueue q = populatedQueue(SIZE);
+ ArrayList l = new ArrayList();
+ q.drainTo(l);
+ assertEquals(0, q.size());
+ assertEquals(SIZE, l.size());
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, l.get(i));
+ }
+ q.add(zero);
+ q.add(one);
+ assertFalse(q.isEmpty());
+ assertTrue(q.contains(zero));
+ assertTrue(q.contains(one));
+ l.clear();
+ q.drainTo(l);
+ assertEquals(0, q.size());
+ assertEquals(2, l.size());
+ for (int i = 0; i < 2; ++i) {
+ assertEquals(i, l.get(i));
+ }
+ }
+
+ /**
+ * drainTo(c) empties full queue, unblocking a waiting put.
+ */
+ public void testDrainToWithActivePut() throws InterruptedException {
+ final LinkedTransferQueue q = populatedQueue(SIZE);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ q.put(SIZE + 1);
+ }});
+ ArrayList l = new ArrayList();
+ q.drainTo(l);
+ assertTrue(l.size() >= SIZE);
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(i, l.get(i));
+ awaitTermination(t, MEDIUM_DELAY_MS);
+ assertTrue(q.size() + l.size() >= SIZE);
+ }
+
+ /**
+ * drainTo(c, n) empties first min(n, size) elements of queue into c
+ */
+ public void testDrainToN() {
+ LinkedTransferQueue q = new LinkedTransferQueue();
+ for (int i = 0; i < SIZE + 2; ++i) {
+ for (int j = 0; j < SIZE; j++) {
+ assertTrue(q.offer(j));
+ }
+ ArrayList l = new ArrayList();
+ q.drainTo(l, i);
+ int k = (i < SIZE) ? i : SIZE;
+ assertEquals(k, l.size());
+ assertEquals(SIZE - k, q.size());
+ for (int j = 0; j < k; ++j)
+ assertEquals(j, l.get(j));
+ while (q.poll() != null)
+ ;
+ }
+ }
+
+ /**
+ * timed poll() or take() increments the waiting consumer count;
+ * offer(e) decrements the waiting consumer count
+ */
+ public void testWaitingConsumer() throws InterruptedException {
+ final LinkedTransferQueue q = new LinkedTransferQueue();
+ assertEquals(0, q.getWaitingConsumerCount());
+ assertFalse(q.hasWaitingConsumer());
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS));
+ assertEquals(0, q.getWaitingConsumerCount());
+ assertFalse(q.hasWaitingConsumer());
+ }});
+
+ threadStarted.await();
+ waitForThreadToEnterWaitState(t, SMALL_DELAY_MS);
+ assertEquals(1, q.getWaitingConsumerCount());
+ assertTrue(q.hasWaitingConsumer());
+
+ assertTrue(q.offer(one));
+ assertEquals(0, q.getWaitingConsumerCount());
+ assertFalse(q.hasWaitingConsumer());
+
+ awaitTermination(t, MEDIUM_DELAY_MS);
+ }
+
+ /**
+ * transfer(null) throws NullPointerException
+ */
+ public void testTransfer1() throws InterruptedException {
+ try {
+ LinkedTransferQueue q = new LinkedTransferQueue();
+ q.transfer(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * transfer waits until a poll occurs. The transfered element
+ * is returned by this associated poll.
+ */
+ public void testTransfer2() throws InterruptedException {
+ final LinkedTransferQueue<Integer> q
+ = new LinkedTransferQueue<Integer>();
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ q.transfer(five);
+ checkEmpty(q);
+ }});
+
+ threadStarted.await();
+ waitForThreadToEnterWaitState(t, SMALL_DELAY_MS);
+ assertEquals(1, q.size());
+ assertSame(five, q.poll());
+ checkEmpty(q);
+ awaitTermination(t, MEDIUM_DELAY_MS);
+ }
+
+ /**
+ * transfer waits until a poll occurs, and then transfers in fifo order
+ */
+ public void testTransfer3() throws InterruptedException {
+ final LinkedTransferQueue<Integer> q
+ = new LinkedTransferQueue<Integer>();
+
+ Thread first = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ q.transfer(four);
+ assertTrue(!q.contains(four));
+ assertEquals(1, q.size());
+ }});
+
+ Thread interruptedThread = newStartedThread(
+ new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ while (q.isEmpty())
+ Thread.yield();
+ q.transfer(five);
+ }});
+
+ while (q.size() < 2)
+ Thread.yield();
+ assertEquals(2, q.size());
+ assertSame(four, q.poll());
+ first.join();
+ assertEquals(1, q.size());
+ interruptedThread.interrupt();
+ interruptedThread.join();
+ checkEmpty(q);
+ }
+
+ /**
+ * transfer waits until a poll occurs, at which point the polling
+ * thread returns the element
+ */
+ public void testTransfer4() throws InterruptedException {
+ final LinkedTransferQueue q = new LinkedTransferQueue();
+
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ q.transfer(four);
+ assertFalse(q.contains(four));
+ assertSame(three, q.poll());
+ }});
+
+ while (q.isEmpty())
+ Thread.yield();
+ assertFalse(q.isEmpty());
+ assertEquals(1, q.size());
+ assertTrue(q.offer(three));
+ assertSame(four, q.poll());
+ awaitTermination(t, MEDIUM_DELAY_MS);
+ }
+
+ /**
+ * transfer waits until a take occurs. The transfered element
+ * is returned by this associated take.
+ */
+ public void testTransfer5() throws InterruptedException {
+ final LinkedTransferQueue<Integer> q
+ = new LinkedTransferQueue<Integer>();
+
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ q.transfer(four);
+ checkEmpty(q);
+ }});
+
+ while (q.isEmpty())
+ Thread.yield();
+ assertFalse(q.isEmpty());
+ assertEquals(1, q.size());
+ assertSame(four, q.take());
+ checkEmpty(q);
+ awaitTermination(t, MEDIUM_DELAY_MS);
+ }
+
+ /**
+ * tryTransfer(null) throws NullPointerException
+ */
+ public void testTryTransfer1() {
+ try {
+ final LinkedTransferQueue q = new LinkedTransferQueue();
+ q.tryTransfer(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * tryTransfer returns false and does not enqueue if there are no
+ * consumers waiting to poll or take.
+ */
+ public void testTryTransfer2() throws InterruptedException {
+ final LinkedTransferQueue q = new LinkedTransferQueue();
+ assertFalse(q.tryTransfer(new Object()));
+ assertFalse(q.hasWaitingConsumer());
+ checkEmpty(q);
+ }
+
+ /**
+ * If there is a consumer waiting in timed poll, tryTransfer
+ * returns true while successfully transfering object.
+ */
+ public void testTryTransfer3() throws InterruptedException {
+ final Object hotPotato = new Object();
+ final LinkedTransferQueue q = new LinkedTransferQueue();
+
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ while (! q.hasWaitingConsumer())
+ Thread.yield();
+ assertTrue(q.hasWaitingConsumer());
+ checkEmpty(q);
+ assertTrue(q.tryTransfer(hotPotato));
+ }});
+
+ assertSame(hotPotato, q.poll(MEDIUM_DELAY_MS, MILLISECONDS));
+ checkEmpty(q);
+ awaitTermination(t, MEDIUM_DELAY_MS);
+ }
+
+ /**
+ * If there is a consumer waiting in take, tryTransfer returns
+ * true while successfully transfering object.
+ */
+ public void testTryTransfer4() throws InterruptedException {
+ final Object hotPotato = new Object();
+ final LinkedTransferQueue q = new LinkedTransferQueue();
+
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ while (! q.hasWaitingConsumer())
+ Thread.yield();
+ assertTrue(q.hasWaitingConsumer());
+ checkEmpty(q);
+ assertTrue(q.tryTransfer(hotPotato));
+ }});
+
+ assertSame(q.take(), hotPotato);
+ checkEmpty(q);
+ awaitTermination(t, MEDIUM_DELAY_MS);
+ }
+
+ /**
+ * tryTransfer blocks interruptibly if no takers
+ */
+ public void testTryTransfer5() throws InterruptedException {
+ final LinkedTransferQueue q = new LinkedTransferQueue();
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ assertTrue(q.isEmpty());
+
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ Thread.currentThread().interrupt();
+ try {
+ q.tryTransfer(new Object(), LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ q.tryTransfer(new Object(), LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ checkEmpty(q);
+ }
+
+ /**
+ * tryTransfer gives up after the timeout and returns false
+ */
+ public void testTryTransfer6() throws InterruptedException {
+ final LinkedTransferQueue q = new LinkedTransferQueue();
+
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ long t0 = System.nanoTime();
+ assertFalse(q.tryTransfer(new Object(),
+ timeoutMillis(), MILLISECONDS));
+ assertTrue(millisElapsedSince(t0) >= timeoutMillis());
+ checkEmpty(q);
+ }});
+
+ awaitTermination(t);
+ checkEmpty(q);
+ }
+
+ /**
+ * tryTransfer waits for any elements previously in to be removed
+ * before transfering to a poll or take
+ */
+ public void testTryTransfer7() throws InterruptedException {
+ final LinkedTransferQueue q = new LinkedTransferQueue();
+ assertTrue(q.offer(four));
+
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertTrue(q.tryTransfer(five, MEDIUM_DELAY_MS, MILLISECONDS));
+ checkEmpty(q);
+ }});
+
+ while (q.size() != 2)
+ Thread.yield();
+ assertEquals(2, q.size());
+ assertSame(four, q.poll());
+ assertSame(five, q.poll());
+ checkEmpty(q);
+ awaitTermination(t, MEDIUM_DELAY_MS);
+ }
+
+ /**
+ * tryTransfer attempts to enqueue into the queue and fails
+ * returning false not enqueueing and the successive poll is null
+ */
+ public void testTryTransfer8() throws InterruptedException {
+ final LinkedTransferQueue q = new LinkedTransferQueue();
+ assertTrue(q.offer(four));
+ assertEquals(1, q.size());
+ long t0 = System.nanoTime();
+ assertFalse(q.tryTransfer(five, timeoutMillis(), MILLISECONDS));
+ assertTrue(millisElapsedSince(t0) >= timeoutMillis());
+ assertEquals(1, q.size());
+ assertSame(four, q.poll());
+ assertNull(q.poll());
+ checkEmpty(q);
+ }
+
+ private LinkedTransferQueue<Integer> populatedQueue(int n) {
+ LinkedTransferQueue<Integer> q = new LinkedTransferQueue<Integer>();
+ checkEmpty(q);
+ for (int i = 0; i < n; i++) {
+ assertEquals(i, q.size());
+ assertTrue(q.offer(i));
+ assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
+ }
+ assertFalse(q.isEmpty());
+ return q;
+ }
+}
diff --git a/jsr166-tests/src/test/java/jsr166/LockSupportTest.java b/jsr166-tests/src/test/java/jsr166/LockSupportTest.java
new file mode 100644
index 0000000..051de35
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/LockSupportTest.java
@@ -0,0 +1,362 @@
+/*
+ * Written by Doug Lea and Martin Buchholz with assistance from
+ * members of JCP JSR-166 Expert Group and released to the public
+ * domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.LockSupport;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+public class LockSupportTest extends JSR166TestCase {
+
+ /**
+ * Returns the blocker object used by tests in this file.
+ * Any old object will do; we'll return a convenient one.
+ */
+ static Object theBlocker() {
+ return LockSupportTest.class;
+ }
+
+ enum ParkMethod {
+ park() {
+ void park() {
+ LockSupport.park();
+ }
+ void park(long millis) {
+ throw new UnsupportedOperationException();
+ }
+ },
+ parkUntil() {
+ void park(long millis) {
+ LockSupport.parkUntil(deadline(millis));
+ }
+ },
+ parkNanos() {
+ void park(long millis) {
+ LockSupport.parkNanos(MILLISECONDS.toNanos(millis));
+ }
+ },
+ parkBlocker() {
+ void park() {
+ LockSupport.park(theBlocker());
+ }
+ void park(long millis) {
+ throw new UnsupportedOperationException();
+ }
+ },
+ parkUntilBlocker() {
+ void park(long millis) {
+ LockSupport.parkUntil(theBlocker(), deadline(millis));
+ }
+ },
+ parkNanosBlocker() {
+ void park(long millis) {
+ LockSupport.parkNanos(theBlocker(),
+ MILLISECONDS.toNanos(millis));
+ }
+ };
+
+ void park() { park(2 * LONG_DELAY_MS); }
+ abstract void park(long millis);
+
+ /** Returns a deadline to use with parkUntil. */
+ long deadline(long millis) {
+ // beware of rounding
+ return System.currentTimeMillis() + millis + 1;
+ }
+ }
+
+ /**
+ * park is released by subsequent unpark
+ */
+ public void testParkBeforeUnpark_park() {
+ testParkBeforeUnpark(ParkMethod.park);
+ }
+ public void testParkBeforeUnpark_parkNanos() {
+ testParkBeforeUnpark(ParkMethod.parkNanos);
+ }
+ public void testParkBeforeUnpark_parkUntil() {
+ testParkBeforeUnpark(ParkMethod.parkUntil);
+ }
+ public void testParkBeforeUnpark_parkBlocker() {
+ testParkBeforeUnpark(ParkMethod.parkBlocker);
+ }
+ public void testParkBeforeUnpark_parkNanosBlocker() {
+ testParkBeforeUnpark(ParkMethod.parkNanosBlocker);
+ }
+ public void testParkBeforeUnpark_parkUntilBlocker() {
+ testParkBeforeUnpark(ParkMethod.parkUntilBlocker);
+ }
+ public void testParkBeforeUnpark(final ParkMethod parkMethod) {
+ final CountDownLatch pleaseUnpark = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ pleaseUnpark.countDown();
+ parkMethod.park();
+ }});
+
+ await(pleaseUnpark);
+ LockSupport.unpark(t);
+ awaitTermination(t);
+ }
+
+ /**
+ * park is released by preceding unpark
+ */
+ public void testParkAfterUnpark_park() {
+ testParkAfterUnpark(ParkMethod.park);
+ }
+ public void testParkAfterUnpark_parkNanos() {
+ testParkAfterUnpark(ParkMethod.parkNanos);
+ }
+ public void testParkAfterUnpark_parkUntil() {
+ testParkAfterUnpark(ParkMethod.parkUntil);
+ }
+ public void testParkAfterUnpark_parkBlocker() {
+ testParkAfterUnpark(ParkMethod.parkBlocker);
+ }
+ public void testParkAfterUnpark_parkNanosBlocker() {
+ testParkAfterUnpark(ParkMethod.parkNanosBlocker);
+ }
+ public void testParkAfterUnpark_parkUntilBlocker() {
+ testParkAfterUnpark(ParkMethod.parkUntilBlocker);
+ }
+ public void testParkAfterUnpark(final ParkMethod parkMethod) {
+ final CountDownLatch pleaseUnpark = new CountDownLatch(1);
+ final AtomicBoolean pleasePark = new AtomicBoolean(false);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ pleaseUnpark.countDown();
+ while (!pleasePark.get())
+ Thread.yield();
+ parkMethod.park();
+ }});
+
+ await(pleaseUnpark);
+ LockSupport.unpark(t);
+ pleasePark.set(true);
+ awaitTermination(t);
+ }
+
+ /**
+ * park is released by subsequent interrupt
+ */
+ public void testParkBeforeInterrupt_park() {
+ testParkBeforeInterrupt(ParkMethod.park);
+ }
+ public void testParkBeforeInterrupt_parkNanos() {
+ testParkBeforeInterrupt(ParkMethod.parkNanos);
+ }
+ public void testParkBeforeInterrupt_parkUntil() {
+ testParkBeforeInterrupt(ParkMethod.parkUntil);
+ }
+ public void testParkBeforeInterrupt_parkBlocker() {
+ testParkBeforeInterrupt(ParkMethod.parkBlocker);
+ }
+ public void testParkBeforeInterrupt_parkNanosBlocker() {
+ testParkBeforeInterrupt(ParkMethod.parkNanosBlocker);
+ }
+ public void testParkBeforeInterrupt_parkUntilBlocker() {
+ testParkBeforeInterrupt(ParkMethod.parkUntilBlocker);
+ }
+ public void testParkBeforeInterrupt(final ParkMethod parkMethod) {
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ pleaseInterrupt.countDown();
+ do {
+ parkMethod.park();
+ // park may return spuriously
+ } while (! Thread.currentThread().isInterrupted());
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * park is released by preceding interrupt
+ */
+ public void testParkAfterInterrupt_park() {
+ testParkAfterInterrupt(ParkMethod.park);
+ }
+ public void testParkAfterInterrupt_parkNanos() {
+ testParkAfterInterrupt(ParkMethod.parkNanos);
+ }
+ public void testParkAfterInterrupt_parkUntil() {
+ testParkAfterInterrupt(ParkMethod.parkUntil);
+ }
+ public void testParkAfterInterrupt_parkBlocker() {
+ testParkAfterInterrupt(ParkMethod.parkBlocker);
+ }
+ public void testParkAfterInterrupt_parkNanosBlocker() {
+ testParkAfterInterrupt(ParkMethod.parkNanosBlocker);
+ }
+ public void testParkAfterInterrupt_parkUntilBlocker() {
+ testParkAfterInterrupt(ParkMethod.parkUntilBlocker);
+ }
+ public void testParkAfterInterrupt(final ParkMethod parkMethod) {
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ final AtomicBoolean pleasePark = new AtomicBoolean(false);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws Exception {
+ pleaseInterrupt.countDown();
+ while (!pleasePark.get())
+ Thread.yield();
+ assertTrue(Thread.currentThread().isInterrupted());
+ parkMethod.park();
+ assertTrue(Thread.currentThread().isInterrupted());
+ }});
+
+ await(pleaseInterrupt);
+ t.interrupt();
+ pleasePark.set(true);
+ awaitTermination(t);
+ }
+
+ /**
+ * timed park times out if not unparked
+ */
+ public void testParkTimesOut_parkNanos() {
+ testParkTimesOut(ParkMethod.parkNanos);
+ }
+ public void testParkTimesOut_parkUntil() {
+ testParkTimesOut(ParkMethod.parkUntil);
+ }
+ public void testParkTimesOut_parkNanosBlocker() {
+ testParkTimesOut(ParkMethod.parkNanosBlocker);
+ }
+ public void testParkTimesOut_parkUntilBlocker() {
+ testParkTimesOut(ParkMethod.parkUntilBlocker);
+ }
+ public void testParkTimesOut(final ParkMethod parkMethod) {
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ for (;;) {
+ long startTime = System.nanoTime();
+ parkMethod.park(timeoutMillis());
+ // park may return spuriously
+ if (millisElapsedSince(startTime) >= timeoutMillis())
+ return;
+ }
+ }});
+
+ awaitTermination(t);
+ }
+
+ /**
+ * getBlocker(null) throws NullPointerException
+ */
+ public void testGetBlockerNull() {
+ try {
+ LockSupport.getBlocker(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * getBlocker returns the blocker object passed to park
+ */
+ public void testGetBlocker_parkBlocker() {
+ testGetBlocker(ParkMethod.parkBlocker);
+ }
+ public void testGetBlocker_parkNanosBlocker() {
+ testGetBlocker(ParkMethod.parkNanosBlocker);
+ }
+ public void testGetBlocker_parkUntilBlocker() {
+ testGetBlocker(ParkMethod.parkUntilBlocker);
+ }
+ public void testGetBlocker(final ParkMethod parkMethod) {
+ final CountDownLatch started = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ Thread t = Thread.currentThread();
+ started.countDown();
+ do {
+ assertNull(LockSupport.getBlocker(t));
+ parkMethod.park();
+ assertNull(LockSupport.getBlocker(t));
+ // park may return spuriously
+ } while (! Thread.currentThread().isInterrupted());
+ }});
+
+ long startTime = System.nanoTime();
+ await(started);
+ for (;;) {
+ Object x = LockSupport.getBlocker(t);
+ if (x == theBlocker()) { // success
+ t.interrupt();
+ awaitTermination(t);
+ assertNull(LockSupport.getBlocker(t));
+ return;
+ } else {
+ assertNull(x); // ok
+ if (millisElapsedSince(startTime) > LONG_DELAY_MS)
+ fail("timed out");
+ Thread.yield();
+ }
+ }
+ }
+
+ /**
+ * timed park(0) returns immediately.
+ *
+ * Requires hotspot fix for:
+ * 6763959 java.util.concurrent.locks.LockSupport.parkUntil(0) blocks forever
+ * which is in jdk7-b118 and 6u25.
+ */
+ public void testPark0_parkNanos() {
+ testPark0(ParkMethod.parkNanos);
+ }
+ public void testPark0_parkUntil() {
+ testPark0(ParkMethod.parkUntil);
+ }
+ public void testPark0_parkNanosBlocker() {
+ testPark0(ParkMethod.parkNanosBlocker);
+ }
+ public void testPark0_parkUntilBlocker() {
+ testPark0(ParkMethod.parkUntilBlocker);
+ }
+ public void testPark0(final ParkMethod parkMethod) {
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ parkMethod.park(0L);
+ }});
+
+ awaitTermination(t);
+ }
+
+ /**
+ * timed park(Long.MIN_VALUE) returns immediately.
+ */
+ public void testParkNeg_parkNanos() {
+ testParkNeg(ParkMethod.parkNanos);
+ }
+ public void testParkNeg_parkUntil() {
+ testParkNeg(ParkMethod.parkUntil);
+ }
+ public void testParkNeg_parkNanosBlocker() {
+ testParkNeg(ParkMethod.parkNanosBlocker);
+ }
+ public void testParkNeg_parkUntilBlocker() {
+ testParkNeg(ParkMethod.parkUntilBlocker);
+ }
+ public void testParkNeg(final ParkMethod parkMethod) {
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ parkMethod.park(Long.MIN_VALUE);
+ }});
+
+ awaitTermination(t);
+ }
+}
diff --git a/jsr166-tests/src/test/java/jsr166/PhaserTest.java b/jsr166-tests/src/test/java/jsr166/PhaserTest.java
new file mode 100644
index 0000000..3889c1f
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/PhaserTest.java
@@ -0,0 +1,786 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include John Vint
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Phaser;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeoutException;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class PhaserTest extends JSR166TestCase {
+
+ private static final int maxParties = 65535;
+
+ /** Checks state of unterminated phaser. */
+ protected void assertState(Phaser phaser,
+ int phase, int parties, int unarrived) {
+ assertEquals(phase, phaser.getPhase());
+ assertEquals(parties, phaser.getRegisteredParties());
+ assertEquals(unarrived, phaser.getUnarrivedParties());
+ assertEquals(parties - unarrived, phaser.getArrivedParties());
+ assertFalse(phaser.isTerminated());
+ }
+
+ /** Checks state of terminated phaser. */
+ protected void assertTerminated(Phaser phaser, int maxPhase, int parties) {
+ assertTrue(phaser.isTerminated());
+ int expectedPhase = maxPhase + Integer.MIN_VALUE;
+ assertEquals(expectedPhase, phaser.getPhase());
+ assertEquals(parties, phaser.getRegisteredParties());
+ assertEquals(expectedPhase, phaser.register());
+ assertEquals(expectedPhase, phaser.arrive());
+ assertEquals(expectedPhase, phaser.arriveAndDeregister());
+ }
+
+ protected void assertTerminated(Phaser phaser, int maxPhase) {
+ assertTerminated(phaser, maxPhase, 0);
+ }
+
+ /**
+ * Empty constructor builds a new Phaser with no parent, no registered
+ * parties and initial phase number of 0
+ */
+ public void testConstructorDefaultValues() {
+ Phaser phaser = new Phaser();
+ assertNull(phaser.getParent());
+ assertEquals(0, phaser.getRegisteredParties());
+ assertEquals(0, phaser.getArrivedParties());
+ assertEquals(0, phaser.getUnarrivedParties());
+ assertEquals(0, phaser.getPhase());
+ }
+
+ /**
+ * Constructing with a negative number of parties throws
+ * IllegalArgumentException
+ */
+ public void testConstructorNegativeParties() {
+ try {
+ new Phaser(-1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructing with a negative number of parties throws
+ * IllegalArgumentException
+ */
+ public void testConstructorNegativeParties2() {
+ try {
+ new Phaser(new Phaser(), -1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructing with a number of parties > 65535 throws
+ * IllegalArgumentException
+ */
+ public void testConstructorPartiesExceedsLimit() {
+ new Phaser(maxParties);
+ try {
+ new Phaser(maxParties + 1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+
+ new Phaser(new Phaser(), maxParties);
+ try {
+ new Phaser(new Phaser(), maxParties + 1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * The parent provided to the constructor should be returned from
+ * a later call to getParent
+ */
+ public void testConstructor3() {
+ Phaser parent = new Phaser();
+ assertSame(parent, new Phaser(parent).getParent());
+ assertNull(new Phaser(null).getParent());
+ }
+
+ /**
+ * The parent being input into the parameter should equal the original
+ * parent when being returned
+ */
+ public void testConstructor5() {
+ Phaser parent = new Phaser();
+ assertSame(parent, new Phaser(parent, 0).getParent());
+ assertNull(new Phaser(null, 0).getParent());
+ }
+
+ /**
+ * register() will increment the number of unarrived parties by
+ * one and not affect its arrived parties
+ */
+ public void testRegister1() {
+ Phaser phaser = new Phaser();
+ assertState(phaser, 0, 0, 0);
+ assertEquals(0, phaser.register());
+ assertState(phaser, 0, 1, 1);
+ }
+
+ /**
+ * Registering more than 65536 parties causes IllegalStateException
+ */
+ public void testRegister2() {
+ Phaser phaser = new Phaser(0);
+ assertState(phaser, 0, 0, 0);
+ assertEquals(0, phaser.bulkRegister(maxParties - 10));
+ assertState(phaser, 0, maxParties - 10, maxParties - 10);
+ for (int i = 0; i < 10; i++) {
+ assertState(phaser, 0, maxParties - 10 + i, maxParties - 10 + i);
+ assertEquals(0, phaser.register());
+ }
+ assertState(phaser, 0, maxParties, maxParties);
+ try {
+ phaser.register();
+ shouldThrow();
+ } catch (IllegalStateException success) {}
+
+ try {
+ phaser.bulkRegister(Integer.MAX_VALUE);
+ shouldThrow();
+ } catch (IllegalStateException success) {}
+
+ assertEquals(0, phaser.bulkRegister(0));
+ assertState(phaser, 0, maxParties, maxParties);
+ }
+
+ /**
+ * register() correctly returns the current barrier phase number
+ * when invoked
+ */
+ public void testRegister3() {
+ Phaser phaser = new Phaser();
+ assertEquals(0, phaser.register());
+ assertEquals(0, phaser.arrive());
+ assertEquals(1, phaser.register());
+ assertState(phaser, 1, 2, 2);
+ }
+
+ /**
+ * register causes the next arrive to not increment the phase
+ * rather retain the phase number
+ */
+ public void testRegister4() {
+ Phaser phaser = new Phaser(1);
+ assertEquals(0, phaser.arrive());
+ assertEquals(1, phaser.register());
+ assertEquals(1, phaser.arrive());
+ assertState(phaser, 1, 2, 1);
+ }
+
+ /**
+ * register on a subphaser that is currently empty succeeds, even
+ * in the presence of another non-empty subphaser
+ */
+ public void testRegisterEmptySubPhaser() {
+ Phaser root = new Phaser();
+ Phaser child1 = new Phaser(root, 1);
+ Phaser child2 = new Phaser(root, 0);
+ assertEquals(0, child2.register());
+ assertState(root, 0, 2, 2);
+ assertState(child1, 0, 1, 1);
+ assertState(child2, 0, 1, 1);
+ assertEquals(0, child2.arriveAndDeregister());
+ assertState(root, 0, 1, 1);
+ assertState(child1, 0, 1, 1);
+ assertState(child2, 0, 0, 0);
+ assertEquals(0, child2.register());
+ assertEquals(0, child2.arriveAndDeregister());
+ assertState(root, 0, 1, 1);
+ assertState(child1, 0, 1, 1);
+ assertState(child2, 0, 0, 0);
+ assertEquals(0, child1.arriveAndDeregister());
+ assertTerminated(root, 1);
+ assertTerminated(child1, 1);
+ assertTerminated(child2, 1);
+ }
+
+ /**
+ * Invoking bulkRegister with a negative parameter throws an
+ * IllegalArgumentException
+ */
+ public void testBulkRegister1() {
+ try {
+ new Phaser().bulkRegister(-1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * bulkRegister should correctly record the number of unarrived
+ * parties with the number of parties being registered
+ */
+ public void testBulkRegister2() {
+ Phaser phaser = new Phaser();
+ assertEquals(0, phaser.bulkRegister(0));
+ assertState(phaser, 0, 0, 0);
+ assertEquals(0, phaser.bulkRegister(20));
+ assertState(phaser, 0, 20, 20);
+ }
+
+ /**
+ * Registering with a number of parties greater than or equal to 1<<16
+ * throws IllegalStateException.
+ */
+ public void testBulkRegister3() {
+ assertEquals(0, new Phaser().bulkRegister((1 << 16) - 1));
+
+ try {
+ new Phaser().bulkRegister(1 << 16);
+ shouldThrow();
+ } catch (IllegalStateException success) {}
+
+ try {
+ new Phaser(2).bulkRegister((1 << 16) - 2);
+ shouldThrow();
+ } catch (IllegalStateException success) {}
+ }
+
+ /**
+ * the phase number increments correctly when tripping the barrier
+ */
+ public void testPhaseIncrement1() {
+ for (int size = 1; size < nine; size++) {
+ final Phaser phaser = new Phaser(size);
+ for (int index = 0; index <= (1 << size); index++) {
+ int phase = phaser.arrive();
+ assertTrue(index % size == 0 ? (index / size) == phase : index - (phase * size) > 0);
+ }
+ }
+ }
+
+ /**
+ * arrive() on a registered phaser increments phase.
+ */
+ public void testArrive1() {
+ Phaser phaser = new Phaser(1);
+ assertState(phaser, 0, 1, 1);
+ assertEquals(0, phaser.arrive());
+ assertState(phaser, 1, 1, 1);
+ }
+
+ /**
+ * arriveAndDeregister does not wait for others to arrive at barrier
+ */
+ public void testArriveAndDeregister() {
+ final Phaser phaser = new Phaser(1);
+ for (int i = 0; i < 10; i++) {
+ assertState(phaser, 0, 1, 1);
+ assertEquals(0, phaser.register());
+ assertState(phaser, 0, 2, 2);
+ assertEquals(0, phaser.arriveAndDeregister());
+ assertState(phaser, 0, 1, 1);
+ }
+ assertEquals(0, phaser.arriveAndDeregister());
+ assertTerminated(phaser, 1);
+ }
+
+ /**
+ * arriveAndDeregister does not wait for others to arrive at barrier
+ */
+ public void testArrive2() {
+ final Phaser phaser = new Phaser();
+ assertEquals(0, phaser.register());
+ List<Thread> threads = new ArrayList<Thread>();
+ for (int i = 0; i < 10; i++) {
+ assertEquals(0, phaser.register());
+ threads.add(newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ assertEquals(0, phaser.arriveAndDeregister());
+ }}));
+ }
+
+ for (Thread thread : threads)
+ awaitTermination(thread);
+ assertState(phaser, 0, 1, 1);
+ assertEquals(0, phaser.arrive());
+ assertState(phaser, 1, 1, 1);
+ }
+
+ /**
+ * arrive() returns a negative number if the Phaser is terminated
+ */
+ public void testArrive3() {
+ Phaser phaser = new Phaser(1);
+ phaser.forceTermination();
+ assertTerminated(phaser, 0, 1);
+ assertEquals(0, phaser.getPhase() + Integer.MIN_VALUE);
+ assertTrue(phaser.arrive() < 0);
+ assertTrue(phaser.register() < 0);
+ assertTrue(phaser.arriveAndDeregister() < 0);
+ assertTrue(phaser.awaitAdvance(1) < 0);
+ assertTrue(phaser.getPhase() < 0);
+ }
+
+ /**
+ * arriveAndDeregister() throws IllegalStateException if number of
+ * registered or unarrived parties would become negative
+ */
+ public void testArriveAndDeregister1() {
+ try {
+ Phaser phaser = new Phaser();
+ phaser.arriveAndDeregister();
+ shouldThrow();
+ } catch (IllegalStateException success) {}
+ }
+
+ /**
+ * arriveAndDeregister reduces the number of arrived parties
+ */
+ public void testArriveAndDeregister2() {
+ final Phaser phaser = new Phaser(1);
+ assertEquals(0, phaser.register());
+ assertEquals(0, phaser.arrive());
+ assertState(phaser, 0, 2, 1);
+ assertEquals(0, phaser.arriveAndDeregister());
+ assertState(phaser, 1, 1, 1);
+ }
+
+ /**
+ * arriveAndDeregister arrives at the barrier on a phaser with a parent and
+ * when a deregistration occurs and causes the phaser to have zero parties
+ * its parent will be deregistered as well
+ */
+ public void testArriveAndDeregister3() {
+ Phaser parent = new Phaser();
+ Phaser child = new Phaser(parent);
+ assertState(child, 0, 0, 0);
+ assertState(parent, 0, 0, 0);
+ assertEquals(0, child.register());
+ assertState(child, 0, 1, 1);
+ assertState(parent, 0, 1, 1);
+ assertEquals(0, child.arriveAndDeregister());
+ assertTerminated(child, 1);
+ assertTerminated(parent, 1);
+ }
+
+ /**
+ * arriveAndDeregister deregisters one party from its parent when
+ * the number of parties of child is zero after deregistration
+ */
+ public void testArriveAndDeregister4() {
+ Phaser parent = new Phaser();
+ Phaser child = new Phaser(parent);
+ assertEquals(0, parent.register());
+ assertEquals(0, child.register());
+ assertState(child, 0, 1, 1);
+ assertState(parent, 0, 2, 2);
+ assertEquals(0, child.arriveAndDeregister());
+ assertState(child, 0, 0, 0);
+ assertState(parent, 0, 1, 1);
+ }
+
+ /**
+ * arriveAndDeregister deregisters one party from its parent when
+ * the number of parties of root is nonzero after deregistration.
+ */
+ public void testArriveAndDeregister5() {
+ Phaser root = new Phaser();
+ Phaser parent = new Phaser(root);
+ Phaser child = new Phaser(parent);
+ assertState(root, 0, 0, 0);
+ assertState(parent, 0, 0, 0);
+ assertState(child, 0, 0, 0);
+ assertEquals(0, child.register());
+ assertState(root, 0, 1, 1);
+ assertState(parent, 0, 1, 1);
+ assertState(child, 0, 1, 1);
+ assertEquals(0, child.arriveAndDeregister());
+ assertTerminated(child, 1);
+ assertTerminated(parent, 1);
+ assertTerminated(root, 1);
+ }
+
+ /**
+ * arriveAndDeregister returns the phase in which it leaves the
+ * phaser in after deregistration
+ */
+ public void testArriveAndDeregister6() {
+ final Phaser phaser = new Phaser(2);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ assertEquals(0, phaser.arrive());
+ }});
+ assertEquals(1, phaser.arriveAndAwaitAdvance());
+ assertState(phaser, 1, 2, 2);
+ assertEquals(1, phaser.arriveAndDeregister());
+ assertState(phaser, 1, 1, 1);
+ assertEquals(1, phaser.arriveAndDeregister());
+ assertTerminated(phaser, 2);
+ awaitTermination(t);
+ }
+
+ /**
+ * awaitAdvance succeeds upon advance
+ */
+ public void testAwaitAdvance1() {
+ final Phaser phaser = new Phaser(1);
+ assertEquals(0, phaser.arrive());
+ assertEquals(1, phaser.awaitAdvance(0));
+ }
+
+ /**
+ * awaitAdvance with a negative parameter will return without affecting the
+ * phaser
+ */
+ public void testAwaitAdvance2() {
+ Phaser phaser = new Phaser();
+ assertTrue(phaser.awaitAdvance(-1) < 0);
+ assertState(phaser, 0, 0, 0);
+ }
+
+ /**
+ * awaitAdvanceInterruptibly blocks interruptibly
+ */
+ public void testAwaitAdvanceInterruptibly_interruptible() throws InterruptedException {
+ final Phaser phaser = new Phaser(1);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(2);
+
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ Thread.currentThread().interrupt();
+ try {
+ phaser.awaitAdvanceInterruptibly(0);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ phaser.awaitAdvanceInterruptibly(0);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws TimeoutException {
+ Thread.currentThread().interrupt();
+ try {
+ phaser.awaitAdvanceInterruptibly(0, 2*LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ phaser.awaitAdvanceInterruptibly(0, 2*LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ assertState(phaser, 0, 1, 1);
+ assertThreadsStayAlive(t1, t2);
+ t1.interrupt();
+ t2.interrupt();
+ awaitTermination(t1);
+ awaitTermination(t2);
+ assertState(phaser, 0, 1, 1);
+ assertEquals(0, phaser.arrive());
+ assertState(phaser, 1, 1, 1);
+ }
+
+ /**
+ * awaitAdvance continues waiting if interrupted before waiting
+ */
+ public void testAwaitAdvanceAfterInterrupt() {
+ final Phaser phaser = new Phaser();
+ assertEquals(0, phaser.register());
+ final CountDownLatch pleaseArrive = new CountDownLatch(1);
+
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ Thread.currentThread().interrupt();
+ assertEquals(0, phaser.register());
+ assertEquals(0, phaser.arrive());
+ pleaseArrive.countDown();
+ assertTrue(Thread.currentThread().isInterrupted());
+ assertEquals(1, phaser.awaitAdvance(0));
+ assertTrue(Thread.interrupted());
+ }});
+
+ await(pleaseArrive);
+ waitForThreadToEnterWaitState(t, SHORT_DELAY_MS);
+ assertEquals(0, phaser.arrive());
+ awaitTermination(t);
+
+ Thread.currentThread().interrupt();
+ assertEquals(1, phaser.awaitAdvance(0));
+ assertTrue(Thread.interrupted());
+ }
+
+ /**
+ * awaitAdvance continues waiting if interrupted while waiting
+ */
+ public void testAwaitAdvanceBeforeInterrupt() {
+ final Phaser phaser = new Phaser();
+ assertEquals(0, phaser.register());
+ final CountDownLatch pleaseArrive = new CountDownLatch(1);
+
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ assertEquals(0, phaser.register());
+ assertEquals(0, phaser.arrive());
+ assertFalse(Thread.currentThread().isInterrupted());
+ pleaseArrive.countDown();
+ assertEquals(1, phaser.awaitAdvance(0));
+ assertTrue(Thread.interrupted());
+ }});
+
+ await(pleaseArrive);
+ waitForThreadToEnterWaitState(t, SHORT_DELAY_MS);
+ t.interrupt();
+ assertEquals(0, phaser.arrive());
+ awaitTermination(t);
+
+ Thread.currentThread().interrupt();
+ assertEquals(1, phaser.awaitAdvance(0));
+ assertTrue(Thread.interrupted());
+ }
+
+ /**
+ * arriveAndAwaitAdvance continues waiting if interrupted before waiting
+ */
+ public void testArriveAndAwaitAdvanceAfterInterrupt() {
+ final Phaser phaser = new Phaser();
+ assertEquals(0, phaser.register());
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ Thread.currentThread().interrupt();
+ assertEquals(0, phaser.register());
+ pleaseInterrupt.countDown();
+ assertTrue(Thread.currentThread().isInterrupted());
+ assertEquals(1, phaser.arriveAndAwaitAdvance());
+ assertTrue(Thread.currentThread().isInterrupted());
+ }});
+
+ await(pleaseInterrupt);
+ waitForThreadToEnterWaitState(t, SHORT_DELAY_MS);
+ Thread.currentThread().interrupt();
+ assertEquals(1, phaser.arriveAndAwaitAdvance());
+ assertTrue(Thread.interrupted());
+ awaitTermination(t);
+ }
+
+ /**
+ * arriveAndAwaitAdvance continues waiting if interrupted while waiting
+ */
+ public void testArriveAndAwaitAdvanceBeforeInterrupt() {
+ final Phaser phaser = new Phaser();
+ assertEquals(0, phaser.register());
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ assertEquals(0, phaser.register());
+ assertFalse(Thread.currentThread().isInterrupted());
+ pleaseInterrupt.countDown();
+ assertEquals(1, phaser.arriveAndAwaitAdvance());
+ assertTrue(Thread.currentThread().isInterrupted());
+ }});
+
+ await(pleaseInterrupt);
+ waitForThreadToEnterWaitState(t, SHORT_DELAY_MS);
+ t.interrupt();
+ Thread.currentThread().interrupt();
+ assertEquals(1, phaser.arriveAndAwaitAdvance());
+ assertTrue(Thread.interrupted());
+ awaitTermination(t);
+ }
+
+ /**
+ * awaitAdvance atomically waits for all parties within the same phase to
+ * complete before continuing
+ */
+ public void testAwaitAdvance4() {
+ final Phaser phaser = new Phaser(4);
+ final AtomicInteger count = new AtomicInteger(0);
+ List<Thread> threads = new ArrayList<Thread>();
+ for (int i = 0; i < 4; i++)
+ threads.add(newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ for (int k = 0; k < 3; k++) {
+ assertEquals(2*k+1, phaser.arriveAndAwaitAdvance());
+ count.incrementAndGet();
+ assertEquals(2*k+1, phaser.arrive());
+ assertEquals(2*k+2, phaser.awaitAdvance(2*k+1));
+ assertEquals(4*(k+1), count.get());
+ }}}));
+
+ for (Thread thread : threads)
+ awaitTermination(thread);
+ }
+
+ /**
+ * awaitAdvance returns the current phase
+ */
+ public void testAwaitAdvance5() {
+ final Phaser phaser = new Phaser(1);
+ assertEquals(1, phaser.awaitAdvance(phaser.arrive()));
+ assertEquals(1, phaser.getPhase());
+ assertEquals(1, phaser.register());
+ List<Thread> threads = new ArrayList<Thread>();
+ for (int i = 0; i < 8; i++) {
+ final CountDownLatch latch = new CountDownLatch(1);
+ final boolean goesFirst = ((i & 1) == 0);
+ threads.add(newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ if (goesFirst)
+ latch.countDown();
+ else
+ await(latch);
+ phaser.arrive();
+ }}));
+ if (goesFirst)
+ await(latch);
+ else
+ latch.countDown();
+ assertEquals(i + 2, phaser.awaitAdvance(phaser.arrive()));
+ assertEquals(i + 2, phaser.getPhase());
+ }
+ for (Thread thread : threads)
+ awaitTermination(thread);
+ }
+
+ /**
+ * awaitAdvance returns the current phase in child phasers
+ */
+ public void testAwaitAdvanceTieredPhaser() throws Exception {
+ final Phaser parent = new Phaser();
+ final List<Phaser> zeroPartyChildren = new ArrayList<Phaser>(3);
+ final List<Phaser> onePartyChildren = new ArrayList<Phaser>(3);
+ for (int i = 0; i < 3; i++) {
+ zeroPartyChildren.add(new Phaser(parent, 0));
+ onePartyChildren.add(new Phaser(parent, 1));
+ }
+ final List<Phaser> phasers = new ArrayList<Phaser>();
+ phasers.addAll(zeroPartyChildren);
+ phasers.addAll(onePartyChildren);
+ phasers.add(parent);
+ for (Phaser phaser : phasers) {
+ assertEquals(-42, phaser.awaitAdvance(-42));
+ assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42));
+ assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42, SMALL_DELAY_MS, MILLISECONDS));
+ }
+
+ for (Phaser child : onePartyChildren)
+ assertEquals(0, child.arrive());
+ for (Phaser phaser : phasers) {
+ assertEquals(-42, phaser.awaitAdvance(-42));
+ assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42));
+ assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42, SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(1, phaser.awaitAdvance(0));
+ assertEquals(1, phaser.awaitAdvanceInterruptibly(0));
+ assertEquals(1, phaser.awaitAdvanceInterruptibly(0, SMALL_DELAY_MS, MILLISECONDS));
+ }
+
+ for (Phaser child : onePartyChildren)
+ assertEquals(1, child.arrive());
+ for (Phaser phaser : phasers) {
+ assertEquals(-42, phaser.awaitAdvance(-42));
+ assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42));
+ assertEquals(-42, phaser.awaitAdvanceInterruptibly(-42, SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(2, phaser.awaitAdvance(0));
+ assertEquals(2, phaser.awaitAdvanceInterruptibly(0));
+ assertEquals(2, phaser.awaitAdvanceInterruptibly(0, SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(2, phaser.awaitAdvance(1));
+ assertEquals(2, phaser.awaitAdvanceInterruptibly(1));
+ assertEquals(2, phaser.awaitAdvanceInterruptibly(1, SMALL_DELAY_MS, MILLISECONDS));
+ }
+ }
+
+ /**
+ * awaitAdvance returns when the phaser is externally terminated
+ */
+ public void testAwaitAdvance6() {
+ final Phaser phaser = new Phaser(3);
+ final CountDownLatch pleaseForceTermination = new CountDownLatch(2);
+ final List<Thread> threads = new ArrayList<Thread>();
+ for (int i = 0; i < 2; i++) {
+ Runnable r = new CheckedRunnable() {
+ public void realRun() {
+ assertEquals(0, phaser.arrive());
+ pleaseForceTermination.countDown();
+ assertTrue(phaser.awaitAdvance(0) < 0);
+ assertTrue(phaser.isTerminated());
+ assertTrue(phaser.getPhase() < 0);
+ assertEquals(0, phaser.getPhase() + Integer.MIN_VALUE);
+ assertEquals(3, phaser.getRegisteredParties());
+ }};
+ threads.add(newStartedThread(r));
+ }
+ await(pleaseForceTermination);
+ phaser.forceTermination();
+ assertTrue(phaser.isTerminated());
+ assertEquals(0, phaser.getPhase() + Integer.MIN_VALUE);
+ for (Thread thread : threads)
+ awaitTermination(thread);
+ assertEquals(3, phaser.getRegisteredParties());
+ }
+
+ /**
+ * arriveAndAwaitAdvance throws IllegalStateException with no
+ * unarrived parties
+ */
+ public void testArriveAndAwaitAdvance1() {
+ try {
+ Phaser phaser = new Phaser();
+ phaser.arriveAndAwaitAdvance();
+ shouldThrow();
+ } catch (IllegalStateException success) {}
+ }
+
+ /**
+ * arriveAndAwaitAdvance waits for all threads to arrive, the
+ * number of arrived parties is the same number that is accounted
+ * for when the main thread awaitsAdvance
+ */
+ public void testArriveAndAwaitAdvance3() {
+ final Phaser phaser = new Phaser(1);
+ final int THREADS = 3;
+ final CountDownLatch pleaseArrive = new CountDownLatch(THREADS);
+ final List<Thread> threads = new ArrayList<Thread>();
+ for (int i = 0; i < THREADS; i++)
+ threads.add(newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ assertEquals(0, phaser.register());
+ pleaseArrive.countDown();
+ assertEquals(1, phaser.arriveAndAwaitAdvance());
+ }}));
+
+ await(pleaseArrive);
+ long startTime = System.nanoTime();
+ while (phaser.getArrivedParties() < THREADS)
+ Thread.yield();
+ assertEquals(THREADS, phaser.getArrivedParties());
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ for (Thread thread : threads)
+ waitForThreadToEnterWaitState(thread, SHORT_DELAY_MS);
+ for (Thread thread : threads)
+ assertTrue(thread.isAlive());
+ assertState(phaser, 0, THREADS + 1, 1);
+ phaser.arriveAndAwaitAdvance();
+ for (Thread thread : threads)
+ awaitTermination(thread);
+ assertState(phaser, 1, THREADS + 1, THREADS + 1);
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/PriorityBlockingQueueTest.java b/jsr166-tests/src/test/java/jsr166/PriorityBlockingQueueTest.java
new file mode 100644
index 0000000..908910b
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/PriorityBlockingQueueTest.java
@@ -0,0 +1,711 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+import java.util.concurrent.PriorityBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+public class PriorityBlockingQueueTest extends JSR166TestCase {
+
+ public static class Generic extends BlockingQueueTest {
+ protected BlockingQueue emptyCollection() {
+ return new PriorityBlockingQueue();
+ }
+ }
+
+ public static class InitialCapacity extends BlockingQueueTest {
+ protected BlockingQueue emptyCollection() {
+ return new PriorityBlockingQueue(SIZE);
+ }
+ }
+
+ private static final int NOCAP = Integer.MAX_VALUE;
+
+ /** Sample Comparator */
+ static class MyReverseComparator implements Comparator {
+ public int compare(Object x, Object y) {
+ return ((Comparable)y).compareTo(x);
+ }
+ }
+
+ /**
+ * Returns a new queue of given size containing consecutive
+ * Integers 0 ... n.
+ */
+ private PriorityBlockingQueue<Integer> populatedQueue(int n) {
+ PriorityBlockingQueue<Integer> q =
+ new PriorityBlockingQueue<Integer>(n);
+ assertTrue(q.isEmpty());
+ for (int i = n-1; i >= 0; i-=2)
+ assertTrue(q.offer(new Integer(i)));
+ for (int i = (n & 1); i < n; i+=2)
+ assertTrue(q.offer(new Integer(i)));
+ assertFalse(q.isEmpty());
+ assertEquals(NOCAP, q.remainingCapacity());
+ assertEquals(n, q.size());
+ return q;
+ }
+
+ /**
+ * A new queue has unbounded capacity
+ */
+ public void testConstructor1() {
+ assertEquals(NOCAP, new PriorityBlockingQueue(SIZE).remainingCapacity());
+ }
+
+ /**
+ * Constructor throws IAE if capacity argument nonpositive
+ */
+ public void testConstructor2() {
+ try {
+ new PriorityBlockingQueue(0);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Initializing from null Collection throws NPE
+ */
+ public void testConstructor3() {
+ try {
+ new PriorityBlockingQueue(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing from Collection of null elements throws NPE
+ */
+ public void testConstructor4() {
+ Collection<Integer> elements = Arrays.asList(new Integer[SIZE]);
+ try {
+ new PriorityBlockingQueue(elements);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing from Collection with some null elements throws NPE
+ */
+ public void testConstructor5() {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = i;
+ Collection<Integer> elements = Arrays.asList(ints);
+ try {
+ new PriorityBlockingQueue(elements);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Queue contains all elements of collection used to initialize
+ */
+ public void testConstructor6() {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = i;
+ PriorityBlockingQueue q = new PriorityBlockingQueue(Arrays.asList(ints));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(ints[i], q.poll());
+ }
+
+ /**
+ * The comparator used in constructor is used
+ */
+ public void testConstructor7() {
+ MyReverseComparator cmp = new MyReverseComparator();
+ PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE, cmp);
+ assertEquals(cmp, q.comparator());
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(i);
+ q.addAll(Arrays.asList(ints));
+ for (int i = SIZE-1; i >= 0; --i)
+ assertEquals(ints[i], q.poll());
+ }
+
+ /**
+ * isEmpty is true before add, false after
+ */
+ public void testEmpty() {
+ PriorityBlockingQueue q = new PriorityBlockingQueue(2);
+ assertTrue(q.isEmpty());
+ assertEquals(NOCAP, q.remainingCapacity());
+ q.add(one);
+ assertFalse(q.isEmpty());
+ q.add(two);
+ q.remove();
+ q.remove();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * remainingCapacity does not change when elements added or removed,
+ * but size does
+ */
+ public void testRemainingCapacity() {
+ PriorityBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(NOCAP, q.remainingCapacity());
+ assertEquals(SIZE-i, q.size());
+ q.remove();
+ }
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(NOCAP, q.remainingCapacity());
+ assertEquals(i, q.size());
+ q.add(new Integer(i));
+ }
+ }
+
+ /**
+ * Offer of comparable element succeeds
+ */
+ public void testOffer() {
+ PriorityBlockingQueue q = new PriorityBlockingQueue(1);
+ assertTrue(q.offer(zero));
+ assertTrue(q.offer(one));
+ }
+
+ /**
+ * Offer of non-Comparable throws CCE
+ */
+ public void testOfferNonComparable() {
+ try {
+ PriorityBlockingQueue q = new PriorityBlockingQueue(1);
+ q.offer(new Object());
+ q.offer(new Object());
+ q.offer(new Object());
+ shouldThrow();
+ } catch (ClassCastException success) {}
+ }
+
+ /**
+ * add of comparable succeeds
+ */
+ public void testAdd() {
+ PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.size());
+ assertTrue(q.add(new Integer(i)));
+ }
+ }
+
+ /**
+ * addAll(this) throws IAE
+ */
+ public void testAddAllSelf() {
+ try {
+ PriorityBlockingQueue q = populatedQueue(SIZE);
+ q.addAll(q);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * addAll of a collection with any null elements throws NPE after
+ * possibly adding some elements
+ */
+ public void testAddAll3() {
+ try {
+ PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE);
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Queue contains all elements of successful addAll
+ */
+ public void testAddAll5() {
+ Integer[] empty = new Integer[0];
+ Integer[] ints = new Integer[SIZE];
+ for (int i = SIZE-1; i >= 0; --i)
+ ints[i] = new Integer(i);
+ PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE);
+ assertFalse(q.addAll(Arrays.asList(empty)));
+ assertTrue(q.addAll(Arrays.asList(ints)));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(ints[i], q.poll());
+ }
+
+ /**
+ * all elements successfully put are contained
+ */
+ public void testPut() {
+ PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ Integer I = new Integer(i);
+ q.put(I);
+ assertTrue(q.contains(I));
+ }
+ assertEquals(SIZE, q.size());
+ }
+
+ /**
+ * put doesn't block waiting for take
+ */
+ public void testPutWithTake() throws InterruptedException {
+ final PriorityBlockingQueue q = new PriorityBlockingQueue(2);
+ final int size = 4;
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ for (int i = 0; i < size; i++)
+ q.put(new Integer(0));
+ }});
+
+ awaitTermination(t);
+ assertEquals(size, q.size());
+ q.take();
+ }
+
+ /**
+ * timed offer does not time out
+ */
+ public void testTimedOffer() throws InterruptedException {
+ final PriorityBlockingQueue q = new PriorityBlockingQueue(2);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ q.put(new Integer(0));
+ q.put(new Integer(0));
+ assertTrue(q.offer(new Integer(0), SHORT_DELAY_MS, MILLISECONDS));
+ assertTrue(q.offer(new Integer(0), LONG_DELAY_MS, MILLISECONDS));
+ }});
+
+ awaitTermination(t);
+ }
+
+ /**
+ * take retrieves elements in priority order
+ */
+ public void testTake() throws InterruptedException {
+ PriorityBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.take());
+ }
+ }
+
+ /**
+ * Take removes existing elements until empty, then blocks interruptibly
+ */
+ public void testBlockingTake() throws InterruptedException {
+ final PriorityBlockingQueue q = populatedQueue(SIZE);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.take());
+ }
+
+ Thread.currentThread().interrupt();
+ try {
+ q.take();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ q.take();
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * poll succeeds unless empty
+ */
+ public void testPoll() {
+ PriorityBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.poll());
+ }
+ assertNull(q.poll());
+ }
+
+ /**
+ * timed poll with zero timeout succeeds when non-empty, else times out
+ */
+ public void testTimedPoll0() throws InterruptedException {
+ PriorityBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.poll(0, MILLISECONDS));
+ }
+ assertNull(q.poll(0, MILLISECONDS));
+ }
+
+ /**
+ * timed poll with nonzero timeout succeeds when non-empty, else times out
+ */
+ public void testTimedPoll() throws InterruptedException {
+ PriorityBlockingQueue<Integer> q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ long startTime = System.nanoTime();
+ assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ }
+ long startTime = System.nanoTime();
+ assertNull(q.poll(timeoutMillis(), MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ checkEmpty(q);
+ }
+
+ /**
+ * Interrupted timed poll throws InterruptedException instead of
+ * returning timeout status
+ */
+ public void testInterruptedTimedPoll() throws InterruptedException {
+ final BlockingQueue<Integer> q = populatedQueue(SIZE);
+ final CountDownLatch aboutToWait = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ for (int i = 0; i < SIZE; ++i) {
+ long t0 = System.nanoTime();
+ assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(t0) < SMALL_DELAY_MS);
+ }
+ long t0 = System.nanoTime();
+ aboutToWait.countDown();
+ try {
+ q.poll(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {
+ assertTrue(millisElapsedSince(t0) < MEDIUM_DELAY_MS);
+ }
+ }});
+
+ aboutToWait.await();
+ waitForThreadToEnterWaitState(t, SMALL_DELAY_MS);
+ t.interrupt();
+ awaitTermination(t, MEDIUM_DELAY_MS);
+ }
+
+ /**
+ * peek returns next element, or null if empty
+ */
+ public void testPeek() {
+ PriorityBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.peek());
+ assertEquals(i, q.poll());
+ assertTrue(q.peek() == null ||
+ !q.peek().equals(i));
+ }
+ assertNull(q.peek());
+ }
+
+ /**
+ * element returns next element, or throws NSEE if empty
+ */
+ public void testElement() {
+ PriorityBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.element());
+ assertEquals(i, q.poll());
+ }
+ try {
+ q.element();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * remove removes next element, or throws NSEE if empty
+ */
+ public void testRemove() {
+ PriorityBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.remove());
+ }
+ try {
+ q.remove();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * contains(x) reports true when elements added but not yet removed
+ */
+ public void testContains() {
+ PriorityBlockingQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.contains(new Integer(i)));
+ q.poll();
+ assertFalse(q.contains(new Integer(i)));
+ }
+ }
+
+ /**
+ * clear removes all elements
+ */
+ public void testClear() {
+ PriorityBlockingQueue q = populatedQueue(SIZE);
+ q.clear();
+ assertTrue(q.isEmpty());
+ assertEquals(0, q.size());
+ q.add(one);
+ assertFalse(q.isEmpty());
+ assertTrue(q.contains(one));
+ q.clear();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * containsAll(c) is true when c contains a subset of elements
+ */
+ public void testContainsAll() {
+ PriorityBlockingQueue q = populatedQueue(SIZE);
+ PriorityBlockingQueue p = new PriorityBlockingQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.containsAll(p));
+ assertFalse(p.containsAll(q));
+ p.add(new Integer(i));
+ }
+ assertTrue(p.containsAll(q));
+ }
+
+ /**
+ * retainAll(c) retains only those elements of c and reports true if changed
+ */
+ public void testRetainAll() {
+ PriorityBlockingQueue q = populatedQueue(SIZE);
+ PriorityBlockingQueue p = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ boolean changed = q.retainAll(p);
+ if (i == 0)
+ assertFalse(changed);
+ else
+ assertTrue(changed);
+
+ assertTrue(q.containsAll(p));
+ assertEquals(SIZE-i, q.size());
+ p.remove();
+ }
+ }
+
+ /**
+ * removeAll(c) removes only those elements of c and reports true if changed
+ */
+ public void testRemoveAll() {
+ for (int i = 1; i < SIZE; ++i) {
+ PriorityBlockingQueue q = populatedQueue(SIZE);
+ PriorityBlockingQueue p = populatedQueue(i);
+ assertTrue(q.removeAll(p));
+ assertEquals(SIZE-i, q.size());
+ for (int j = 0; j < i; ++j) {
+ Integer I = (Integer)(p.remove());
+ assertFalse(q.contains(I));
+ }
+ }
+ }
+
+ /**
+ * toArray contains all elements
+ */
+ public void testToArray() throws InterruptedException {
+ PriorityBlockingQueue q = populatedQueue(SIZE);
+ Object[] o = q.toArray();
+ Arrays.sort(o);
+ for (int i = 0; i < o.length; i++)
+ assertSame(o[i], q.take());
+ }
+
+ /**
+ * toArray(a) contains all elements
+ */
+ public void testToArray2() throws InterruptedException {
+ PriorityBlockingQueue<Integer> q = populatedQueue(SIZE);
+ Integer[] ints = new Integer[SIZE];
+ Integer[] array = q.toArray(ints);
+ assertSame(ints, array);
+ Arrays.sort(ints);
+ for (int i = 0; i < ints.length; i++)
+ assertSame(ints[i], q.take());
+ }
+
+ /**
+ * toArray(incompatible array type) throws ArrayStoreException
+ */
+ public void testToArray1_BadArg() {
+ PriorityBlockingQueue q = populatedQueue(SIZE);
+ try {
+ q.toArray(new String[10]);
+ shouldThrow();
+ } catch (ArrayStoreException success) {}
+ }
+
+ /**
+ * iterator iterates through all elements
+ */
+ public void testIterator() {
+ PriorityBlockingQueue q = populatedQueue(SIZE);
+ int i = 0;
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ assertTrue(q.contains(it.next()));
+ ++i;
+ }
+ assertEquals(i, SIZE);
+ }
+
+ /**
+ * iterator.remove removes current element
+ */
+ public void testIteratorRemove() {
+ final PriorityBlockingQueue q = new PriorityBlockingQueue(3);
+ q.add(new Integer(2));
+ q.add(new Integer(1));
+ q.add(new Integer(3));
+
+ Iterator it = q.iterator();
+ it.next();
+ it.remove();
+
+ it = q.iterator();
+ assertEquals(it.next(), new Integer(2));
+ assertEquals(it.next(), new Integer(3));
+ assertFalse(it.hasNext());
+ }
+
+ /**
+ * toString contains toStrings of elements
+ */
+ public void testToString() {
+ PriorityBlockingQueue q = populatedQueue(SIZE);
+ String s = q.toString();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(s.contains(String.valueOf(i)));
+ }
+ }
+
+ /**
+ * timed poll transfers elements across Executor tasks
+ */
+ public void testPollInExecutor() {
+ final PriorityBlockingQueue q = new PriorityBlockingQueue(2);
+ final CheckedBarrier threadsStarted = new CheckedBarrier(2);
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertNull(q.poll());
+ threadsStarted.await();
+ assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS));
+ checkEmpty(q);
+ }});
+
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ q.put(one);
+ }});
+
+ joinPool(executor);
+ }
+
+ /**
+ * A deserialized serialized queue has same elements
+ */
+ public void testSerialization() throws Exception {
+ Queue x = populatedQueue(SIZE);
+ Queue y = serialClone(x);
+
+ assertNotSame(x, y);
+ assertEquals(x.size(), y.size());
+ while (!x.isEmpty()) {
+ assertFalse(y.isEmpty());
+ assertEquals(x.remove(), y.remove());
+ }
+ assertTrue(y.isEmpty());
+ }
+
+ /**
+ * drainTo(c) empties queue into another collection c
+ */
+ public void testDrainTo() {
+ PriorityBlockingQueue q = populatedQueue(SIZE);
+ ArrayList l = new ArrayList();
+ q.drainTo(l);
+ assertEquals(0, q.size());
+ assertEquals(SIZE, l.size());
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(l.get(i), new Integer(i));
+ q.add(zero);
+ q.add(one);
+ assertFalse(q.isEmpty());
+ assertTrue(q.contains(zero));
+ assertTrue(q.contains(one));
+ l.clear();
+ q.drainTo(l);
+ assertEquals(0, q.size());
+ assertEquals(2, l.size());
+ for (int i = 0; i < 2; ++i)
+ assertEquals(l.get(i), new Integer(i));
+ }
+
+ /**
+ * drainTo empties queue
+ */
+ public void testDrainToWithActivePut() throws InterruptedException {
+ final PriorityBlockingQueue q = populatedQueue(SIZE);
+ Thread t = new Thread(new CheckedRunnable() {
+ public void realRun() {
+ q.put(new Integer(SIZE+1));
+ }});
+
+ t.start();
+ ArrayList l = new ArrayList();
+ q.drainTo(l);
+ assertTrue(l.size() >= SIZE);
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(l.get(i), new Integer(i));
+ t.join();
+ assertTrue(q.size() + l.size() >= SIZE);
+ }
+
+ /**
+ * drainTo(c, n) empties first min(n, size) elements of queue into c
+ */
+ public void testDrainToN() {
+ PriorityBlockingQueue q = new PriorityBlockingQueue(SIZE*2);
+ for (int i = 0; i < SIZE + 2; ++i) {
+ for (int j = 0; j < SIZE; j++)
+ assertTrue(q.offer(new Integer(j)));
+ ArrayList l = new ArrayList();
+ q.drainTo(l, i);
+ int k = (i < SIZE) ? i : SIZE;
+ assertEquals(k, l.size());
+ assertEquals(SIZE-k, q.size());
+ for (int j = 0; j < k; ++j)
+ assertEquals(l.get(j), new Integer(j));
+ while (q.poll() != null) ;
+ }
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/PriorityQueueTest.java b/jsr166-tests/src/test/java/jsr166/PriorityQueueTest.java
new file mode 100644
index 0000000..2b237dd
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/PriorityQueueTest.java
@@ -0,0 +1,492 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.PriorityQueue;
+import java.util.Queue;
+
+public class PriorityQueueTest extends JSR166TestCase {
+
+ static class MyReverseComparator implements Comparator {
+ public int compare(Object x, Object y) {
+ return ((Comparable)y).compareTo(x);
+ }
+ }
+
+ /**
+ * Returns a new queue of given size containing consecutive
+ * Integers 0 ... n.
+ */
+ private PriorityQueue<Integer> populatedQueue(int n) {
+ PriorityQueue<Integer> q = new PriorityQueue<Integer>(n);
+ assertTrue(q.isEmpty());
+ for (int i = n-1; i >= 0; i-=2)
+ assertTrue(q.offer(new Integer(i)));
+ for (int i = (n & 1); i < n; i+=2)
+ assertTrue(q.offer(new Integer(i)));
+ assertFalse(q.isEmpty());
+ assertEquals(n, q.size());
+ return q;
+ }
+
+ /**
+ * A new queue has unbounded capacity
+ */
+ public void testConstructor1() {
+ assertEquals(0, new PriorityQueue(SIZE).size());
+ }
+
+ /**
+ * Constructor throws IAE if capacity argument nonpositive
+ */
+ public void testConstructor2() {
+ try {
+ PriorityQueue q = new PriorityQueue(0);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Initializing from null Collection throws NPE
+ */
+ public void testConstructor3() {
+ try {
+ PriorityQueue q = new PriorityQueue((Collection)null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing from Collection of null elements throws NPE
+ */
+ public void testConstructor4() {
+ try {
+ Integer[] ints = new Integer[SIZE];
+ PriorityQueue q = new PriorityQueue(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing from Collection with some null elements throws NPE
+ */
+ public void testConstructor5() {
+ try {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
+ PriorityQueue q = new PriorityQueue(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Queue contains all elements of collection used to initialize
+ */
+ public void testConstructor6() {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(i);
+ PriorityQueue q = new PriorityQueue(Arrays.asList(ints));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(ints[i], q.poll());
+ }
+
+ /**
+ * The comparator used in constructor is used
+ */
+ public void testConstructor7() {
+ MyReverseComparator cmp = new MyReverseComparator();
+ PriorityQueue q = new PriorityQueue(SIZE, cmp);
+ assertEquals(cmp, q.comparator());
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(i);
+ q.addAll(Arrays.asList(ints));
+ for (int i = SIZE-1; i >= 0; --i)
+ assertEquals(ints[i], q.poll());
+ }
+
+ /**
+ * isEmpty is true before add, false after
+ */
+ public void testEmpty() {
+ PriorityQueue q = new PriorityQueue(2);
+ assertTrue(q.isEmpty());
+ q.add(new Integer(1));
+ assertFalse(q.isEmpty());
+ q.add(new Integer(2));
+ q.remove();
+ q.remove();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * size changes when elements added and removed
+ */
+ public void testSize() {
+ PriorityQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(SIZE-i, q.size());
+ q.remove();
+ }
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.size());
+ q.add(new Integer(i));
+ }
+ }
+
+ /**
+ * offer(null) throws NPE
+ */
+ public void testOfferNull() {
+ try {
+ PriorityQueue q = new PriorityQueue(1);
+ q.offer(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * add(null) throws NPE
+ */
+ public void testAddNull() {
+ try {
+ PriorityQueue q = new PriorityQueue(1);
+ q.add(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Offer of comparable element succeeds
+ */
+ public void testOffer() {
+ PriorityQueue q = new PriorityQueue(1);
+ assertTrue(q.offer(zero));
+ assertTrue(q.offer(one));
+ }
+
+ /**
+ * Offer of non-Comparable throws CCE
+ */
+ public void testOfferNonComparable() {
+ try {
+ PriorityQueue q = new PriorityQueue(1);
+ q.offer(new Object());
+ q.offer(new Object());
+ q.offer(new Object());
+ shouldThrow();
+ } catch (ClassCastException success) {}
+ }
+
+ /**
+ * add of comparable succeeds
+ */
+ public void testAdd() {
+ PriorityQueue q = new PriorityQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.size());
+ assertTrue(q.add(new Integer(i)));
+ }
+ }
+
+ /**
+ * addAll(null) throws NPE
+ */
+ public void testAddAll1() {
+ try {
+ PriorityQueue q = new PriorityQueue(1);
+ q.addAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll of a collection with null elements throws NPE
+ */
+ public void testAddAll2() {
+ try {
+ PriorityQueue q = new PriorityQueue(SIZE);
+ Integer[] ints = new Integer[SIZE];
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll of a collection with any null elements throws NPE after
+ * possibly adding some elements
+ */
+ public void testAddAll3() {
+ try {
+ PriorityQueue q = new PriorityQueue(SIZE);
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Queue contains all elements of successful addAll
+ */
+ public void testAddAll5() {
+ Integer[] empty = new Integer[0];
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(SIZE-1-i);
+ PriorityQueue q = new PriorityQueue(SIZE);
+ assertFalse(q.addAll(Arrays.asList(empty)));
+ assertTrue(q.addAll(Arrays.asList(ints)));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(new Integer(i), q.poll());
+ }
+
+ /**
+ * poll succeeds unless empty
+ */
+ public void testPoll() {
+ PriorityQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.poll());
+ }
+ assertNull(q.poll());
+ }
+
+ /**
+ * peek returns next element, or null if empty
+ */
+ public void testPeek() {
+ PriorityQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.peek());
+ assertEquals(i, q.poll());
+ assertTrue(q.peek() == null ||
+ !q.peek().equals(i));
+ }
+ assertNull(q.peek());
+ }
+
+ /**
+ * element returns next element, or throws NSEE if empty
+ */
+ public void testElement() {
+ PriorityQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.element());
+ assertEquals(i, q.poll());
+ }
+ try {
+ q.element();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * remove removes next element, or throws NSEE if empty
+ */
+ public void testRemove() {
+ PriorityQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.remove());
+ }
+ try {
+ q.remove();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * remove(x) removes x and returns true if present
+ */
+ public void testRemoveElement() {
+ PriorityQueue q = populatedQueue(SIZE);
+ for (int i = 1; i < SIZE; i+=2) {
+ assertTrue(q.contains(i));
+ assertTrue(q.remove(i));
+ assertFalse(q.contains(i));
+ assertTrue(q.contains(i-1));
+ }
+ for (int i = 0; i < SIZE; i+=2) {
+ assertTrue(q.contains(i));
+ assertTrue(q.remove(i));
+ assertFalse(q.contains(i));
+ assertFalse(q.remove(i+1));
+ assertFalse(q.contains(i+1));
+ }
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * contains(x) reports true when elements added but not yet removed
+ */
+ public void testContains() {
+ PriorityQueue q = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.contains(new Integer(i)));
+ q.poll();
+ assertFalse(q.contains(new Integer(i)));
+ }
+ }
+
+ /**
+ * clear removes all elements
+ */
+ public void testClear() {
+ PriorityQueue q = populatedQueue(SIZE);
+ q.clear();
+ assertTrue(q.isEmpty());
+ assertEquals(0, q.size());
+ q.add(new Integer(1));
+ assertFalse(q.isEmpty());
+ q.clear();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * containsAll(c) is true when c contains a subset of elements
+ */
+ public void testContainsAll() {
+ PriorityQueue q = populatedQueue(SIZE);
+ PriorityQueue p = new PriorityQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.containsAll(p));
+ assertFalse(p.containsAll(q));
+ p.add(new Integer(i));
+ }
+ assertTrue(p.containsAll(q));
+ }
+
+ /**
+ * retainAll(c) retains only those elements of c and reports true if changed
+ */
+ public void testRetainAll() {
+ PriorityQueue q = populatedQueue(SIZE);
+ PriorityQueue p = populatedQueue(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ boolean changed = q.retainAll(p);
+ if (i == 0)
+ assertFalse(changed);
+ else
+ assertTrue(changed);
+
+ assertTrue(q.containsAll(p));
+ assertEquals(SIZE-i, q.size());
+ p.remove();
+ }
+ }
+
+ /**
+ * removeAll(c) removes only those elements of c and reports true if changed
+ */
+ public void testRemoveAll() {
+ for (int i = 1; i < SIZE; ++i) {
+ PriorityQueue q = populatedQueue(SIZE);
+ PriorityQueue p = populatedQueue(i);
+ assertTrue(q.removeAll(p));
+ assertEquals(SIZE-i, q.size());
+ for (int j = 0; j < i; ++j) {
+ Integer I = (Integer)(p.remove());
+ assertFalse(q.contains(I));
+ }
+ }
+ }
+
+ /**
+ * toArray contains all elements
+ */
+ public void testToArray() {
+ PriorityQueue q = populatedQueue(SIZE);
+ Object[] o = q.toArray();
+ Arrays.sort(o);
+ for (int i = 0; i < o.length; i++)
+ assertSame(o[i], q.poll());
+ }
+
+ /**
+ * toArray(a) contains all elements
+ */
+ public void testToArray2() {
+ PriorityQueue<Integer> q = populatedQueue(SIZE);
+ Integer[] ints = new Integer[SIZE];
+ Integer[] array = q.toArray(ints);
+ assertSame(ints, array);
+ Arrays.sort(ints);
+ for (int i = 0; i < ints.length; i++)
+ assertSame(ints[i], q.poll());
+ }
+
+ /**
+ * iterator iterates through all elements
+ */
+ public void testIterator() {
+ PriorityQueue q = populatedQueue(SIZE);
+ int i = 0;
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ assertTrue(q.contains(it.next()));
+ ++i;
+ }
+ assertEquals(i, SIZE);
+ }
+
+ /**
+ * iterator.remove removes current element
+ */
+ public void testIteratorRemove() {
+ final PriorityQueue q = new PriorityQueue(3);
+ q.add(new Integer(2));
+ q.add(new Integer(1));
+ q.add(new Integer(3));
+
+ Iterator it = q.iterator();
+ it.next();
+ it.remove();
+
+ it = q.iterator();
+ assertEquals(it.next(), new Integer(2));
+ assertEquals(it.next(), new Integer(3));
+ assertFalse(it.hasNext());
+ }
+
+ /**
+ * toString contains toStrings of elements
+ */
+ public void testToString() {
+ PriorityQueue q = populatedQueue(SIZE);
+ String s = q.toString();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(s.contains(String.valueOf(i)));
+ }
+ }
+
+ /**
+ * A deserialized serialized queue has same elements
+ */
+ public void testSerialization() throws Exception {
+ Queue x = populatedQueue(SIZE);
+ Queue y = serialClone(x);
+
+ assertNotSame(x, y);
+ assertEquals(x.size(), y.size());
+ while (!x.isEmpty()) {
+ assertFalse(y.isEmpty());
+ assertEquals(x.remove(), y.remove());
+ }
+ assertTrue(y.isEmpty());
+ }
+}
diff --git a/jsr166-tests/src/test/java/jsr166/RecursiveActionTest.java b/jsr166-tests/src/test/java/jsr166/RecursiveActionTest.java
new file mode 100644
index 0000000..ad61a2e
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/RecursiveActionTest.java
@@ -0,0 +1,1237 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.ForkJoinTask;
+import java.util.concurrent.ForkJoinWorkerThread;
+import java.util.concurrent.RecursiveAction;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import java.util.Arrays;
+import java.util.HashSet;
+
+public class RecursiveActionTest extends JSR166TestCase {
+
+ private static ForkJoinPool mainPool() {
+ return new ForkJoinPool();
+ }
+
+ private static ForkJoinPool singletonPool() {
+ return new ForkJoinPool(1);
+ }
+
+ private static ForkJoinPool asyncSingletonPool() {
+ return new ForkJoinPool(1,
+ ForkJoinPool.defaultForkJoinWorkerThreadFactory,
+ null, true);
+ }
+
+ private void testInvokeOnPool(ForkJoinPool pool, RecursiveAction a) {
+ try {
+ checkNotDone(a);
+
+ assertNull(pool.invoke(a));
+
+ checkCompletedNormally(a);
+ } finally {
+ joinPool(pool);
+ }
+ }
+
+ void checkNotDone(RecursiveAction a) {
+ assertFalse(a.isDone());
+ assertFalse(a.isCompletedNormally());
+ assertFalse(a.isCompletedAbnormally());
+ assertFalse(a.isCancelled());
+ assertNull(a.getException());
+ assertNull(a.getRawResult());
+
+ if (! ForkJoinTask.inForkJoinPool()) {
+ Thread.currentThread().interrupt();
+ try {
+ a.get();
+ shouldThrow();
+ } catch (InterruptedException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+
+ Thread.currentThread().interrupt();
+ try {
+ a.get(5L, SECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ try {
+ a.get(0L, SECONDS);
+ shouldThrow();
+ } catch (TimeoutException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ void checkCompletedNormally(RecursiveAction a) {
+ assertTrue(a.isDone());
+ assertFalse(a.isCancelled());
+ assertTrue(a.isCompletedNormally());
+ assertFalse(a.isCompletedAbnormally());
+ assertNull(a.getException());
+ assertNull(a.getRawResult());
+ assertNull(a.join());
+ assertFalse(a.cancel(false));
+ assertFalse(a.cancel(true));
+ try {
+ assertNull(a.get());
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ try {
+ assertNull(a.get(5L, SECONDS));
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ void checkCancelled(RecursiveAction a) {
+ assertTrue(a.isDone());
+ assertTrue(a.isCancelled());
+ assertFalse(a.isCompletedNormally());
+ assertTrue(a.isCompletedAbnormally());
+ assertTrue(a.getException() instanceof CancellationException);
+ assertNull(a.getRawResult());
+
+ try {
+ a.join();
+ shouldThrow();
+ } catch (CancellationException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+
+ try {
+ a.get();
+ shouldThrow();
+ } catch (CancellationException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+
+ try {
+ a.get(5L, SECONDS);
+ shouldThrow();
+ } catch (CancellationException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ void checkCompletedAbnormally(RecursiveAction a, Throwable t) {
+ assertTrue(a.isDone());
+ assertFalse(a.isCancelled());
+ assertFalse(a.isCompletedNormally());
+ assertTrue(a.isCompletedAbnormally());
+ assertSame(t.getClass(), a.getException().getClass());
+ assertNull(a.getRawResult());
+ assertFalse(a.cancel(false));
+ assertFalse(a.cancel(true));
+
+ try {
+ a.join();
+ shouldThrow();
+ } catch (Throwable expected) {
+ assertSame(expected.getClass(), t.getClass());
+ }
+
+ try {
+ a.get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertSame(t.getClass(), success.getCause().getClass());
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+
+ try {
+ a.get(5L, SECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertSame(t.getClass(), success.getCause().getClass());
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ public static final class FJException extends RuntimeException {
+ public FJException() { super(); }
+ public FJException(Throwable cause) { super(cause); }
+ }
+
+ // A simple recursive action for testing
+ final class FibAction extends CheckedRecursiveAction {
+ final int number;
+ int result;
+ FibAction(int n) { number = n; }
+ protected void realCompute() {
+ int n = number;
+ if (n <= 1)
+ result = n;
+ else {
+ FibAction f1 = new FibAction(n - 1);
+ FibAction f2 = new FibAction(n - 2);
+ invokeAll(f1, f2);
+ result = f1.result + f2.result;
+ }
+ }
+ }
+
+ // A recursive action failing in base case
+ static final class FailingFibAction extends RecursiveAction {
+ final int number;
+ int result;
+ FailingFibAction(int n) { number = n; }
+ public void compute() {
+ int n = number;
+ if (n <= 1)
+ throw new FJException();
+ else {
+ FailingFibAction f1 = new FailingFibAction(n - 1);
+ FailingFibAction f2 = new FailingFibAction(n - 2);
+ invokeAll(f1, f2);
+ result = f1.result + f2.result;
+ }
+ }
+ }
+
+ /**
+ * invoke returns when task completes normally.
+ * isCompletedAbnormally and isCancelled return false for normally
+ * completed tasks. getRawResult of a RecursiveAction returns null;
+ */
+ public void testInvoke() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ assertNull(f.invoke());
+ assertEquals(21, f.result);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * quietlyInvoke task returns when task completes normally.
+ * isCompletedAbnormally and isCancelled return false for normally
+ * completed tasks
+ */
+ public void testQuietlyInvoke() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ f.quietlyInvoke();
+ assertEquals(21, f.result);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * join of a forked task returns when task completes
+ */
+ public void testForkJoin() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ assertNull(f.join());
+ assertEquals(21, f.result);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * join/quietlyJoin of a forked task succeeds in the presence of interrupts
+ */
+ public void testJoinIgnoresInterrupts() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ final Thread myself = Thread.currentThread();
+
+ // test join()
+ assertSame(f, f.fork());
+ myself.interrupt();
+ assertTrue(myself.isInterrupted());
+ assertNull(f.join());
+ Thread.interrupted();
+ assertEquals(21, f.result);
+ checkCompletedNormally(f);
+
+ f = new FibAction(8);
+ f.cancel(true);
+ assertSame(f, f.fork());
+ myself.interrupt();
+ assertTrue(myself.isInterrupted());
+ try {
+ f.join();
+ shouldThrow();
+ } catch (CancellationException success) {
+ Thread.interrupted();
+ checkCancelled(f);
+ }
+
+ f = new FibAction(8);
+ f.completeExceptionally(new FJException());
+ assertSame(f, f.fork());
+ myself.interrupt();
+ assertTrue(myself.isInterrupted());
+ try {
+ f.join();
+ shouldThrow();
+ } catch (FJException success) {
+ Thread.interrupted();
+ checkCompletedAbnormally(f, success);
+ }
+
+ // test quietlyJoin()
+ f = new FibAction(8);
+ assertSame(f, f.fork());
+ myself.interrupt();
+ assertTrue(myself.isInterrupted());
+ f.quietlyJoin();
+ Thread.interrupted();
+ assertEquals(21, f.result);
+ checkCompletedNormally(f);
+
+ f = new FibAction(8);
+ f.cancel(true);
+ assertSame(f, f.fork());
+ myself.interrupt();
+ assertTrue(myself.isInterrupted());
+ f.quietlyJoin();
+ Thread.interrupted();
+ checkCancelled(f);
+
+ f = new FibAction(8);
+ f.completeExceptionally(new FJException());
+ assertSame(f, f.fork());
+ myself.interrupt();
+ assertTrue(myself.isInterrupted());
+ f.quietlyJoin();
+ Thread.interrupted();
+ checkCompletedAbnormally(f, f.getException());
+ }};
+ testInvokeOnPool(mainPool(), a);
+ a.reinitialize();
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * join/quietlyJoin of a forked task when not in ForkJoinPool
+ * succeeds in the presence of interrupts
+ */
+ public void testJoinIgnoresInterruptsOutsideForkJoinPool() {
+ final SynchronousQueue<FibAction[]> sq =
+ new SynchronousQueue<FibAction[]>();
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws InterruptedException {
+ FibAction[] fibActions = new FibAction[6];
+ for (int i = 0; i < fibActions.length; i++)
+ fibActions[i] = new FibAction(8);
+
+ fibActions[1].cancel(false);
+ fibActions[2].completeExceptionally(new FJException());
+ fibActions[4].cancel(true);
+ fibActions[5].completeExceptionally(new FJException());
+
+ for (int i = 0; i < fibActions.length; i++)
+ fibActions[i].fork();
+
+ sq.put(fibActions);
+
+ helpQuiesce();
+ }};
+
+ Runnable r = new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ FibAction[] fibActions = sq.take();
+ FibAction f;
+ final Thread myself = Thread.currentThread();
+
+ // test join() ------------
+
+ f = fibActions[0];
+ assertFalse(ForkJoinTask.inForkJoinPool());
+ myself.interrupt();
+ assertTrue(myself.isInterrupted());
+ assertNull(f.join());
+ assertTrue(Thread.interrupted());
+ assertEquals(21, f.result);
+ checkCompletedNormally(f);
+
+ f = fibActions[1];
+ myself.interrupt();
+ assertTrue(myself.isInterrupted());
+ try {
+ f.join();
+ shouldThrow();
+ } catch (CancellationException success) {
+ assertTrue(Thread.interrupted());
+ checkCancelled(f);
+ }
+
+ f = fibActions[2];
+ myself.interrupt();
+ assertTrue(myself.isInterrupted());
+ try {
+ f.join();
+ shouldThrow();
+ } catch (FJException success) {
+ assertTrue(Thread.interrupted());
+ checkCompletedAbnormally(f, success);
+ }
+
+ // test quietlyJoin() ---------
+
+ f = fibActions[3];
+ myself.interrupt();
+ assertTrue(myself.isInterrupted());
+ f.quietlyJoin();
+ assertTrue(Thread.interrupted());
+ assertEquals(21, f.result);
+ checkCompletedNormally(f);
+
+ f = fibActions[4];
+ myself.interrupt();
+ assertTrue(myself.isInterrupted());
+ f.quietlyJoin();
+ assertTrue(Thread.interrupted());
+ checkCancelled(f);
+
+ f = fibActions[5];
+ myself.interrupt();
+ assertTrue(myself.isInterrupted());
+ f.quietlyJoin();
+ assertTrue(Thread.interrupted());
+ assertTrue(f.getException() instanceof FJException);
+ checkCompletedAbnormally(f, f.getException());
+ }};
+
+ Thread t;
+
+ t = newStartedThread(r);
+ testInvokeOnPool(mainPool(), a);
+ awaitTermination(t, LONG_DELAY_MS);
+
+ a.reinitialize();
+ t = newStartedThread(r);
+ testInvokeOnPool(singletonPool(), a);
+ awaitTermination(t, LONG_DELAY_MS);
+ }
+
+ /**
+ * get of a forked task returns when task completes
+ */
+ public void testForkGet() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ assertNull(f.get());
+ assertEquals(21, f.result);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * timed get of a forked task returns when task completes
+ */
+ public void testForkTimedGet() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ assertNull(f.get(5L, SECONDS));
+ assertEquals(21, f.result);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * timed get with null time unit throws NPE
+ */
+ public void testForkTimedGetNPE() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ try {
+ f.get(5L, null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * quietlyJoin of a forked task returns when task completes
+ */
+ public void testForkQuietlyJoin() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ f.quietlyJoin();
+ assertEquals(21, f.result);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * helpQuiesce returns when tasks are complete.
+ * getQueuedTaskCount returns 0 when quiescent
+ */
+ public void testForkHelpQuiesce() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ helpQuiesce();
+ assertEquals(21, f.result);
+ assertEquals(0, getQueuedTaskCount());
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invoke task throws exception when task completes abnormally
+ */
+ public void testAbnormalInvoke() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingFibAction f = new FailingFibAction(8);
+ try {
+ f.invoke();
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * quietlyInvoke task returns when task completes abnormally
+ */
+ public void testAbnormalQuietlyInvoke() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingFibAction f = new FailingFibAction(8);
+ f.quietlyInvoke();
+ assertTrue(f.getException() instanceof FJException);
+ checkCompletedAbnormally(f, f.getException());
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * join of a forked task throws exception when task completes abnormally
+ */
+ public void testAbnormalForkJoin() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingFibAction f = new FailingFibAction(8);
+ assertSame(f, f.fork());
+ try {
+ f.join();
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * get of a forked task throws exception when task completes abnormally
+ */
+ public void testAbnormalForkGet() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ FailingFibAction f = new FailingFibAction(8);
+ assertSame(f, f.fork());
+ try {
+ f.get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ Throwable cause = success.getCause();
+ assertTrue(cause instanceof FJException);
+ checkCompletedAbnormally(f, cause);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * timed get of a forked task throws exception when task completes abnormally
+ */
+ public void testAbnormalForkTimedGet() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ FailingFibAction f = new FailingFibAction(8);
+ assertSame(f, f.fork());
+ try {
+ f.get(5L, TimeUnit.SECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ Throwable cause = success.getCause();
+ assertTrue(cause instanceof FJException);
+ checkCompletedAbnormally(f, cause);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * quietlyJoin of a forked task returns when task completes abnormally
+ */
+ public void testAbnormalForkQuietlyJoin() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingFibAction f = new FailingFibAction(8);
+ assertSame(f, f.fork());
+ f.quietlyJoin();
+ assertTrue(f.getException() instanceof FJException);
+ checkCompletedAbnormally(f, f.getException());
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invoke task throws exception when task cancelled
+ */
+ public void testCancelledInvoke() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ assertTrue(f.cancel(true));
+ try {
+ f.invoke();
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * join of a forked task throws exception when task cancelled
+ */
+ public void testCancelledForkJoin() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ try {
+ f.join();
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * get of a forked task throws exception when task cancelled
+ */
+ public void testCancelledForkGet() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ FibAction f = new FibAction(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ try {
+ f.get();
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * timed get of a forked task throws exception when task cancelled
+ */
+ public void testCancelledForkTimedGet() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() throws Exception {
+ FibAction f = new FibAction(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ try {
+ f.get(5L, SECONDS);
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * quietlyJoin of a forked task returns when task cancelled
+ */
+ public void testCancelledForkQuietlyJoin() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ f.quietlyJoin();
+ checkCancelled(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * getPool of executing task returns its pool
+ */
+ public void testGetPool() {
+ final ForkJoinPool mainPool = mainPool();
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ assertSame(mainPool, getPool());
+ }};
+ testInvokeOnPool(mainPool, a);
+ }
+
+ /**
+ * getPool of non-FJ task returns null
+ */
+ public void testGetPool2() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ assertNull(getPool());
+ }};
+ assertNull(a.invoke());
+ }
+
+ /**
+ * inForkJoinPool of executing task returns true
+ */
+ public void testInForkJoinPool() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ assertTrue(inForkJoinPool());
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * inForkJoinPool of non-FJ task returns false
+ */
+ public void testInForkJoinPool2() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ assertFalse(inForkJoinPool());
+ }};
+ assertNull(a.invoke());
+ }
+
+ /**
+ * getPool of current thread in pool returns its pool
+ */
+ public void testWorkerGetPool() {
+ final ForkJoinPool mainPool = mainPool();
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ ForkJoinWorkerThread w =
+ (ForkJoinWorkerThread) Thread.currentThread();
+ assertSame(mainPool, w.getPool());
+ }};
+ testInvokeOnPool(mainPool, a);
+ }
+
+ /**
+ * getPoolIndex of current thread in pool returns 0 <= value < poolSize
+ */
+ public void testWorkerGetPoolIndex() {
+ final ForkJoinPool mainPool = mainPool();
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ ForkJoinWorkerThread w =
+ (ForkJoinWorkerThread) Thread.currentThread();
+ assertTrue(w.getPoolIndex() >= 0);
+ // pool size can shrink after assigning index, so cannot check
+ // assertTrue(w.getPoolIndex() < mainPool.getPoolSize());
+ }};
+ testInvokeOnPool(mainPool, a);
+ }
+
+ /**
+ * setRawResult(null) succeeds
+ */
+ public void testSetRawResult() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ setRawResult(null);
+ assertNull(getRawResult());
+ }};
+ assertNull(a.invoke());
+ }
+
+ /**
+ * A reinitialized normally completed task may be re-invoked
+ */
+ public void testReinitialize() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ checkNotDone(f);
+
+ for (int i = 0; i < 3; i++) {
+ assertNull(f.invoke());
+ assertEquals(21, f.result);
+ checkCompletedNormally(f);
+ f.reinitialize();
+ checkNotDone(f);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * A reinitialized abnormally completed task may be re-invoked
+ */
+ public void testReinitializeAbnormal() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingFibAction f = new FailingFibAction(8);
+ checkNotDone(f);
+
+ for (int i = 0; i < 3; i++) {
+ try {
+ f.invoke();
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ f.reinitialize();
+ checkNotDone(f);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invoke task throws exception after invoking completeExceptionally
+ */
+ public void testCompleteExceptionally() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ f.completeExceptionally(new FJException());
+ try {
+ f.invoke();
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invoke task suppresses execution invoking complete
+ */
+ public void testComplete() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ f.complete(null);
+ assertNull(f.invoke());
+ assertEquals(0, f.result);
+ checkCompletedNormally(f);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(t1, t2) invokes all task arguments
+ */
+ public void testInvokeAll2() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ FibAction g = new FibAction(9);
+ invokeAll(f, g);
+ checkCompletedNormally(f);
+ assertEquals(21, f.result);
+ checkCompletedNormally(g);
+ assertEquals(34, g.result);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with 1 argument invokes task
+ */
+ public void testInvokeAll1() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ invokeAll(f);
+ checkCompletedNormally(f);
+ assertEquals(21, f.result);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with > 2 argument invokes tasks
+ */
+ public void testInvokeAll3() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ FibAction g = new FibAction(9);
+ FibAction h = new FibAction(7);
+ invokeAll(f, g, h);
+ assertTrue(f.isDone());
+ assertTrue(g.isDone());
+ assertTrue(h.isDone());
+ checkCompletedNormally(f);
+ assertEquals(21, f.result);
+ checkCompletedNormally(g);
+ assertEquals(34, g.result);
+ checkCompletedNormally(g);
+ assertEquals(13, h.result);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(collection) invokes all tasks in the collection
+ */
+ public void testInvokeAllCollection() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ FibAction g = new FibAction(9);
+ FibAction h = new FibAction(7);
+ HashSet set = new HashSet();
+ set.add(f);
+ set.add(g);
+ set.add(h);
+ invokeAll(set);
+ assertTrue(f.isDone());
+ assertTrue(g.isDone());
+ assertTrue(h.isDone());
+ checkCompletedNormally(f);
+ assertEquals(21, f.result);
+ checkCompletedNormally(g);
+ assertEquals(34, g.result);
+ checkCompletedNormally(g);
+ assertEquals(13, h.result);
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with any null task throws NPE
+ */
+ public void testInvokeAllNPE() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ FibAction g = new FibAction(9);
+ FibAction h = null;
+ try {
+ invokeAll(f, g, h);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(t1, t2) throw exception if any task does
+ */
+ public void testAbnormalInvokeAll2() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ FailingFibAction g = new FailingFibAction(9);
+ try {
+ invokeAll(f, g);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(g, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with 1 argument throws exception if task does
+ */
+ public void testAbnormalInvokeAll1() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingFibAction g = new FailingFibAction(9);
+ try {
+ invokeAll(g);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(g, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(tasks) with > 2 argument throws exception if any task does
+ */
+ public void testAbnormalInvokeAll3() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction f = new FibAction(8);
+ FailingFibAction g = new FailingFibAction(9);
+ FibAction h = new FibAction(7);
+ try {
+ invokeAll(f, g, h);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(g, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * invokeAll(collection) throws exception if any task does
+ */
+ public void testAbnormalInvokeAllCollection() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FailingFibAction f = new FailingFibAction(8);
+ FibAction g = new FibAction(9);
+ FibAction h = new FibAction(7);
+ HashSet set = new HashSet();
+ set.add(f);
+ set.add(g);
+ set.add(h);
+ try {
+ invokeAll(set);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ }};
+ testInvokeOnPool(mainPool(), a);
+ }
+
+ /**
+ * tryUnfork returns true for most recent unexecuted task,
+ * and suppresses execution
+ */
+ public void testTryUnfork() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction g = new FibAction(9);
+ assertSame(g, g.fork());
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ assertTrue(f.tryUnfork());
+ helpQuiesce();
+ checkNotDone(f);
+ checkCompletedNormally(g);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * getSurplusQueuedTaskCount returns > 0 when
+ * there are more tasks than threads
+ */
+ public void testGetSurplusQueuedTaskCount() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction h = new FibAction(7);
+ assertSame(h, h.fork());
+ FibAction g = new FibAction(9);
+ assertSame(g, g.fork());
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ assertTrue(getSurplusQueuedTaskCount() > 0);
+ helpQuiesce();
+ assertEquals(0, getSurplusQueuedTaskCount());
+ checkCompletedNormally(f);
+ checkCompletedNormally(g);
+ checkCompletedNormally(h);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * peekNextLocalTask returns most recent unexecuted task.
+ */
+ public void testPeekNextLocalTask() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction g = new FibAction(9);
+ assertSame(g, g.fork());
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ assertSame(f, peekNextLocalTask());
+ assertNull(f.join());
+ checkCompletedNormally(f);
+ helpQuiesce();
+ checkCompletedNormally(f);
+ checkCompletedNormally(g);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * pollNextLocalTask returns most recent unexecuted task
+ * without executing it
+ */
+ public void testPollNextLocalTask() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction g = new FibAction(9);
+ assertSame(g, g.fork());
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ assertSame(f, pollNextLocalTask());
+ helpQuiesce();
+ checkNotDone(f);
+ checkCompletedNormally(g);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * pollTask returns an unexecuted task without executing it
+ */
+ public void testPollTask() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction g = new FibAction(9);
+ assertSame(g, g.fork());
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ assertSame(f, pollTask());
+ helpQuiesce();
+ checkNotDone(f);
+ checkCompletedNormally(g);
+ }};
+ testInvokeOnPool(singletonPool(), a);
+ }
+
+ /**
+ * peekNextLocalTask returns least recent unexecuted task in async mode
+ */
+ public void testPeekNextLocalTaskAsync() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction g = new FibAction(9);
+ assertSame(g, g.fork());
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ assertSame(g, peekNextLocalTask());
+ assertNull(f.join());
+ helpQuiesce();
+ checkCompletedNormally(f);
+ checkCompletedNormally(g);
+ }};
+ testInvokeOnPool(asyncSingletonPool(), a);
+ }
+
+ /**
+ * pollNextLocalTask returns least recent unexecuted task without
+ * executing it, in async mode
+ */
+ public void testPollNextLocalTaskAsync() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction g = new FibAction(9);
+ assertSame(g, g.fork());
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ assertSame(g, pollNextLocalTask());
+ helpQuiesce();
+ checkCompletedNormally(f);
+ checkNotDone(g);
+ }};
+ testInvokeOnPool(asyncSingletonPool(), a);
+ }
+
+ /**
+ * pollTask returns an unexecuted task without executing it, in
+ * async mode
+ */
+ public void testPollTaskAsync() {
+ RecursiveAction a = new CheckedRecursiveAction() {
+ protected void realCompute() {
+ FibAction g = new FibAction(9);
+ assertSame(g, g.fork());
+ FibAction f = new FibAction(8);
+ assertSame(f, f.fork());
+ assertSame(g, pollTask());
+ helpQuiesce();
+ checkCompletedNormally(f);
+ checkNotDone(g);
+ }};
+ testInvokeOnPool(asyncSingletonPool(), a);
+ }
+
+ /** Demo from RecursiveAction javadoc */
+ static class SortTask extends RecursiveAction {
+ final long[] array; final int lo, hi;
+ SortTask(long[] array, int lo, int hi) {
+ this.array = array; this.lo = lo; this.hi = hi;
+ }
+ SortTask(long[] array) { this(array, 0, array.length); }
+ protected void compute() {
+ if (hi - lo < THRESHOLD)
+ sortSequentially(lo, hi);
+ else {
+ int mid = (lo + hi) >>> 1;
+ invokeAll(new SortTask(array, lo, mid),
+ new SortTask(array, mid, hi));
+ merge(lo, mid, hi);
+ }
+ }
+ // implementation details follow:
+ static final int THRESHOLD = 100;
+ void sortSequentially(int lo, int hi) {
+ Arrays.sort(array, lo, hi);
+ }
+ void merge(int lo, int mid, int hi) {
+ long[] buf = Arrays.copyOfRange(array, lo, mid);
+ for (int i = 0, j = lo, k = mid; i < buf.length; j++)
+ array[j] = (k == hi || buf[i] < array[k]) ?
+ buf[i++] : array[k++];
+ }
+ }
+
+ /**
+ * SortTask demo works as advertised
+ */
+ public void testSortTaskDemo() {
+ ThreadLocalRandom rnd = ThreadLocalRandom.current();
+ long[] array = new long[1007];
+ for (int i = 0; i < array.length; i++)
+ array[i] = rnd.nextLong();
+ long[] arrayClone = array.clone();
+ testInvokeOnPool(mainPool(), new SortTask(array));
+ Arrays.sort(arrayClone);
+ assertTrue(Arrays.equals(array, arrayClone));
+ }
+}
diff --git a/jsr166-tests/src/test/java/jsr166/RecursiveTaskTest.java b/jsr166-tests/src/test/java/jsr166/RecursiveTaskTest.java
new file mode 100644
index 0000000..48b6470
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/RecursiveTaskTest.java
@@ -0,0 +1,1020 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.ForkJoinTask;
+import java.util.concurrent.ForkJoinWorkerThread;
+import java.util.concurrent.RecursiveTask;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import java.util.HashSet;
+
+public class RecursiveTaskTest extends JSR166TestCase {
+
+ private static ForkJoinPool mainPool() {
+ return new ForkJoinPool();
+ }
+
+ private static ForkJoinPool singletonPool() {
+ return new ForkJoinPool(1);
+ }
+
+ private static ForkJoinPool asyncSingletonPool() {
+ return new ForkJoinPool(1,
+ ForkJoinPool.defaultForkJoinWorkerThreadFactory,
+ null, true);
+ }
+
+ private <T> T testInvokeOnPool(ForkJoinPool pool, RecursiveTask<T> a) {
+ try {
+ checkNotDone(a);
+
+ T result = pool.invoke(a);
+
+ checkCompletedNormally(a, result);
+ return result;
+ } finally {
+ joinPool(pool);
+ }
+ }
+
+ void checkNotDone(RecursiveTask a) {
+ assertFalse(a.isDone());
+ assertFalse(a.isCompletedNormally());
+ assertFalse(a.isCompletedAbnormally());
+ assertFalse(a.isCancelled());
+ assertNull(a.getException());
+ assertNull(a.getRawResult());
+
+ if (! ForkJoinTask.inForkJoinPool()) {
+ Thread.currentThread().interrupt();
+ try {
+ a.get();
+ shouldThrow();
+ } catch (InterruptedException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+
+ Thread.currentThread().interrupt();
+ try {
+ a.get(5L, SECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ try {
+ a.get(0L, SECONDS);
+ shouldThrow();
+ } catch (TimeoutException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ <T> void checkCompletedNormally(RecursiveTask<T> a, T expected) {
+ assertTrue(a.isDone());
+ assertFalse(a.isCancelled());
+ assertTrue(a.isCompletedNormally());
+ assertFalse(a.isCompletedAbnormally());
+ assertNull(a.getException());
+ assertSame(expected, a.getRawResult());
+ assertSame(expected, a.join());
+ assertFalse(a.cancel(false));
+ assertFalse(a.cancel(true));
+ try {
+ assertSame(expected, a.get());
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ try {
+ assertSame(expected, a.get(5L, SECONDS));
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ /**
+ * Waits for the task to complete, and checks that when it does,
+ * it will have an Integer result equals to the given int.
+ */
+ void checkCompletesNormally(RecursiveTask<Integer> a, int expected) {
+ Integer r = a.join();
+ assertEquals(expected, (int) r);
+ checkCompletedNormally(a, r);
+ }
+
+ /**
+ * Like checkCompletesNormally, but verifies that the task has
+ * already completed.
+ */
+ void checkCompletedNormally(RecursiveTask<Integer> a, int expected) {
+ Integer r = a.getRawResult();
+ assertEquals(expected, (int) r);
+ checkCompletedNormally(a, r);
+ }
+
+ void checkCancelled(RecursiveTask a) {
+ assertTrue(a.isDone());
+ assertTrue(a.isCancelled());
+ assertFalse(a.isCompletedNormally());
+ assertTrue(a.isCompletedAbnormally());
+ assertTrue(a.getException() instanceof CancellationException);
+ assertNull(a.getRawResult());
+
+ try {
+ a.join();
+ shouldThrow();
+ } catch (CancellationException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+
+ try {
+ a.get();
+ shouldThrow();
+ } catch (CancellationException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+
+ try {
+ a.get(5L, SECONDS);
+ shouldThrow();
+ } catch (CancellationException success) {
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ void checkCompletedAbnormally(RecursiveTask a, Throwable t) {
+ assertTrue(a.isDone());
+ assertFalse(a.isCancelled());
+ assertFalse(a.isCompletedNormally());
+ assertTrue(a.isCompletedAbnormally());
+ assertSame(t.getClass(), a.getException().getClass());
+ assertNull(a.getRawResult());
+ assertFalse(a.cancel(false));
+ assertFalse(a.cancel(true));
+
+ try {
+ a.join();
+ shouldThrow();
+ } catch (Throwable expected) {
+ assertSame(t.getClass(), expected.getClass());
+ }
+
+ try {
+ a.get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertSame(t.getClass(), success.getCause().getClass());
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+
+ try {
+ a.get(5L, SECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertSame(t.getClass(), success.getCause().getClass());
+ } catch (Throwable fail) { threadUnexpectedException(fail); }
+ }
+
+ public static final class FJException extends RuntimeException {
+ public FJException() { super(); }
+ }
+
+ // An invalid return value for Fib
+ static final Integer NoResult = Integer.valueOf(-17);
+
+ // A simple recursive task for testing
+ final class FibTask extends CheckedRecursiveTask<Integer> {
+ final int number;
+ FibTask(int n) { number = n; }
+ public Integer realCompute() {
+ int n = number;
+ if (n <= 1)
+ return n;
+ FibTask f1 = new FibTask(n - 1);
+ f1.fork();
+ return (new FibTask(n - 2)).compute() + f1.join();
+ }
+
+ public void publicSetRawResult(Integer result) {
+ setRawResult(result);
+ }
+ }
+
+ // A recursive action failing in base case
+ final class FailingFibTask extends RecursiveTask<Integer> {
+ final int number;
+ int result;
+ FailingFibTask(int n) { number = n; }
+ public Integer compute() {
+ int n = number;
+ if (n <= 1)
+ throw new FJException();
+ FailingFibTask f1 = new FailingFibTask(n - 1);
+ f1.fork();
+ return (new FibTask(n - 2)).compute() + f1.join();
+ }
+ }
+
+ /**
+ * invoke returns value when task completes normally.
+ * isCompletedAbnormally and isCancelled return false for normally
+ * completed tasks. getRawResult of a completed non-null task
+ * returns value;
+ */
+ public void testInvoke() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask f = new FibTask(8);
+ Integer r = f.invoke();
+ assertEquals(21, (int) r);
+ checkCompletedNormally(f, r);
+ return r;
+ }};
+ assertEquals(21, (int) testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * quietlyInvoke task returns when task completes normally.
+ * isCompletedAbnormally and isCancelled return false for normally
+ * completed tasks
+ */
+ public void testQuietlyInvoke() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask f = new FibTask(8);
+ f.quietlyInvoke();
+ checkCompletedNormally(f, 21);
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * join of a forked task returns when task completes
+ */
+ public void testForkJoin() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask f = new FibTask(8);
+ assertSame(f, f.fork());
+ Integer r = f.join();
+ assertEquals(21, (int) r);
+ checkCompletedNormally(f, r);
+ return r;
+ }};
+ assertEquals(21, (int) testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * get of a forked task returns when task completes
+ */
+ public void testForkGet() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() throws Exception {
+ FibTask f = new FibTask(8);
+ assertSame(f, f.fork());
+ Integer r = f.get();
+ assertEquals(21, (int) r);
+ checkCompletedNormally(f, r);
+ return r;
+ }};
+ assertEquals(21, (int) testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * timed get of a forked task returns when task completes
+ */
+ public void testForkTimedGet() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() throws Exception {
+ FibTask f = new FibTask(8);
+ assertSame(f, f.fork());
+ Integer r = f.get(5L, SECONDS);
+ assertEquals(21, (int) r);
+ checkCompletedNormally(f, r);
+ return r;
+ }};
+ assertEquals(21, (int) testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * quietlyJoin of a forked task returns when task completes
+ */
+ public void testForkQuietlyJoin() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask f = new FibTask(8);
+ assertSame(f, f.fork());
+ f.quietlyJoin();
+ Integer r = f.getRawResult();
+ assertEquals(21, (int) r);
+ checkCompletedNormally(f, r);
+ return r;
+ }};
+ assertEquals(21, (int) testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * helpQuiesce returns when tasks are complete.
+ * getQueuedTaskCount returns 0 when quiescent
+ */
+ public void testForkHelpQuiesce() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask f = new FibTask(8);
+ assertSame(f, f.fork());
+ helpQuiesce();
+ assertEquals(0, getQueuedTaskCount());
+ checkCompletedNormally(f, 21);
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * invoke task throws exception when task completes abnormally
+ */
+ public void testAbnormalInvoke() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FailingFibTask f = new FailingFibTask(8);
+ try {
+ f.invoke();
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * quietlyInvoke task returns when task completes abnormally
+ */
+ public void testAbnormalQuietlyInvoke() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FailingFibTask f = new FailingFibTask(8);
+ f.quietlyInvoke();
+ assertTrue(f.getException() instanceof FJException);
+ checkCompletedAbnormally(f, f.getException());
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * join of a forked task throws exception when task completes abnormally
+ */
+ public void testAbnormalForkJoin() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FailingFibTask f = new FailingFibTask(8);
+ assertSame(f, f.fork());
+ try {
+ Integer r = f.join();
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * get of a forked task throws exception when task completes abnormally
+ */
+ public void testAbnormalForkGet() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() throws Exception {
+ FailingFibTask f = new FailingFibTask(8);
+ assertSame(f, f.fork());
+ try {
+ Integer r = f.get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ Throwable cause = success.getCause();
+ assertTrue(cause instanceof FJException);
+ checkCompletedAbnormally(f, cause);
+ }
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * timed get of a forked task throws exception when task completes abnormally
+ */
+ public void testAbnormalForkTimedGet() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() throws Exception {
+ FailingFibTask f = new FailingFibTask(8);
+ assertSame(f, f.fork());
+ try {
+ Integer r = f.get(5L, SECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ Throwable cause = success.getCause();
+ assertTrue(cause instanceof FJException);
+ checkCompletedAbnormally(f, cause);
+ }
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * quietlyJoin of a forked task returns when task completes abnormally
+ */
+ public void testAbnormalForkQuietlyJoin() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FailingFibTask f = new FailingFibTask(8);
+ assertSame(f, f.fork());
+ f.quietlyJoin();
+ assertTrue(f.getException() instanceof FJException);
+ checkCompletedAbnormally(f, f.getException());
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * invoke task throws exception when task cancelled
+ */
+ public void testCancelledInvoke() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask f = new FibTask(8);
+ assertTrue(f.cancel(true));
+ try {
+ Integer r = f.invoke();
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * join of a forked task throws exception when task cancelled
+ */
+ public void testCancelledForkJoin() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask f = new FibTask(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ try {
+ Integer r = f.join();
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * get of a forked task throws exception when task cancelled
+ */
+ public void testCancelledForkGet() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() throws Exception {
+ FibTask f = new FibTask(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ try {
+ Integer r = f.get();
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * timed get of a forked task throws exception when task cancelled
+ */
+ public void testCancelledForkTimedGet() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() throws Exception {
+ FibTask f = new FibTask(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ try {
+ Integer r = f.get(5L, SECONDS);
+ shouldThrow();
+ } catch (CancellationException success) {
+ checkCancelled(f);
+ }
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * quietlyJoin of a forked task returns when task cancelled
+ */
+ public void testCancelledForkQuietlyJoin() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask f = new FibTask(8);
+ assertTrue(f.cancel(true));
+ assertSame(f, f.fork());
+ f.quietlyJoin();
+ checkCancelled(f);
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * getPool of executing task returns its pool
+ */
+ public void testGetPool() {
+ final ForkJoinPool mainPool = mainPool();
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ assertSame(mainPool, getPool());
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool, a));
+ }
+
+ /**
+ * getPool of non-FJ task returns null
+ */
+ public void testGetPool2() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ assertNull(getPool());
+ return NoResult;
+ }};
+ assertSame(NoResult, a.invoke());
+ }
+
+ /**
+ * inForkJoinPool of executing task returns true
+ */
+ public void testInForkJoinPool() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ assertTrue(inForkJoinPool());
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * inForkJoinPool of non-FJ task returns false
+ */
+ public void testInForkJoinPool2() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ assertFalse(inForkJoinPool());
+ return NoResult;
+ }};
+ assertSame(NoResult, a.invoke());
+ }
+
+ /**
+ * The value set by setRawResult is returned by getRawResult
+ */
+ public void testSetRawResult() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ setRawResult(NoResult);
+ assertSame(NoResult, getRawResult());
+ return NoResult;
+ }
+ };
+ assertSame(NoResult, a.invoke());
+ }
+
+ /**
+ * A reinitialized normally completed task may be re-invoked
+ */
+ public void testReinitialize() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask f = new FibTask(8);
+ checkNotDone(f);
+
+ for (int i = 0; i < 3; i++) {
+ Integer r = f.invoke();
+ assertEquals(21, (int) r);
+ checkCompletedNormally(f, r);
+ f.reinitialize();
+ f.publicSetRawResult(null);
+ checkNotDone(f);
+ }
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * A reinitialized abnormally completed task may be re-invoked
+ */
+ public void testReinitializeAbnormal() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FailingFibTask f = new FailingFibTask(8);
+ checkNotDone(f);
+
+ for (int i = 0; i < 3; i++) {
+ try {
+ f.invoke();
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ f.reinitialize();
+ checkNotDone(f);
+ }
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * invoke task throws exception after invoking completeExceptionally
+ */
+ public void testCompleteExceptionally() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask f = new FibTask(8);
+ f.completeExceptionally(new FJException());
+ try {
+ Integer r = f.invoke();
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * invoke task suppresses execution invoking complete
+ */
+ public void testComplete() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask f = new FibTask(8);
+ f.complete(NoResult);
+ Integer r = f.invoke();
+ assertSame(NoResult, r);
+ checkCompletedNormally(f, NoResult);
+ return r;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * invokeAll(t1, t2) invokes all task arguments
+ */
+ public void testInvokeAll2() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask f = new FibTask(8);
+ FibTask g = new FibTask(9);
+ invokeAll(f, g);
+ checkCompletedNormally(f, 21);
+ checkCompletedNormally(g, 34);
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * invokeAll(tasks) with 1 argument invokes task
+ */
+ public void testInvokeAll1() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask f = new FibTask(8);
+ invokeAll(f);
+ checkCompletedNormally(f, 21);
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * invokeAll(tasks) with > 2 argument invokes tasks
+ */
+ public void testInvokeAll3() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask f = new FibTask(8);
+ FibTask g = new FibTask(9);
+ FibTask h = new FibTask(7);
+ invokeAll(f, g, h);
+ assertTrue(f.isDone());
+ assertTrue(g.isDone());
+ assertTrue(h.isDone());
+ checkCompletedNormally(f, 21);
+ checkCompletedNormally(g, 34);
+ checkCompletedNormally(h, 13);
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * invokeAll(collection) invokes all tasks in the collection
+ */
+ public void testInvokeAllCollection() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask f = new FibTask(8);
+ FibTask g = new FibTask(9);
+ FibTask h = new FibTask(7);
+ HashSet set = new HashSet();
+ set.add(f);
+ set.add(g);
+ set.add(h);
+ invokeAll(set);
+ assertTrue(f.isDone());
+ assertTrue(g.isDone());
+ assertTrue(h.isDone());
+ checkCompletedNormally(f, 21);
+ checkCompletedNormally(g, 34);
+ checkCompletedNormally(h, 13);
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * invokeAll(tasks) with any null task throws NPE
+ */
+ public void testInvokeAllNPE() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask f = new FibTask(8);
+ FibTask g = new FibTask(9);
+ FibTask h = null;
+ try {
+ invokeAll(f, g, h);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * invokeAll(t1, t2) throw exception if any task does
+ */
+ public void testAbnormalInvokeAll2() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask f = new FibTask(8);
+ FailingFibTask g = new FailingFibTask(9);
+ try {
+ invokeAll(f, g);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(g, success);
+ }
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * invokeAll(tasks) with 1 argument throws exception if task does
+ */
+ public void testAbnormalInvokeAll1() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FailingFibTask g = new FailingFibTask(9);
+ try {
+ invokeAll(g);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(g, success);
+ }
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * invokeAll(tasks) with > 2 argument throws exception if any task does
+ */
+ public void testAbnormalInvokeAll3() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask f = new FibTask(8);
+ FailingFibTask g = new FailingFibTask(9);
+ FibTask h = new FibTask(7);
+ try {
+ invokeAll(f, g, h);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(g, success);
+ }
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * invokeAll(collection) throws exception if any task does
+ */
+ public void testAbnormalInvokeAllCollection() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FailingFibTask f = new FailingFibTask(8);
+ FibTask g = new FibTask(9);
+ FibTask h = new FibTask(7);
+ HashSet set = new HashSet();
+ set.add(f);
+ set.add(g);
+ set.add(h);
+ try {
+ invokeAll(set);
+ shouldThrow();
+ } catch (FJException success) {
+ checkCompletedAbnormally(f, success);
+ }
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(mainPool(), a));
+ }
+
+ /**
+ * tryUnfork returns true for most recent unexecuted task,
+ * and suppresses execution
+ */
+ public void testTryUnfork() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask g = new FibTask(9);
+ assertSame(g, g.fork());
+ FibTask f = new FibTask(8);
+ assertSame(f, f.fork());
+ assertTrue(f.tryUnfork());
+ helpQuiesce();
+ checkNotDone(f);
+ checkCompletedNormally(g, 34);
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(singletonPool(), a));
+ }
+
+ /**
+ * getSurplusQueuedTaskCount returns > 0 when
+ * there are more tasks than threads
+ */
+ public void testGetSurplusQueuedTaskCount() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask h = new FibTask(7);
+ assertSame(h, h.fork());
+ FibTask g = new FibTask(9);
+ assertSame(g, g.fork());
+ FibTask f = new FibTask(8);
+ assertSame(f, f.fork());
+ assertTrue(getSurplusQueuedTaskCount() > 0);
+ helpQuiesce();
+ assertEquals(0, getSurplusQueuedTaskCount());
+ checkCompletedNormally(f, 21);
+ checkCompletedNormally(g, 34);
+ checkCompletedNormally(h, 13);
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(singletonPool(), a));
+ }
+
+ /**
+ * peekNextLocalTask returns most recent unexecuted task.
+ */
+ public void testPeekNextLocalTask() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask g = new FibTask(9);
+ assertSame(g, g.fork());
+ FibTask f = new FibTask(8);
+ assertSame(f, f.fork());
+ assertSame(f, peekNextLocalTask());
+ checkCompletesNormally(f, 21);
+ helpQuiesce();
+ checkCompletedNormally(g, 34);
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(singletonPool(), a));
+ }
+
+ /**
+ * pollNextLocalTask returns most recent unexecuted task
+ * without executing it
+ */
+ public void testPollNextLocalTask() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask g = new FibTask(9);
+ assertSame(g, g.fork());
+ FibTask f = new FibTask(8);
+ assertSame(f, f.fork());
+ assertSame(f, pollNextLocalTask());
+ helpQuiesce();
+ checkNotDone(f);
+ checkCompletedNormally(g, 34);
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(singletonPool(), a));
+ }
+
+ /**
+ * pollTask returns an unexecuted task without executing it
+ */
+ public void testPollTask() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask g = new FibTask(9);
+ assertSame(g, g.fork());
+ FibTask f = new FibTask(8);
+ assertSame(f, f.fork());
+ assertSame(f, pollTask());
+ helpQuiesce();
+ checkNotDone(f);
+ checkCompletedNormally(g, 34);
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(singletonPool(), a));
+ }
+
+ /**
+ * peekNextLocalTask returns least recent unexecuted task in async mode
+ */
+ public void testPeekNextLocalTaskAsync() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask g = new FibTask(9);
+ assertSame(g, g.fork());
+ FibTask f = new FibTask(8);
+ assertSame(f, f.fork());
+ assertSame(g, peekNextLocalTask());
+ assertEquals(21, (int) f.join());
+ helpQuiesce();
+ checkCompletedNormally(f, 21);
+ checkCompletedNormally(g, 34);
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(asyncSingletonPool(), a));
+ }
+
+ /**
+ * pollNextLocalTask returns least recent unexecuted task without
+ * executing it, in async mode
+ */
+ public void testPollNextLocalTaskAsync() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask g = new FibTask(9);
+ assertSame(g, g.fork());
+ FibTask f = new FibTask(8);
+ assertSame(f, f.fork());
+ assertSame(g, pollNextLocalTask());
+ helpQuiesce();
+ checkCompletedNormally(f, 21);
+ checkNotDone(g);
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(asyncSingletonPool(), a));
+ }
+
+ /**
+ * pollTask returns an unexecuted task without executing it, in
+ * async mode
+ */
+ public void testPollTaskAsync() {
+ RecursiveTask<Integer> a = new CheckedRecursiveTask<Integer>() {
+ public Integer realCompute() {
+ FibTask g = new FibTask(9);
+ assertSame(g, g.fork());
+ FibTask f = new FibTask(8);
+ assertSame(f, f.fork());
+ assertSame(g, pollTask());
+ helpQuiesce();
+ checkCompletedNormally(f, 21);
+ checkNotDone(g);
+ return NoResult;
+ }};
+ assertSame(NoResult, testInvokeOnPool(asyncSingletonPool(), a));
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/ReentrantLockTest.java b/jsr166-tests/src/test/java/jsr166/ReentrantLockTest.java
new file mode 100644
index 0000000..6fe8122
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/ReentrantLockTest.java
@@ -0,0 +1,1133 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.CyclicBarrier;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import java.util.*;
+
+public class ReentrantLockTest extends JSR166TestCase {
+
+ /**
+ * A runnable calling lockInterruptibly
+ */
+ class InterruptibleLockRunnable extends CheckedRunnable {
+ final ReentrantLock lock;
+ InterruptibleLockRunnable(ReentrantLock l) { lock = l; }
+ public void realRun() throws InterruptedException {
+ lock.lockInterruptibly();
+ }
+ }
+
+ /**
+ * A runnable calling lockInterruptibly that expects to be
+ * interrupted
+ */
+ class InterruptedLockRunnable extends CheckedInterruptedRunnable {
+ final ReentrantLock lock;
+ InterruptedLockRunnable(ReentrantLock l) { lock = l; }
+ public void realRun() throws InterruptedException {
+ lock.lockInterruptibly();
+ }
+ }
+
+ /**
+ * Subclass to expose protected methods
+ */
+ static class PublicReentrantLock extends ReentrantLock {
+ PublicReentrantLock() { super(); }
+ PublicReentrantLock(boolean fair) { super(fair); }
+ public Thread getOwner() {
+ return super.getOwner();
+ }
+ public Collection<Thread> getQueuedThreads() {
+ return super.getQueuedThreads();
+ }
+ public Collection<Thread> getWaitingThreads(Condition c) {
+ return super.getWaitingThreads(c);
+ }
+ }
+
+ /**
+ * Releases write lock, checking that it had a hold count of 1.
+ */
+ void releaseLock(PublicReentrantLock lock) {
+ assertLockedByMoi(lock);
+ lock.unlock();
+ assertFalse(lock.isHeldByCurrentThread());
+ assertNotLocked(lock);
+ }
+
+ /**
+ * Spin-waits until lock.hasQueuedThread(t) becomes true.
+ */
+ void waitForQueuedThread(PublicReentrantLock lock, Thread t) {
+ long startTime = System.nanoTime();
+ while (!lock.hasQueuedThread(t)) {
+ if (millisElapsedSince(startTime) > LONG_DELAY_MS)
+ throw new AssertionFailedError("timed out");
+ Thread.yield();
+ }
+ assertTrue(t.isAlive());
+ assertNotSame(t, lock.getOwner());
+ }
+
+ /**
+ * Checks that lock is not locked.
+ */
+ void assertNotLocked(PublicReentrantLock lock) {
+ assertFalse(lock.isLocked());
+ assertFalse(lock.isHeldByCurrentThread());
+ assertNull(lock.getOwner());
+ assertEquals(0, lock.getHoldCount());
+ }
+
+ /**
+ * Checks that lock is locked by the given thread.
+ */
+ void assertLockedBy(PublicReentrantLock lock, Thread t) {
+ assertTrue(lock.isLocked());
+ assertSame(t, lock.getOwner());
+ assertEquals(t == Thread.currentThread(),
+ lock.isHeldByCurrentThread());
+ assertEquals(t == Thread.currentThread(),
+ lock.getHoldCount() > 0);
+ }
+
+ /**
+ * Checks that lock is locked by the current thread.
+ */
+ void assertLockedByMoi(PublicReentrantLock lock) {
+ assertLockedBy(lock, Thread.currentThread());
+ }
+
+ /**
+ * Checks that condition c has no waiters.
+ */
+ void assertHasNoWaiters(PublicReentrantLock lock, Condition c) {
+ assertHasWaiters(lock, c, new Thread[] {});
+ }
+
+ /**
+ * Checks that condition c has exactly the given waiter threads.
+ */
+ void assertHasWaiters(PublicReentrantLock lock, Condition c,
+ Thread... threads) {
+ lock.lock();
+ assertEquals(threads.length > 0, lock.hasWaiters(c));
+ assertEquals(threads.length, lock.getWaitQueueLength(c));
+ assertEquals(threads.length == 0, lock.getWaitingThreads(c).isEmpty());
+ assertEquals(threads.length, lock.getWaitingThreads(c).size());
+ assertEquals(new HashSet<Thread>(lock.getWaitingThreads(c)),
+ new HashSet<Thread>(Arrays.asList(threads)));
+ lock.unlock();
+ }
+
+ enum AwaitMethod { await, awaitTimed, awaitNanos, awaitUntil };
+
+ /**
+ * Awaits condition using the specified AwaitMethod.
+ */
+ void await(Condition c, AwaitMethod awaitMethod)
+ throws InterruptedException {
+ long timeoutMillis = 2 * LONG_DELAY_MS;
+ switch (awaitMethod) {
+ case await:
+ c.await();
+ break;
+ case awaitTimed:
+ assertTrue(c.await(timeoutMillis, MILLISECONDS));
+ break;
+ case awaitNanos:
+ long nanosTimeout = MILLISECONDS.toNanos(timeoutMillis);
+ long nanosRemaining = c.awaitNanos(nanosTimeout);
+ assertTrue(nanosRemaining > 0);
+ break;
+ case awaitUntil:
+ assertTrue(c.awaitUntil(delayedDate(timeoutMillis)));
+ break;
+ }
+ }
+
+ /**
+ * Constructor sets given fairness, and is in unlocked state
+ */
+ public void testConstructor() {
+ PublicReentrantLock lock;
+
+ lock = new PublicReentrantLock();
+ assertFalse(lock.isFair());
+ assertNotLocked(lock);
+
+ lock = new PublicReentrantLock(true);
+ assertTrue(lock.isFair());
+ assertNotLocked(lock);
+
+ lock = new PublicReentrantLock(false);
+ assertFalse(lock.isFair());
+ assertNotLocked(lock);
+ }
+
+ /**
+ * locking an unlocked lock succeeds
+ */
+ public void testLock() { testLock(false); }
+ public void testLock_fair() { testLock(true); }
+ public void testLock(boolean fair) {
+ PublicReentrantLock lock = new PublicReentrantLock(fair);
+ lock.lock();
+ assertLockedByMoi(lock);
+ releaseLock(lock);
+ }
+
+ /**
+ * Unlocking an unlocked lock throws IllegalMonitorStateException
+ */
+ public void testUnlock_IMSE() { testUnlock_IMSE(false); }
+ public void testUnlock_IMSE_fair() { testUnlock_IMSE(true); }
+ public void testUnlock_IMSE(boolean fair) {
+ ReentrantLock lock = new ReentrantLock(fair);
+ try {
+ lock.unlock();
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {}
+ }
+
+ /**
+ * tryLock on an unlocked lock succeeds
+ */
+ public void testTryLock() { testTryLock(false); }
+ public void testTryLock_fair() { testTryLock(true); }
+ public void testTryLock(boolean fair) {
+ PublicReentrantLock lock = new PublicReentrantLock(fair);
+ assertTrue(lock.tryLock());
+ assertLockedByMoi(lock);
+ assertTrue(lock.tryLock());
+ assertLockedByMoi(lock);
+ lock.unlock();
+ releaseLock(lock);
+ }
+
+ /**
+ * hasQueuedThreads reports whether there are waiting threads
+ */
+ public void testHasQueuedThreads() { testHasQueuedThreads(false); }
+ public void testHasQueuedThreads_fair() { testHasQueuedThreads(true); }
+ public void testHasQueuedThreads(boolean fair) {
+ final PublicReentrantLock lock = new PublicReentrantLock(fair);
+ Thread t1 = new Thread(new InterruptedLockRunnable(lock));
+ Thread t2 = new Thread(new InterruptibleLockRunnable(lock));
+ assertFalse(lock.hasQueuedThreads());
+ lock.lock();
+ assertFalse(lock.hasQueuedThreads());
+ t1.start();
+ waitForQueuedThread(lock, t1);
+ assertTrue(lock.hasQueuedThreads());
+ t2.start();
+ waitForQueuedThread(lock, t2);
+ assertTrue(lock.hasQueuedThreads());
+ t1.interrupt();
+ awaitTermination(t1);
+ assertTrue(lock.hasQueuedThreads());
+ lock.unlock();
+ awaitTermination(t2);
+ assertFalse(lock.hasQueuedThreads());
+ }
+
+ /**
+ * getQueueLength reports number of waiting threads
+ */
+ public void testGetQueueLength() { testGetQueueLength(false); }
+ public void testGetQueueLength_fair() { testGetQueueLength(true); }
+ public void testGetQueueLength(boolean fair) {
+ final PublicReentrantLock lock = new PublicReentrantLock(fair);
+ Thread t1 = new Thread(new InterruptedLockRunnable(lock));
+ Thread t2 = new Thread(new InterruptibleLockRunnable(lock));
+ assertEquals(0, lock.getQueueLength());
+ lock.lock();
+ t1.start();
+ waitForQueuedThread(lock, t1);
+ assertEquals(1, lock.getQueueLength());
+ t2.start();
+ waitForQueuedThread(lock, t2);
+ assertEquals(2, lock.getQueueLength());
+ t1.interrupt();
+ awaitTermination(t1);
+ assertEquals(1, lock.getQueueLength());
+ lock.unlock();
+ awaitTermination(t2);
+ assertEquals(0, lock.getQueueLength());
+ }
+
+ /**
+ * hasQueuedThread(null) throws NPE
+ */
+ public void testHasQueuedThreadNPE() { testHasQueuedThreadNPE(false); }
+ public void testHasQueuedThreadNPE_fair() { testHasQueuedThreadNPE(true); }
+ public void testHasQueuedThreadNPE(boolean fair) {
+ final ReentrantLock lock = new ReentrantLock(fair);
+ try {
+ lock.hasQueuedThread(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * hasQueuedThread reports whether a thread is queued
+ */
+ public void testHasQueuedThread() { testHasQueuedThread(false); }
+ public void testHasQueuedThread_fair() { testHasQueuedThread(true); }
+ public void testHasQueuedThread(boolean fair) {
+ final PublicReentrantLock lock = new PublicReentrantLock(fair);
+ Thread t1 = new Thread(new InterruptedLockRunnable(lock));
+ Thread t2 = new Thread(new InterruptibleLockRunnable(lock));
+ assertFalse(lock.hasQueuedThread(t1));
+ assertFalse(lock.hasQueuedThread(t2));
+ lock.lock();
+ t1.start();
+ waitForQueuedThread(lock, t1);
+ assertTrue(lock.hasQueuedThread(t1));
+ assertFalse(lock.hasQueuedThread(t2));
+ t2.start();
+ waitForQueuedThread(lock, t2);
+ assertTrue(lock.hasQueuedThread(t1));
+ assertTrue(lock.hasQueuedThread(t2));
+ t1.interrupt();
+ awaitTermination(t1);
+ assertFalse(lock.hasQueuedThread(t1));
+ assertTrue(lock.hasQueuedThread(t2));
+ lock.unlock();
+ awaitTermination(t2);
+ assertFalse(lock.hasQueuedThread(t1));
+ assertFalse(lock.hasQueuedThread(t2));
+ }
+
+ /**
+ * getQueuedThreads includes waiting threads
+ */
+ public void testGetQueuedThreads() { testGetQueuedThreads(false); }
+ public void testGetQueuedThreads_fair() { testGetQueuedThreads(true); }
+ public void testGetQueuedThreads(boolean fair) {
+ final PublicReentrantLock lock = new PublicReentrantLock(fair);
+ Thread t1 = new Thread(new InterruptedLockRunnable(lock));
+ Thread t2 = new Thread(new InterruptibleLockRunnable(lock));
+ assertTrue(lock.getQueuedThreads().isEmpty());
+ lock.lock();
+ assertTrue(lock.getQueuedThreads().isEmpty());
+ t1.start();
+ waitForQueuedThread(lock, t1);
+ assertEquals(1, lock.getQueuedThreads().size());
+ assertTrue(lock.getQueuedThreads().contains(t1));
+ t2.start();
+ waitForQueuedThread(lock, t2);
+ assertEquals(2, lock.getQueuedThreads().size());
+ assertTrue(lock.getQueuedThreads().contains(t1));
+ assertTrue(lock.getQueuedThreads().contains(t2));
+ t1.interrupt();
+ awaitTermination(t1);
+ assertFalse(lock.getQueuedThreads().contains(t1));
+ assertTrue(lock.getQueuedThreads().contains(t2));
+ assertEquals(1, lock.getQueuedThreads().size());
+ lock.unlock();
+ awaitTermination(t2);
+ assertTrue(lock.getQueuedThreads().isEmpty());
+ }
+
+ /**
+ * timed tryLock is interruptible
+ */
+ public void testTryLock_Interruptible() { testTryLock_Interruptible(false); }
+ public void testTryLock_Interruptible_fair() { testTryLock_Interruptible(true); }
+ public void testTryLock_Interruptible(boolean fair) {
+ final PublicReentrantLock lock = new PublicReentrantLock(fair);
+ lock.lock();
+ Thread t = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.tryLock(2 * LONG_DELAY_MS, MILLISECONDS);
+ }});
+
+ waitForQueuedThread(lock, t);
+ t.interrupt();
+ awaitTermination(t);
+ releaseLock(lock);
+ }
+
+ /**
+ * tryLock on a locked lock fails
+ */
+ public void testTryLockWhenLocked() { testTryLockWhenLocked(false); }
+ public void testTryLockWhenLocked_fair() { testTryLockWhenLocked(true); }
+ public void testTryLockWhenLocked(boolean fair) {
+ final PublicReentrantLock lock = new PublicReentrantLock(fair);
+ lock.lock();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ assertFalse(lock.tryLock());
+ }});
+
+ awaitTermination(t);
+ releaseLock(lock);
+ }
+
+ /**
+ * Timed tryLock on a locked lock times out
+ */
+ public void testTryLock_Timeout() { testTryLock_Timeout(false); }
+ public void testTryLock_Timeout_fair() { testTryLock_Timeout(true); }
+ public void testTryLock_Timeout(boolean fair) {
+ final PublicReentrantLock lock = new PublicReentrantLock(fair);
+ lock.lock();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ long startTime = System.nanoTime();
+ long timeoutMillis = 10;
+ assertFalse(lock.tryLock(timeoutMillis, MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
+ }});
+
+ awaitTermination(t);
+ releaseLock(lock);
+ }
+
+ /**
+ * getHoldCount returns number of recursive holds
+ */
+ public void testGetHoldCount() { testGetHoldCount(false); }
+ public void testGetHoldCount_fair() { testGetHoldCount(true); }
+ public void testGetHoldCount(boolean fair) {
+ ReentrantLock lock = new ReentrantLock(fair);
+ for (int i = 1; i <= SIZE; i++) {
+ lock.lock();
+ assertEquals(i, lock.getHoldCount());
+ }
+ for (int i = SIZE; i > 0; i--) {
+ lock.unlock();
+ assertEquals(i-1, lock.getHoldCount());
+ }
+ }
+
+ /**
+ * isLocked is true when locked and false when not
+ */
+ public void testIsLocked() { testIsLocked(false); }
+ public void testIsLocked_fair() { testIsLocked(true); }
+ public void testIsLocked(boolean fair) {
+ try {
+ final ReentrantLock lock = new ReentrantLock(fair);
+ assertFalse(lock.isLocked());
+ lock.lock();
+ assertTrue(lock.isLocked());
+ lock.lock();
+ assertTrue(lock.isLocked());
+ lock.unlock();
+ assertTrue(lock.isLocked());
+ lock.unlock();
+ assertFalse(lock.isLocked());
+ final CyclicBarrier barrier = new CyclicBarrier(2);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws Exception {
+ lock.lock();
+ assertTrue(lock.isLocked());
+ barrier.await();
+ barrier.await();
+ lock.unlock();
+ }});
+
+ barrier.await();
+ assertTrue(lock.isLocked());
+ barrier.await();
+ awaitTermination(t);
+ assertFalse(lock.isLocked());
+ } catch (Exception e) {
+ threadUnexpectedException(e);
+ }
+ }
+
+ /**
+ * lockInterruptibly succeeds when unlocked, else is interruptible
+ */
+ public void testLockInterruptibly() { testLockInterruptibly(false); }
+ public void testLockInterruptibly_fair() { testLockInterruptibly(true); }
+ public void testLockInterruptibly(boolean fair) {
+ final PublicReentrantLock lock = new PublicReentrantLock(fair);
+ try {
+ lock.lockInterruptibly();
+ } catch (InterruptedException ie) {
+ threadUnexpectedException(ie);
+ }
+ assertLockedByMoi(lock);
+ Thread t = newStartedThread(new InterruptedLockRunnable(lock));
+ waitForQueuedThread(lock, t);
+ t.interrupt();
+ assertTrue(lock.isLocked());
+ assertTrue(lock.isHeldByCurrentThread());
+ awaitTermination(t);
+ releaseLock(lock);
+ }
+
+ /**
+ * Calling await without holding lock throws IllegalMonitorStateException
+ */
+ public void testAwait_IMSE() { testAwait_IMSE(false); }
+ public void testAwait_IMSE_fair() { testAwait_IMSE(true); }
+ public void testAwait_IMSE(boolean fair) {
+ final ReentrantLock lock = new ReentrantLock(fair);
+ final Condition c = lock.newCondition();
+ for (AwaitMethod awaitMethod : AwaitMethod.values()) {
+ long startTime = System.nanoTime();
+ try {
+ await(c, awaitMethod);
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {
+ } catch (InterruptedException e) { threadUnexpectedException(e); }
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ }
+ }
+
+ /**
+ * Calling signal without holding lock throws IllegalMonitorStateException
+ */
+ public void testSignal_IMSE() { testSignal_IMSE(false); }
+ public void testSignal_IMSE_fair() { testSignal_IMSE(true); }
+ public void testSignal_IMSE(boolean fair) {
+ final ReentrantLock lock = new ReentrantLock(fair);
+ final Condition c = lock.newCondition();
+ try {
+ c.signal();
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {}
+ }
+
+ /**
+ * awaitNanos without a signal times out
+ */
+ public void testAwaitNanos_Timeout() { testAwaitNanos_Timeout(false); }
+ public void testAwaitNanos_Timeout_fair() { testAwaitNanos_Timeout(true); }
+ public void testAwaitNanos_Timeout(boolean fair) {
+ try {
+ final ReentrantLock lock = new ReentrantLock(fair);
+ final Condition c = lock.newCondition();
+ lock.lock();
+ long startTime = System.nanoTime();
+ long timeoutMillis = 10;
+ long timeoutNanos = MILLISECONDS.toNanos(timeoutMillis);
+ long nanosRemaining = c.awaitNanos(timeoutNanos);
+ assertTrue(nanosRemaining <= 0);
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
+ lock.unlock();
+ } catch (InterruptedException e) {
+ threadUnexpectedException(e);
+ }
+ }
+
+ /**
+ * timed await without a signal times out
+ */
+ public void testAwait_Timeout() { testAwait_Timeout(false); }
+ public void testAwait_Timeout_fair() { testAwait_Timeout(true); }
+ public void testAwait_Timeout(boolean fair) {
+ try {
+ final ReentrantLock lock = new ReentrantLock(fair);
+ final Condition c = lock.newCondition();
+ lock.lock();
+ long startTime = System.nanoTime();
+ long timeoutMillis = 10;
+ assertFalse(c.await(timeoutMillis, MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
+ lock.unlock();
+ } catch (InterruptedException e) {
+ threadUnexpectedException(e);
+ }
+ }
+
+ /**
+ * awaitUntil without a signal times out
+ */
+ public void testAwaitUntil_Timeout() { testAwaitUntil_Timeout(false); }
+ public void testAwaitUntil_Timeout_fair() { testAwaitUntil_Timeout(true); }
+ public void testAwaitUntil_Timeout(boolean fair) {
+ try {
+ final ReentrantLock lock = new ReentrantLock(fair);
+ final Condition c = lock.newCondition();
+ lock.lock();
+ long startTime = System.nanoTime();
+ long timeoutMillis = 10;
+ java.util.Date d = new java.util.Date();
+ assertFalse(c.awaitUntil(new java.util.Date(d.getTime() + timeoutMillis)));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
+ lock.unlock();
+ } catch (InterruptedException e) {
+ threadUnexpectedException(e);
+ }
+ }
+
+ /**
+ * await returns when signalled
+ */
+ public void testAwait() { testAwait(false); }
+ public void testAwait_fair() { testAwait(true); }
+ public void testAwait(boolean fair) {
+ final PublicReentrantLock lock = new PublicReentrantLock(fair);
+ final Condition c = lock.newCondition();
+ final CountDownLatch locked = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.lock();
+ locked.countDown();
+ c.await();
+ lock.unlock();
+ }});
+
+ await(locked);
+ lock.lock();
+ assertHasWaiters(lock, c, t);
+ c.signal();
+ assertHasNoWaiters(lock, c);
+ assertTrue(t.isAlive());
+ lock.unlock();
+ awaitTermination(t);
+ }
+
+ /**
+ * hasWaiters throws NPE if null
+ */
+ public void testHasWaitersNPE() { testHasWaitersNPE(false); }
+ public void testHasWaitersNPE_fair() { testHasWaitersNPE(true); }
+ public void testHasWaitersNPE(boolean fair) {
+ final ReentrantLock lock = new ReentrantLock(fair);
+ try {
+ lock.hasWaiters(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * getWaitQueueLength throws NPE if null
+ */
+ public void testGetWaitQueueLengthNPE() { testGetWaitQueueLengthNPE(false); }
+ public void testGetWaitQueueLengthNPE_fair() { testGetWaitQueueLengthNPE(true); }
+ public void testGetWaitQueueLengthNPE(boolean fair) {
+ final ReentrantLock lock = new ReentrantLock(fair);
+ try {
+ lock.getWaitQueueLength(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * getWaitingThreads throws NPE if null
+ */
+ public void testGetWaitingThreadsNPE() { testGetWaitingThreadsNPE(false); }
+ public void testGetWaitingThreadsNPE_fair() { testGetWaitingThreadsNPE(true); }
+ public void testGetWaitingThreadsNPE(boolean fair) {
+ final PublicReentrantLock lock = new PublicReentrantLock(fair);
+ try {
+ lock.getWaitingThreads(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * hasWaiters throws IllegalArgumentException if not owned
+ */
+ public void testHasWaitersIAE() { testHasWaitersIAE(false); }
+ public void testHasWaitersIAE_fair() { testHasWaitersIAE(true); }
+ public void testHasWaitersIAE(boolean fair) {
+ final ReentrantLock lock = new ReentrantLock(fair);
+ final Condition c = lock.newCondition();
+ final ReentrantLock lock2 = new ReentrantLock(fair);
+ try {
+ lock2.hasWaiters(c);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * hasWaiters throws IllegalMonitorStateException if not locked
+ */
+ public void testHasWaitersIMSE() { testHasWaitersIMSE(false); }
+ public void testHasWaitersIMSE_fair() { testHasWaitersIMSE(true); }
+ public void testHasWaitersIMSE(boolean fair) {
+ final ReentrantLock lock = new ReentrantLock(fair);
+ final Condition c = lock.newCondition();
+ try {
+ lock.hasWaiters(c);
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {}
+ }
+
+ /**
+ * getWaitQueueLength throws IllegalArgumentException if not owned
+ */
+ public void testGetWaitQueueLengthIAE() { testGetWaitQueueLengthIAE(false); }
+ public void testGetWaitQueueLengthIAE_fair() { testGetWaitQueueLengthIAE(true); }
+ public void testGetWaitQueueLengthIAE(boolean fair) {
+ final ReentrantLock lock = new ReentrantLock(fair);
+ final Condition c = lock.newCondition();
+ final ReentrantLock lock2 = new ReentrantLock(fair);
+ try {
+ lock2.getWaitQueueLength(c);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * getWaitQueueLength throws IllegalMonitorStateException if not locked
+ */
+ public void testGetWaitQueueLengthIMSE() { testGetWaitQueueLengthIMSE(false); }
+ public void testGetWaitQueueLengthIMSE_fair() { testGetWaitQueueLengthIMSE(true); }
+ public void testGetWaitQueueLengthIMSE(boolean fair) {
+ final ReentrantLock lock = new ReentrantLock(fair);
+ final Condition c = lock.newCondition();
+ try {
+ lock.getWaitQueueLength(c);
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {}
+ }
+
+ /**
+ * getWaitingThreads throws IllegalArgumentException if not owned
+ */
+ public void testGetWaitingThreadsIAE() { testGetWaitingThreadsIAE(false); }
+ public void testGetWaitingThreadsIAE_fair() { testGetWaitingThreadsIAE(true); }
+ public void testGetWaitingThreadsIAE(boolean fair) {
+ final PublicReentrantLock lock = new PublicReentrantLock(fair);
+ final Condition c = lock.newCondition();
+ final PublicReentrantLock lock2 = new PublicReentrantLock(fair);
+ try {
+ lock2.getWaitingThreads(c);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * getWaitingThreads throws IllegalMonitorStateException if not locked
+ */
+ public void testGetWaitingThreadsIMSE() { testGetWaitingThreadsIMSE(false); }
+ public void testGetWaitingThreadsIMSE_fair() { testGetWaitingThreadsIMSE(true); }
+ public void testGetWaitingThreadsIMSE(boolean fair) {
+ final PublicReentrantLock lock = new PublicReentrantLock(fair);
+ final Condition c = lock.newCondition();
+ try {
+ lock.getWaitingThreads(c);
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {}
+ }
+
+ /**
+ * hasWaiters returns true when a thread is waiting, else false
+ */
+ public void testHasWaiters() { testHasWaiters(false); }
+ public void testHasWaiters_fair() { testHasWaiters(true); }
+ public void testHasWaiters(boolean fair) {
+ final PublicReentrantLock lock = new PublicReentrantLock(fair);
+ final Condition c = lock.newCondition();
+ final CountDownLatch pleaseSignal = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.lock();
+ assertHasNoWaiters(lock, c);
+ assertFalse(lock.hasWaiters(c));
+ pleaseSignal.countDown();
+ c.await();
+ assertHasNoWaiters(lock, c);
+ assertFalse(lock.hasWaiters(c));
+ lock.unlock();
+ }});
+
+ await(pleaseSignal);
+ lock.lock();
+ assertHasWaiters(lock, c, t);
+ assertTrue(lock.hasWaiters(c));
+ c.signal();
+ assertHasNoWaiters(lock, c);
+ assertFalse(lock.hasWaiters(c));
+ lock.unlock();
+ awaitTermination(t);
+ assertHasNoWaiters(lock, c);
+ }
+
+ /**
+ * getWaitQueueLength returns number of waiting threads
+ */
+ public void testGetWaitQueueLength() { testGetWaitQueueLength(false); }
+ public void testGetWaitQueueLength_fair() { testGetWaitQueueLength(true); }
+ public void testGetWaitQueueLength(boolean fair) {
+ final PublicReentrantLock lock = new PublicReentrantLock(fair);
+ final Condition c = lock.newCondition();
+ final CountDownLatch locked1 = new CountDownLatch(1);
+ final CountDownLatch locked2 = new CountDownLatch(1);
+ Thread t1 = new Thread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.lock();
+ assertFalse(lock.hasWaiters(c));
+ assertEquals(0, lock.getWaitQueueLength(c));
+ locked1.countDown();
+ c.await();
+ lock.unlock();
+ }});
+
+ Thread t2 = new Thread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.lock();
+ assertTrue(lock.hasWaiters(c));
+ assertEquals(1, lock.getWaitQueueLength(c));
+ locked2.countDown();
+ c.await();
+ lock.unlock();
+ }});
+
+ lock.lock();
+ assertEquals(0, lock.getWaitQueueLength(c));
+ lock.unlock();
+
+ t1.start();
+ await(locked1);
+
+ lock.lock();
+ assertHasWaiters(lock, c, t1);
+ assertEquals(1, lock.getWaitQueueLength(c));
+ lock.unlock();
+
+ t2.start();
+ await(locked2);
+
+ lock.lock();
+ assertHasWaiters(lock, c, t1, t2);
+ assertEquals(2, lock.getWaitQueueLength(c));
+ c.signalAll();
+ assertHasNoWaiters(lock, c);
+ lock.unlock();
+
+ awaitTermination(t1);
+ awaitTermination(t2);
+
+ assertHasNoWaiters(lock, c);
+ }
+
+ /**
+ * getWaitingThreads returns only and all waiting threads
+ */
+ public void testGetWaitingThreads() { testGetWaitingThreads(false); }
+ public void testGetWaitingThreads_fair() { testGetWaitingThreads(true); }
+ public void testGetWaitingThreads(boolean fair) {
+ final PublicReentrantLock lock = new PublicReentrantLock(fair);
+ final Condition c = lock.newCondition();
+ final CountDownLatch locked1 = new CountDownLatch(1);
+ final CountDownLatch locked2 = new CountDownLatch(1);
+ Thread t1 = new Thread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.lock();
+ assertTrue(lock.getWaitingThreads(c).isEmpty());
+ locked1.countDown();
+ c.await();
+ lock.unlock();
+ }});
+
+ Thread t2 = new Thread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.lock();
+ assertFalse(lock.getWaitingThreads(c).isEmpty());
+ locked2.countDown();
+ c.await();
+ lock.unlock();
+ }});
+
+ lock.lock();
+ assertTrue(lock.getWaitingThreads(c).isEmpty());
+ lock.unlock();
+
+ t1.start();
+ await(locked1);
+
+ lock.lock();
+ assertHasWaiters(lock, c, t1);
+ assertTrue(lock.getWaitingThreads(c).contains(t1));
+ assertFalse(lock.getWaitingThreads(c).contains(t2));
+ assertEquals(1, lock.getWaitingThreads(c).size());
+ lock.unlock();
+
+ t2.start();
+ await(locked2);
+
+ lock.lock();
+ assertHasWaiters(lock, c, t1, t2);
+ assertTrue(lock.getWaitingThreads(c).contains(t1));
+ assertTrue(lock.getWaitingThreads(c).contains(t2));
+ assertEquals(2, lock.getWaitingThreads(c).size());
+ c.signalAll();
+ assertHasNoWaiters(lock, c);
+ lock.unlock();
+
+ awaitTermination(t1);
+ awaitTermination(t2);
+
+ assertHasNoWaiters(lock, c);
+ }
+
+ /**
+ * awaitUninterruptibly is uninterruptible
+ */
+ public void testAwaitUninterruptibly() { testAwaitUninterruptibly(false); }
+ public void testAwaitUninterruptibly_fair() { testAwaitUninterruptibly(true); }
+ public void testAwaitUninterruptibly(boolean fair) {
+ final ReentrantLock lock = new ReentrantLock(fair);
+ final Condition c = lock.newCondition();
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(2);
+
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ // Interrupt before awaitUninterruptibly
+ lock.lock();
+ pleaseInterrupt.countDown();
+ Thread.currentThread().interrupt();
+ c.awaitUninterruptibly();
+ assertTrue(Thread.interrupted());
+ lock.unlock();
+ }});
+
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ // Interrupt during awaitUninterruptibly
+ lock.lock();
+ pleaseInterrupt.countDown();
+ c.awaitUninterruptibly();
+ assertTrue(Thread.interrupted());
+ lock.unlock();
+ }});
+
+ await(pleaseInterrupt);
+ lock.lock();
+ lock.unlock();
+ t2.interrupt();
+
+ assertThreadStaysAlive(t1);
+ assertTrue(t2.isAlive());
+
+ lock.lock();
+ c.signalAll();
+ lock.unlock();
+
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * await/awaitNanos/awaitUntil is interruptible
+ */
+ public void testInterruptible_await() { testInterruptible(false, AwaitMethod.await); }
+ public void testInterruptible_await_fair() { testInterruptible(true, AwaitMethod.await); }
+ public void testInterruptible_awaitTimed() { testInterruptible(false, AwaitMethod.awaitTimed); }
+ public void testInterruptible_awaitTimed_fair() { testInterruptible(true, AwaitMethod.awaitTimed); }
+ public void testInterruptible_awaitNanos() { testInterruptible(false, AwaitMethod.awaitNanos); }
+ public void testInterruptible_awaitNanos_fair() { testInterruptible(true, AwaitMethod.awaitNanos); }
+ public void testInterruptible_awaitUntil() { testInterruptible(false, AwaitMethod.awaitUntil); }
+ public void testInterruptible_awaitUntil_fair() { testInterruptible(true, AwaitMethod.awaitUntil); }
+ public void testInterruptible(boolean fair, final AwaitMethod awaitMethod) {
+ final PublicReentrantLock lock =
+ new PublicReentrantLock(fair);
+ final Condition c = lock.newCondition();
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.lock();
+ assertLockedByMoi(lock);
+ assertHasNoWaiters(lock, c);
+ pleaseInterrupt.countDown();
+ try {
+ await(c, awaitMethod);
+ } finally {
+ assertLockedByMoi(lock);
+ assertHasNoWaiters(lock, c);
+ lock.unlock();
+ assertFalse(Thread.interrupted());
+ }
+ }});
+
+ await(pleaseInterrupt);
+ assertHasWaiters(lock, c, t);
+ t.interrupt();
+ awaitTermination(t);
+ assertNotLocked(lock);
+ }
+
+ /**
+ * signalAll wakes up all threads
+ */
+ public void testSignalAll_await() { testSignalAll(false, AwaitMethod.await); }
+ public void testSignalAll_await_fair() { testSignalAll(true, AwaitMethod.await); }
+ public void testSignalAll_awaitTimed() { testSignalAll(false, AwaitMethod.awaitTimed); }
+ public void testSignalAll_awaitTimed_fair() { testSignalAll(true, AwaitMethod.awaitTimed); }
+ public void testSignalAll_awaitNanos() { testSignalAll(false, AwaitMethod.awaitNanos); }
+ public void testSignalAll_awaitNanos_fair() { testSignalAll(true, AwaitMethod.awaitNanos); }
+ public void testSignalAll_awaitUntil() { testSignalAll(false, AwaitMethod.awaitUntil); }
+ public void testSignalAll_awaitUntil_fair() { testSignalAll(true, AwaitMethod.awaitUntil); }
+ public void testSignalAll(boolean fair, final AwaitMethod awaitMethod) {
+ final PublicReentrantLock lock = new PublicReentrantLock(fair);
+ final Condition c = lock.newCondition();
+ final CountDownLatch pleaseSignal = new CountDownLatch(2);
+ class Awaiter extends CheckedRunnable {
+ public void realRun() throws InterruptedException {
+ lock.lock();
+ pleaseSignal.countDown();
+ await(c, awaitMethod);
+ lock.unlock();
+ }
+ }
+
+ Thread t1 = newStartedThread(new Awaiter());
+ Thread t2 = newStartedThread(new Awaiter());
+
+ await(pleaseSignal);
+ lock.lock();
+ assertHasWaiters(lock, c, t1, t2);
+ c.signalAll();
+ assertHasNoWaiters(lock, c);
+ lock.unlock();
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * signal wakes up waiting threads in FIFO order
+ */
+ public void testSignalWakesFifo() { testSignalWakesFifo(false); }
+ public void testSignalWakesFifo_fair() { testSignalWakesFifo(true); }
+ public void testSignalWakesFifo(boolean fair) {
+ final PublicReentrantLock lock =
+ new PublicReentrantLock(fair);
+ final Condition c = lock.newCondition();
+ final CountDownLatch locked1 = new CountDownLatch(1);
+ final CountDownLatch locked2 = new CountDownLatch(1);
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.lock();
+ locked1.countDown();
+ c.await();
+ lock.unlock();
+ }});
+
+ await(locked1);
+
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.lock();
+ locked2.countDown();
+ c.await();
+ lock.unlock();
+ }});
+
+ await(locked2);
+
+ lock.lock();
+ assertHasWaiters(lock, c, t1, t2);
+ assertFalse(lock.hasQueuedThreads());
+ c.signal();
+ assertHasWaiters(lock, c, t2);
+ assertTrue(lock.hasQueuedThread(t1));
+ assertFalse(lock.hasQueuedThread(t2));
+ c.signal();
+ assertHasNoWaiters(lock, c);
+ assertTrue(lock.hasQueuedThread(t1));
+ assertTrue(lock.hasQueuedThread(t2));
+ lock.unlock();
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * await after multiple reentrant locking preserves lock count
+ */
+ public void testAwaitLockCount() { testAwaitLockCount(false); }
+ public void testAwaitLockCount_fair() { testAwaitLockCount(true); }
+ public void testAwaitLockCount(boolean fair) {
+ final PublicReentrantLock lock = new PublicReentrantLock(fair);
+ final Condition c = lock.newCondition();
+ final CountDownLatch pleaseSignal = new CountDownLatch(2);
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.lock();
+ assertLockedByMoi(lock);
+ assertEquals(1, lock.getHoldCount());
+ pleaseSignal.countDown();
+ c.await();
+ assertLockedByMoi(lock);
+ assertEquals(1, lock.getHoldCount());
+ lock.unlock();
+ }});
+
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.lock();
+ lock.lock();
+ assertLockedByMoi(lock);
+ assertEquals(2, lock.getHoldCount());
+ pleaseSignal.countDown();
+ c.await();
+ assertLockedByMoi(lock);
+ assertEquals(2, lock.getHoldCount());
+ lock.unlock();
+ lock.unlock();
+ }});
+
+ await(pleaseSignal);
+ lock.lock();
+ assertHasWaiters(lock, c, t1, t2);
+ assertEquals(1, lock.getHoldCount());
+ c.signalAll();
+ assertHasNoWaiters(lock, c);
+ lock.unlock();
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * A serialized lock deserializes as unlocked
+ */
+ public void testSerialization() { testSerialization(false); }
+ public void testSerialization_fair() { testSerialization(true); }
+ public void testSerialization(boolean fair) {
+ ReentrantLock lock = new ReentrantLock(fair);
+ lock.lock();
+
+ ReentrantLock clone = serialClone(lock);
+ assertEquals(lock.isFair(), clone.isFair());
+ assertTrue(lock.isLocked());
+ assertFalse(clone.isLocked());
+ assertEquals(1, lock.getHoldCount());
+ assertEquals(0, clone.getHoldCount());
+ clone.lock();
+ clone.lock();
+ assertTrue(clone.isLocked());
+ assertEquals(2, clone.getHoldCount());
+ assertEquals(1, lock.getHoldCount());
+ clone.unlock();
+ clone.unlock();
+ assertTrue(lock.isLocked());
+ assertFalse(clone.isLocked());
+ }
+
+ /**
+ * toString indicates current lock state
+ */
+ public void testToString() { testToString(false); }
+ public void testToString_fair() { testToString(true); }
+ public void testToString(boolean fair) {
+ ReentrantLock lock = new ReentrantLock(fair);
+ assertTrue(lock.toString().contains("Unlocked"));
+ lock.lock();
+ assertTrue(lock.toString().contains("Locked"));
+ lock.unlock();
+ assertTrue(lock.toString().contains("Unlocked"));
+ }
+}
diff --git a/jsr166-tests/src/test/java/jsr166/ReentrantReadWriteLockTest.java b/jsr166-tests/src/test/java/jsr166/ReentrantReadWriteLockTest.java
new file mode 100644
index 0000000..2be27d2
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/ReentrantReadWriteLockTest.java
@@ -0,0 +1,1670 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.CountDownLatch;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import java.util.*;
+
+public class ReentrantReadWriteLockTest extends JSR166TestCase {
+
+ /**
+ * A runnable calling lockInterruptibly
+ */
+ class InterruptibleLockRunnable extends CheckedRunnable {
+ final ReentrantReadWriteLock lock;
+ InterruptibleLockRunnable(ReentrantReadWriteLock l) { lock = l; }
+ public void realRun() throws InterruptedException {
+ lock.writeLock().lockInterruptibly();
+ }
+ }
+
+ /**
+ * A runnable calling lockInterruptibly that expects to be
+ * interrupted
+ */
+ class InterruptedLockRunnable extends CheckedInterruptedRunnable {
+ final ReentrantReadWriteLock lock;
+ InterruptedLockRunnable(ReentrantReadWriteLock l) { lock = l; }
+ public void realRun() throws InterruptedException {
+ lock.writeLock().lockInterruptibly();
+ }
+ }
+
+ /**
+ * Subclass to expose protected methods
+ */
+ static class PublicReentrantReadWriteLock extends ReentrantReadWriteLock {
+ PublicReentrantReadWriteLock() { super(); }
+ PublicReentrantReadWriteLock(boolean fair) { super(fair); }
+ public Thread getOwner() {
+ return super.getOwner();
+ }
+ public Collection<Thread> getQueuedThreads() {
+ return super.getQueuedThreads();
+ }
+ public Collection<Thread> getWaitingThreads(Condition c) {
+ return super.getWaitingThreads(c);
+ }
+ }
+
+ /**
+ * Releases write lock, checking that it had a hold count of 1.
+ */
+ void releaseWriteLock(PublicReentrantReadWriteLock lock) {
+ ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
+ assertWriteLockedByMoi(lock);
+ assertEquals(1, lock.getWriteHoldCount());
+ writeLock.unlock();
+ assertNotWriteLocked(lock);
+ }
+
+ /**
+ * Spin-waits until lock.hasQueuedThread(t) becomes true.
+ */
+ void waitForQueuedThread(PublicReentrantReadWriteLock lock, Thread t) {
+ long startTime = System.nanoTime();
+ while (!lock.hasQueuedThread(t)) {
+ if (millisElapsedSince(startTime) > LONG_DELAY_MS)
+ throw new AssertionFailedError("timed out");
+ Thread.yield();
+ }
+ assertTrue(t.isAlive());
+ assertNotSame(t, lock.getOwner());
+ }
+
+ /**
+ * Checks that lock is not write-locked.
+ */
+ void assertNotWriteLocked(PublicReentrantReadWriteLock lock) {
+ assertFalse(lock.isWriteLocked());
+ assertFalse(lock.isWriteLockedByCurrentThread());
+ assertFalse(lock.writeLock().isHeldByCurrentThread());
+ assertEquals(0, lock.getWriteHoldCount());
+ assertEquals(0, lock.writeLock().getHoldCount());
+ assertNull(lock.getOwner());
+ }
+
+ /**
+ * Checks that lock is write-locked by the given thread.
+ */
+ void assertWriteLockedBy(PublicReentrantReadWriteLock lock, Thread t) {
+ assertTrue(lock.isWriteLocked());
+ assertSame(t, lock.getOwner());
+ assertEquals(t == Thread.currentThread(),
+ lock.isWriteLockedByCurrentThread());
+ assertEquals(t == Thread.currentThread(),
+ lock.writeLock().isHeldByCurrentThread());
+ assertEquals(t == Thread.currentThread(),
+ lock.getWriteHoldCount() > 0);
+ assertEquals(t == Thread.currentThread(),
+ lock.writeLock().getHoldCount() > 0);
+ assertEquals(0, lock.getReadLockCount());
+ }
+
+ /**
+ * Checks that lock is write-locked by the current thread.
+ */
+ void assertWriteLockedByMoi(PublicReentrantReadWriteLock lock) {
+ assertWriteLockedBy(lock, Thread.currentThread());
+ }
+
+ /**
+ * Checks that condition c has no waiters.
+ */
+ void assertHasNoWaiters(PublicReentrantReadWriteLock lock, Condition c) {
+ assertHasWaiters(lock, c, new Thread[] {});
+ }
+
+ /**
+ * Checks that condition c has exactly the given waiter threads.
+ */
+ void assertHasWaiters(PublicReentrantReadWriteLock lock, Condition c,
+ Thread... threads) {
+ lock.writeLock().lock();
+ assertEquals(threads.length > 0, lock.hasWaiters(c));
+ assertEquals(threads.length, lock.getWaitQueueLength(c));
+ assertEquals(threads.length == 0, lock.getWaitingThreads(c).isEmpty());
+ assertEquals(threads.length, lock.getWaitingThreads(c).size());
+ assertEquals(new HashSet<Thread>(lock.getWaitingThreads(c)),
+ new HashSet<Thread>(Arrays.asList(threads)));
+ lock.writeLock().unlock();
+ }
+
+ enum AwaitMethod { await, awaitTimed, awaitNanos, awaitUntil };
+
+ /**
+ * Awaits condition using the specified AwaitMethod.
+ */
+ void await(Condition c, AwaitMethod awaitMethod)
+ throws InterruptedException {
+ switch (awaitMethod) {
+ case await:
+ c.await();
+ break;
+ case awaitTimed:
+ assertTrue(c.await(2 * LONG_DELAY_MS, MILLISECONDS));
+ break;
+ case awaitNanos:
+ long nanosRemaining = c.awaitNanos(MILLISECONDS.toNanos(2 * LONG_DELAY_MS));
+ assertTrue(nanosRemaining > 0);
+ break;
+ case awaitUntil:
+ java.util.Date d = new java.util.Date();
+ assertTrue(c.awaitUntil(new java.util.Date(d.getTime() + 2 * LONG_DELAY_MS)));
+ break;
+ }
+ }
+
+ /**
+ * Constructor sets given fairness, and is in unlocked state
+ */
+ public void testConstructor() {
+ PublicReentrantReadWriteLock lock;
+
+ lock = new PublicReentrantReadWriteLock();
+ assertFalse(lock.isFair());
+ assertNotWriteLocked(lock);
+ assertEquals(0, lock.getReadLockCount());
+
+ lock = new PublicReentrantReadWriteLock(true);
+ assertTrue(lock.isFair());
+ assertNotWriteLocked(lock);
+ assertEquals(0, lock.getReadLockCount());
+
+ lock = new PublicReentrantReadWriteLock(false);
+ assertFalse(lock.isFair());
+ assertNotWriteLocked(lock);
+ assertEquals(0, lock.getReadLockCount());
+ }
+
+ /**
+ * write-locking and read-locking an unlocked lock succeed
+ */
+ public void testLock() { testLock(false); }
+ public void testLock_fair() { testLock(true); }
+ public void testLock(boolean fair) {
+ PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ assertNotWriteLocked(lock);
+ lock.writeLock().lock();
+ assertWriteLockedByMoi(lock);
+ lock.writeLock().unlock();
+ assertNotWriteLocked(lock);
+ assertEquals(0, lock.getReadLockCount());
+ lock.readLock().lock();
+ assertNotWriteLocked(lock);
+ assertEquals(1, lock.getReadLockCount());
+ lock.readLock().unlock();
+ assertNotWriteLocked(lock);
+ assertEquals(0, lock.getReadLockCount());
+ }
+
+ /**
+ * getWriteHoldCount returns number of recursive holds
+ */
+ public void testGetWriteHoldCount() { testGetWriteHoldCount(false); }
+ public void testGetWriteHoldCount_fair() { testGetWriteHoldCount(true); }
+ public void testGetWriteHoldCount(boolean fair) {
+ ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ for (int i = 1; i <= SIZE; i++) {
+ lock.writeLock().lock();
+ assertEquals(i,lock.getWriteHoldCount());
+ }
+ for (int i = SIZE; i > 0; i--) {
+ lock.writeLock().unlock();
+ assertEquals(i-1,lock.getWriteHoldCount());
+ }
+ }
+
+ /**
+ * writelock.getHoldCount returns number of recursive holds
+ */
+ public void testGetHoldCount() { testGetHoldCount(false); }
+ public void testGetHoldCount_fair() { testGetHoldCount(true); }
+ public void testGetHoldCount(boolean fair) {
+ ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ for (int i = 1; i <= SIZE; i++) {
+ lock.writeLock().lock();
+ assertEquals(i,lock.writeLock().getHoldCount());
+ }
+ for (int i = SIZE; i > 0; i--) {
+ lock.writeLock().unlock();
+ assertEquals(i-1,lock.writeLock().getHoldCount());
+ }
+ }
+
+ /**
+ * getReadHoldCount returns number of recursive holds
+ */
+ public void testGetReadHoldCount() { testGetReadHoldCount(false); }
+ public void testGetReadHoldCount_fair() { testGetReadHoldCount(true); }
+ public void testGetReadHoldCount(boolean fair) {
+ ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ for (int i = 1; i <= SIZE; i++) {
+ lock.readLock().lock();
+ assertEquals(i,lock.getReadHoldCount());
+ }
+ for (int i = SIZE; i > 0; i--) {
+ lock.readLock().unlock();
+ assertEquals(i-1,lock.getReadHoldCount());
+ }
+ }
+
+ /**
+ * write-unlocking an unlocked lock throws IllegalMonitorStateException
+ */
+ public void testWriteUnlock_IMSE() { testWriteUnlock_IMSE(false); }
+ public void testWriteUnlock_IMSE_fair() { testWriteUnlock_IMSE(true); }
+ public void testWriteUnlock_IMSE(boolean fair) {
+ ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ try {
+ lock.writeLock().unlock();
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {}
+ }
+
+ /**
+ * read-unlocking an unlocked lock throws IllegalMonitorStateException
+ */
+ public void testReadUnlock_IMSE() { testReadUnlock_IMSE(false); }
+ public void testReadUnlock_IMSE_fair() { testReadUnlock_IMSE(true); }
+ public void testReadUnlock_IMSE(boolean fair) {
+ ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ try {
+ lock.readLock().unlock();
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {}
+ }
+
+ /**
+ * write-lockInterruptibly is interruptible
+ */
+ public void testWriteLockInterruptibly_Interruptible() { testWriteLockInterruptibly_Interruptible(false); }
+ public void testWriteLockInterruptibly_Interruptible_fair() { testWriteLockInterruptibly_Interruptible(true); }
+ public void testWriteLockInterruptibly_Interruptible(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ lock.writeLock().lock();
+ Thread t = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.writeLock().lockInterruptibly();
+ }});
+
+ waitForQueuedThread(lock, t);
+ t.interrupt();
+ awaitTermination(t);
+ releaseWriteLock(lock);
+ }
+
+ /**
+ * timed write-tryLock is interruptible
+ */
+ public void testWriteTryLock_Interruptible() { testWriteTryLock_Interruptible(false); }
+ public void testWriteTryLock_Interruptible_fair() { testWriteTryLock_Interruptible(true); }
+ public void testWriteTryLock_Interruptible(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ lock.writeLock().lock();
+ Thread t = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.writeLock().tryLock(2 * LONG_DELAY_MS, MILLISECONDS);
+ }});
+
+ waitForQueuedThread(lock, t);
+ t.interrupt();
+ awaitTermination(t);
+ releaseWriteLock(lock);
+ }
+
+ /**
+ * read-lockInterruptibly is interruptible
+ */
+ public void testReadLockInterruptibly_Interruptible() { testReadLockInterruptibly_Interruptible(false); }
+ public void testReadLockInterruptibly_Interruptible_fair() { testReadLockInterruptibly_Interruptible(true); }
+ public void testReadLockInterruptibly_Interruptible(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ lock.writeLock().lock();
+ Thread t = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.readLock().lockInterruptibly();
+ }});
+
+ waitForQueuedThread(lock, t);
+ t.interrupt();
+ awaitTermination(t);
+ releaseWriteLock(lock);
+ }
+
+ /**
+ * timed read-tryLock is interruptible
+ */
+ public void testReadTryLock_Interruptible() { testReadTryLock_Interruptible(false); }
+ public void testReadTryLock_Interruptible_fair() { testReadTryLock_Interruptible(true); }
+ public void testReadTryLock_Interruptible(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ lock.writeLock().lock();
+ Thread t = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.readLock().tryLock(2 * LONG_DELAY_MS, MILLISECONDS);
+ }});
+
+ waitForQueuedThread(lock, t);
+ t.interrupt();
+ awaitTermination(t);
+ releaseWriteLock(lock);
+ }
+
+ /**
+ * write-tryLock on an unlocked lock succeeds
+ */
+ public void testWriteTryLock() { testWriteTryLock(false); }
+ public void testWriteTryLock_fair() { testWriteTryLock(true); }
+ public void testWriteTryLock(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ assertTrue(lock.writeLock().tryLock());
+ assertWriteLockedByMoi(lock);
+ assertTrue(lock.writeLock().tryLock());
+ assertWriteLockedByMoi(lock);
+ lock.writeLock().unlock();
+ releaseWriteLock(lock);
+ }
+
+ /**
+ * write-tryLock fails if locked
+ */
+ public void testWriteTryLockWhenLocked() { testWriteTryLockWhenLocked(false); }
+ public void testWriteTryLockWhenLocked_fair() { testWriteTryLockWhenLocked(true); }
+ public void testWriteTryLockWhenLocked(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ lock.writeLock().lock();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ assertFalse(lock.writeLock().tryLock());
+ }});
+
+ awaitTermination(t);
+ releaseWriteLock(lock);
+ }
+
+ /**
+ * read-tryLock fails if locked
+ */
+ public void testReadTryLockWhenLocked() { testReadTryLockWhenLocked(false); }
+ public void testReadTryLockWhenLocked_fair() { testReadTryLockWhenLocked(true); }
+ public void testReadTryLockWhenLocked(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ lock.writeLock().lock();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ assertFalse(lock.readLock().tryLock());
+ }});
+
+ awaitTermination(t);
+ releaseWriteLock(lock);
+ }
+
+ /**
+ * Multiple threads can hold a read lock when not write-locked
+ */
+ public void testMultipleReadLocks() { testMultipleReadLocks(false); }
+ public void testMultipleReadLocks_fair() { testMultipleReadLocks(true); }
+ public void testMultipleReadLocks(boolean fair) {
+ final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ lock.readLock().lock();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertTrue(lock.readLock().tryLock());
+ lock.readLock().unlock();
+ assertTrue(lock.readLock().tryLock(LONG_DELAY_MS, MILLISECONDS));
+ lock.readLock().unlock();
+ lock.readLock().lock();
+ lock.readLock().unlock();
+ }});
+
+ awaitTermination(t);
+ lock.readLock().unlock();
+ }
+
+ /**
+ * A writelock succeeds only after a reading thread unlocks
+ */
+ public void testWriteAfterReadLock() { testWriteAfterReadLock(false); }
+ public void testWriteAfterReadLock_fair() { testWriteAfterReadLock(true); }
+ public void testWriteAfterReadLock(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ lock.readLock().lock();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ assertEquals(1, lock.getReadLockCount());
+ lock.writeLock().lock();
+ assertEquals(0, lock.getReadLockCount());
+ lock.writeLock().unlock();
+ }});
+ waitForQueuedThread(lock, t);
+ assertNotWriteLocked(lock);
+ assertEquals(1, lock.getReadLockCount());
+ lock.readLock().unlock();
+ assertEquals(0, lock.getReadLockCount());
+ awaitTermination(t);
+ assertNotWriteLocked(lock);
+ }
+
+ /**
+ * A writelock succeeds only after reading threads unlock
+ */
+ public void testWriteAfterMultipleReadLocks() { testWriteAfterMultipleReadLocks(false); }
+ public void testWriteAfterMultipleReadLocks_fair() { testWriteAfterMultipleReadLocks(true); }
+ public void testWriteAfterMultipleReadLocks(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ lock.readLock().lock();
+ lock.readLock().lock();
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ lock.readLock().lock();
+ assertEquals(3, lock.getReadLockCount());
+ lock.readLock().unlock();
+ }});
+ awaitTermination(t1);
+
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ assertEquals(2, lock.getReadLockCount());
+ lock.writeLock().lock();
+ assertEquals(0, lock.getReadLockCount());
+ lock.writeLock().unlock();
+ }});
+ waitForQueuedThread(lock, t2);
+ assertNotWriteLocked(lock);
+ assertEquals(2, lock.getReadLockCount());
+ lock.readLock().unlock();
+ lock.readLock().unlock();
+ assertEquals(0, lock.getReadLockCount());
+ awaitTermination(t2);
+ assertNotWriteLocked(lock);
+ }
+
+ /**
+ * A thread that tries to acquire a fair read lock (non-reentrantly)
+ * will block if there is a waiting writer thread
+ */
+ public void testReaderWriterReaderFairFifo() {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(true);
+ final AtomicBoolean t1GotLock = new AtomicBoolean(false);
+
+ lock.readLock().lock();
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ assertEquals(1, lock.getReadLockCount());
+ lock.writeLock().lock();
+ assertEquals(0, lock.getReadLockCount());
+ t1GotLock.set(true);
+ lock.writeLock().unlock();
+ }});
+ waitForQueuedThread(lock, t1);
+
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ assertEquals(1, lock.getReadLockCount());
+ lock.readLock().lock();
+ assertEquals(1, lock.getReadLockCount());
+ assertTrue(t1GotLock.get());
+ lock.readLock().unlock();
+ }});
+ waitForQueuedThread(lock, t2);
+ assertTrue(t1.isAlive());
+ assertNotWriteLocked(lock);
+ assertEquals(1, lock.getReadLockCount());
+ lock.readLock().unlock();
+ awaitTermination(t1);
+ awaitTermination(t2);
+ assertNotWriteLocked(lock);
+ }
+
+ /**
+ * Readlocks succeed only after a writing thread unlocks
+ */
+ public void testReadAfterWriteLock() { testReadAfterWriteLock(false); }
+ public void testReadAfterWriteLock_fair() { testReadAfterWriteLock(true); }
+ public void testReadAfterWriteLock(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ lock.writeLock().lock();
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ lock.readLock().lock();
+ lock.readLock().unlock();
+ }});
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ lock.readLock().lock();
+ lock.readLock().unlock();
+ }});
+
+ waitForQueuedThread(lock, t1);
+ waitForQueuedThread(lock, t2);
+ releaseWriteLock(lock);
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * Read trylock succeeds if write locked by current thread
+ */
+ public void testReadHoldingWriteLock() { testReadHoldingWriteLock(false); }
+ public void testReadHoldingWriteLock_fair() { testReadHoldingWriteLock(true); }
+ public void testReadHoldingWriteLock(boolean fair) {
+ final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ lock.writeLock().lock();
+ assertTrue(lock.readLock().tryLock());
+ lock.readLock().unlock();
+ lock.writeLock().unlock();
+ }
+
+ /**
+ * Read trylock succeeds (barging) even in the presence of waiting
+ * readers and/or writers
+ */
+ public void testReadTryLockBarging() { testReadTryLockBarging(false); }
+ public void testReadTryLockBarging_fair() { testReadTryLockBarging(true); }
+ public void testReadTryLockBarging(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ lock.readLock().lock();
+
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ lock.writeLock().lock();
+ lock.writeLock().unlock();
+ }});
+
+ waitForQueuedThread(lock, t1);
+
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ lock.readLock().lock();
+ lock.readLock().unlock();
+ }});
+
+ if (fair)
+ waitForQueuedThread(lock, t2);
+
+ Thread t3 = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ lock.readLock().tryLock();
+ lock.readLock().unlock();
+ }});
+
+ assertTrue(lock.getReadLockCount() > 0);
+ awaitTermination(t3);
+ assertTrue(t1.isAlive());
+ if (fair) assertTrue(t2.isAlive());
+ lock.readLock().unlock();
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * Read lock succeeds if write locked by current thread even if
+ * other threads are waiting for readlock
+ */
+ public void testReadHoldingWriteLock2() { testReadHoldingWriteLock2(false); }
+ public void testReadHoldingWriteLock2_fair() { testReadHoldingWriteLock2(true); }
+ public void testReadHoldingWriteLock2(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ lock.writeLock().lock();
+ lock.readLock().lock();
+ lock.readLock().unlock();
+
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ lock.readLock().lock();
+ lock.readLock().unlock();
+ }});
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ lock.readLock().lock();
+ lock.readLock().unlock();
+ }});
+
+ waitForQueuedThread(lock, t1);
+ waitForQueuedThread(lock, t2);
+ assertWriteLockedByMoi(lock);
+ lock.readLock().lock();
+ lock.readLock().unlock();
+ releaseWriteLock(lock);
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * Read lock succeeds if write locked by current thread even if
+ * other threads are waiting for writelock
+ */
+ public void testReadHoldingWriteLock3() { testReadHoldingWriteLock3(false); }
+ public void testReadHoldingWriteLock3_fair() { testReadHoldingWriteLock3(true); }
+ public void testReadHoldingWriteLock3(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ lock.writeLock().lock();
+ lock.readLock().lock();
+ lock.readLock().unlock();
+
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ lock.writeLock().lock();
+ lock.writeLock().unlock();
+ }});
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ lock.writeLock().lock();
+ lock.writeLock().unlock();
+ }});
+
+ waitForQueuedThread(lock, t1);
+ waitForQueuedThread(lock, t2);
+ assertWriteLockedByMoi(lock);
+ lock.readLock().lock();
+ lock.readLock().unlock();
+ assertWriteLockedByMoi(lock);
+ lock.writeLock().unlock();
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * Write lock succeeds if write locked by current thread even if
+ * other threads are waiting for writelock
+ */
+ public void testWriteHoldingWriteLock4() { testWriteHoldingWriteLock4(false); }
+ public void testWriteHoldingWriteLock4_fair() { testWriteHoldingWriteLock4(true); }
+ public void testWriteHoldingWriteLock4(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ lock.writeLock().lock();
+ lock.writeLock().lock();
+ lock.writeLock().unlock();
+
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ lock.writeLock().lock();
+ lock.writeLock().unlock();
+ }});
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ lock.writeLock().lock();
+ lock.writeLock().unlock();
+ }});
+
+ waitForQueuedThread(lock, t1);
+ waitForQueuedThread(lock, t2);
+ assertWriteLockedByMoi(lock);
+ assertEquals(1, lock.getWriteHoldCount());
+ lock.writeLock().lock();
+ assertWriteLockedByMoi(lock);
+ assertEquals(2, lock.getWriteHoldCount());
+ lock.writeLock().unlock();
+ assertWriteLockedByMoi(lock);
+ assertEquals(1, lock.getWriteHoldCount());
+ lock.writeLock().unlock();
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * Read tryLock succeeds if readlocked but not writelocked
+ */
+ public void testTryLockWhenReadLocked() { testTryLockWhenReadLocked(false); }
+ public void testTryLockWhenReadLocked_fair() { testTryLockWhenReadLocked(true); }
+ public void testTryLockWhenReadLocked(boolean fair) {
+ final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ lock.readLock().lock();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ assertTrue(lock.readLock().tryLock());
+ lock.readLock().unlock();
+ }});
+
+ awaitTermination(t);
+ lock.readLock().unlock();
+ }
+
+ /**
+ * write tryLock fails when readlocked
+ */
+ public void testWriteTryLockWhenReadLocked() { testWriteTryLockWhenReadLocked(false); }
+ public void testWriteTryLockWhenReadLocked_fair() { testWriteTryLockWhenReadLocked(true); }
+ public void testWriteTryLockWhenReadLocked(boolean fair) {
+ final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ lock.readLock().lock();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ assertFalse(lock.writeLock().tryLock());
+ }});
+
+ awaitTermination(t);
+ lock.readLock().unlock();
+ }
+
+ /**
+ * write timed tryLock times out if locked
+ */
+ public void testWriteTryLock_Timeout() { testWriteTryLock_Timeout(false); }
+ public void testWriteTryLock_Timeout_fair() { testWriteTryLock_Timeout(true); }
+ public void testWriteTryLock_Timeout(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ lock.writeLock().lock();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ long startTime = System.nanoTime();
+ long timeoutMillis = 10;
+ assertFalse(lock.writeLock().tryLock(timeoutMillis, MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
+ }});
+
+ awaitTermination(t);
+ releaseWriteLock(lock);
+ }
+
+ /**
+ * read timed tryLock times out if write-locked
+ */
+ public void testReadTryLock_Timeout() { testReadTryLock_Timeout(false); }
+ public void testReadTryLock_Timeout_fair() { testReadTryLock_Timeout(true); }
+ public void testReadTryLock_Timeout(boolean fair) {
+ final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ lock.writeLock().lock();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ long startTime = System.nanoTime();
+ long timeoutMillis = 10;
+ assertFalse(lock.readLock().tryLock(timeoutMillis, MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
+ }});
+
+ awaitTermination(t);
+ assertTrue(lock.writeLock().isHeldByCurrentThread());
+ lock.writeLock().unlock();
+ }
+
+ /**
+ * write lockInterruptibly succeeds if unlocked, else is interruptible
+ */
+ public void testWriteLockInterruptibly() { testWriteLockInterruptibly(false); }
+ public void testWriteLockInterruptibly_fair() { testWriteLockInterruptibly(true); }
+ public void testWriteLockInterruptibly(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ try {
+ lock.writeLock().lockInterruptibly();
+ } catch (InterruptedException ie) {
+ threadUnexpectedException(ie);
+ }
+ Thread t = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.writeLock().lockInterruptibly();
+ }});
+
+ waitForQueuedThread(lock, t);
+ t.interrupt();
+ assertTrue(lock.writeLock().isHeldByCurrentThread());
+ awaitTermination(t);
+ releaseWriteLock(lock);
+ }
+
+ /**
+ * read lockInterruptibly succeeds if lock free else is interruptible
+ */
+ public void testReadLockInterruptibly() { testReadLockInterruptibly(false); }
+ public void testReadLockInterruptibly_fair() { testReadLockInterruptibly(true); }
+ public void testReadLockInterruptibly(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ try {
+ lock.readLock().lockInterruptibly();
+ lock.readLock().unlock();
+ lock.writeLock().lockInterruptibly();
+ } catch (InterruptedException ie) {
+ threadUnexpectedException(ie);
+ }
+ Thread t = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.readLock().lockInterruptibly();
+ }});
+
+ waitForQueuedThread(lock, t);
+ t.interrupt();
+ awaitTermination(t);
+ releaseWriteLock(lock);
+ }
+
+ /**
+ * Calling await without holding lock throws IllegalMonitorStateException
+ */
+ public void testAwait_IMSE() { testAwait_IMSE(false); }
+ public void testAwait_IMSE_fair() { testAwait_IMSE(true); }
+ public void testAwait_IMSE(boolean fair) {
+ final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ final Condition c = lock.writeLock().newCondition();
+ for (AwaitMethod awaitMethod : AwaitMethod.values()) {
+ long startTime = System.nanoTime();
+ try {
+ await(c, awaitMethod);
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {
+ } catch (InterruptedException e) { threadUnexpectedException(e); }
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ }
+ }
+
+ /**
+ * Calling signal without holding lock throws IllegalMonitorStateException
+ */
+ public void testSignal_IMSE() { testSignal_IMSE(false); }
+ public void testSignal_IMSE_fair() { testSignal_IMSE(true); }
+ public void testSignal_IMSE(boolean fair) {
+ final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ final Condition c = lock.writeLock().newCondition();
+ try {
+ c.signal();
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {}
+ }
+
+ /**
+ * Calling signalAll without holding lock throws IllegalMonitorStateException
+ */
+ public void testSignalAll_IMSE() { testSignalAll_IMSE(false); }
+ public void testSignalAll_IMSE_fair() { testSignalAll_IMSE(true); }
+ public void testSignalAll_IMSE(boolean fair) {
+ final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ final Condition c = lock.writeLock().newCondition();
+ try {
+ c.signalAll();
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {}
+ }
+
+ /**
+ * awaitNanos without a signal times out
+ */
+ public void testAwaitNanos_Timeout() { testAwaitNanos_Timeout(false); }
+ public void testAwaitNanos_Timeout_fair() { testAwaitNanos_Timeout(true); }
+ public void testAwaitNanos_Timeout(boolean fair) {
+ try {
+ final ReentrantReadWriteLock lock =
+ new ReentrantReadWriteLock(fair);
+ final Condition c = lock.writeLock().newCondition();
+ lock.writeLock().lock();
+ long startTime = System.nanoTime();
+ long timeoutMillis = 10;
+ long timeoutNanos = MILLISECONDS.toNanos(timeoutMillis);
+ long nanosRemaining = c.awaitNanos(timeoutNanos);
+ assertTrue(nanosRemaining <= 0);
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
+ lock.writeLock().unlock();
+ } catch (InterruptedException e) {
+ threadUnexpectedException(e);
+ }
+ }
+
+ /**
+ * timed await without a signal times out
+ */
+ public void testAwait_Timeout() { testAwait_Timeout(false); }
+ public void testAwait_Timeout_fair() { testAwait_Timeout(true); }
+ public void testAwait_Timeout(boolean fair) {
+ try {
+ final ReentrantReadWriteLock lock =
+ new ReentrantReadWriteLock(fair);
+ final Condition c = lock.writeLock().newCondition();
+ lock.writeLock().lock();
+ long startTime = System.nanoTime();
+ long timeoutMillis = 10;
+ assertFalse(c.await(timeoutMillis, MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
+ lock.writeLock().unlock();
+ } catch (InterruptedException e) {
+ threadUnexpectedException(e);
+ }
+ }
+
+ /**
+ * awaitUntil without a signal times out
+ */
+ public void testAwaitUntil_Timeout() { testAwaitUntil_Timeout(false); }
+ public void testAwaitUntil_Timeout_fair() { testAwaitUntil_Timeout(true); }
+ public void testAwaitUntil_Timeout(boolean fair) {
+ try {
+ final ReentrantReadWriteLock lock =
+ new ReentrantReadWriteLock(fair);
+ final Condition c = lock.writeLock().newCondition();
+ lock.writeLock().lock();
+ long startTime = System.nanoTime();
+ long timeoutMillis = 10;
+ java.util.Date d = new java.util.Date();
+ assertFalse(c.awaitUntil(new java.util.Date(d.getTime() + timeoutMillis)));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
+ lock.writeLock().unlock();
+ } catch (InterruptedException e) {
+ threadUnexpectedException(e);
+ }
+ }
+
+ /**
+ * await returns when signalled
+ */
+ public void testAwait() { testAwait(false); }
+ public void testAwait_fair() { testAwait(true); }
+ public void testAwait(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ final Condition c = lock.writeLock().newCondition();
+ final CountDownLatch locked = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.writeLock().lock();
+ locked.countDown();
+ c.await();
+ lock.writeLock().unlock();
+ }});
+
+ await(locked);
+ lock.writeLock().lock();
+ assertHasWaiters(lock, c, t);
+ c.signal();
+ assertHasNoWaiters(lock, c);
+ assertTrue(t.isAlive());
+ lock.writeLock().unlock();
+ awaitTermination(t);
+ }
+
+ /**
+ * awaitUninterruptibly is uninterruptible
+ */
+ public void testAwaitUninterruptibly() { testAwaitUninterruptibly(false); }
+ public void testAwaitUninterruptibly_fair() { testAwaitUninterruptibly(true); }
+ public void testAwaitUninterruptibly(boolean fair) {
+ final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ final Condition c = lock.writeLock().newCondition();
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(2);
+
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ // Interrupt before awaitUninterruptibly
+ lock.writeLock().lock();
+ pleaseInterrupt.countDown();
+ Thread.currentThread().interrupt();
+ c.awaitUninterruptibly();
+ assertTrue(Thread.interrupted());
+ lock.writeLock().unlock();
+ }});
+
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ // Interrupt during awaitUninterruptibly
+ lock.writeLock().lock();
+ pleaseInterrupt.countDown();
+ c.awaitUninterruptibly();
+ assertTrue(Thread.interrupted());
+ lock.writeLock().unlock();
+ }});
+
+ await(pleaseInterrupt);
+ lock.writeLock().lock();
+ lock.writeLock().unlock();
+ t2.interrupt();
+
+ assertThreadStaysAlive(t1);
+ assertTrue(t2.isAlive());
+
+ lock.writeLock().lock();
+ c.signalAll();
+ lock.writeLock().unlock();
+
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * await/awaitNanos/awaitUntil is interruptible
+ */
+ public void testInterruptible_await() { testInterruptible(false, AwaitMethod.await); }
+ public void testInterruptible_await_fair() { testInterruptible(true, AwaitMethod.await); }
+ public void testInterruptible_awaitTimed() { testInterruptible(false, AwaitMethod.awaitTimed); }
+ public void testInterruptible_awaitTimed_fair() { testInterruptible(true, AwaitMethod.awaitTimed); }
+ public void testInterruptible_awaitNanos() { testInterruptible(false, AwaitMethod.awaitNanos); }
+ public void testInterruptible_awaitNanos_fair() { testInterruptible(true, AwaitMethod.awaitNanos); }
+ public void testInterruptible_awaitUntil() { testInterruptible(false, AwaitMethod.awaitUntil); }
+ public void testInterruptible_awaitUntil_fair() { testInterruptible(true, AwaitMethod.awaitUntil); }
+ public void testInterruptible(boolean fair, final AwaitMethod awaitMethod) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ final Condition c = lock.writeLock().newCondition();
+ final CountDownLatch locked = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.writeLock().lock();
+ assertWriteLockedByMoi(lock);
+ assertHasNoWaiters(lock, c);
+ locked.countDown();
+ try {
+ await(c, awaitMethod);
+ } finally {
+ assertWriteLockedByMoi(lock);
+ assertHasNoWaiters(lock, c);
+ lock.writeLock().unlock();
+ assertFalse(Thread.interrupted());
+ }
+ }});
+
+ await(locked);
+ assertHasWaiters(lock, c, t);
+ t.interrupt();
+ awaitTermination(t);
+ assertNotWriteLocked(lock);
+ }
+
+ /**
+ * signalAll wakes up all threads
+ */
+ public void testSignalAll_await() { testSignalAll(false, AwaitMethod.await); }
+ public void testSignalAll_await_fair() { testSignalAll(true, AwaitMethod.await); }
+ public void testSignalAll_awaitTimed() { testSignalAll(false, AwaitMethod.awaitTimed); }
+ public void testSignalAll_awaitTimed_fair() { testSignalAll(true, AwaitMethod.awaitTimed); }
+ public void testSignalAll_awaitNanos() { testSignalAll(false, AwaitMethod.awaitNanos); }
+ public void testSignalAll_awaitNanos_fair() { testSignalAll(true, AwaitMethod.awaitNanos); }
+ public void testSignalAll_awaitUntil() { testSignalAll(false, AwaitMethod.awaitUntil); }
+ public void testSignalAll_awaitUntil_fair() { testSignalAll(true, AwaitMethod.awaitUntil); }
+ public void testSignalAll(boolean fair, final AwaitMethod awaitMethod) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ final Condition c = lock.writeLock().newCondition();
+ final CountDownLatch locked = new CountDownLatch(2);
+ final Lock writeLock = lock.writeLock();
+ class Awaiter extends CheckedRunnable {
+ public void realRun() throws InterruptedException {
+ writeLock.lock();
+ locked.countDown();
+ await(c, awaitMethod);
+ writeLock.unlock();
+ }
+ }
+
+ Thread t1 = newStartedThread(new Awaiter());
+ Thread t2 = newStartedThread(new Awaiter());
+
+ await(locked);
+ writeLock.lock();
+ assertHasWaiters(lock, c, t1, t2);
+ c.signalAll();
+ assertHasNoWaiters(lock, c);
+ writeLock.unlock();
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * signal wakes up waiting threads in FIFO order
+ */
+ public void testSignalWakesFifo() { testSignalWakesFifo(false); }
+ public void testSignalWakesFifo_fair() { testSignalWakesFifo(true); }
+ public void testSignalWakesFifo(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ final Condition c = lock.writeLock().newCondition();
+ final CountDownLatch locked1 = new CountDownLatch(1);
+ final CountDownLatch locked2 = new CountDownLatch(1);
+ final Lock writeLock = lock.writeLock();
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ writeLock.lock();
+ locked1.countDown();
+ c.await();
+ writeLock.unlock();
+ }});
+
+ await(locked1);
+
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ writeLock.lock();
+ locked2.countDown();
+ c.await();
+ writeLock.unlock();
+ }});
+
+ await(locked2);
+
+ writeLock.lock();
+ assertHasWaiters(lock, c, t1, t2);
+ assertFalse(lock.hasQueuedThreads());
+ c.signal();
+ assertHasWaiters(lock, c, t2);
+ assertTrue(lock.hasQueuedThread(t1));
+ assertFalse(lock.hasQueuedThread(t2));
+ c.signal();
+ assertHasNoWaiters(lock, c);
+ assertTrue(lock.hasQueuedThread(t1));
+ assertTrue(lock.hasQueuedThread(t2));
+ writeLock.unlock();
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * await after multiple reentrant locking preserves lock count
+ */
+ public void testAwaitLockCount() { testAwaitLockCount(false); }
+ public void testAwaitLockCount_fair() { testAwaitLockCount(true); }
+ public void testAwaitLockCount(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ final Condition c = lock.writeLock().newCondition();
+ final CountDownLatch locked = new CountDownLatch(2);
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.writeLock().lock();
+ assertWriteLockedByMoi(lock);
+ assertEquals(1, lock.writeLock().getHoldCount());
+ locked.countDown();
+ c.await();
+ assertWriteLockedByMoi(lock);
+ assertEquals(1, lock.writeLock().getHoldCount());
+ lock.writeLock().unlock();
+ }});
+
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.writeLock().lock();
+ lock.writeLock().lock();
+ assertWriteLockedByMoi(lock);
+ assertEquals(2, lock.writeLock().getHoldCount());
+ locked.countDown();
+ c.await();
+ assertWriteLockedByMoi(lock);
+ assertEquals(2, lock.writeLock().getHoldCount());
+ lock.writeLock().unlock();
+ lock.writeLock().unlock();
+ }});
+
+ await(locked);
+ lock.writeLock().lock();
+ assertHasWaiters(lock, c, t1, t2);
+ c.signalAll();
+ assertHasNoWaiters(lock, c);
+ lock.writeLock().unlock();
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * A serialized lock deserializes as unlocked
+ */
+ public void testSerialization() { testSerialization(false); }
+ public void testSerialization_fair() { testSerialization(true); }
+ public void testSerialization(boolean fair) {
+ ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ lock.writeLock().lock();
+ lock.readLock().lock();
+
+ ReentrantReadWriteLock clone = serialClone(lock);
+ assertEquals(lock.isFair(), clone.isFair());
+ assertTrue(lock.isWriteLocked());
+ assertFalse(clone.isWriteLocked());
+ assertEquals(1, lock.getReadLockCount());
+ assertEquals(0, clone.getReadLockCount());
+ clone.writeLock().lock();
+ clone.readLock().lock();
+ assertTrue(clone.isWriteLocked());
+ assertEquals(1, clone.getReadLockCount());
+ clone.readLock().unlock();
+ clone.writeLock().unlock();
+ assertFalse(clone.isWriteLocked());
+ assertEquals(1, lock.getReadLockCount());
+ assertEquals(0, clone.getReadLockCount());
+ }
+
+ /**
+ * hasQueuedThreads reports whether there are waiting threads
+ */
+ public void testHasQueuedThreads() { testHasQueuedThreads(false); }
+ public void testHasQueuedThreads_fair() { testHasQueuedThreads(true); }
+ public void testHasQueuedThreads(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ Thread t1 = new Thread(new InterruptedLockRunnable(lock));
+ Thread t2 = new Thread(new InterruptibleLockRunnable(lock));
+ assertFalse(lock.hasQueuedThreads());
+ lock.writeLock().lock();
+ assertFalse(lock.hasQueuedThreads());
+ t1.start();
+ waitForQueuedThread(lock, t1);
+ assertTrue(lock.hasQueuedThreads());
+ t2.start();
+ waitForQueuedThread(lock, t2);
+ assertTrue(lock.hasQueuedThreads());
+ t1.interrupt();
+ awaitTermination(t1);
+ assertTrue(lock.hasQueuedThreads());
+ lock.writeLock().unlock();
+ awaitTermination(t2);
+ assertFalse(lock.hasQueuedThreads());
+ }
+
+ /**
+ * hasQueuedThread(null) throws NPE
+ */
+ public void testHasQueuedThreadNPE() { testHasQueuedThreadNPE(false); }
+ public void testHasQueuedThreadNPE_fair() { testHasQueuedThreadNPE(true); }
+ public void testHasQueuedThreadNPE(boolean fair) {
+ final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ try {
+ lock.hasQueuedThread(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * hasQueuedThread reports whether a thread is queued
+ */
+ public void testHasQueuedThread() { testHasQueuedThread(false); }
+ public void testHasQueuedThread_fair() { testHasQueuedThread(true); }
+ public void testHasQueuedThread(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ Thread t1 = new Thread(new InterruptedLockRunnable(lock));
+ Thread t2 = new Thread(new InterruptibleLockRunnable(lock));
+ assertFalse(lock.hasQueuedThread(t1));
+ assertFalse(lock.hasQueuedThread(t2));
+ lock.writeLock().lock();
+ t1.start();
+ waitForQueuedThread(lock, t1);
+ assertTrue(lock.hasQueuedThread(t1));
+ assertFalse(lock.hasQueuedThread(t2));
+ t2.start();
+ waitForQueuedThread(lock, t2);
+ assertTrue(lock.hasQueuedThread(t1));
+ assertTrue(lock.hasQueuedThread(t2));
+ t1.interrupt();
+ awaitTermination(t1);
+ assertFalse(lock.hasQueuedThread(t1));
+ assertTrue(lock.hasQueuedThread(t2));
+ lock.writeLock().unlock();
+ awaitTermination(t2);
+ assertFalse(lock.hasQueuedThread(t1));
+ assertFalse(lock.hasQueuedThread(t2));
+ }
+
+ /**
+ * getQueueLength reports number of waiting threads
+ */
+ public void testGetQueueLength() { testGetQueueLength(false); }
+ public void testGetQueueLength_fair() { testGetQueueLength(true); }
+ public void testGetQueueLength(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ Thread t1 = new Thread(new InterruptedLockRunnable(lock));
+ Thread t2 = new Thread(new InterruptibleLockRunnable(lock));
+ assertEquals(0, lock.getQueueLength());
+ lock.writeLock().lock();
+ t1.start();
+ waitForQueuedThread(lock, t1);
+ assertEquals(1, lock.getQueueLength());
+ t2.start();
+ waitForQueuedThread(lock, t2);
+ assertEquals(2, lock.getQueueLength());
+ t1.interrupt();
+ awaitTermination(t1);
+ assertEquals(1, lock.getQueueLength());
+ lock.writeLock().unlock();
+ awaitTermination(t2);
+ assertEquals(0, lock.getQueueLength());
+ }
+
+ /**
+ * getQueuedThreads includes waiting threads
+ */
+ public void testGetQueuedThreads() { testGetQueuedThreads(false); }
+ public void testGetQueuedThreads_fair() { testGetQueuedThreads(true); }
+ public void testGetQueuedThreads(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ Thread t1 = new Thread(new InterruptedLockRunnable(lock));
+ Thread t2 = new Thread(new InterruptibleLockRunnable(lock));
+ assertTrue(lock.getQueuedThreads().isEmpty());
+ lock.writeLock().lock();
+ assertTrue(lock.getQueuedThreads().isEmpty());
+ t1.start();
+ waitForQueuedThread(lock, t1);
+ assertEquals(1, lock.getQueuedThreads().size());
+ assertTrue(lock.getQueuedThreads().contains(t1));
+ t2.start();
+ waitForQueuedThread(lock, t2);
+ assertEquals(2, lock.getQueuedThreads().size());
+ assertTrue(lock.getQueuedThreads().contains(t1));
+ assertTrue(lock.getQueuedThreads().contains(t2));
+ t1.interrupt();
+ awaitTermination(t1);
+ assertFalse(lock.getQueuedThreads().contains(t1));
+ assertTrue(lock.getQueuedThreads().contains(t2));
+ assertEquals(1, lock.getQueuedThreads().size());
+ lock.writeLock().unlock();
+ awaitTermination(t2);
+ assertTrue(lock.getQueuedThreads().isEmpty());
+ }
+
+ /**
+ * hasWaiters throws NPE if null
+ */
+ public void testHasWaitersNPE() { testHasWaitersNPE(false); }
+ public void testHasWaitersNPE_fair() { testHasWaitersNPE(true); }
+ public void testHasWaitersNPE(boolean fair) {
+ final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ try {
+ lock.hasWaiters(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * getWaitQueueLength throws NPE if null
+ */
+ public void testGetWaitQueueLengthNPE() { testGetWaitQueueLengthNPE(false); }
+ public void testGetWaitQueueLengthNPE_fair() { testGetWaitQueueLengthNPE(true); }
+ public void testGetWaitQueueLengthNPE(boolean fair) {
+ final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ try {
+ lock.getWaitQueueLength(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * getWaitingThreads throws NPE if null
+ */
+ public void testGetWaitingThreadsNPE() { testGetWaitingThreadsNPE(false); }
+ public void testGetWaitingThreadsNPE_fair() { testGetWaitingThreadsNPE(true); }
+ public void testGetWaitingThreadsNPE(boolean fair) {
+ final PublicReentrantReadWriteLock lock = new PublicReentrantReadWriteLock(fair);
+ try {
+ lock.getWaitingThreads(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * hasWaiters throws IllegalArgumentException if not owned
+ */
+ public void testHasWaitersIAE() { testHasWaitersIAE(false); }
+ public void testHasWaitersIAE_fair() { testHasWaitersIAE(true); }
+ public void testHasWaitersIAE(boolean fair) {
+ final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ final Condition c = lock.writeLock().newCondition();
+ final ReentrantReadWriteLock lock2 = new ReentrantReadWriteLock(fair);
+ try {
+ lock2.hasWaiters(c);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * hasWaiters throws IllegalMonitorStateException if not locked
+ */
+ public void testHasWaitersIMSE() { testHasWaitersIMSE(false); }
+ public void testHasWaitersIMSE_fair() { testHasWaitersIMSE(true); }
+ public void testHasWaitersIMSE(boolean fair) {
+ final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ final Condition c = lock.writeLock().newCondition();
+ try {
+ lock.hasWaiters(c);
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {}
+ }
+
+ /**
+ * getWaitQueueLength throws IllegalArgumentException if not owned
+ */
+ public void testGetWaitQueueLengthIAE() { testGetWaitQueueLengthIAE(false); }
+ public void testGetWaitQueueLengthIAE_fair() { testGetWaitQueueLengthIAE(true); }
+ public void testGetWaitQueueLengthIAE(boolean fair) {
+ final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ final Condition c = lock.writeLock().newCondition();
+ final ReentrantReadWriteLock lock2 = new ReentrantReadWriteLock(fair);
+ try {
+ lock2.getWaitQueueLength(c);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * getWaitQueueLength throws IllegalMonitorStateException if not locked
+ */
+ public void testGetWaitQueueLengthIMSE() { testGetWaitQueueLengthIMSE(false); }
+ public void testGetWaitQueueLengthIMSE_fair() { testGetWaitQueueLengthIMSE(true); }
+ public void testGetWaitQueueLengthIMSE(boolean fair) {
+ final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ final Condition c = lock.writeLock().newCondition();
+ try {
+ lock.getWaitQueueLength(c);
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {}
+ }
+
+ /**
+ * getWaitingThreads throws IllegalArgumentException if not owned
+ */
+ public void testGetWaitingThreadsIAE() { testGetWaitingThreadsIAE(false); }
+ public void testGetWaitingThreadsIAE_fair() { testGetWaitingThreadsIAE(true); }
+ public void testGetWaitingThreadsIAE(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ final Condition c = lock.writeLock().newCondition();
+ final PublicReentrantReadWriteLock lock2 =
+ new PublicReentrantReadWriteLock(fair);
+ try {
+ lock2.getWaitingThreads(c);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * getWaitingThreads throws IllegalMonitorStateException if not locked
+ */
+ public void testGetWaitingThreadsIMSE() { testGetWaitingThreadsIMSE(false); }
+ public void testGetWaitingThreadsIMSE_fair() { testGetWaitingThreadsIMSE(true); }
+ public void testGetWaitingThreadsIMSE(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ final Condition c = lock.writeLock().newCondition();
+ try {
+ lock.getWaitingThreads(c);
+ shouldThrow();
+ } catch (IllegalMonitorStateException success) {}
+ }
+
+ /**
+ * hasWaiters returns true when a thread is waiting, else false
+ */
+ public void testHasWaiters() { testHasWaiters(false); }
+ public void testHasWaiters_fair() { testHasWaiters(true); }
+ public void testHasWaiters(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ final Condition c = lock.writeLock().newCondition();
+ final CountDownLatch locked = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.writeLock().lock();
+ assertHasNoWaiters(lock, c);
+ assertFalse(lock.hasWaiters(c));
+ locked.countDown();
+ c.await();
+ assertHasNoWaiters(lock, c);
+ assertFalse(lock.hasWaiters(c));
+ lock.writeLock().unlock();
+ }});
+
+ await(locked);
+ lock.writeLock().lock();
+ assertHasWaiters(lock, c, t);
+ assertTrue(lock.hasWaiters(c));
+ c.signal();
+ assertHasNoWaiters(lock, c);
+ assertFalse(lock.hasWaiters(c));
+ lock.writeLock().unlock();
+ awaitTermination(t);
+ assertHasNoWaiters(lock, c);
+ }
+
+ /**
+ * getWaitQueueLength returns number of waiting threads
+ */
+ public void testGetWaitQueueLength() { testGetWaitQueueLength(false); }
+ public void testGetWaitQueueLength_fair() { testGetWaitQueueLength(true); }
+ public void testGetWaitQueueLength(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ final Condition c = lock.writeLock().newCondition();
+ final CountDownLatch locked = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.writeLock().lock();
+ assertEquals(0, lock.getWaitQueueLength(c));
+ locked.countDown();
+ c.await();
+ lock.writeLock().unlock();
+ }});
+
+ await(locked);
+ lock.writeLock().lock();
+ assertHasWaiters(lock, c, t);
+ assertEquals(1, lock.getWaitQueueLength(c));
+ c.signal();
+ assertHasNoWaiters(lock, c);
+ assertEquals(0, lock.getWaitQueueLength(c));
+ lock.writeLock().unlock();
+ awaitTermination(t);
+ }
+
+ /**
+ * getWaitingThreads returns only and all waiting threads
+ */
+ public void testGetWaitingThreads() { testGetWaitingThreads(false); }
+ public void testGetWaitingThreads_fair() { testGetWaitingThreads(true); }
+ public void testGetWaitingThreads(boolean fair) {
+ final PublicReentrantReadWriteLock lock =
+ new PublicReentrantReadWriteLock(fair);
+ final Condition c = lock.writeLock().newCondition();
+ final CountDownLatch locked1 = new CountDownLatch(1);
+ final CountDownLatch locked2 = new CountDownLatch(1);
+ Thread t1 = new Thread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.writeLock().lock();
+ assertTrue(lock.getWaitingThreads(c).isEmpty());
+ locked1.countDown();
+ c.await();
+ lock.writeLock().unlock();
+ }});
+
+ Thread t2 = new Thread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ lock.writeLock().lock();
+ assertFalse(lock.getWaitingThreads(c).isEmpty());
+ locked2.countDown();
+ c.await();
+ lock.writeLock().unlock();
+ }});
+
+ lock.writeLock().lock();
+ assertTrue(lock.getWaitingThreads(c).isEmpty());
+ lock.writeLock().unlock();
+
+ t1.start();
+ await(locked1);
+ t2.start();
+ await(locked2);
+
+ lock.writeLock().lock();
+ assertTrue(lock.hasWaiters(c));
+ assertTrue(lock.getWaitingThreads(c).contains(t1));
+ assertTrue(lock.getWaitingThreads(c).contains(t2));
+ assertEquals(2, lock.getWaitingThreads(c).size());
+ c.signalAll();
+ assertHasNoWaiters(lock, c);
+ lock.writeLock().unlock();
+
+ awaitTermination(t1);
+ awaitTermination(t2);
+
+ assertHasNoWaiters(lock, c);
+ }
+
+ /**
+ * toString indicates current lock state
+ */
+ public void testToString() { testToString(false); }
+ public void testToString_fair() { testToString(true); }
+ public void testToString(boolean fair) {
+ ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ assertTrue(lock.toString().contains("Write locks = 0"));
+ assertTrue(lock.toString().contains("Read locks = 0"));
+ lock.writeLock().lock();
+ assertTrue(lock.toString().contains("Write locks = 1"));
+ assertTrue(lock.toString().contains("Read locks = 0"));
+ lock.writeLock().unlock();
+ lock.readLock().lock();
+ lock.readLock().lock();
+ assertTrue(lock.toString().contains("Write locks = 0"));
+ assertTrue(lock.toString().contains("Read locks = 2"));
+ }
+
+ /**
+ * readLock.toString indicates current lock state
+ */
+ public void testReadLockToString() { testReadLockToString(false); }
+ public void testReadLockToString_fair() { testReadLockToString(true); }
+ public void testReadLockToString(boolean fair) {
+ ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ assertTrue(lock.readLock().toString().contains("Read locks = 0"));
+ lock.readLock().lock();
+ lock.readLock().lock();
+ assertTrue(lock.readLock().toString().contains("Read locks = 2"));
+ }
+
+ /**
+ * writeLock.toString indicates current lock state
+ */
+ public void testWriteLockToString() { testWriteLockToString(false); }
+ public void testWriteLockToString_fair() { testWriteLockToString(true); }
+ public void testWriteLockToString(boolean fair) {
+ ReentrantReadWriteLock lock = new ReentrantReadWriteLock(fair);
+ assertTrue(lock.writeLock().toString().contains("Unlocked"));
+ lock.writeLock().lock();
+ assertTrue(lock.writeLock().toString().contains("Locked"));
+ lock.writeLock().unlock();
+ assertTrue(lock.writeLock().toString().contains("Unlocked"));
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java b/jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java
new file mode 100644
index 0000000..b72ad02
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/ScheduledExecutorSubclassTest.java
@@ -0,0 +1,1213 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.*;
+import java.util.concurrent.*;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class ScheduledExecutorSubclassTest extends JSR166TestCase {
+
+ static class CustomTask<V> implements RunnableScheduledFuture<V> {
+ RunnableScheduledFuture<V> task;
+ volatile boolean ran;
+ CustomTask(RunnableScheduledFuture<V> t) { task = t; }
+ public boolean isPeriodic() { return task.isPeriodic(); }
+ public void run() {
+ ran = true;
+ task.run();
+ }
+ public long getDelay(TimeUnit unit) { return task.getDelay(unit); }
+ public int compareTo(Delayed t) {
+ return task.compareTo(((CustomTask)t).task);
+ }
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ return task.cancel(mayInterruptIfRunning);
+ }
+ public boolean isCancelled() { return task.isCancelled(); }
+ public boolean isDone() { return task.isDone(); }
+ public V get() throws InterruptedException, ExecutionException {
+ V v = task.get();
+ assertTrue(ran);
+ return v;
+ }
+ public V get(long time, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+ V v = task.get(time, unit);
+ assertTrue(ran);
+ return v;
+ }
+ }
+
+ public class CustomExecutor extends ScheduledThreadPoolExecutor {
+
+ protected <V> RunnableScheduledFuture<V> decorateTask(Runnable r, RunnableScheduledFuture<V> task) {
+ return new CustomTask<V>(task);
+ }
+
+ protected <V> RunnableScheduledFuture<V> decorateTask(Callable<V> c, RunnableScheduledFuture<V> task) {
+ return new CustomTask<V>(task);
+ }
+ CustomExecutor(int corePoolSize) { super(corePoolSize); }
+ CustomExecutor(int corePoolSize, RejectedExecutionHandler handler) {
+ super(corePoolSize, handler);
+ }
+
+ CustomExecutor(int corePoolSize, ThreadFactory threadFactory) {
+ super(corePoolSize, threadFactory);
+ }
+ CustomExecutor(int corePoolSize, ThreadFactory threadFactory,
+ RejectedExecutionHandler handler) {
+ super(corePoolSize, threadFactory, handler);
+ }
+
+ }
+
+ /**
+ * execute successfully executes a runnable
+ */
+ public void testExecute() throws InterruptedException {
+ CustomExecutor p = new CustomExecutor(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ final Runnable task = new CheckedRunnable() {
+ public void realRun() {
+ done.countDown();
+ }};
+ try {
+ p.execute(task);
+ assertTrue(done.await(SMALL_DELAY_MS, MILLISECONDS));
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * delayed schedule of callable successfully executes after delay
+ */
+ public void testSchedule1() throws Exception {
+ CustomExecutor p = new CustomExecutor(1);
+ final long startTime = System.nanoTime();
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ Callable task = new CheckedCallable<Boolean>() {
+ public Boolean realCall() {
+ done.countDown();
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ return Boolean.TRUE;
+ }};
+ Future f = p.schedule(task, timeoutMillis(), MILLISECONDS);
+ assertSame(Boolean.TRUE, f.get());
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ assertTrue(done.await(0L, MILLISECONDS));
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * delayed schedule of runnable successfully executes after delay
+ */
+ public void testSchedule3() throws Exception {
+ CustomExecutor p = new CustomExecutor(1);
+ final long startTime = System.nanoTime();
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ Runnable task = new CheckedRunnable() {
+ public void realRun() {
+ done.countDown();
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ }};
+ Future f = p.schedule(task, timeoutMillis(), MILLISECONDS);
+ await(done);
+ assertNull(f.get(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * scheduleAtFixedRate executes runnable after given initial delay
+ */
+ public void testSchedule4() throws InterruptedException {
+ CustomExecutor p = new CustomExecutor(1);
+ final long startTime = System.nanoTime();
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ Runnable task = new CheckedRunnable() {
+ public void realRun() {
+ done.countDown();
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ }};
+ ScheduledFuture f =
+ p.scheduleAtFixedRate(task, timeoutMillis(),
+ LONG_DELAY_MS, MILLISECONDS);
+ await(done);
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ f.cancel(true);
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * scheduleWithFixedDelay executes runnable after given initial delay
+ */
+ public void testSchedule5() throws InterruptedException {
+ CustomExecutor p = new CustomExecutor(1);
+ final long startTime = System.nanoTime();
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ Runnable task = new CheckedRunnable() {
+ public void realRun() {
+ done.countDown();
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ }};
+ ScheduledFuture f =
+ p.scheduleWithFixedDelay(task, timeoutMillis(),
+ LONG_DELAY_MS, MILLISECONDS);
+ await(done);
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ f.cancel(true);
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ static class RunnableCounter implements Runnable {
+ AtomicInteger count = new AtomicInteger(0);
+ public void run() { count.getAndIncrement(); }
+ }
+
+ /**
+ * scheduleAtFixedRate executes series of tasks at given rate
+ */
+ public void testFixedRateSequence() throws InterruptedException {
+ CustomExecutor p = new CustomExecutor(1);
+ RunnableCounter counter = new RunnableCounter();
+ ScheduledFuture h =
+ p.scheduleAtFixedRate(counter, 0, 1, MILLISECONDS);
+ delay(SMALL_DELAY_MS);
+ h.cancel(true);
+ int c = counter.count.get();
+ // By time scaling conventions, we must have at least
+ // an execution per SHORT delay, but no more than one SHORT more
+ assertTrue(c >= SMALL_DELAY_MS / SHORT_DELAY_MS);
+ assertTrue(c <= SMALL_DELAY_MS + SHORT_DELAY_MS);
+ joinPool(p);
+ }
+
+ /**
+ * scheduleWithFixedDelay executes series of tasks with given period
+ */
+ public void testFixedDelaySequence() throws InterruptedException {
+ CustomExecutor p = new CustomExecutor(1);
+ RunnableCounter counter = new RunnableCounter();
+ ScheduledFuture h =
+ p.scheduleWithFixedDelay(counter, 0, 1, MILLISECONDS);
+ delay(SMALL_DELAY_MS);
+ h.cancel(true);
+ int c = counter.count.get();
+ assertTrue(c >= SMALL_DELAY_MS / SHORT_DELAY_MS);
+ assertTrue(c <= SMALL_DELAY_MS + SHORT_DELAY_MS);
+ joinPool(p);
+ }
+
+ /**
+ * execute(null) throws NPE
+ */
+ public void testExecuteNull() throws InterruptedException {
+ CustomExecutor se = new CustomExecutor(1);
+ try {
+ se.execute(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ joinPool(se);
+ }
+
+ /**
+ * schedule(null) throws NPE
+ */
+ public void testScheduleNull() throws InterruptedException {
+ CustomExecutor se = new CustomExecutor(1);
+ try {
+ TrackedCallable callable = null;
+ Future f = se.schedule(callable, SHORT_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ joinPool(se);
+ }
+
+ /**
+ * execute throws RejectedExecutionException if shutdown
+ */
+ public void testSchedule1_RejectedExecutionException() {
+ CustomExecutor se = new CustomExecutor(1);
+ try {
+ se.shutdown();
+ se.schedule(new NoOpRunnable(),
+ MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (RejectedExecutionException success) {
+ } catch (SecurityException ok) {
+ }
+
+ joinPool(se);
+ }
+
+ /**
+ * schedule throws RejectedExecutionException if shutdown
+ */
+ public void testSchedule2_RejectedExecutionException() {
+ CustomExecutor se = new CustomExecutor(1);
+ try {
+ se.shutdown();
+ se.schedule(new NoOpCallable(),
+ MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (RejectedExecutionException success) {
+ } catch (SecurityException ok) {
+ }
+ joinPool(se);
+ }
+
+ /**
+ * schedule callable throws RejectedExecutionException if shutdown
+ */
+ public void testSchedule3_RejectedExecutionException() {
+ CustomExecutor se = new CustomExecutor(1);
+ try {
+ se.shutdown();
+ se.schedule(new NoOpCallable(),
+ MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (RejectedExecutionException success) {
+ } catch (SecurityException ok) {
+ }
+ joinPool(se);
+ }
+
+ /**
+ * scheduleAtFixedRate throws RejectedExecutionException if shutdown
+ */
+ public void testScheduleAtFixedRate1_RejectedExecutionException() {
+ CustomExecutor se = new CustomExecutor(1);
+ try {
+ se.shutdown();
+ se.scheduleAtFixedRate(new NoOpRunnable(),
+ MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (RejectedExecutionException success) {
+ } catch (SecurityException ok) {
+ }
+ joinPool(se);
+ }
+
+ /**
+ * scheduleWithFixedDelay throws RejectedExecutionException if shutdown
+ */
+ public void testScheduleWithFixedDelay1_RejectedExecutionException() {
+ CustomExecutor se = new CustomExecutor(1);
+ try {
+ se.shutdown();
+ se.scheduleWithFixedDelay(new NoOpRunnable(),
+ MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (RejectedExecutionException success) {
+ } catch (SecurityException ok) {
+ }
+ joinPool(se);
+ }
+
+ /**
+ * getActiveCount increases but doesn't overestimate, when a
+ * thread becomes active
+ */
+ public void testGetActiveCount() throws InterruptedException {
+ final ThreadPoolExecutor p = new CustomExecutor(2);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ assertEquals(0, p.getActiveCount());
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ assertEquals(1, p.getActiveCount());
+ done.await();
+ }});
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(1, p.getActiveCount());
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * getCompletedTaskCount increases, but doesn't overestimate,
+ * when tasks complete
+ */
+ public void testGetCompletedTaskCount() throws InterruptedException {
+ final ThreadPoolExecutor p = new CustomExecutor(2);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadProceed = new CountDownLatch(1);
+ final CountDownLatch threadDone = new CountDownLatch(1);
+ try {
+ assertEquals(0, p.getCompletedTaskCount());
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ assertEquals(0, p.getCompletedTaskCount());
+ threadProceed.await();
+ threadDone.countDown();
+ }});
+ await(threadStarted);
+ assertEquals(0, p.getCompletedTaskCount());
+ threadProceed.countDown();
+ threadDone.await();
+ long startTime = System.nanoTime();
+ while (p.getCompletedTaskCount() != 1) {
+ if (millisElapsedSince(startTime) > LONG_DELAY_MS)
+ fail("timed out");
+ Thread.yield();
+ }
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * getCorePoolSize returns size given in constructor if not otherwise set
+ */
+ public void testGetCorePoolSize() {
+ CustomExecutor p = new CustomExecutor(1);
+ assertEquals(1, p.getCorePoolSize());
+ joinPool(p);
+ }
+
+ /**
+ * getLargestPoolSize increases, but doesn't overestimate, when
+ * multiple threads active
+ */
+ public void testGetLargestPoolSize() throws InterruptedException {
+ final int THREADS = 3;
+ final ThreadPoolExecutor p = new CustomExecutor(THREADS);
+ final CountDownLatch threadsStarted = new CountDownLatch(THREADS);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ assertEquals(0, p.getLargestPoolSize());
+ for (int i = 0; i < THREADS; i++)
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.countDown();
+ done.await();
+ assertEquals(THREADS, p.getLargestPoolSize());
+ }});
+ assertTrue(threadsStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(THREADS, p.getLargestPoolSize());
+ } finally {
+ done.countDown();
+ joinPool(p);
+ assertEquals(THREADS, p.getLargestPoolSize());
+ }
+ }
+
+ /**
+ * getPoolSize increases, but doesn't overestimate, when threads
+ * become active
+ */
+ public void testGetPoolSize() throws InterruptedException {
+ final ThreadPoolExecutor p = new CustomExecutor(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ assertEquals(0, p.getPoolSize());
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ assertEquals(1, p.getPoolSize());
+ done.await();
+ }});
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(1, p.getPoolSize());
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * getTaskCount increases, but doesn't overestimate, when tasks
+ * submitted
+ */
+ public void testGetTaskCount() throws InterruptedException {
+ final ThreadPoolExecutor p = new CustomExecutor(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ final int TASKS = 5;
+ try {
+ assertEquals(0, p.getTaskCount());
+ for (int i = 0; i < TASKS; i++)
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ done.await();
+ }});
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(TASKS, p.getTaskCount());
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * getThreadFactory returns factory in constructor if not set
+ */
+ public void testGetThreadFactory() {
+ ThreadFactory tf = new SimpleThreadFactory();
+ CustomExecutor p = new CustomExecutor(1, tf);
+ assertSame(tf, p.getThreadFactory());
+ joinPool(p);
+ }
+
+ /**
+ * setThreadFactory sets the thread factory returned by getThreadFactory
+ */
+ public void testSetThreadFactory() {
+ ThreadFactory tf = new SimpleThreadFactory();
+ CustomExecutor p = new CustomExecutor(1);
+ p.setThreadFactory(tf);
+ assertSame(tf, p.getThreadFactory());
+ joinPool(p);
+ }
+
+ /**
+ * setThreadFactory(null) throws NPE
+ */
+ public void testSetThreadFactoryNull() {
+ CustomExecutor p = new CustomExecutor(1);
+ try {
+ p.setThreadFactory(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * isShutdown is false before shutdown, true after
+ */
+ public void testIsShutdown() {
+ CustomExecutor p = new CustomExecutor(1);
+ try {
+ assertFalse(p.isShutdown());
+ }
+ finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ }
+ assertTrue(p.isShutdown());
+ }
+
+ /**
+ * isTerminated is false before termination, true after
+ */
+ public void testIsTerminated() throws InterruptedException {
+ final ThreadPoolExecutor p = new CustomExecutor(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ assertFalse(p.isTerminated());
+ try {
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(p.isTerminated());
+ threadStarted.countDown();
+ done.await();
+ }});
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertFalse(p.isTerminating());
+ done.countDown();
+ } finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ }
+ assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
+ }
+
+ /**
+ * isTerminating is not true when running or when terminated
+ */
+ public void testIsTerminating() throws InterruptedException {
+ final ThreadPoolExecutor p = new CustomExecutor(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ assertFalse(p.isTerminating());
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(p.isTerminating());
+ threadStarted.countDown();
+ done.await();
+ }});
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertFalse(p.isTerminating());
+ done.countDown();
+ } finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ }
+ assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
+ assertFalse(p.isTerminating());
+ }
+
+ /**
+ * getQueue returns the work queue, which contains queued tasks
+ */
+ public void testGetQueue() throws InterruptedException {
+ ScheduledThreadPoolExecutor p = new CustomExecutor(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ ScheduledFuture[] tasks = new ScheduledFuture[5];
+ for (int i = 0; i < tasks.length; i++) {
+ Runnable r = new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ done.await();
+ }};
+ tasks[i] = p.schedule(r, 1, MILLISECONDS);
+ }
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ BlockingQueue<Runnable> q = p.getQueue();
+ assertTrue(q.contains(tasks[tasks.length - 1]));
+ assertFalse(q.contains(tasks[0]));
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * remove(task) removes queued task, and fails to remove active task
+ */
+ public void testRemove() throws InterruptedException {
+ final ScheduledThreadPoolExecutor p = new CustomExecutor(1);
+ ScheduledFuture[] tasks = new ScheduledFuture[5];
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ for (int i = 0; i < tasks.length; i++) {
+ Runnable r = new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ done.await();
+ }};
+ tasks[i] = p.schedule(r, 1, MILLISECONDS);
+ }
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ BlockingQueue<Runnable> q = p.getQueue();
+ assertFalse(p.remove((Runnable)tasks[0]));
+ assertTrue(q.contains((Runnable)tasks[4]));
+ assertTrue(q.contains((Runnable)tasks[3]));
+ assertTrue(p.remove((Runnable)tasks[4]));
+ assertFalse(p.remove((Runnable)tasks[4]));
+ assertFalse(q.contains((Runnable)tasks[4]));
+ assertTrue(q.contains((Runnable)tasks[3]));
+ assertTrue(p.remove((Runnable)tasks[3]));
+ assertFalse(q.contains((Runnable)tasks[3]));
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * purge removes cancelled tasks from the queue
+ */
+ public void testPurge() throws InterruptedException {
+ CustomExecutor p = new CustomExecutor(1);
+ ScheduledFuture[] tasks = new ScheduledFuture[5];
+ for (int i = 0; i < tasks.length; i++)
+ tasks[i] = p.schedule(new SmallPossiblyInterruptedRunnable(),
+ LONG_DELAY_MS, MILLISECONDS);
+ try {
+ int max = tasks.length;
+ if (tasks[4].cancel(true)) --max;
+ if (tasks[3].cancel(true)) --max;
+ // There must eventually be an interference-free point at
+ // which purge will not fail. (At worst, when queue is empty.)
+ long startTime = System.nanoTime();
+ do {
+ p.purge();
+ long count = p.getTaskCount();
+ if (count == max)
+ return;
+ } while (millisElapsedSince(startTime) < MEDIUM_DELAY_MS);
+ fail("Purge failed to remove cancelled tasks");
+ } finally {
+ for (ScheduledFuture task : tasks)
+ task.cancel(true);
+ joinPool(p);
+ }
+ }
+
+ /**
+ * shutdownNow returns a list containing tasks that were not run
+ */
+ public void testShutdownNow() {
+ CustomExecutor p = new CustomExecutor(1);
+ for (int i = 0; i < 5; i++)
+ p.schedule(new SmallPossiblyInterruptedRunnable(),
+ LONG_DELAY_MS, MILLISECONDS);
+ try {
+ List<Runnable> l = p.shutdownNow();
+ assertTrue(p.isShutdown());
+ assertEquals(5, l.size());
+ } catch (SecurityException ok) {
+ // Allowed in case test doesn't have privs
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * In default setting, shutdown cancels periodic but not delayed
+ * tasks at shutdown
+ */
+ public void testShutdown1() throws InterruptedException {
+ CustomExecutor p = new CustomExecutor(1);
+ assertTrue(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
+ assertFalse(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
+
+ ScheduledFuture[] tasks = new ScheduledFuture[5];
+ for (int i = 0; i < tasks.length; i++)
+ tasks[i] = p.schedule(new NoOpRunnable(),
+ SHORT_DELAY_MS, MILLISECONDS);
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ BlockingQueue<Runnable> q = p.getQueue();
+ for (ScheduledFuture task : tasks) {
+ assertFalse(task.isDone());
+ assertFalse(task.isCancelled());
+ assertTrue(q.contains(task));
+ }
+ assertTrue(p.isShutdown());
+ assertTrue(p.awaitTermination(SMALL_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
+ for (ScheduledFuture task : tasks) {
+ assertTrue(task.isDone());
+ assertFalse(task.isCancelled());
+ }
+ }
+
+ /**
+ * If setExecuteExistingDelayedTasksAfterShutdownPolicy is false,
+ * delayed tasks are cancelled at shutdown
+ */
+ public void testShutdown2() throws InterruptedException {
+ CustomExecutor p = new CustomExecutor(1);
+ p.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
+ assertFalse(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
+ assertFalse(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
+ ScheduledFuture[] tasks = new ScheduledFuture[5];
+ for (int i = 0; i < tasks.length; i++)
+ tasks[i] = p.schedule(new NoOpRunnable(),
+ SHORT_DELAY_MS, MILLISECONDS);
+ BlockingQueue q = p.getQueue();
+ assertEquals(tasks.length, q.size());
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ assertTrue(p.isShutdown());
+ assertTrue(q.isEmpty());
+ assertTrue(p.awaitTermination(SMALL_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
+ for (ScheduledFuture task : tasks) {
+ assertTrue(task.isDone());
+ assertTrue(task.isCancelled());
+ }
+ }
+
+ /**
+ * If setContinueExistingPeriodicTasksAfterShutdownPolicy is set false,
+ * periodic tasks are cancelled at shutdown
+ */
+ public void testShutdown3() throws InterruptedException {
+ CustomExecutor p = new CustomExecutor(1);
+ assertTrue(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
+ assertFalse(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
+ p.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
+ assertTrue(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
+ assertFalse(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
+ long initialDelay = LONG_DELAY_MS;
+ ScheduledFuture task =
+ p.scheduleAtFixedRate(new NoOpRunnable(), initialDelay,
+ 5, MILLISECONDS);
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ assertTrue(p.isShutdown());
+ assertTrue(p.getQueue().isEmpty());
+ assertTrue(task.isDone());
+ assertTrue(task.isCancelled());
+ joinPool(p);
+ }
+
+ /**
+ * if setContinueExistingPeriodicTasksAfterShutdownPolicy is true,
+ * periodic tasks are not cancelled at shutdown
+ */
+ public void testShutdown4() throws InterruptedException {
+ CustomExecutor p = new CustomExecutor(1);
+ final CountDownLatch counter = new CountDownLatch(2);
+ try {
+ p.setContinueExistingPeriodicTasksAfterShutdownPolicy(true);
+ assertTrue(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
+ assertTrue(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
+ final Runnable r = new CheckedRunnable() {
+ public void realRun() {
+ counter.countDown();
+ }};
+ ScheduledFuture task =
+ p.scheduleAtFixedRate(r, 1, 1, MILLISECONDS);
+ assertFalse(task.isDone());
+ assertFalse(task.isCancelled());
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ assertFalse(task.isCancelled());
+ assertFalse(p.isTerminated());
+ assertTrue(p.isShutdown());
+ assertTrue(counter.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertFalse(task.isCancelled());
+ assertTrue(task.cancel(false));
+ assertTrue(task.isDone());
+ assertTrue(task.isCancelled());
+ assertTrue(p.awaitTermination(SMALL_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
+ }
+ finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * completed submit of callable returns result
+ */
+ public void testSubmitCallable() throws Exception {
+ ExecutorService e = new CustomExecutor(2);
+ try {
+ Future<String> future = e.submit(new StringTask());
+ String result = future.get();
+ assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * completed submit of runnable returns successfully
+ */
+ public void testSubmitRunnable() throws Exception {
+ ExecutorService e = new CustomExecutor(2);
+ try {
+ Future<?> future = e.submit(new NoOpRunnable());
+ future.get();
+ assertTrue(future.isDone());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * completed submit of (runnable, result) returns result
+ */
+ public void testSubmitRunnable2() throws Exception {
+ ExecutorService e = new CustomExecutor(2);
+ try {
+ Future<String> future = e.submit(new NoOpRunnable(), TEST_STRING);
+ String result = future.get();
+ assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(null) throws NPE
+ */
+ public void testInvokeAny1() throws Exception {
+ ExecutorService e = new CustomExecutor(2);
+ try {
+ e.invokeAny(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(empty collection) throws IAE
+ */
+ public void testInvokeAny2() throws Exception {
+ ExecutorService e = new CustomExecutor(2);
+ try {
+ e.invokeAny(new ArrayList<Callable<String>>());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(c) throws NPE if c has null elements
+ */
+ public void testInvokeAny3() throws Exception {
+ CountDownLatch latch = new CountDownLatch(1);
+ ExecutorService e = new CustomExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(latchAwaitingStringTask(latch));
+ l.add(null);
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ latch.countDown();
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(c) throws ExecutionException if no task completes
+ */
+ public void testInvokeAny4() throws Exception {
+ ExecutorService e = new CustomExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(c) returns result of some task
+ */
+ public void testInvokeAny5() throws Exception {
+ ExecutorService e = new CustomExecutor(2);
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(new StringTask());
+ String result = e.invokeAny(l);
+ assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAll(null) throws NPE
+ */
+ public void testInvokeAll1() throws Exception {
+ ExecutorService e = new CustomExecutor(2);
+ try {
+ e.invokeAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAll(empty collection) returns empty collection
+ */
+ public void testInvokeAll2() throws Exception {
+ ExecutorService e = new CustomExecutor(2);
+ try {
+ List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>());
+ assertTrue(r.isEmpty());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAll(c) throws NPE if c has null elements
+ */
+ public void testInvokeAll3() throws Exception {
+ ExecutorService e = new CustomExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(null);
+ try {
+ e.invokeAll(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * get of invokeAll(c) throws exception on failed task
+ */
+ public void testInvokeAll4() throws Exception {
+ ExecutorService e = new CustomExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ List<Future<String>> futures = e.invokeAll(l);
+ assertEquals(1, futures.size());
+ try {
+ futures.get(0).get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAll(c) returns results of all completed tasks
+ */
+ public void testInvokeAll5() throws Exception {
+ ExecutorService e = new CustomExecutor(2);
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(new StringTask());
+ List<Future<String>> futures = e.invokeAll(l);
+ assertEquals(2, futures.size());
+ for (Future<String> future : futures)
+ assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(null) throws NPE
+ */
+ public void testTimedInvokeAny1() throws Exception {
+ ExecutorService e = new CustomExecutor(2);
+ try {
+ e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(,,null) throws NPE
+ */
+ public void testTimedInvokeAnyNullTimeUnit() throws Exception {
+ ExecutorService e = new CustomExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(empty collection) throws IAE
+ */
+ public void testTimedInvokeAny2() throws Exception {
+ ExecutorService e = new CustomExecutor(2);
+ try {
+ e.invokeAny(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(c) throws NPE if c has null elements
+ */
+ public void testTimedInvokeAny3() throws Exception {
+ CountDownLatch latch = new CountDownLatch(1);
+ ExecutorService e = new CustomExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(latchAwaitingStringTask(latch));
+ l.add(null);
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ latch.countDown();
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(c) throws ExecutionException if no task completes
+ */
+ public void testTimedInvokeAny4() throws Exception {
+ ExecutorService e = new CustomExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(c) returns result of some task
+ */
+ public void testTimedInvokeAny5() throws Exception {
+ ExecutorService e = new CustomExecutor(2);
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(new StringTask());
+ String result = e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(null) throws NPE
+ */
+ public void testTimedInvokeAll1() throws Exception {
+ ExecutorService e = new CustomExecutor(2);
+ try {
+ e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(,,null) throws NPE
+ */
+ public void testTimedInvokeAllNullTimeUnit() throws Exception {
+ ExecutorService e = new CustomExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ try {
+ e.invokeAll(l, MEDIUM_DELAY_MS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(empty collection) returns empty collection
+ */
+ public void testTimedInvokeAll2() throws Exception {
+ ExecutorService e = new CustomExecutor(2);
+ try {
+ List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
+ assertTrue(r.isEmpty());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(c) throws NPE if c has null elements
+ */
+ public void testTimedInvokeAll3() throws Exception {
+ ExecutorService e = new CustomExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(null);
+ try {
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * get of element of invokeAll(c) throws exception on failed task
+ */
+ public void testTimedInvokeAll4() throws Exception {
+ ExecutorService e = new CustomExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ List<Future<String>> futures =
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ assertEquals(1, futures.size());
+ try {
+ futures.get(0).get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(c) returns results of all completed tasks
+ */
+ public void testTimedInvokeAll5() throws Exception {
+ ExecutorService e = new CustomExecutor(2);
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(new StringTask());
+ List<Future<String>> futures =
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ assertEquals(2, futures.size());
+ for (Future<String> future : futures)
+ assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(c) cancels tasks not completed by timeout
+ */
+ public void testTimedInvokeAll6() throws Exception {
+ ExecutorService e = new CustomExecutor(2);
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(Executors.callable(new MediumPossiblyInterruptedRunnable(), TEST_STRING));
+ l.add(new StringTask());
+ List<Future<String>> futures =
+ e.invokeAll(l, SHORT_DELAY_MS, MILLISECONDS);
+ assertEquals(l.size(), futures.size());
+ for (Future future : futures)
+ assertTrue(future.isDone());
+ assertFalse(futures.get(0).isCancelled());
+ assertTrue(futures.get(1).isCancelled());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java b/jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java
new file mode 100644
index 0000000..4eea2c9
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/ScheduledExecutorTest.java
@@ -0,0 +1,1164 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.*;
+import java.util.concurrent.*;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class ScheduledExecutorTest extends JSR166TestCase {
+
+ /**
+ * execute successfully executes a runnable
+ */
+ public void testExecute() throws InterruptedException {
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ final Runnable task = new CheckedRunnable() {
+ public void realRun() {
+ done.countDown();
+ }};
+ try {
+ p.execute(task);
+ assertTrue(done.await(SMALL_DELAY_MS, MILLISECONDS));
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * delayed schedule of callable successfully executes after delay
+ */
+ public void testSchedule1() throws Exception {
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ final long startTime = System.nanoTime();
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ Callable task = new CheckedCallable<Boolean>() {
+ public Boolean realCall() {
+ done.countDown();
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ return Boolean.TRUE;
+ }};
+ Future f = p.schedule(task, timeoutMillis(), MILLISECONDS);
+ assertSame(Boolean.TRUE, f.get());
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ assertTrue(done.await(0L, MILLISECONDS));
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * delayed schedule of runnable successfully executes after delay
+ */
+ public void testSchedule3() throws Exception {
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ final long startTime = System.nanoTime();
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ Runnable task = new CheckedRunnable() {
+ public void realRun() {
+ done.countDown();
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ }};
+ Future f = p.schedule(task, timeoutMillis(), MILLISECONDS);
+ await(done);
+ assertNull(f.get(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * scheduleAtFixedRate executes runnable after given initial delay
+ */
+ public void testSchedule4() throws Exception {
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ final long startTime = System.nanoTime();
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ Runnable task = new CheckedRunnable() {
+ public void realRun() {
+ done.countDown();
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ }};
+ ScheduledFuture f =
+ p.scheduleAtFixedRate(task, timeoutMillis(),
+ LONG_DELAY_MS, MILLISECONDS);
+ await(done);
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ f.cancel(true);
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * scheduleWithFixedDelay executes runnable after given initial delay
+ */
+ public void testSchedule5() throws Exception {
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ final long startTime = System.nanoTime();
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ Runnable task = new CheckedRunnable() {
+ public void realRun() {
+ done.countDown();
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ }};
+ ScheduledFuture f =
+ p.scheduleWithFixedDelay(task, timeoutMillis(),
+ LONG_DELAY_MS, MILLISECONDS);
+ await(done);
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ f.cancel(true);
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ static class RunnableCounter implements Runnable {
+ AtomicInteger count = new AtomicInteger(0);
+ public void run() { count.getAndIncrement(); }
+ }
+
+ /**
+ * scheduleAtFixedRate executes series of tasks at given rate
+ */
+ public void testFixedRateSequence() throws InterruptedException {
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ RunnableCounter counter = new RunnableCounter();
+ ScheduledFuture h =
+ p.scheduleAtFixedRate(counter, 0, 1, MILLISECONDS);
+ delay(SMALL_DELAY_MS);
+ h.cancel(true);
+ int c = counter.count.get();
+ // By time scaling conventions, we must have at least
+ // an execution per SHORT delay, but no more than one SHORT more
+ assertTrue(c >= SMALL_DELAY_MS / SHORT_DELAY_MS);
+ assertTrue(c <= SMALL_DELAY_MS + SHORT_DELAY_MS);
+ joinPool(p);
+ }
+
+ /**
+ * scheduleWithFixedDelay executes series of tasks with given period
+ */
+ public void testFixedDelaySequence() throws InterruptedException {
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ RunnableCounter counter = new RunnableCounter();
+ ScheduledFuture h =
+ p.scheduleWithFixedDelay(counter, 0, 1, MILLISECONDS);
+ delay(SMALL_DELAY_MS);
+ h.cancel(true);
+ int c = counter.count.get();
+ assertTrue(c >= SMALL_DELAY_MS / SHORT_DELAY_MS);
+ assertTrue(c <= SMALL_DELAY_MS + SHORT_DELAY_MS);
+ joinPool(p);
+ }
+
+ /**
+ * execute(null) throws NPE
+ */
+ public void testExecuteNull() throws InterruptedException {
+ ScheduledThreadPoolExecutor se = null;
+ try {
+ se = new ScheduledThreadPoolExecutor(1);
+ se.execute(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+
+ joinPool(se);
+ }
+
+ /**
+ * schedule(null) throws NPE
+ */
+ public void testScheduleNull() throws InterruptedException {
+ ScheduledThreadPoolExecutor se = new ScheduledThreadPoolExecutor(1);
+ try {
+ TrackedCallable callable = null;
+ Future f = se.schedule(callable, SHORT_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ joinPool(se);
+ }
+
+ /**
+ * execute throws RejectedExecutionException if shutdown
+ */
+ public void testSchedule1_RejectedExecutionException() throws InterruptedException {
+ ScheduledThreadPoolExecutor se = new ScheduledThreadPoolExecutor(1);
+ try {
+ se.shutdown();
+ se.schedule(new NoOpRunnable(),
+ MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (RejectedExecutionException success) {
+ } catch (SecurityException ok) {
+ }
+
+ joinPool(se);
+ }
+
+ /**
+ * schedule throws RejectedExecutionException if shutdown
+ */
+ public void testSchedule2_RejectedExecutionException() throws InterruptedException {
+ ScheduledThreadPoolExecutor se = new ScheduledThreadPoolExecutor(1);
+ try {
+ se.shutdown();
+ se.schedule(new NoOpCallable(),
+ MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (RejectedExecutionException success) {
+ } catch (SecurityException ok) {
+ }
+ joinPool(se);
+ }
+
+ /**
+ * schedule callable throws RejectedExecutionException if shutdown
+ */
+ public void testSchedule3_RejectedExecutionException() throws InterruptedException {
+ ScheduledThreadPoolExecutor se = new ScheduledThreadPoolExecutor(1);
+ try {
+ se.shutdown();
+ se.schedule(new NoOpCallable(),
+ MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (RejectedExecutionException success) {
+ } catch (SecurityException ok) {
+ }
+ joinPool(se);
+ }
+
+ /**
+ * scheduleAtFixedRate throws RejectedExecutionException if shutdown
+ */
+ public void testScheduleAtFixedRate1_RejectedExecutionException() throws InterruptedException {
+ ScheduledThreadPoolExecutor se = new ScheduledThreadPoolExecutor(1);
+ try {
+ se.shutdown();
+ se.scheduleAtFixedRate(new NoOpRunnable(),
+ MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (RejectedExecutionException success) {
+ } catch (SecurityException ok) {
+ }
+ joinPool(se);
+ }
+
+ /**
+ * scheduleWithFixedDelay throws RejectedExecutionException if shutdown
+ */
+ public void testScheduleWithFixedDelay1_RejectedExecutionException() throws InterruptedException {
+ ScheduledThreadPoolExecutor se = new ScheduledThreadPoolExecutor(1);
+ try {
+ se.shutdown();
+ se.scheduleWithFixedDelay(new NoOpRunnable(),
+ MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (RejectedExecutionException success) {
+ } catch (SecurityException ok) {
+ }
+ joinPool(se);
+ }
+
+ /**
+ * getActiveCount increases but doesn't overestimate, when a
+ * thread becomes active
+ */
+ public void testGetActiveCount() throws InterruptedException {
+ final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(2);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ assertEquals(0, p.getActiveCount());
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ assertEquals(1, p.getActiveCount());
+ done.await();
+ }});
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(1, p.getActiveCount());
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * getCompletedTaskCount increases, but doesn't overestimate,
+ * when tasks complete
+ */
+ public void testGetCompletedTaskCount() throws InterruptedException {
+ final ThreadPoolExecutor p = new ScheduledThreadPoolExecutor(2);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadProceed = new CountDownLatch(1);
+ final CountDownLatch threadDone = new CountDownLatch(1);
+ try {
+ assertEquals(0, p.getCompletedTaskCount());
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ assertEquals(0, p.getCompletedTaskCount());
+ threadProceed.await();
+ threadDone.countDown();
+ }});
+ await(threadStarted);
+ assertEquals(0, p.getCompletedTaskCount());
+ threadProceed.countDown();
+ threadDone.await();
+ long startTime = System.nanoTime();
+ while (p.getCompletedTaskCount() != 1) {
+ if (millisElapsedSince(startTime) > LONG_DELAY_MS)
+ fail("timed out");
+ Thread.yield();
+ }
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * getCorePoolSize returns size given in constructor if not otherwise set
+ */
+ public void testGetCorePoolSize() throws InterruptedException {
+ ThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ assertEquals(1, p.getCorePoolSize());
+ joinPool(p);
+ }
+
+ /**
+ * getLargestPoolSize increases, but doesn't overestimate, when
+ * multiple threads active
+ */
+ public void testGetLargestPoolSize() throws InterruptedException {
+ final int THREADS = 3;
+ final ThreadPoolExecutor p = new ScheduledThreadPoolExecutor(THREADS);
+ final CountDownLatch threadsStarted = new CountDownLatch(THREADS);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ assertEquals(0, p.getLargestPoolSize());
+ for (int i = 0; i < THREADS; i++)
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.countDown();
+ done.await();
+ assertEquals(THREADS, p.getLargestPoolSize());
+ }});
+ assertTrue(threadsStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(THREADS, p.getLargestPoolSize());
+ } finally {
+ done.countDown();
+ joinPool(p);
+ assertEquals(THREADS, p.getLargestPoolSize());
+ }
+ }
+
+ /**
+ * getPoolSize increases, but doesn't overestimate, when threads
+ * become active
+ */
+ public void testGetPoolSize() throws InterruptedException {
+ final ThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ assertEquals(0, p.getPoolSize());
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ assertEquals(1, p.getPoolSize());
+ done.await();
+ }});
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(1, p.getPoolSize());
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * getTaskCount increases, but doesn't overestimate, when tasks
+ * submitted
+ */
+ public void testGetTaskCount() throws InterruptedException {
+ final ThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ final int TASKS = 5;
+ try {
+ assertEquals(0, p.getTaskCount());
+ for (int i = 0; i < TASKS; i++)
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ done.await();
+ }});
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(TASKS, p.getTaskCount());
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * getThreadFactory returns factory in constructor if not set
+ */
+ public void testGetThreadFactory() throws InterruptedException {
+ ThreadFactory tf = new SimpleThreadFactory();
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1, tf);
+ assertSame(tf, p.getThreadFactory());
+ joinPool(p);
+ }
+
+ /**
+ * setThreadFactory sets the thread factory returned by getThreadFactory
+ */
+ public void testSetThreadFactory() throws InterruptedException {
+ ThreadFactory tf = new SimpleThreadFactory();
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ p.setThreadFactory(tf);
+ assertSame(tf, p.getThreadFactory());
+ joinPool(p);
+ }
+
+ /**
+ * setThreadFactory(null) throws NPE
+ */
+ public void testSetThreadFactoryNull() throws InterruptedException {
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ try {
+ p.setThreadFactory(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * isShutdown is false before shutdown, true after
+ */
+ public void testIsShutdown() {
+
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ try {
+ assertFalse(p.isShutdown());
+ }
+ finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ }
+ assertTrue(p.isShutdown());
+ }
+
+ /**
+ * isTerminated is false before termination, true after
+ */
+ public void testIsTerminated() throws InterruptedException {
+ final ThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ assertFalse(p.isTerminated());
+ try {
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(p.isTerminated());
+ threadStarted.countDown();
+ done.await();
+ }});
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertFalse(p.isTerminating());
+ done.countDown();
+ } finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ }
+ assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
+ }
+
+ /**
+ * isTerminating is not true when running or when terminated
+ */
+ public void testIsTerminating() throws InterruptedException {
+ final ThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ assertFalse(p.isTerminating());
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(p.isTerminating());
+ threadStarted.countDown();
+ done.await();
+ }});
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertFalse(p.isTerminating());
+ done.countDown();
+ } finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ }
+ assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
+ assertFalse(p.isTerminating());
+ }
+
+ /**
+ * getQueue returns the work queue, which contains queued tasks
+ */
+ public void testGetQueue() throws InterruptedException {
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ ScheduledFuture[] tasks = new ScheduledFuture[5];
+ for (int i = 0; i < tasks.length; i++) {
+ Runnable r = new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ done.await();
+ }};
+ tasks[i] = p.schedule(r, 1, MILLISECONDS);
+ }
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ BlockingQueue<Runnable> q = p.getQueue();
+ assertTrue(q.contains(tasks[tasks.length - 1]));
+ assertFalse(q.contains(tasks[0]));
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * remove(task) removes queued task, and fails to remove active task
+ */
+ public void testRemove() throws InterruptedException {
+ final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ ScheduledFuture[] tasks = new ScheduledFuture[5];
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ for (int i = 0; i < tasks.length; i++) {
+ Runnable r = new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ done.await();
+ }};
+ tasks[i] = p.schedule(r, 1, MILLISECONDS);
+ }
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ BlockingQueue<Runnable> q = p.getQueue();
+ assertFalse(p.remove((Runnable)tasks[0]));
+ assertTrue(q.contains((Runnable)tasks[4]));
+ assertTrue(q.contains((Runnable)tasks[3]));
+ assertTrue(p.remove((Runnable)tasks[4]));
+ assertFalse(p.remove((Runnable)tasks[4]));
+ assertFalse(q.contains((Runnable)tasks[4]));
+ assertTrue(q.contains((Runnable)tasks[3]));
+ assertTrue(p.remove((Runnable)tasks[3]));
+ assertFalse(q.contains((Runnable)tasks[3]));
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * purge eventually removes cancelled tasks from the queue
+ */
+ public void testPurge() throws InterruptedException {
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ ScheduledFuture[] tasks = new ScheduledFuture[5];
+ for (int i = 0; i < tasks.length; i++)
+ tasks[i] = p.schedule(new SmallPossiblyInterruptedRunnable(),
+ LONG_DELAY_MS, MILLISECONDS);
+ try {
+ int max = tasks.length;
+ if (tasks[4].cancel(true)) --max;
+ if (tasks[3].cancel(true)) --max;
+ // There must eventually be an interference-free point at
+ // which purge will not fail. (At worst, when queue is empty.)
+ long startTime = System.nanoTime();
+ do {
+ p.purge();
+ long count = p.getTaskCount();
+ if (count == max)
+ return;
+ } while (millisElapsedSince(startTime) < MEDIUM_DELAY_MS);
+ fail("Purge failed to remove cancelled tasks");
+ } finally {
+ for (ScheduledFuture task : tasks)
+ task.cancel(true);
+ joinPool(p);
+ }
+ }
+
+ /**
+ * shutdownNow returns a list containing tasks that were not run
+ */
+ public void testShutdownNow() {
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ for (int i = 0; i < 5; i++)
+ p.schedule(new SmallPossiblyInterruptedRunnable(),
+ LONG_DELAY_MS, MILLISECONDS);
+ try {
+ List<Runnable> l = p.shutdownNow();
+ assertTrue(p.isShutdown());
+ assertEquals(5, l.size());
+ } catch (SecurityException ok) {
+ // Allowed in case test doesn't have privs
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * In default setting, shutdown cancels periodic but not delayed
+ * tasks at shutdown
+ */
+ public void testShutdown1() throws InterruptedException {
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ assertTrue(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
+ assertFalse(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
+
+ ScheduledFuture[] tasks = new ScheduledFuture[5];
+ for (int i = 0; i < tasks.length; i++)
+ tasks[i] = p.schedule(new NoOpRunnable(),
+ SHORT_DELAY_MS, MILLISECONDS);
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ BlockingQueue<Runnable> q = p.getQueue();
+ for (ScheduledFuture task : tasks) {
+ assertFalse(task.isDone());
+ assertFalse(task.isCancelled());
+ assertTrue(q.contains(task));
+ }
+ assertTrue(p.isShutdown());
+ assertTrue(p.awaitTermination(SMALL_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
+ for (ScheduledFuture task : tasks) {
+ assertTrue(task.isDone());
+ assertFalse(task.isCancelled());
+ }
+ }
+
+ /**
+ * If setExecuteExistingDelayedTasksAfterShutdownPolicy is false,
+ * delayed tasks are cancelled at shutdown
+ */
+ public void testShutdown2() throws InterruptedException {
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ p.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
+ assertFalse(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
+ assertFalse(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
+ ScheduledFuture[] tasks = new ScheduledFuture[5];
+ for (int i = 0; i < tasks.length; i++)
+ tasks[i] = p.schedule(new NoOpRunnable(),
+ SHORT_DELAY_MS, MILLISECONDS);
+ BlockingQueue q = p.getQueue();
+ assertEquals(tasks.length, q.size());
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ assertTrue(p.isShutdown());
+ assertTrue(q.isEmpty());
+ assertTrue(p.awaitTermination(SMALL_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
+ for (ScheduledFuture task : tasks) {
+ assertTrue(task.isDone());
+ assertTrue(task.isCancelled());
+ }
+ }
+
+ /**
+ * If setContinueExistingPeriodicTasksAfterShutdownPolicy is set false,
+ * periodic tasks are cancelled at shutdown
+ */
+ public void testShutdown3() throws InterruptedException {
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ assertTrue(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
+ assertFalse(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
+ p.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
+ assertTrue(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
+ assertFalse(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
+ long initialDelay = LONG_DELAY_MS;
+ ScheduledFuture task =
+ p.scheduleAtFixedRate(new NoOpRunnable(), initialDelay,
+ 5, MILLISECONDS);
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ assertTrue(p.isShutdown());
+ assertTrue(p.getQueue().isEmpty());
+ assertTrue(task.isDone());
+ assertTrue(task.isCancelled());
+ joinPool(p);
+ }
+
+ /**
+ * if setContinueExistingPeriodicTasksAfterShutdownPolicy is true,
+ * periodic tasks are not cancelled at shutdown
+ */
+ public void testShutdown4() throws InterruptedException {
+ ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1);
+ final CountDownLatch counter = new CountDownLatch(2);
+ try {
+ p.setContinueExistingPeriodicTasksAfterShutdownPolicy(true);
+ assertTrue(p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
+ assertTrue(p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
+ final Runnable r = new CheckedRunnable() {
+ public void realRun() {
+ counter.countDown();
+ }};
+ ScheduledFuture task =
+ p.scheduleAtFixedRate(r, 1, 1, MILLISECONDS);
+ assertFalse(task.isDone());
+ assertFalse(task.isCancelled());
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ assertFalse(task.isCancelled());
+ assertFalse(p.isTerminated());
+ assertTrue(p.isShutdown());
+ assertTrue(counter.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertFalse(task.isCancelled());
+ assertTrue(task.cancel(false));
+ assertTrue(task.isDone());
+ assertTrue(task.isCancelled());
+ assertTrue(p.awaitTermination(SMALL_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
+ }
+ finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * completed submit of callable returns result
+ */
+ public void testSubmitCallable() throws Exception {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
+ Future<String> future = e.submit(new StringTask());
+ String result = future.get();
+ assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * completed submit of runnable returns successfully
+ */
+ public void testSubmitRunnable() throws Exception {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
+ Future<?> future = e.submit(new NoOpRunnable());
+ future.get();
+ assertTrue(future.isDone());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * completed submit of (runnable, result) returns result
+ */
+ public void testSubmitRunnable2() throws Exception {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
+ Future<String> future = e.submit(new NoOpRunnable(), TEST_STRING);
+ String result = future.get();
+ assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(null) throws NPE
+ */
+ public void testInvokeAny1() throws Exception {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
+ e.invokeAny(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(empty collection) throws IAE
+ */
+ public void testInvokeAny2() throws Exception {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
+ e.invokeAny(new ArrayList<Callable<String>>());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(c) throws NPE if c has null elements
+ */
+ public void testInvokeAny3() throws Exception {
+ CountDownLatch latch = new CountDownLatch(1);
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(latchAwaitingStringTask(latch));
+ l.add(null);
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ latch.countDown();
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(c) throws ExecutionException if no task completes
+ */
+ public void testInvokeAny4() throws Exception {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(c) returns result of some task
+ */
+ public void testInvokeAny5() throws Exception {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(new StringTask());
+ String result = e.invokeAny(l);
+ assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAll(null) throws NPE
+ */
+ public void testInvokeAll1() throws Exception {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
+ e.invokeAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAll(empty collection) returns empty collection
+ */
+ public void testInvokeAll2() throws Exception {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
+ List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>());
+ assertTrue(r.isEmpty());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAll(c) throws NPE if c has null elements
+ */
+ public void testInvokeAll3() throws Exception {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(null);
+ try {
+ e.invokeAll(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * get of invokeAll(c) throws exception on failed task
+ */
+ public void testInvokeAll4() throws Exception {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ List<Future<String>> futures = e.invokeAll(l);
+ assertEquals(1, futures.size());
+ try {
+ futures.get(0).get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAll(c) returns results of all completed tasks
+ */
+ public void testInvokeAll5() throws Exception {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(new StringTask());
+ List<Future<String>> futures = e.invokeAll(l);
+ assertEquals(2, futures.size());
+ for (Future<String> future : futures)
+ assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(null) throws NPE
+ */
+ public void testTimedInvokeAny1() throws Exception {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
+ e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(,,null) throws NPE
+ */
+ public void testTimedInvokeAnyNullTimeUnit() throws Exception {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(empty collection) throws IAE
+ */
+ public void testTimedInvokeAny2() throws Exception {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
+ e.invokeAny(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(c) throws NPE if c has null elements
+ */
+ public void testTimedInvokeAny3() throws Exception {
+ CountDownLatch latch = new CountDownLatch(1);
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(latchAwaitingStringTask(latch));
+ l.add(null);
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ latch.countDown();
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(c) throws ExecutionException if no task completes
+ */
+ public void testTimedInvokeAny4() throws Exception {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(c) returns result of some task
+ */
+ public void testTimedInvokeAny5() throws Exception {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(new StringTask());
+ String result = e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(null) throws NPE
+ */
+ public void testTimedInvokeAll1() throws Exception {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
+ e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(,,null) throws NPE
+ */
+ public void testTimedInvokeAllNullTimeUnit() throws Exception {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ try {
+ e.invokeAll(l, MEDIUM_DELAY_MS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(empty collection) returns empty collection
+ */
+ public void testTimedInvokeAll2() throws Exception {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
+ List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
+ assertTrue(r.isEmpty());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(c) throws NPE if c has null elements
+ */
+ public void testTimedInvokeAll3() throws Exception {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(null);
+ try {
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * get of element of invokeAll(c) throws exception on failed task
+ */
+ public void testTimedInvokeAll4() throws Exception {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ List<Future<String>> futures =
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ assertEquals(1, futures.size());
+ try {
+ futures.get(0).get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(c) returns results of all completed tasks
+ */
+ public void testTimedInvokeAll5() throws Exception {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(new StringTask());
+ List<Future<String>> futures =
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ assertEquals(2, futures.size());
+ for (Future<String> future : futures)
+ assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(c) cancels tasks not completed by timeout
+ */
+ public void testTimedInvokeAll6() throws Exception {
+ ExecutorService e = new ScheduledThreadPoolExecutor(2);
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(Executors.callable(new MediumPossiblyInterruptedRunnable(), TEST_STRING));
+ l.add(new StringTask());
+ List<Future<String>> futures =
+ e.invokeAll(l, SHORT_DELAY_MS, MILLISECONDS);
+ assertEquals(l.size(), futures.size());
+ for (Future future : futures)
+ assertTrue(future.isDone());
+ assertFalse(futures.get(0).isCancelled());
+ assertTrue(futures.get(1).isCancelled());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/SemaphoreTest.java b/jsr166-tests/src/test/java/jsr166/SemaphoreTest.java
new file mode 100644
index 0000000..f303285
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/SemaphoreTest.java
@@ -0,0 +1,629 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.*;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Semaphore;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+public class SemaphoreTest extends JSR166TestCase {
+
+ /**
+ * Subclass to expose protected methods
+ */
+ static class PublicSemaphore extends Semaphore {
+ PublicSemaphore(int permits) { super(permits); }
+ PublicSemaphore(int permits, boolean fair) { super(permits, fair); }
+ public Collection<Thread> getQueuedThreads() {
+ return super.getQueuedThreads();
+ }
+ public boolean hasQueuedThread(Thread t) {
+ return super.getQueuedThreads().contains(t);
+ }
+ public void reducePermits(int reduction) {
+ super.reducePermits(reduction);
+ }
+ }
+
+ /**
+ * A runnable calling acquire
+ */
+ class InterruptibleLockRunnable extends CheckedRunnable {
+ final Semaphore lock;
+ InterruptibleLockRunnable(Semaphore s) { lock = s; }
+ public void realRun() {
+ try {
+ lock.acquire();
+ }
+ catch (InterruptedException ignored) {}
+ }
+ }
+
+ /**
+ * A runnable calling acquire that expects to be interrupted
+ */
+ class InterruptedLockRunnable extends CheckedInterruptedRunnable {
+ final Semaphore lock;
+ InterruptedLockRunnable(Semaphore s) { lock = s; }
+ public void realRun() throws InterruptedException {
+ lock.acquire();
+ }
+ }
+
+ /**
+ * Spin-waits until s.hasQueuedThread(t) becomes true.
+ */
+ void waitForQueuedThread(PublicSemaphore s, Thread t) {
+ long startTime = System.nanoTime();
+ while (!s.hasQueuedThread(t)) {
+ if (millisElapsedSince(startTime) > LONG_DELAY_MS)
+ throw new AssertionFailedError("timed out");
+ Thread.yield();
+ }
+ assertTrue(s.hasQueuedThreads());
+ assertTrue(t.isAlive());
+ }
+
+ /**
+ * Spin-waits until s.hasQueuedThreads() becomes true.
+ */
+ void waitForQueuedThreads(Semaphore s) {
+ long startTime = System.nanoTime();
+ while (!s.hasQueuedThreads()) {
+ if (millisElapsedSince(startTime) > LONG_DELAY_MS)
+ throw new AssertionFailedError("timed out");
+ Thread.yield();
+ }
+ }
+
+ enum AcquireMethod {
+ acquire() {
+ void acquire(Semaphore s) throws InterruptedException {
+ s.acquire();
+ }
+ },
+ acquireN() {
+ void acquire(Semaphore s, int permits) throws InterruptedException {
+ s.acquire(permits);
+ }
+ },
+ acquireUninterruptibly() {
+ void acquire(Semaphore s) {
+ s.acquireUninterruptibly();
+ }
+ },
+ acquireUninterruptiblyN() {
+ void acquire(Semaphore s, int permits) {
+ s.acquireUninterruptibly(permits);
+ }
+ },
+ tryAcquire() {
+ void acquire(Semaphore s) {
+ assertTrue(s.tryAcquire());
+ }
+ },
+ tryAcquireN() {
+ void acquire(Semaphore s, int permits) {
+ assertTrue(s.tryAcquire(permits));
+ }
+ },
+ tryAcquireTimed() {
+ void acquire(Semaphore s) throws InterruptedException {
+ assertTrue(s.tryAcquire(2 * LONG_DELAY_MS, MILLISECONDS));
+ }
+ },
+ tryAcquireTimedN {
+ void acquire(Semaphore s, int permits) throws InterruptedException {
+ assertTrue(s.tryAcquire(permits, 2 * LONG_DELAY_MS, MILLISECONDS));
+ }
+ };
+
+ // Intentionally meta-circular
+
+ /** Acquires 1 permit. */
+ void acquire(Semaphore s) throws InterruptedException {
+ acquire(s, 1);
+ }
+ /** Acquires the given number of permits. */
+ void acquire(Semaphore s, int permits) throws InterruptedException {
+ for (int i = 0; i < permits; i++)
+ acquire(s);
+ }
+ }
+
+ /**
+ * Zero, negative, and positive initial values are allowed in constructor
+ */
+ public void testConstructor() { testConstructor(false); }
+ public void testConstructor_fair() { testConstructor(true); }
+ public void testConstructor(boolean fair) {
+ for (int permits : new int[] { -42, -1, 0, 1, 42 }) {
+ Semaphore s = new Semaphore(permits, fair);
+ assertEquals(permits, s.availablePermits());
+ assertEquals(fair, s.isFair());
+ }
+ }
+
+ /**
+ * Constructor without fairness argument behaves as nonfair
+ */
+ public void testConstructorDefaultsToNonFair() {
+ for (int permits : new int[] { -42, -1, 0, 1, 42 }) {
+ Semaphore s = new Semaphore(permits);
+ assertEquals(permits, s.availablePermits());
+ assertFalse(s.isFair());
+ }
+ }
+
+ /**
+ * tryAcquire succeeds when sufficient permits, else fails
+ */
+ public void testTryAcquireInSameThread() { testTryAcquireInSameThread(false); }
+ public void testTryAcquireInSameThread_fair() { testTryAcquireInSameThread(true); }
+ public void testTryAcquireInSameThread(boolean fair) {
+ Semaphore s = new Semaphore(2, fair);
+ assertEquals(2, s.availablePermits());
+ assertTrue(s.tryAcquire());
+ assertTrue(s.tryAcquire());
+ assertEquals(0, s.availablePermits());
+ assertFalse(s.tryAcquire());
+ assertFalse(s.tryAcquire());
+ assertEquals(0, s.availablePermits());
+ }
+
+ /**
+ * timed tryAcquire times out
+ */
+ public void testTryAcquire_timeout() { testTryAcquire_timeout(false); }
+ public void testTryAcquire_timeout_fair() { testTryAcquire_timeout(true); }
+ public void testTryAcquire_timeout(boolean fair) {
+ Semaphore s = new Semaphore(0, fair);
+ long startTime = System.nanoTime();
+ try { assertFalse(s.tryAcquire(timeoutMillis(), MILLISECONDS)); }
+ catch (InterruptedException e) { threadUnexpectedException(e); }
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ }
+
+ /**
+ * timed tryAcquire(N) times out
+ */
+ public void testTryAcquireN_timeout() { testTryAcquireN_timeout(false); }
+ public void testTryAcquireN_timeout_fair() { testTryAcquireN_timeout(true); }
+ public void testTryAcquireN_timeout(boolean fair) {
+ Semaphore s = new Semaphore(2, fair);
+ long startTime = System.nanoTime();
+ try { assertFalse(s.tryAcquire(3, timeoutMillis(), MILLISECONDS)); }
+ catch (InterruptedException e) { threadUnexpectedException(e); }
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ }
+
+ /**
+ * acquire(), acquire(N), timed tryAcquired, timed tryAcquire(N)
+ * are interruptible
+ */
+ public void testInterruptible_acquire() { testInterruptible(false, AcquireMethod.acquire); }
+ public void testInterruptible_acquire_fair() { testInterruptible(true, AcquireMethod.acquire); }
+ public void testInterruptible_acquireN() { testInterruptible(false, AcquireMethod.acquireN); }
+ public void testInterruptible_acquireN_fair() { testInterruptible(true, AcquireMethod.acquireN); }
+ public void testInterruptible_tryAcquireTimed() { testInterruptible(false, AcquireMethod.tryAcquireTimed); }
+ public void testInterruptible_tryAcquireTimed_fair() { testInterruptible(true, AcquireMethod.tryAcquireTimed); }
+ public void testInterruptible_tryAcquireTimedN() { testInterruptible(false, AcquireMethod.tryAcquireTimedN); }
+ public void testInterruptible_tryAcquireTimedN_fair() { testInterruptible(true, AcquireMethod.tryAcquireTimedN); }
+ public void testInterruptible(boolean fair, final AcquireMethod acquirer) {
+ final PublicSemaphore s = new PublicSemaphore(0, fair);
+ final Semaphore pleaseInterrupt = new Semaphore(0, fair);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() {
+ // Interrupt before acquire
+ Thread.currentThread().interrupt();
+ try {
+ acquirer.acquire(s);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+
+ // Interrupt during acquire
+ try {
+ acquirer.acquire(s);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+
+ // Interrupt before acquire(N)
+ Thread.currentThread().interrupt();
+ try {
+ acquirer.acquire(s, 3);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+
+ pleaseInterrupt.release();
+
+ // Interrupt during acquire(N)
+ try {
+ acquirer.acquire(s, 3);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ }});
+
+ waitForQueuedThread(s, t);
+ t.interrupt();
+ await(pleaseInterrupt);
+ waitForQueuedThread(s, t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * acquireUninterruptibly(), acquireUninterruptibly(N) are
+ * uninterruptible
+ */
+ public void testUninterruptible_acquireUninterruptibly() { testUninterruptible(false, AcquireMethod.acquireUninterruptibly); }
+ public void testUninterruptible_acquireUninterruptibly_fair() { testUninterruptible(true, AcquireMethod.acquireUninterruptibly); }
+ public void testUninterruptible_acquireUninterruptiblyN() { testUninterruptible(false, AcquireMethod.acquireUninterruptiblyN); }
+ public void testUninterruptible_acquireUninterruptiblyN_fair() { testUninterruptible(true, AcquireMethod.acquireUninterruptiblyN); }
+ public void testUninterruptible(boolean fair, final AcquireMethod acquirer) {
+ final PublicSemaphore s = new PublicSemaphore(0, fair);
+ final Semaphore pleaseInterrupt = new Semaphore(-1, fair);
+
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ // Interrupt before acquire
+ pleaseInterrupt.release();
+ Thread.currentThread().interrupt();
+ acquirer.acquire(s);
+ assertTrue(Thread.interrupted());
+ }});
+
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ // Interrupt during acquire
+ pleaseInterrupt.release();
+ acquirer.acquire(s);
+ assertTrue(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ waitForQueuedThread(s, t1);
+ waitForQueuedThread(s, t2);
+ t2.interrupt();
+
+ assertThreadStaysAlive(t1);
+ assertTrue(t2.isAlive());
+
+ s.release(2);
+
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+ /**
+ * hasQueuedThreads reports whether there are waiting threads
+ */
+ public void testHasQueuedThreads() { testHasQueuedThreads(false); }
+ public void testHasQueuedThreads_fair() { testHasQueuedThreads(true); }
+ public void testHasQueuedThreads(boolean fair) {
+ final PublicSemaphore lock = new PublicSemaphore(1, fair);
+ assertFalse(lock.hasQueuedThreads());
+ lock.acquireUninterruptibly();
+ Thread t1 = newStartedThread(new InterruptedLockRunnable(lock));
+ waitForQueuedThread(lock, t1);
+ assertTrue(lock.hasQueuedThreads());
+ Thread t2 = newStartedThread(new InterruptibleLockRunnable(lock));
+ waitForQueuedThread(lock, t2);
+ assertTrue(lock.hasQueuedThreads());
+ t1.interrupt();
+ awaitTermination(t1);
+ assertTrue(lock.hasQueuedThreads());
+ lock.release();
+ awaitTermination(t2);
+ assertFalse(lock.hasQueuedThreads());
+ }
+
+ /**
+ * getQueueLength reports number of waiting threads
+ */
+ public void testGetQueueLength() { testGetQueueLength(false); }
+ public void testGetQueueLength_fair() { testGetQueueLength(true); }
+ public void testGetQueueLength(boolean fair) {
+ final PublicSemaphore lock = new PublicSemaphore(1, fair);
+ assertEquals(0, lock.getQueueLength());
+ lock.acquireUninterruptibly();
+ Thread t1 = newStartedThread(new InterruptedLockRunnable(lock));
+ waitForQueuedThread(lock, t1);
+ assertEquals(1, lock.getQueueLength());
+ Thread t2 = newStartedThread(new InterruptibleLockRunnable(lock));
+ waitForQueuedThread(lock, t2);
+ assertEquals(2, lock.getQueueLength());
+ t1.interrupt();
+ awaitTermination(t1);
+ assertEquals(1, lock.getQueueLength());
+ lock.release();
+ awaitTermination(t2);
+ assertEquals(0, lock.getQueueLength());
+ }
+
+ /**
+ * getQueuedThreads includes waiting threads
+ */
+ public void testGetQueuedThreads() { testGetQueuedThreads(false); }
+ public void testGetQueuedThreads_fair() { testGetQueuedThreads(true); }
+ public void testGetQueuedThreads(boolean fair) {
+ final PublicSemaphore lock = new PublicSemaphore(1, fair);
+ assertTrue(lock.getQueuedThreads().isEmpty());
+ lock.acquireUninterruptibly();
+ assertTrue(lock.getQueuedThreads().isEmpty());
+ Thread t1 = newStartedThread(new InterruptedLockRunnable(lock));
+ waitForQueuedThread(lock, t1);
+ assertTrue(lock.getQueuedThreads().contains(t1));
+ Thread t2 = newStartedThread(new InterruptibleLockRunnable(lock));
+ waitForQueuedThread(lock, t2);
+ assertTrue(lock.getQueuedThreads().contains(t1));
+ assertTrue(lock.getQueuedThreads().contains(t2));
+ t1.interrupt();
+ awaitTermination(t1);
+ assertFalse(lock.getQueuedThreads().contains(t1));
+ assertTrue(lock.getQueuedThreads().contains(t2));
+ lock.release();
+ awaitTermination(t2);
+ assertTrue(lock.getQueuedThreads().isEmpty());
+ }
+
+ /**
+ * drainPermits reports and removes given number of permits
+ */
+ public void testDrainPermits() { testDrainPermits(false); }
+ public void testDrainPermits_fair() { testDrainPermits(true); }
+ public void testDrainPermits(boolean fair) {
+ Semaphore s = new Semaphore(0, fair);
+ assertEquals(0, s.availablePermits());
+ assertEquals(0, s.drainPermits());
+ s.release(10);
+ assertEquals(10, s.availablePermits());
+ assertEquals(10, s.drainPermits());
+ assertEquals(0, s.availablePermits());
+ assertEquals(0, s.drainPermits());
+ }
+
+ /**
+ * release(-N) throws IllegalArgumentException
+ */
+ public void testReleaseIAE() { testReleaseIAE(false); }
+ public void testReleaseIAE_fair() { testReleaseIAE(true); }
+ public void testReleaseIAE(boolean fair) {
+ Semaphore s = new Semaphore(10, fair);
+ try {
+ s.release(-1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * reducePermits(-N) throws IllegalArgumentException
+ */
+ public void testReducePermitsIAE() { testReducePermitsIAE(false); }
+ public void testReducePermitsIAE_fair() { testReducePermitsIAE(true); }
+ public void testReducePermitsIAE(boolean fair) {
+ PublicSemaphore s = new PublicSemaphore(10, fair);
+ try {
+ s.reducePermits(-1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * reducePermits reduces number of permits
+ */
+ public void testReducePermits() { testReducePermits(false); }
+ public void testReducePermits_fair() { testReducePermits(true); }
+ public void testReducePermits(boolean fair) {
+ PublicSemaphore s = new PublicSemaphore(10, fair);
+ assertEquals(10, s.availablePermits());
+ s.reducePermits(0);
+ assertEquals(10, s.availablePermits());
+ s.reducePermits(1);
+ assertEquals(9, s.availablePermits());
+ s.reducePermits(10);
+ assertEquals(-1, s.availablePermits());
+ s.reducePermits(10);
+ assertEquals(-11, s.availablePermits());
+ s.reducePermits(0);
+ assertEquals(-11, s.availablePermits());
+ }
+
+ /**
+ * a reserialized semaphore has same number of permits and
+ * fairness, but no queued threads
+ */
+ public void testSerialization() { testSerialization(false); }
+ public void testSerialization_fair() { testSerialization(true); }
+ public void testSerialization(boolean fair) {
+ try {
+ Semaphore s = new Semaphore(3, fair);
+ s.acquire();
+ s.acquire();
+ s.release();
+
+ Semaphore clone = serialClone(s);
+ assertEquals(fair, s.isFair());
+ assertEquals(fair, clone.isFair());
+ assertEquals(2, s.availablePermits());
+ assertEquals(2, clone.availablePermits());
+ clone.acquire();
+ clone.acquire();
+ clone.release();
+ assertEquals(2, s.availablePermits());
+ assertEquals(1, clone.availablePermits());
+
+ s = new Semaphore(0, fair);
+ Thread t = newStartedThread(new InterruptibleLockRunnable(s));
+ waitForQueuedThreads(s);
+ clone = serialClone(s);
+ assertEquals(fair, s.isFair());
+ assertEquals(fair, clone.isFair());
+ assertEquals(0, s.availablePermits());
+ assertEquals(0, clone.availablePermits());
+ assertTrue(s.hasQueuedThreads());
+ assertFalse(clone.hasQueuedThreads());
+ s.release();
+ awaitTermination(t);
+ assertFalse(s.hasQueuedThreads());
+ assertFalse(clone.hasQueuedThreads());
+ } catch (InterruptedException e) { threadUnexpectedException(e); }
+ }
+
+ /**
+ * tryAcquire(n) succeeds when sufficient permits, else fails
+ */
+ public void testTryAcquireNInSameThread() { testTryAcquireNInSameThread(false); }
+ public void testTryAcquireNInSameThread_fair() { testTryAcquireNInSameThread(true); }
+ public void testTryAcquireNInSameThread(boolean fair) {
+ Semaphore s = new Semaphore(2, fair);
+ assertEquals(2, s.availablePermits());
+ assertFalse(s.tryAcquire(3));
+ assertEquals(2, s.availablePermits());
+ assertTrue(s.tryAcquire(2));
+ assertEquals(0, s.availablePermits());
+ assertFalse(s.tryAcquire(1));
+ assertFalse(s.tryAcquire(2));
+ assertEquals(0, s.availablePermits());
+ }
+
+ /**
+ * acquire succeeds if permits available
+ */
+ public void testReleaseAcquireSameThread_acquire() { testReleaseAcquireSameThread(false, AcquireMethod.acquire); }
+ public void testReleaseAcquireSameThread_acquire_fair() { testReleaseAcquireSameThread(true, AcquireMethod.acquire); }
+ public void testReleaseAcquireSameThread_acquireN() { testReleaseAcquireSameThread(false, AcquireMethod.acquireN); }
+ public void testReleaseAcquireSameThread_acquireN_fair() { testReleaseAcquireSameThread(true, AcquireMethod.acquireN); }
+ public void testReleaseAcquireSameThread_acquireUninterruptibly() { testReleaseAcquireSameThread(false, AcquireMethod.acquireUninterruptibly); }
+ public void testReleaseAcquireSameThread_acquireUninterruptibly_fair() { testReleaseAcquireSameThread(true, AcquireMethod.acquireUninterruptibly); }
+ public void testReleaseAcquireSameThread_acquireUninterruptiblyN() { testReleaseAcquireSameThread(false, AcquireMethod.acquireUninterruptibly); }
+ public void testReleaseAcquireSameThread_acquireUninterruptiblyN_fair() { testReleaseAcquireSameThread(true, AcquireMethod.acquireUninterruptibly); }
+ public void testReleaseAcquireSameThread_tryAcquire() { testReleaseAcquireSameThread(false, AcquireMethod.tryAcquire); }
+ public void testReleaseAcquireSameThread_tryAcquire_fair() { testReleaseAcquireSameThread(true, AcquireMethod.tryAcquire); }
+ public void testReleaseAcquireSameThread_tryAcquireN() { testReleaseAcquireSameThread(false, AcquireMethod.tryAcquireN); }
+ public void testReleaseAcquireSameThread_tryAcquireN_fair() { testReleaseAcquireSameThread(true, AcquireMethod.tryAcquireN); }
+ public void testReleaseAcquireSameThread_tryAcquireTimed() { testReleaseAcquireSameThread(false, AcquireMethod.tryAcquireTimed); }
+ public void testReleaseAcquireSameThread_tryAcquireTimed_fair() { testReleaseAcquireSameThread(true, AcquireMethod.tryAcquireTimed); }
+ public void testReleaseAcquireSameThread_tryAcquireTimedN() { testReleaseAcquireSameThread(false, AcquireMethod.tryAcquireTimedN); }
+ public void testReleaseAcquireSameThread_tryAcquireTimedN_fair() { testReleaseAcquireSameThread(true, AcquireMethod.tryAcquireTimedN); }
+ public void testReleaseAcquireSameThread(boolean fair,
+ final AcquireMethod acquirer) {
+ Semaphore s = new Semaphore(1, fair);
+ for (int i = 1; i < 6; i++) {
+ s.release(i);
+ assertEquals(1 + i, s.availablePermits());
+ try {
+ acquirer.acquire(s, i);
+ } catch (InterruptedException e) { threadUnexpectedException(e); }
+ assertEquals(1, s.availablePermits());
+ }
+ }
+
+ /**
+ * release in one thread enables acquire in another thread
+ */
+ public void testReleaseAcquireDifferentThreads_acquire() { testReleaseAcquireDifferentThreads(false, AcquireMethod.acquire); }
+ public void testReleaseAcquireDifferentThreads_acquire_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.acquire); }
+ public void testReleaseAcquireDifferentThreads_acquireN() { testReleaseAcquireDifferentThreads(false, AcquireMethod.acquireN); }
+ public void testReleaseAcquireDifferentThreads_acquireN_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.acquireN); }
+ public void testReleaseAcquireDifferentThreads_acquireUninterruptibly() { testReleaseAcquireDifferentThreads(false, AcquireMethod.acquireUninterruptibly); }
+ public void testReleaseAcquireDifferentThreads_acquireUninterruptibly_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.acquireUninterruptibly); }
+ public void testReleaseAcquireDifferentThreads_acquireUninterruptiblyN() { testReleaseAcquireDifferentThreads(false, AcquireMethod.acquireUninterruptibly); }
+ public void testReleaseAcquireDifferentThreads_acquireUninterruptiblyN_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.acquireUninterruptibly); }
+ public void testReleaseAcquireDifferentThreads_tryAcquireTimed() { testReleaseAcquireDifferentThreads(false, AcquireMethod.tryAcquireTimed); }
+ public void testReleaseAcquireDifferentThreads_tryAcquireTimed_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.tryAcquireTimed); }
+ public void testReleaseAcquireDifferentThreads_tryAcquireTimedN() { testReleaseAcquireDifferentThreads(false, AcquireMethod.tryAcquireTimedN); }
+ public void testReleaseAcquireDifferentThreads_tryAcquireTimedN_fair() { testReleaseAcquireDifferentThreads(true, AcquireMethod.tryAcquireTimedN); }
+ public void testReleaseAcquireDifferentThreads(boolean fair,
+ final AcquireMethod acquirer) {
+ final Semaphore s = new Semaphore(0, fair);
+ final int rounds = 4;
+ long startTime = System.nanoTime();
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ for (int i = 0; i < rounds; i++) {
+ assertFalse(s.hasQueuedThreads());
+ if (i % 2 == 0)
+ acquirer.acquire(s);
+ else
+ acquirer.acquire(s, 3);
+ }}});
+
+ for (int i = 0; i < rounds; i++) {
+ while (! (s.availablePermits() == 0 && s.hasQueuedThreads()))
+ Thread.yield();
+ assertTrue(t.isAlive());
+ if (i % 2 == 0)
+ s.release();
+ else
+ s.release(3);
+ }
+ awaitTermination(t);
+ assertEquals(0, s.availablePermits());
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ }
+
+ /**
+ * fair locks are strictly FIFO
+ */
+ public void testFairLocksFifo() {
+ final PublicSemaphore s = new PublicSemaphore(1, true);
+ final CountDownLatch pleaseRelease = new CountDownLatch(1);
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ // Will block; permits are available, but not three
+ s.acquire(3);
+ }});
+
+ waitForQueuedThreads(s);
+
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ // Will fail, even though 1 permit is available
+ assertFalse(s.tryAcquire(0L, MILLISECONDS));
+ assertFalse(s.tryAcquire(1, 0L, MILLISECONDS));
+
+ // untimed tryAcquire will barge and succeed
+ assertTrue(s.tryAcquire());
+ s.release(2);
+ assertTrue(s.tryAcquire(2));
+ s.release();
+
+ pleaseRelease.countDown();
+ // Will queue up behind t1, even though 1 permit is available
+ s.acquire();
+ }});
+
+ await(pleaseRelease);
+ waitForQueuedThread(s, t2);
+ s.release(2);
+ awaitTermination(t1);
+ assertTrue(t2.isAlive());
+ s.release();
+ awaitTermination(t2);
+ }
+
+ /**
+ * toString indicates current number of permits
+ */
+ public void testToString() { testToString(false); }
+ public void testToString_fair() { testToString(true); }
+ public void testToString(boolean fair) {
+ PublicSemaphore s = new PublicSemaphore(0, fair);
+ assertTrue(s.toString().contains("Permits = 0"));
+ s.release();
+ assertTrue(s.toString().contains("Permits = 1"));
+ s.release(2);
+ assertTrue(s.toString().contains("Permits = 3"));
+ s.reducePermits(5);
+ assertTrue(s.toString().contains("Permits = -2"));
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/SynchronousQueueTest.java b/jsr166-tests/src/test/java/jsr166/SynchronousQueueTest.java
new file mode 100644
index 0000000..711b47b
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/SynchronousQueueTest.java
@@ -0,0 +1,601 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.SynchronousQueue;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+public class SynchronousQueueTest extends JSR166TestCase {
+
+ public static class Fair extends BlockingQueueTest {
+ protected BlockingQueue emptyCollection() {
+ return new SynchronousQueue(true);
+ }
+ }
+
+ public static class NonFair extends BlockingQueueTest {
+ protected BlockingQueue emptyCollection() {
+ return new SynchronousQueue(false);
+ }
+ }
+
+ /**
+ * Any SynchronousQueue is both empty and full
+ */
+ public void testEmptyFull() { testEmptyFull(false); }
+ public void testEmptyFull_fair() { testEmptyFull(true); }
+ public void testEmptyFull(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ assertTrue(q.isEmpty());
+ assertEquals(0, q.size());
+ assertEquals(0, q.remainingCapacity());
+ assertFalse(q.offer(zero));
+ }
+
+ /**
+ * offer fails if no active taker
+ */
+ public void testOffer() { testOffer(false); }
+ public void testOffer_fair() { testOffer(true); }
+ public void testOffer(boolean fair) {
+ SynchronousQueue q = new SynchronousQueue(fair);
+ assertFalse(q.offer(one));
+ }
+
+ /**
+ * add throws IllegalStateException if no active taker
+ */
+ public void testAdd() { testAdd(false); }
+ public void testAdd_fair() { testAdd(true); }
+ public void testAdd(boolean fair) {
+ SynchronousQueue q = new SynchronousQueue(fair);
+ assertEquals(0, q.remainingCapacity());
+ try {
+ q.add(one);
+ shouldThrow();
+ } catch (IllegalStateException success) {}
+ }
+
+ /**
+ * addAll(this) throws IllegalArgumentException
+ */
+ public void testAddAll_self() { testAddAll_self(false); }
+ public void testAddAll_self_fair() { testAddAll_self(true); }
+ public void testAddAll_self(boolean fair) {
+ SynchronousQueue q = new SynchronousQueue(fair);
+ try {
+ q.addAll(q);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * addAll throws ISE if no active taker
+ */
+ public void testAddAll_ISE() { testAddAll_ISE(false); }
+ public void testAddAll_ISE_fair() { testAddAll_ISE(true); }
+ public void testAddAll_ISE(boolean fair) {
+ SynchronousQueue q = new SynchronousQueue(fair);
+ Integer[] ints = new Integer[1];
+ for (int i = 0; i < ints.length; i++)
+ ints[i] = i;
+ Collection<Integer> coll = Arrays.asList(ints);
+ try {
+ q.addAll(coll);
+ shouldThrow();
+ } catch (IllegalStateException success) {}
+ }
+
+ /**
+ * put blocks interruptibly if no active taker
+ */
+ public void testBlockingPut() { testBlockingPut(false); }
+ public void testBlockingPut_fair() { testBlockingPut(true); }
+ public void testBlockingPut(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ Thread.currentThread().interrupt();
+ try {
+ q.put(99);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ q.put(99);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ assertEquals(0, q.remainingCapacity());
+ }
+
+ /**
+ * put blocks interruptibly waiting for take
+ */
+ public void testPutWithTake() { testPutWithTake(false); }
+ public void testPutWithTake_fair() { testPutWithTake(true); }
+ public void testPutWithTake(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ final CountDownLatch pleaseTake = new CountDownLatch(1);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ pleaseTake.countDown();
+ q.put(one);
+
+ pleaseInterrupt.countDown();
+ try {
+ q.put(99);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseTake);
+ assertEquals(0, q.remainingCapacity());
+ try { assertSame(one, q.take()); }
+ catch (InterruptedException e) { threadUnexpectedException(e); }
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ assertEquals(0, q.remainingCapacity());
+ }
+
+ /**
+ * timed offer times out if elements not taken
+ */
+ public void testTimedOffer() { testTimedOffer(false); }
+ public void testTimedOffer_fair() { testTimedOffer(true); }
+ public void testTimedOffer(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ long startTime = System.nanoTime();
+ assertFalse(q.offer(new Object(), timeoutMillis(), MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ pleaseInterrupt.countDown();
+ try {
+ q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * poll return null if no active putter
+ */
+ public void testPoll() { testPoll(false); }
+ public void testPoll_fair() { testPoll(true); }
+ public void testPoll(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ assertNull(q.poll());
+ }
+
+ /**
+ * timed poll with zero timeout times out if no active putter
+ */
+ public void testTimedPoll0() { testTimedPoll0(false); }
+ public void testTimedPoll0_fair() { testTimedPoll0(true); }
+ public void testTimedPoll0(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ try { assertNull(q.poll(0, MILLISECONDS)); }
+ catch (InterruptedException e) { threadUnexpectedException(e); }
+ }
+
+ /**
+ * timed poll with nonzero timeout times out if no active putter
+ */
+ public void testTimedPoll() { testTimedPoll(false); }
+ public void testTimedPoll_fair() { testTimedPoll(true); }
+ public void testTimedPoll(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ long startTime = System.nanoTime();
+ try { assertNull(q.poll(timeoutMillis(), MILLISECONDS)); }
+ catch (InterruptedException e) { threadUnexpectedException(e); }
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+ }
+
+ /**
+ * timed poll before a delayed offer times out, returning null;
+ * after offer succeeds; on interruption throws
+ */
+ public void testTimedPollWithOffer() { testTimedPollWithOffer(false); }
+ public void testTimedPollWithOffer_fair() { testTimedPollWithOffer(true); }
+ public void testTimedPollWithOffer(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ final CountDownLatch pleaseOffer = new CountDownLatch(1);
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ long startTime = System.nanoTime();
+ assertNull(q.poll(timeoutMillis(), MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+
+ pleaseOffer.countDown();
+ startTime = System.nanoTime();
+ assertSame(zero, q.poll(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) < MEDIUM_DELAY_MS);
+
+ Thread.currentThread().interrupt();
+ try {
+ q.poll(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ q.poll(LONG_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseOffer);
+ long startTime = System.nanoTime();
+ try { assertTrue(q.offer(zero, LONG_DELAY_MS, MILLISECONDS)); }
+ catch (InterruptedException e) { threadUnexpectedException(e); }
+ assertTrue(millisElapsedSince(startTime) < MEDIUM_DELAY_MS);
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * peek() returns null if no active putter
+ */
+ public void testPeek() { testPeek(false); }
+ public void testPeek_fair() { testPeek(true); }
+ public void testPeek(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ assertNull(q.peek());
+ }
+
+ /**
+ * element() throws NoSuchElementException if no active putter
+ */
+ public void testElement() { testElement(false); }
+ public void testElement_fair() { testElement(true); }
+ public void testElement(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ try {
+ q.element();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * remove() throws NoSuchElementException if no active putter
+ */
+ public void testRemove() { testRemove(false); }
+ public void testRemove_fair() { testRemove(true); }
+ public void testRemove(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ try {
+ q.remove();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * contains returns false
+ */
+ public void testContains() { testContains(false); }
+ public void testContains_fair() { testContains(true); }
+ public void testContains(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ assertFalse(q.contains(zero));
+ }
+
+ /**
+ * clear ensures isEmpty
+ */
+ public void testClear() { testClear(false); }
+ public void testClear_fair() { testClear(true); }
+ public void testClear(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ q.clear();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * containsAll returns false unless empty
+ */
+ public void testContainsAll() { testContainsAll(false); }
+ public void testContainsAll_fair() { testContainsAll(true); }
+ public void testContainsAll(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ Integer[] empty = new Integer[0];
+ assertTrue(q.containsAll(Arrays.asList(empty)));
+ Integer[] ints = new Integer[1]; ints[0] = zero;
+ assertFalse(q.containsAll(Arrays.asList(ints)));
+ }
+
+ /**
+ * retainAll returns false
+ */
+ public void testRetainAll() { testRetainAll(false); }
+ public void testRetainAll_fair() { testRetainAll(true); }
+ public void testRetainAll(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ Integer[] empty = new Integer[0];
+ assertFalse(q.retainAll(Arrays.asList(empty)));
+ Integer[] ints = new Integer[1]; ints[0] = zero;
+ assertFalse(q.retainAll(Arrays.asList(ints)));
+ }
+
+ /**
+ * removeAll returns false
+ */
+ public void testRemoveAll() { testRemoveAll(false); }
+ public void testRemoveAll_fair() { testRemoveAll(true); }
+ public void testRemoveAll(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ Integer[] empty = new Integer[0];
+ assertFalse(q.removeAll(Arrays.asList(empty)));
+ Integer[] ints = new Integer[1]; ints[0] = zero;
+ assertFalse(q.containsAll(Arrays.asList(ints)));
+ }
+
+ /**
+ * toArray is empty
+ */
+ public void testToArray() { testToArray(false); }
+ public void testToArray_fair() { testToArray(true); }
+ public void testToArray(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ Object[] o = q.toArray();
+ assertEquals(0, o.length);
+ }
+
+ /**
+ * toArray(Integer array) returns its argument with the first
+ * element (if present) nulled out
+ */
+ public void testToArray2() { testToArray2(false); }
+ public void testToArray2_fair() { testToArray2(true); }
+ public void testToArray2(boolean fair) {
+ final SynchronousQueue<Integer> q
+ = new SynchronousQueue<Integer>(fair);
+ Integer[] a;
+
+ a = new Integer[0];
+ assertSame(a, q.toArray(a));
+
+ a = new Integer[3];
+ Arrays.fill(a, 42);
+ assertSame(a, q.toArray(a));
+ assertNull(a[0]);
+ for (int i = 1; i < a.length; i++)
+ assertEquals(42, (int) a[i]);
+ }
+
+ /**
+ * toArray(null) throws NPE
+ */
+ public void testToArray_null() { testToArray_null(false); }
+ public void testToArray_null_fair() { testToArray_null(true); }
+ public void testToArray_null(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ try {
+ Object o[] = q.toArray(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * iterator does not traverse any elements
+ */
+ public void testIterator() { testIterator(false); }
+ public void testIterator_fair() { testIterator(true); }
+ public void testIterator(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ Iterator it = q.iterator();
+ assertFalse(it.hasNext());
+ try {
+ Object x = it.next();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+
+ /**
+ * iterator remove throws ISE
+ */
+ public void testIteratorRemove() { testIteratorRemove(false); }
+ public void testIteratorRemove_fair() { testIteratorRemove(true); }
+ public void testIteratorRemove(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ Iterator it = q.iterator();
+ try {
+ it.remove();
+ shouldThrow();
+ } catch (IllegalStateException success) {}
+ }
+
+ /**
+ * toString returns a non-null string
+ */
+ public void testToString() { testToString(false); }
+ public void testToString_fair() { testToString(true); }
+ public void testToString(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ String s = q.toString();
+ assertNotNull(s);
+ }
+
+ /**
+ * offer transfers elements across Executor tasks
+ */
+ public void testOfferInExecutor() { testOfferInExecutor(false); }
+ public void testOfferInExecutor_fair() { testOfferInExecutor(true); }
+ public void testOfferInExecutor(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+ final CheckedBarrier threadsStarted = new CheckedBarrier(2);
+
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(q.offer(one));
+ threadsStarted.await();
+ assertTrue(q.offer(one, LONG_DELAY_MS, MILLISECONDS));
+ assertEquals(0, q.remainingCapacity());
+ }});
+
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ assertSame(one, q.take());
+ }});
+
+ joinPool(executor);
+ }
+
+ /**
+ * timed poll retrieves elements across Executor threads
+ */
+ public void testPollInExecutor() { testPollInExecutor(false); }
+ public void testPollInExecutor_fair() { testPollInExecutor(true); }
+ public void testPollInExecutor(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ final CheckedBarrier threadsStarted = new CheckedBarrier(2);
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertNull(q.poll());
+ threadsStarted.await();
+ assertSame(one, q.poll(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(q.isEmpty());
+ }});
+
+ executor.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.await();
+ q.put(one);
+ }});
+
+ joinPool(executor);
+ }
+
+ /**
+ * a deserialized serialized queue is usable
+ */
+ public void testSerialization() {
+ final SynchronousQueue x = new SynchronousQueue();
+ final SynchronousQueue y = new SynchronousQueue(false);
+ final SynchronousQueue z = new SynchronousQueue(true);
+ assertSerialEquals(x, y);
+ assertNotSerialEquals(x, z);
+ SynchronousQueue[] qs = { x, y, z };
+ for (SynchronousQueue q : qs) {
+ SynchronousQueue clone = serialClone(q);
+ assertNotSame(q, clone);
+ assertSerialEquals(q, clone);
+ assertTrue(clone.isEmpty());
+ assertEquals(0, clone.size());
+ assertEquals(0, clone.remainingCapacity());
+ assertFalse(clone.offer(zero));
+ }
+ }
+
+ /**
+ * drainTo(c) of empty queue doesn't transfer elements
+ */
+ public void testDrainTo() { testDrainTo(false); }
+ public void testDrainTo_fair() { testDrainTo(true); }
+ public void testDrainTo(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ ArrayList l = new ArrayList();
+ q.drainTo(l);
+ assertEquals(0, q.size());
+ assertEquals(0, l.size());
+ }
+
+ /**
+ * drainTo empties queue, unblocking a waiting put.
+ */
+ public void testDrainToWithActivePut() { testDrainToWithActivePut(false); }
+ public void testDrainToWithActivePut_fair() { testDrainToWithActivePut(true); }
+ public void testDrainToWithActivePut(boolean fair) {
+ final SynchronousQueue q = new SynchronousQueue(fair);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ q.put(one);
+ }});
+
+ ArrayList l = new ArrayList();
+ long startTime = System.nanoTime();
+ while (l.isEmpty()) {
+ q.drainTo(l);
+ if (millisElapsedSince(startTime) > LONG_DELAY_MS)
+ fail("timed out");
+ Thread.yield();
+ }
+ assertTrue(l.size() == 1);
+ assertSame(one, l.get(0));
+ awaitTermination(t);
+ }
+
+ /**
+ * drainTo(c, n) empties up to n elements of queue into c
+ */
+ public void testDrainToN() throws InterruptedException {
+ final SynchronousQueue q = new SynchronousQueue();
+ Thread t1 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ q.put(one);
+ }});
+
+ Thread t2 = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ q.put(two);
+ }});
+
+ ArrayList l = new ArrayList();
+ delay(SHORT_DELAY_MS);
+ q.drainTo(l, 1);
+ assertEquals(1, l.size());
+ q.drainTo(l, 1);
+ assertEquals(2, l.size());
+ assertTrue(l.contains(one));
+ assertTrue(l.contains(two));
+ awaitTermination(t1);
+ awaitTermination(t2);
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/SystemTest.java b/jsr166-tests/src/test/java/jsr166/SystemTest.java
new file mode 100644
index 0000000..32caec2
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/SystemTest.java
@@ -0,0 +1,63 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+
+public class SystemTest extends JSR166TestCase {
+
+ /**
+ * Worst case rounding for millisecs; set for 60 cycle millis clock.
+ * This value might need to be changed on JVMs with coarser
+ * System.currentTimeMillis clocks.
+ */
+ static final long MILLIS_ROUND = 17;
+
+ /**
+ * Nanos between readings of millis is no longer than millis (plus
+ * possible rounding).
+ * This shows only that nano timing not (much) worse than milli.
+ */
+ public void testNanoTime1() throws InterruptedException {
+ long m1 = System.currentTimeMillis();
+ Thread.sleep(1);
+ long n1 = System.nanoTime();
+ Thread.sleep(SHORT_DELAY_MS);
+ long n2 = System.nanoTime();
+ Thread.sleep(1);
+ long m2 = System.currentTimeMillis();
+ long millis = m2 - m1;
+ long nanos = n2 - n1;
+ assertTrue(nanos >= 0);
+ long nanosAsMillis = nanos / 1000000;
+ assertTrue(nanosAsMillis <= millis + MILLIS_ROUND);
+ }
+
+ /**
+ * Millis between readings of nanos is less than nanos, adjusting
+ * for rounding.
+ * This shows only that nano timing not (much) worse than milli.
+ */
+ public void testNanoTime2() throws InterruptedException {
+ long n1 = System.nanoTime();
+ Thread.sleep(1);
+ long m1 = System.currentTimeMillis();
+ Thread.sleep(SHORT_DELAY_MS);
+ long m2 = System.currentTimeMillis();
+ Thread.sleep(1);
+ long n2 = System.nanoTime();
+ long millis = m2 - m1;
+ long nanos = n2 - n1;
+
+ assertTrue(nanos >= 0);
+ long nanosAsMillis = nanos / 1000000;
+ assertTrue(millis <= nanosAsMillis + MILLIS_ROUND);
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/ThreadLocalRandomTest.java b/jsr166-tests/src/test/java/jsr166/ThreadLocalRandomTest.java
new file mode 100644
index 0000000..665a2b7
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/ThreadLocalRandomTest.java
@@ -0,0 +1,290 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.*;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class ThreadLocalRandomTest extends JSR166TestCase {
+
+ /*
+ * Testing coverage notes:
+ *
+ * We don't test randomness properties, but only that repeated
+ * calls, up to NCALLS tries, produce at least one different
+ * result. For bounded versions, we sample various intervals
+ * across multiples of primes.
+ */
+
+ //
+ static final int NCALLS = 10000;
+
+ // max sampled int bound
+ static final int MAX_INT_BOUND = (1 << 28);
+
+ // Max sampled long bound
+ static final long MAX_LONG_BOUND = (1L << 42);
+
+ /**
+ * setSeed throws UnsupportedOperationException
+ */
+ public void testSetSeed() {
+ try {
+ ThreadLocalRandom.current().setSeed(17);
+ shouldThrow();
+ } catch (UnsupportedOperationException success) {}
+ }
+
+ /**
+ * Repeated calls to nextInt produce at least one different result
+ */
+ public void testNextInt() {
+ int f = ThreadLocalRandom.current().nextInt();
+ int i = 0;
+ while (i < NCALLS && ThreadLocalRandom.current().nextInt() == f)
+ ++i;
+ assertTrue(i < NCALLS);
+ }
+
+ /**
+ * Repeated calls to nextLong produce at least one different result
+ */
+ public void testNextLong() {
+ long f = ThreadLocalRandom.current().nextLong();
+ int i = 0;
+ while (i < NCALLS && ThreadLocalRandom.current().nextLong() == f)
+ ++i;
+ assertTrue(i < NCALLS);
+ }
+
+ /**
+ * Repeated calls to nextBoolean produce at least one different result
+ */
+ public void testNextBoolean() {
+ boolean f = ThreadLocalRandom.current().nextBoolean();
+ int i = 0;
+ while (i < NCALLS && ThreadLocalRandom.current().nextBoolean() == f)
+ ++i;
+ assertTrue(i < NCALLS);
+ }
+
+ /**
+ * Repeated calls to nextFloat produce at least one different result
+ */
+ public void testNextFloat() {
+ float f = ThreadLocalRandom.current().nextFloat();
+ int i = 0;
+ while (i < NCALLS && ThreadLocalRandom.current().nextFloat() == f)
+ ++i;
+ assertTrue(i < NCALLS);
+ }
+
+ /**
+ * Repeated calls to nextDouble produce at least one different result
+ */
+ public void testNextDouble() {
+ double f = ThreadLocalRandom.current().nextDouble();
+ double i = 0;
+ while (i < NCALLS && ThreadLocalRandom.current().nextDouble() == f)
+ ++i;
+ assertTrue(i < NCALLS);
+ }
+
+ /**
+ * Repeated calls to nextGaussian produce at least one different result
+ */
+ public void testNextGaussian() {
+ double f = ThreadLocalRandom.current().nextGaussian();
+ int i = 0;
+ while (i < NCALLS && ThreadLocalRandom.current().nextGaussian() == f)
+ ++i;
+ assertTrue(i < NCALLS);
+ }
+
+ /**
+ * nextInt(negative) throws IllegalArgumentException;
+ */
+ public void testNextIntBoundedNeg() {
+ try {
+ int f = ThreadLocalRandom.current().nextInt(-17);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * nextInt(least >= bound) throws IllegalArgumentException;
+ */
+ public void testNextIntBadBounds() {
+ try {
+ int f = ThreadLocalRandom.current().nextInt(17, 2);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * nextInt(bound) returns 0 <= value < bound;
+ * repeated calls produce at least one different result
+ */
+ public void testNextIntBounded() {
+ // sample bound space across prime number increments
+ for (int bound = 2; bound < MAX_INT_BOUND; bound += 524959) {
+ int f = ThreadLocalRandom.current().nextInt(bound);
+ assertTrue(0 <= f && f < bound);
+ int i = 0;
+ int j;
+ while (i < NCALLS &&
+ (j = ThreadLocalRandom.current().nextInt(bound)) == f) {
+ assertTrue(0 <= j && j < bound);
+ ++i;
+ }
+ assertTrue(i < NCALLS);
+ }
+ }
+
+ /**
+ * nextInt(least, bound) returns least <= value < bound;
+ * repeated calls produce at least one different result
+ */
+ public void testNextIntBounded2() {
+ for (int least = -15485863; least < MAX_INT_BOUND; least += 524959) {
+ for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 49979687) {
+ int f = ThreadLocalRandom.current().nextInt(least, bound);
+ assertTrue(least <= f && f < bound);
+ int i = 0;
+ int j;
+ while (i < NCALLS &&
+ (j = ThreadLocalRandom.current().nextInt(least, bound)) == f) {
+ assertTrue(least <= j && j < bound);
+ ++i;
+ }
+ assertTrue(i < NCALLS);
+ }
+ }
+ }
+
+ /**
+ * nextLong(negative) throws IllegalArgumentException;
+ */
+ public void testNextLongBoundedNeg() {
+ try {
+ long f = ThreadLocalRandom.current().nextLong(-17);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * nextLong(least >= bound) throws IllegalArgumentException;
+ */
+ public void testNextLongBadBounds() {
+ try {
+ long f = ThreadLocalRandom.current().nextLong(17, 2);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * nextLong(bound) returns 0 <= value < bound;
+ * repeated calls produce at least one different result
+ */
+ public void testNextLongBounded() {
+ for (long bound = 2; bound < MAX_LONG_BOUND; bound += 15485863) {
+ long f = ThreadLocalRandom.current().nextLong(bound);
+ assertTrue(0 <= f && f < bound);
+ int i = 0;
+ long j;
+ while (i < NCALLS &&
+ (j = ThreadLocalRandom.current().nextLong(bound)) == f) {
+ assertTrue(0 <= j && j < bound);
+ ++i;
+ }
+ assertTrue(i < NCALLS);
+ }
+ }
+
+ /**
+ * nextLong(least, bound) returns least <= value < bound;
+ * repeated calls produce at least one different result
+ */
+ public void testNextLongBounded2() {
+ for (long least = -86028121; least < MAX_LONG_BOUND; least += 982451653L) {
+ for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) {
+ long f = ThreadLocalRandom.current().nextLong(least, bound);
+ assertTrue(least <= f && f < bound);
+ int i = 0;
+ long j;
+ while (i < NCALLS &&
+ (j = ThreadLocalRandom.current().nextLong(least, bound)) == f) {
+ assertTrue(least <= j && j < bound);
+ ++i;
+ }
+ assertTrue(i < NCALLS);
+ }
+ }
+ }
+
+ /**
+ * nextDouble(least, bound) returns least <= value < bound;
+ * repeated calls produce at least one different result
+ */
+ public void testNextDoubleBounded2() {
+ for (double least = 0.0001; least < 1.0e20; least *= 8) {
+ for (double bound = least * 1.001; bound < 1.0e20; bound *= 16) {
+ double f = ThreadLocalRandom.current().nextDouble(least, bound);
+ assertTrue(least <= f && f < bound);
+ int i = 0;
+ double j;
+ while (i < NCALLS &&
+ (j = ThreadLocalRandom.current().nextDouble(least, bound)) == f) {
+ assertTrue(least <= j && j < bound);
+ ++i;
+ }
+ assertTrue(i < NCALLS);
+ }
+ }
+ }
+
+ /**
+ * Different threads produce different pseudo-random sequences
+ */
+ public void testDifferentSequences() {
+ // Don't use main thread's ThreadLocalRandom - it is likely to
+ // be polluted by previous tests.
+ final AtomicReference<ThreadLocalRandom> threadLocalRandom =
+ new AtomicReference<ThreadLocalRandom>();
+ final AtomicLong rand = new AtomicLong();
+
+ long firstRand = 0;
+ ThreadLocalRandom firstThreadLocalRandom = null;
+
+ final CheckedRunnable getRandomState = new CheckedRunnable() {
+ public void realRun() {
+ ThreadLocalRandom current = ThreadLocalRandom.current();
+ assertSame(current, ThreadLocalRandom.current());
+ // test bug: the following is not guaranteed and not true in JDK8
+ // assertNotSame(current, threadLocalRandom.get());
+ rand.set(current.nextLong());
+ threadLocalRandom.set(current);
+ }};
+
+ Thread first = newStartedThread(getRandomState);
+ awaitTermination(first);
+ firstRand = rand.get();
+ firstThreadLocalRandom = threadLocalRandom.get();
+
+ for (int i = 0; i < NCALLS; i++) {
+ Thread t = newStartedThread(getRandomState);
+ awaitTermination(t);
+ if (firstRand != rand.get())
+ return;
+ }
+ fail("all threads generate the same pseudo-random sequence");
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/ThreadLocalTest.java b/jsr166-tests/src/test/java/jsr166/ThreadLocalTest.java
new file mode 100644
index 0000000..885c2b2
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/ThreadLocalTest.java
@@ -0,0 +1,96 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.concurrent.Semaphore;
+
+public class ThreadLocalTest extends JSR166TestCase {
+
+ static ThreadLocal<Integer> tl = new ThreadLocal<Integer>() {
+ public Integer initialValue() {
+ return one;
+ }
+ };
+
+ static InheritableThreadLocal<Integer> itl =
+ new InheritableThreadLocal<Integer>() {
+ protected Integer initialValue() {
+ return zero;
+ }
+
+ protected Integer childValue(Integer parentValue) {
+ return new Integer(parentValue.intValue() + 1);
+ }
+ };
+
+ /**
+ * remove causes next access to return initial value
+ */
+ public void testRemove() {
+ assertSame(tl.get(), one);
+ tl.set(two);
+ assertSame(tl.get(), two);
+ tl.remove();
+ assertSame(tl.get(), one);
+ }
+
+ /**
+ * remove in InheritableThreadLocal causes next access to return
+ * initial value
+ */
+ public void testRemoveITL() {
+ assertSame(itl.get(), zero);
+ itl.set(two);
+ assertSame(itl.get(), two);
+ itl.remove();
+ assertSame(itl.get(), zero);
+ }
+
+ private class ITLThread extends Thread {
+ final int[] x;
+ ITLThread(int[] array) { x = array; }
+ public void run() {
+ Thread child = null;
+ if (itl.get().intValue() < x.length - 1) {
+ child = new ITLThread(x);
+ child.start();
+ }
+ Thread.yield();
+
+ int threadId = itl.get().intValue();
+ for (int j = 0; j < threadId; j++) {
+ x[threadId]++;
+ Thread.yield();
+ }
+
+ if (child != null) { // Wait for child (if any)
+ try {
+ child.join();
+ } catch (InterruptedException e) {
+ threadUnexpectedException(e);
+ }
+ }
+ }
+ }
+
+ /**
+ * InheritableThreadLocal propagates generic values.
+ */
+ public void testGenericITL() throws InterruptedException {
+ final int threadCount = 10;
+ final int x[] = new int[threadCount];
+ Thread progenitor = new ITLThread(x);
+ progenitor.start();
+ progenitor.join();
+ for (int i = 0; i < threadCount; i++) {
+ assertEquals(i, x[i]);
+ }
+ }
+}
diff --git a/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorSubclassTest.java b/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorSubclassTest.java
new file mode 100644
index 0000000..f16f422
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorSubclassTest.java
@@ -0,0 +1,1769 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.concurrent.*;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.*;
+
+public class ThreadPoolExecutorSubclassTest extends JSR166TestCase {
+
+ static class CustomTask<V> implements RunnableFuture<V> {
+ final Callable<V> callable;
+ final ReentrantLock lock = new ReentrantLock();
+ final Condition cond = lock.newCondition();
+ boolean done;
+ boolean cancelled;
+ V result;
+ Thread thread;
+ Exception exception;
+ CustomTask(Callable<V> c) {
+ if (c == null) throw new NullPointerException();
+ callable = c;
+ }
+ CustomTask(final Runnable r, final V res) {
+ if (r == null) throw new NullPointerException();
+ callable = new Callable<V>() {
+ public V call() throws Exception { r.run(); return res; }};
+ }
+ public boolean isDone() {
+ lock.lock(); try { return done; } finally { lock.unlock() ; }
+ }
+ public boolean isCancelled() {
+ lock.lock(); try { return cancelled; } finally { lock.unlock() ; }
+ }
+ public boolean cancel(boolean mayInterrupt) {
+ lock.lock();
+ try {
+ if (!done) {
+ cancelled = true;
+ done = true;
+ if (mayInterrupt && thread != null)
+ thread.interrupt();
+ return true;
+ }
+ return false;
+ }
+ finally { lock.unlock() ; }
+ }
+ public void run() {
+ lock.lock();
+ try {
+ if (done)
+ return;
+ thread = Thread.currentThread();
+ }
+ finally { lock.unlock() ; }
+ V v = null;
+ Exception e = null;
+ try {
+ v = callable.call();
+ }
+ catch (Exception ex) {
+ e = ex;
+ }
+ lock.lock();
+ try {
+ result = v;
+ exception = e;
+ done = true;
+ thread = null;
+ cond.signalAll();
+ }
+ finally { lock.unlock(); }
+ }
+ public V get() throws InterruptedException, ExecutionException {
+ lock.lock();
+ try {
+ while (!done)
+ cond.await();
+ if (exception != null)
+ throw new ExecutionException(exception);
+ return result;
+ }
+ finally { lock.unlock(); }
+ }
+ public V get(long timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ long nanos = unit.toNanos(timeout);
+ lock.lock();
+ try {
+ for (;;) {
+ if (done) break;
+ if (nanos < 0)
+ throw new TimeoutException();
+ nanos = cond.awaitNanos(nanos);
+ }
+ if (exception != null)
+ throw new ExecutionException(exception);
+ return result;
+ }
+ finally { lock.unlock(); }
+ }
+ }
+
+ static class CustomTPE extends ThreadPoolExecutor {
+ protected <V> RunnableFuture<V> newTaskFor(Callable<V> c) {
+ return new CustomTask<V>(c);
+ }
+ protected <V> RunnableFuture<V> newTaskFor(Runnable r, V v) {
+ return new CustomTask<V>(r, v);
+ }
+
+ CustomTPE(int corePoolSize,
+ int maximumPoolSize,
+ long keepAliveTime,
+ TimeUnit unit,
+ BlockingQueue<Runnable> workQueue) {
+ super(corePoolSize, maximumPoolSize, keepAliveTime, unit,
+ workQueue);
+ }
+ CustomTPE(int corePoolSize,
+ int maximumPoolSize,
+ long keepAliveTime,
+ TimeUnit unit,
+ BlockingQueue<Runnable> workQueue,
+ ThreadFactory threadFactory) {
+ super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
+ threadFactory);
+ }
+
+ CustomTPE(int corePoolSize,
+ int maximumPoolSize,
+ long keepAliveTime,
+ TimeUnit unit,
+ BlockingQueue<Runnable> workQueue,
+ RejectedExecutionHandler handler) {
+ super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
+ handler);
+ }
+ CustomTPE(int corePoolSize,
+ int maximumPoolSize,
+ long keepAliveTime,
+ TimeUnit unit,
+ BlockingQueue<Runnable> workQueue,
+ ThreadFactory threadFactory,
+ RejectedExecutionHandler handler) {
+ super(corePoolSize, maximumPoolSize, keepAliveTime, unit,
+ workQueue, threadFactory, handler);
+ }
+
+ final CountDownLatch beforeCalled = new CountDownLatch(1);
+ final CountDownLatch afterCalled = new CountDownLatch(1);
+ final CountDownLatch terminatedCalled = new CountDownLatch(1);
+
+ public CustomTPE() {
+ super(1, 1, LONG_DELAY_MS, MILLISECONDS, new SynchronousQueue<Runnable>());
+ }
+ protected void beforeExecute(Thread t, Runnable r) {
+ beforeCalled.countDown();
+ }
+ protected void afterExecute(Runnable r, Throwable t) {
+ afterCalled.countDown();
+ }
+ protected void terminated() {
+ terminatedCalled.countDown();
+ }
+
+ public boolean beforeCalled() {
+ return beforeCalled.getCount() == 0;
+ }
+ public boolean afterCalled() {
+ return afterCalled.getCount() == 0;
+ }
+ public boolean terminatedCalled() {
+ return terminatedCalled.getCount() == 0;
+ }
+ }
+
+ static class FailingThreadFactory implements ThreadFactory {
+ int calls = 0;
+ public Thread newThread(Runnable r) {
+ if (++calls > 1) return null;
+ return new Thread(r);
+ }
+ }
+
+ /**
+ * execute successfully executes a runnable
+ */
+ public void testExecute() throws InterruptedException {
+ final ThreadPoolExecutor p =
+ new CustomTPE(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ final CountDownLatch done = new CountDownLatch(1);
+ final Runnable task = new CheckedRunnable() {
+ public void realRun() {
+ done.countDown();
+ }};
+ try {
+ p.execute(task);
+ assertTrue(done.await(SMALL_DELAY_MS, MILLISECONDS));
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * getActiveCount increases but doesn't overestimate, when a
+ * thread becomes active
+ */
+ public void testGetActiveCount() throws InterruptedException {
+ final ThreadPoolExecutor p =
+ new CustomTPE(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ assertEquals(0, p.getActiveCount());
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ assertEquals(1, p.getActiveCount());
+ done.await();
+ }});
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(1, p.getActiveCount());
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * prestartCoreThread starts a thread if under corePoolSize, else doesn't
+ */
+ public void testPrestartCoreThread() {
+ ThreadPoolExecutor p = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ assertEquals(0, p.getPoolSize());
+ assertTrue(p.prestartCoreThread());
+ assertEquals(1, p.getPoolSize());
+ assertTrue(p.prestartCoreThread());
+ assertEquals(2, p.getPoolSize());
+ assertFalse(p.prestartCoreThread());
+ assertEquals(2, p.getPoolSize());
+ joinPool(p);
+ }
+
+ /**
+ * prestartAllCoreThreads starts all corePoolSize threads
+ */
+ public void testPrestartAllCoreThreads() {
+ ThreadPoolExecutor p = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ assertEquals(0, p.getPoolSize());
+ p.prestartAllCoreThreads();
+ assertEquals(2, p.getPoolSize());
+ p.prestartAllCoreThreads();
+ assertEquals(2, p.getPoolSize());
+ joinPool(p);
+ }
+
+ /**
+ * getCompletedTaskCount increases, but doesn't overestimate,
+ * when tasks complete
+ */
+ public void testGetCompletedTaskCount() throws InterruptedException {
+ final ThreadPoolExecutor p =
+ new CustomTPE(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadProceed = new CountDownLatch(1);
+ final CountDownLatch threadDone = new CountDownLatch(1);
+ try {
+ assertEquals(0, p.getCompletedTaskCount());
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ assertEquals(0, p.getCompletedTaskCount());
+ threadProceed.await();
+ threadDone.countDown();
+ }});
+ await(threadStarted);
+ assertEquals(0, p.getCompletedTaskCount());
+ threadProceed.countDown();
+ threadDone.await();
+ long startTime = System.nanoTime();
+ while (p.getCompletedTaskCount() != 1) {
+ if (millisElapsedSince(startTime) > LONG_DELAY_MS)
+ fail("timed out");
+ Thread.yield();
+ }
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * getCorePoolSize returns size given in constructor if not otherwise set
+ */
+ public void testGetCorePoolSize() {
+ ThreadPoolExecutor p = new CustomTPE(1, 1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ assertEquals(1, p.getCorePoolSize());
+ joinPool(p);
+ }
+
+ /**
+ * getKeepAliveTime returns value given in constructor if not otherwise set
+ */
+ public void testGetKeepAliveTime() {
+ ThreadPoolExecutor p = new CustomTPE(2, 2, 1000, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ assertEquals(1, p.getKeepAliveTime(TimeUnit.SECONDS));
+ joinPool(p);
+ }
+
+ /**
+ * getThreadFactory returns factory in constructor if not set
+ */
+ public void testGetThreadFactory() {
+ ThreadFactory tf = new SimpleThreadFactory();
+ ThreadPoolExecutor p = new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10), tf, new NoOpREHandler());
+ assertSame(tf, p.getThreadFactory());
+ joinPool(p);
+ }
+
+ /**
+ * setThreadFactory sets the thread factory returned by getThreadFactory
+ */
+ public void testSetThreadFactory() {
+ ThreadPoolExecutor p = new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ ThreadFactory tf = new SimpleThreadFactory();
+ p.setThreadFactory(tf);
+ assertSame(tf, p.getThreadFactory());
+ joinPool(p);
+ }
+
+ /**
+ * setThreadFactory(null) throws NPE
+ */
+ public void testSetThreadFactoryNull() {
+ ThreadPoolExecutor p = new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ p.setThreadFactory(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * getRejectedExecutionHandler returns handler in constructor if not set
+ */
+ public void testGetRejectedExecutionHandler() {
+ RejectedExecutionHandler h = new NoOpREHandler();
+ ThreadPoolExecutor p = new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10), h);
+ assertSame(h, p.getRejectedExecutionHandler());
+ joinPool(p);
+ }
+
+ /**
+ * setRejectedExecutionHandler sets the handler returned by
+ * getRejectedExecutionHandler
+ */
+ public void testSetRejectedExecutionHandler() {
+ ThreadPoolExecutor p = new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ RejectedExecutionHandler h = new NoOpREHandler();
+ p.setRejectedExecutionHandler(h);
+ assertSame(h, p.getRejectedExecutionHandler());
+ joinPool(p);
+ }
+
+ /**
+ * setRejectedExecutionHandler(null) throws NPE
+ */
+ public void testSetRejectedExecutionHandlerNull() {
+ ThreadPoolExecutor p = new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ p.setRejectedExecutionHandler(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * getLargestPoolSize increases, but doesn't overestimate, when
+ * multiple threads active
+ */
+ public void testGetLargestPoolSize() throws InterruptedException {
+ final int THREADS = 3;
+ final ThreadPoolExecutor p =
+ new CustomTPE(THREADS, THREADS,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ final CountDownLatch threadsStarted = new CountDownLatch(THREADS);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ assertEquals(0, p.getLargestPoolSize());
+ for (int i = 0; i < THREADS; i++)
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.countDown();
+ done.await();
+ assertEquals(THREADS, p.getLargestPoolSize());
+ }});
+ assertTrue(threadsStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(THREADS, p.getLargestPoolSize());
+ } finally {
+ done.countDown();
+ joinPool(p);
+ assertEquals(THREADS, p.getLargestPoolSize());
+ }
+ }
+
+ /**
+ * getMaximumPoolSize returns value given in constructor if not
+ * otherwise set
+ */
+ public void testGetMaximumPoolSize() {
+ ThreadPoolExecutor p = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ assertEquals(2, p.getMaximumPoolSize());
+ joinPool(p);
+ }
+
+ /**
+ * getPoolSize increases, but doesn't overestimate, when threads
+ * become active
+ */
+ public void testGetPoolSize() throws InterruptedException {
+ final ThreadPoolExecutor p =
+ new CustomTPE(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ assertEquals(0, p.getPoolSize());
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ assertEquals(1, p.getPoolSize());
+ done.await();
+ }});
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(1, p.getPoolSize());
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * getTaskCount increases, but doesn't overestimate, when tasks submitted
+ */
+ public void testGetTaskCount() throws InterruptedException {
+ final ThreadPoolExecutor p =
+ new CustomTPE(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ assertEquals(0, p.getTaskCount());
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ assertEquals(1, p.getTaskCount());
+ done.await();
+ }});
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(1, p.getTaskCount());
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * isShutdown is false before shutdown, true after
+ */
+ public void testIsShutdown() {
+
+ ThreadPoolExecutor p = new CustomTPE(1, 1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ assertFalse(p.isShutdown());
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ assertTrue(p.isShutdown());
+ joinPool(p);
+ }
+
+ /**
+ * isTerminated is false before termination, true after
+ */
+ public void testIsTerminated() throws InterruptedException {
+ final ThreadPoolExecutor p =
+ new CustomTPE(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ assertFalse(p.isTerminating());
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(p.isTerminating());
+ threadStarted.countDown();
+ done.await();
+ }});
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertFalse(p.isTerminating());
+ done.countDown();
+ } finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ }
+ assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
+ assertFalse(p.isTerminating());
+ }
+
+ /**
+ * isTerminating is not true when running or when terminated
+ */
+ public void testIsTerminating() throws InterruptedException {
+ final ThreadPoolExecutor p =
+ new CustomTPE(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ assertFalse(p.isTerminating());
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(p.isTerminating());
+ threadStarted.countDown();
+ done.await();
+ }});
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertFalse(p.isTerminating());
+ done.countDown();
+ } finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ }
+ assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
+ assertFalse(p.isTerminating());
+ }
+
+ /**
+ * getQueue returns the work queue, which contains queued tasks
+ */
+ public void testGetQueue() throws InterruptedException {
+ final BlockingQueue<Runnable> q = new ArrayBlockingQueue<Runnable>(10);
+ final ThreadPoolExecutor p =
+ new CustomTPE(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ q);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ FutureTask[] tasks = new FutureTask[5];
+ for (int i = 0; i < tasks.length; i++) {
+ Callable task = new CheckedCallable<Boolean>() {
+ public Boolean realCall() throws InterruptedException {
+ threadStarted.countDown();
+ assertSame(q, p.getQueue());
+ done.await();
+ return Boolean.TRUE;
+ }};
+ tasks[i] = new FutureTask(task);
+ p.execute(tasks[i]);
+ }
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertSame(q, p.getQueue());
+ assertFalse(q.contains(tasks[0]));
+ assertTrue(q.contains(tasks[tasks.length - 1]));
+ assertEquals(tasks.length - 1, q.size());
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * remove(task) removes queued task, and fails to remove active task
+ */
+ public void testRemove() throws InterruptedException {
+ BlockingQueue<Runnable> q = new ArrayBlockingQueue<Runnable>(10);
+ final ThreadPoolExecutor p =
+ new CustomTPE(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ q);
+ Runnable[] tasks = new Runnable[6];
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ for (int i = 0; i < tasks.length; i++) {
+ tasks[i] = new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ done.await();
+ }};
+ p.execute(tasks[i]);
+ }
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertFalse(p.remove(tasks[0]));
+ assertTrue(q.contains(tasks[4]));
+ assertTrue(q.contains(tasks[3]));
+ assertTrue(p.remove(tasks[4]));
+ assertFalse(p.remove(tasks[4]));
+ assertFalse(q.contains(tasks[4]));
+ assertTrue(q.contains(tasks[3]));
+ assertTrue(p.remove(tasks[3]));
+ assertFalse(q.contains(tasks[3]));
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * purge removes cancelled tasks from the queue
+ */
+ public void testPurge() throws InterruptedException {
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ final BlockingQueue<Runnable> q = new ArrayBlockingQueue<Runnable>(10);
+ final ThreadPoolExecutor p =
+ new CustomTPE(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ q);
+ FutureTask[] tasks = new FutureTask[5];
+ try {
+ for (int i = 0; i < tasks.length; i++) {
+ Callable task = new CheckedCallable<Boolean>() {
+ public Boolean realCall() throws InterruptedException {
+ threadStarted.countDown();
+ done.await();
+ return Boolean.TRUE;
+ }};
+ tasks[i] = new FutureTask(task);
+ p.execute(tasks[i]);
+ }
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(tasks.length, p.getTaskCount());
+ assertEquals(tasks.length - 1, q.size());
+ assertEquals(1L, p.getActiveCount());
+ assertEquals(0L, p.getCompletedTaskCount());
+ tasks[4].cancel(true);
+ tasks[3].cancel(false);
+ p.purge();
+ assertEquals(tasks.length - 3, q.size());
+ assertEquals(tasks.length - 2, p.getTaskCount());
+ p.purge(); // Nothing to do
+ assertEquals(tasks.length - 3, q.size());
+ assertEquals(tasks.length - 2, p.getTaskCount());
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * shutdownNow returns a list containing tasks that were not run
+ */
+ public void testShutdownNow() {
+ ThreadPoolExecutor p = new CustomTPE(1, 1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ List l;
+ try {
+ for (int i = 0; i < 5; i++)
+ p.execute(new MediumPossiblyInterruptedRunnable());
+ }
+ finally {
+ try {
+ l = p.shutdownNow();
+ } catch (SecurityException ok) { return; }
+ }
+ assertTrue(p.isShutdown());
+ assertTrue(l.size() <= 4);
+ }
+
+ // Exception Tests
+
+ /**
+ * Constructor throws if corePoolSize argument is less than zero
+ */
+ public void testConstructor1() {
+ try {
+ new CustomTPE(-1,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if maximumPoolSize is less than zero
+ */
+ public void testConstructor2() {
+ try {
+ new CustomTPE(1,-1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if maximumPoolSize is equal to zero
+ */
+ public void testConstructor3() {
+ try {
+ new CustomTPE(1,0,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if keepAliveTime is less than zero
+ */
+ public void testConstructor4() {
+ try {
+ new CustomTPE(1,2,-1L,MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if corePoolSize is greater than the maximumPoolSize
+ */
+ public void testConstructor5() {
+ try {
+ new CustomTPE(2,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if workQueue is set to null
+ */
+ public void testConstructorNullPointerException() {
+ try {
+ new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Constructor throws if corePoolSize argument is less than zero
+ */
+ public void testConstructor6() {
+ try {
+ new CustomTPE(-1,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if maximumPoolSize is less than zero
+ */
+ public void testConstructor7() {
+ try {
+ new CustomTPE(1,-1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if maximumPoolSize is equal to zero
+ */
+ public void testConstructor8() {
+ try {
+ new CustomTPE(1,0,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if keepAliveTime is less than zero
+ */
+ public void testConstructor9() {
+ try {
+ new CustomTPE(1,2,-1L,MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if corePoolSize is greater than the maximumPoolSize
+ */
+ public void testConstructor10() {
+ try {
+ new CustomTPE(2,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if workQueue is set to null
+ */
+ public void testConstructorNullPointerException2() {
+ try {
+ new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,null,new SimpleThreadFactory());
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Constructor throws if threadFactory is set to null
+ */
+ public void testConstructorNullPointerException3() {
+ try {
+ ThreadFactory f = null;
+ new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10),f);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Constructor throws if corePoolSize argument is less than zero
+ */
+ public void testConstructor11() {
+ try {
+ new CustomTPE(-1,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if maximumPoolSize is less than zero
+ */
+ public void testConstructor12() {
+ try {
+ new CustomTPE(1,-1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if maximumPoolSize is equal to zero
+ */
+ public void testConstructor13() {
+ try {
+ new CustomTPE(1,0,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if keepAliveTime is less than zero
+ */
+ public void testConstructor14() {
+ try {
+ new CustomTPE(1,2,-1L,MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if corePoolSize is greater than the maximumPoolSize
+ */
+ public void testConstructor15() {
+ try {
+ new CustomTPE(2,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new NoOpREHandler());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if workQueue is set to null
+ */
+ public void testConstructorNullPointerException4() {
+ try {
+ new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,null,new NoOpREHandler());
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Constructor throws if handler is set to null
+ */
+ public void testConstructorNullPointerException5() {
+ try {
+ RejectedExecutionHandler r = null;
+ new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10),r);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Constructor throws if corePoolSize argument is less than zero
+ */
+ public void testConstructor16() {
+ try {
+ new CustomTPE(-1,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if maximumPoolSize is less than zero
+ */
+ public void testConstructor17() {
+ try {
+ new CustomTPE(1,-1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if maximumPoolSize is equal to zero
+ */
+ public void testConstructor18() {
+ try {
+ new CustomTPE(1,0,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if keepAliveTime is less than zero
+ */
+ public void testConstructor19() {
+ try {
+ new CustomTPE(1,2,-1L,MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if corePoolSize is greater than the maximumPoolSize
+ */
+ public void testConstructor20() {
+ try {
+ new CustomTPE(2,1,LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),new NoOpREHandler());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if workQueue is null
+ */
+ public void testConstructorNullPointerException6() {
+ try {
+ new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,null,new SimpleThreadFactory(),new NoOpREHandler());
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Constructor throws if handler is null
+ */
+ public void testConstructorNullPointerException7() {
+ try {
+ RejectedExecutionHandler r = null;
+ new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10),new SimpleThreadFactory(),r);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Constructor throws if ThreadFactory is null
+ */
+ public void testConstructorNullPointerException8() {
+ try {
+ new CustomTPE(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10),
+ (ThreadFactory) null,
+ new NoOpREHandler());
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * execute throws RejectedExecutionException if saturated.
+ */
+ public void testSaturatedExecute() {
+ ThreadPoolExecutor p =
+ new CustomTPE(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(1));
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ Runnable task = new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ done.await();
+ }};
+ for (int i = 0; i < 2; ++i)
+ p.execute(task);
+ for (int i = 0; i < 2; ++i) {
+ try {
+ p.execute(task);
+ shouldThrow();
+ } catch (RejectedExecutionException success) {}
+ assertTrue(p.getTaskCount() <= 2);
+ }
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * executor using CallerRunsPolicy runs task if saturated.
+ */
+ public void testSaturatedExecute2() {
+ RejectedExecutionHandler h = new CustomTPE.CallerRunsPolicy();
+ ThreadPoolExecutor p = new CustomTPE(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(1),
+ h);
+ try {
+ TrackedNoOpRunnable[] tasks = new TrackedNoOpRunnable[5];
+ for (int i = 0; i < tasks.length; ++i)
+ tasks[i] = new TrackedNoOpRunnable();
+ TrackedLongRunnable mr = new TrackedLongRunnable();
+ p.execute(mr);
+ for (int i = 0; i < tasks.length; ++i)
+ p.execute(tasks[i]);
+ for (int i = 1; i < tasks.length; ++i)
+ assertTrue(tasks[i].done);
+ try { p.shutdownNow(); } catch (SecurityException ok) { return; }
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * executor using DiscardPolicy drops task if saturated.
+ */
+ public void testSaturatedExecute3() {
+ RejectedExecutionHandler h = new CustomTPE.DiscardPolicy();
+ ThreadPoolExecutor p =
+ new CustomTPE(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(1),
+ h);
+ try {
+ TrackedNoOpRunnable[] tasks = new TrackedNoOpRunnable[5];
+ for (int i = 0; i < tasks.length; ++i)
+ tasks[i] = new TrackedNoOpRunnable();
+ p.execute(new TrackedLongRunnable());
+ for (TrackedNoOpRunnable task : tasks)
+ p.execute(task);
+ for (TrackedNoOpRunnable task : tasks)
+ assertFalse(task.done);
+ try { p.shutdownNow(); } catch (SecurityException ok) { return; }
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * executor using DiscardOldestPolicy drops oldest task if saturated.
+ */
+ public void testSaturatedExecute4() {
+ RejectedExecutionHandler h = new CustomTPE.DiscardOldestPolicy();
+ ThreadPoolExecutor p = new CustomTPE(1,1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h);
+ try {
+ p.execute(new TrackedLongRunnable());
+ TrackedLongRunnable r2 = new TrackedLongRunnable();
+ p.execute(r2);
+ assertTrue(p.getQueue().contains(r2));
+ TrackedNoOpRunnable r3 = new TrackedNoOpRunnable();
+ p.execute(r3);
+ assertFalse(p.getQueue().contains(r2));
+ assertTrue(p.getQueue().contains(r3));
+ try { p.shutdownNow(); } catch (SecurityException ok) { return; }
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * execute throws RejectedExecutionException if shutdown
+ */
+ public void testRejectedExecutionExceptionOnShutdown() {
+ ThreadPoolExecutor p =
+ new CustomTPE(1,1,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(1));
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ try {
+ p.execute(new NoOpRunnable());
+ shouldThrow();
+ } catch (RejectedExecutionException success) {}
+
+ joinPool(p);
+ }
+
+ /**
+ * execute using CallerRunsPolicy drops task on shutdown
+ */
+ public void testCallerRunsOnShutdown() {
+ RejectedExecutionHandler h = new CustomTPE.CallerRunsPolicy();
+ ThreadPoolExecutor p = new CustomTPE(1,1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h);
+
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ try {
+ TrackedNoOpRunnable r = new TrackedNoOpRunnable();
+ p.execute(r);
+ assertFalse(r.done);
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * execute using DiscardPolicy drops task on shutdown
+ */
+ public void testDiscardOnShutdown() {
+ RejectedExecutionHandler h = new CustomTPE.DiscardPolicy();
+ ThreadPoolExecutor p = new CustomTPE(1,1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h);
+
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ try {
+ TrackedNoOpRunnable r = new TrackedNoOpRunnable();
+ p.execute(r);
+ assertFalse(r.done);
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * execute using DiscardOldestPolicy drops task on shutdown
+ */
+ public void testDiscardOldestOnShutdown() {
+ RejectedExecutionHandler h = new CustomTPE.DiscardOldestPolicy();
+ ThreadPoolExecutor p = new CustomTPE(1,1, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(1), h);
+
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ try {
+ TrackedNoOpRunnable r = new TrackedNoOpRunnable();
+ p.execute(r);
+ assertFalse(r.done);
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * execute(null) throws NPE
+ */
+ public void testExecuteNull() {
+ ThreadPoolExecutor p = null;
+ try {
+ p = new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10));
+ p.execute(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+
+ joinPool(p);
+ }
+
+ /**
+ * setCorePoolSize of negative value throws IllegalArgumentException
+ */
+ public void testCorePoolSizeIllegalArgumentException() {
+ ThreadPoolExecutor p =
+ new CustomTPE(1,2,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10));
+ try {
+ p.setCorePoolSize(-1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ }
+ joinPool(p);
+ }
+
+ /**
+ * setMaximumPoolSize(int) throws IllegalArgumentException
+ * if given a value less the core pool size
+ */
+ public void testMaximumPoolSizeIllegalArgumentException() {
+ ThreadPoolExecutor p =
+ new CustomTPE(2,3,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10));
+ try {
+ p.setMaximumPoolSize(1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ }
+ joinPool(p);
+ }
+
+ /**
+ * setMaximumPoolSize throws IllegalArgumentException
+ * if given a negative value
+ */
+ public void testMaximumPoolSizeIllegalArgumentException2() {
+ ThreadPoolExecutor p =
+ new CustomTPE(2,3,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10));
+ try {
+ p.setMaximumPoolSize(-1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ }
+ joinPool(p);
+ }
+
+ /**
+ * setKeepAliveTime throws IllegalArgumentException
+ * when given a negative value
+ */
+ public void testKeepAliveTimeIllegalArgumentException() {
+ ThreadPoolExecutor p =
+ new CustomTPE(2,3,LONG_DELAY_MS, MILLISECONDS,new ArrayBlockingQueue<Runnable>(10));
+
+ try {
+ p.setKeepAliveTime(-1,MILLISECONDS);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ }
+ joinPool(p);
+ }
+
+ /**
+ * terminated() is called on termination
+ */
+ public void testTerminated() {
+ CustomTPE p = new CustomTPE();
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ assertTrue(p.terminatedCalled());
+ joinPool(p);
+ }
+
+ /**
+ * beforeExecute and afterExecute are called when executing task
+ */
+ public void testBeforeAfter() throws InterruptedException {
+ CustomTPE p = new CustomTPE();
+ try {
+ final CountDownLatch done = new CountDownLatch(1);
+ final CheckedRunnable task = new CheckedRunnable() {
+ public void realRun() {
+ done.countDown();
+ }};
+ p.execute(task);
+ await(p.afterCalled);
+ assertEquals(0, done.getCount());
+ assertTrue(p.afterCalled());
+ assertTrue(p.beforeCalled());
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * completed submit of callable returns result
+ */
+ public void testSubmitCallable() throws Exception {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ Future<String> future = e.submit(new StringTask());
+ String result = future.get();
+ assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * completed submit of runnable returns successfully
+ */
+ public void testSubmitRunnable() throws Exception {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ Future<?> future = e.submit(new NoOpRunnable());
+ future.get();
+ assertTrue(future.isDone());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * completed submit of (runnable, result) returns result
+ */
+ public void testSubmitRunnable2() throws Exception {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ Future<String> future = e.submit(new NoOpRunnable(), TEST_STRING);
+ String result = future.get();
+ assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(null) throws NPE
+ */
+ public void testInvokeAny1() throws Exception {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ e.invokeAny(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(empty collection) throws IAE
+ */
+ public void testInvokeAny2() throws Exception {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ e.invokeAny(new ArrayList<Callable<String>>());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(c) throws NPE if c has null elements
+ */
+ public void testInvokeAny3() throws Exception {
+ CountDownLatch latch = new CountDownLatch(1);
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(latchAwaitingStringTask(latch));
+ l.add(null);
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ latch.countDown();
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(c) throws ExecutionException if no task completes
+ */
+ public void testInvokeAny4() throws Exception {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(c) returns result of some task
+ */
+ public void testInvokeAny5() throws Exception {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(new StringTask());
+ String result = e.invokeAny(l);
+ assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAll(null) throws NPE
+ */
+ public void testInvokeAll1() throws Exception {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ e.invokeAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAll(empty collection) returns empty collection
+ */
+ public void testInvokeAll2() throws Exception {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>());
+ assertTrue(r.isEmpty());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAll(c) throws NPE if c has null elements
+ */
+ public void testInvokeAll3() throws Exception {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(null);
+ try {
+ e.invokeAll(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * get of element of invokeAll(c) throws exception on failed task
+ */
+ public void testInvokeAll4() throws Exception {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ List<Future<String>> futures = e.invokeAll(l);
+ assertEquals(1, futures.size());
+ try {
+ futures.get(0).get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAll(c) returns results of all completed tasks
+ */
+ public void testInvokeAll5() throws Exception {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(new StringTask());
+ List<Future<String>> futures = e.invokeAll(l);
+ assertEquals(2, futures.size());
+ for (Future<String> future : futures)
+ assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(null) throws NPE
+ */
+ public void testTimedInvokeAny1() throws Exception {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(,,null) throws NPE
+ */
+ public void testTimedInvokeAnyNullTimeUnit() throws Exception {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(empty collection) throws IAE
+ */
+ public void testTimedInvokeAny2() throws Exception {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ e.invokeAny(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(c) throws NPE if c has null elements
+ */
+ public void testTimedInvokeAny3() throws Exception {
+ CountDownLatch latch = new CountDownLatch(1);
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(latchAwaitingStringTask(latch));
+ l.add(null);
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ latch.countDown();
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(c) throws ExecutionException if no task completes
+ */
+ public void testTimedInvokeAny4() throws Exception {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(c) returns result of some task
+ */
+ public void testTimedInvokeAny5() throws Exception {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(new StringTask());
+ String result = e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(null) throws NPE
+ */
+ public void testTimedInvokeAll1() throws Exception {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(,,null) throws NPE
+ */
+ public void testTimedInvokeAllNullTimeUnit() throws Exception {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ try {
+ e.invokeAll(l, MEDIUM_DELAY_MS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(empty collection) returns empty collection
+ */
+ public void testTimedInvokeAll2() throws Exception {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
+ assertTrue(r.isEmpty());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(c) throws NPE if c has null elements
+ */
+ public void testTimedInvokeAll3() throws Exception {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(null);
+ try {
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * get of element of invokeAll(c) throws exception on failed task
+ */
+ public void testTimedInvokeAll4() throws Exception {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ List<Future<String>> futures =
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ assertEquals(1, futures.size());
+ try {
+ futures.get(0).get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(c) returns results of all completed tasks
+ */
+ public void testTimedInvokeAll5() throws Exception {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(new StringTask());
+ List<Future<String>> futures =
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ assertEquals(2, futures.size());
+ for (Future<String> future : futures)
+ assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(c) cancels tasks not completed by timeout
+ */
+ public void testTimedInvokeAll6() throws Exception {
+ ExecutorService e = new CustomTPE(2, 2, LONG_DELAY_MS, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(Executors.callable(new MediumPossiblyInterruptedRunnable(), TEST_STRING));
+ l.add(new StringTask());
+ List<Future<String>> futures =
+ e.invokeAll(l, SHORT_DELAY_MS, MILLISECONDS);
+ assertEquals(l.size(), futures.size());
+ for (Future future : futures)
+ assertTrue(future.isDone());
+ assertFalse(futures.get(0).isCancelled());
+ assertTrue(futures.get(1).isCancelled());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * Execution continues if there is at least one thread even if
+ * thread factory fails to create more
+ */
+ public void testFailingThreadFactory() throws InterruptedException {
+ final ExecutorService e =
+ new CustomTPE(100, 100,
+ LONG_DELAY_MS, MILLISECONDS,
+ new LinkedBlockingQueue<Runnable>(),
+ new FailingThreadFactory());
+ try {
+ final int TASKS = 100;
+ final CountDownLatch done = new CountDownLatch(TASKS);
+ for (int k = 0; k < TASKS; ++k)
+ e.execute(new CheckedRunnable() {
+ public void realRun() {
+ done.countDown();
+ }});
+ assertTrue(done.await(LONG_DELAY_MS, MILLISECONDS));
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * allowsCoreThreadTimeOut is by default false.
+ */
+ public void testAllowsCoreThreadTimeOut() {
+ ThreadPoolExecutor p = new CustomTPE(2, 2, 1000, MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
+ assertFalse(p.allowsCoreThreadTimeOut());
+ joinPool(p);
+ }
+
+ /**
+ * allowCoreThreadTimeOut(true) causes idle threads to time out
+ */
+ public void testAllowCoreThreadTimeOut_true() throws Exception {
+ long coreThreadTimeOut = SHORT_DELAY_MS;
+ final ThreadPoolExecutor p =
+ new CustomTPE(2, 10,
+ coreThreadTimeOut, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ try {
+ p.allowCoreThreadTimeOut(true);
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ assertEquals(1, p.getPoolSize());
+ }});
+ await(threadStarted);
+ delay(coreThreadTimeOut);
+ long startTime = System.nanoTime();
+ while (p.getPoolSize() > 0
+ && millisElapsedSince(startTime) < LONG_DELAY_MS)
+ Thread.yield();
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ assertEquals(0, p.getPoolSize());
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * allowCoreThreadTimeOut(false) causes idle threads not to time out
+ */
+ public void testAllowCoreThreadTimeOut_false() throws Exception {
+ long coreThreadTimeOut = SHORT_DELAY_MS;
+ final ThreadPoolExecutor p =
+ new CustomTPE(2, 10,
+ coreThreadTimeOut, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ try {
+ p.allowCoreThreadTimeOut(false);
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ assertTrue(p.getPoolSize() >= 1);
+ }});
+ delay(2 * coreThreadTimeOut);
+ assertTrue(p.getPoolSize() >= 1);
+ } finally {
+ joinPool(p);
+ }
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorTest.java b/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorTest.java
new file mode 100644
index 0000000..55f769b
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/ThreadPoolExecutorTest.java
@@ -0,0 +1,2010 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.concurrent.*;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import java.util.*;
+
+public class ThreadPoolExecutorTest extends JSR166TestCase {
+
+ static class ExtendedTPE extends ThreadPoolExecutor {
+ final CountDownLatch beforeCalled = new CountDownLatch(1);
+ final CountDownLatch afterCalled = new CountDownLatch(1);
+ final CountDownLatch terminatedCalled = new CountDownLatch(1);
+
+ public ExtendedTPE() {
+ super(1, 1, LONG_DELAY_MS, MILLISECONDS, new SynchronousQueue<Runnable>());
+ }
+ protected void beforeExecute(Thread t, Runnable r) {
+ beforeCalled.countDown();
+ }
+ protected void afterExecute(Runnable r, Throwable t) {
+ afterCalled.countDown();
+ }
+ protected void terminated() {
+ terminatedCalled.countDown();
+ }
+
+ public boolean beforeCalled() {
+ return beforeCalled.getCount() == 0;
+ }
+ public boolean afterCalled() {
+ return afterCalled.getCount() == 0;
+ }
+ public boolean terminatedCalled() {
+ return terminatedCalled.getCount() == 0;
+ }
+ }
+
+ static class FailingThreadFactory implements ThreadFactory {
+ int calls = 0;
+ public Thread newThread(Runnable r) {
+ if (++calls > 1) return null;
+ return new Thread(r);
+ }
+ }
+
+ /**
+ * execute successfully executes a runnable
+ */
+ public void testExecute() throws InterruptedException {
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ final CountDownLatch done = new CountDownLatch(1);
+ final Runnable task = new CheckedRunnable() {
+ public void realRun() {
+ done.countDown();
+ }};
+ try {
+ p.execute(task);
+ assertTrue(done.await(SMALL_DELAY_MS, MILLISECONDS));
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * getActiveCount increases but doesn't overestimate, when a
+ * thread becomes active
+ */
+ public void testGetActiveCount() throws InterruptedException {
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ assertEquals(0, p.getActiveCount());
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ assertEquals(1, p.getActiveCount());
+ done.await();
+ }});
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(1, p.getActiveCount());
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * prestartCoreThread starts a thread if under corePoolSize, else doesn't
+ */
+ public void testPrestartCoreThread() {
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ assertEquals(0, p.getPoolSize());
+ assertTrue(p.prestartCoreThread());
+ assertEquals(1, p.getPoolSize());
+ assertTrue(p.prestartCoreThread());
+ assertEquals(2, p.getPoolSize());
+ assertFalse(p.prestartCoreThread());
+ assertEquals(2, p.getPoolSize());
+ joinPool(p);
+ }
+
+ /**
+ * prestartAllCoreThreads starts all corePoolSize threads
+ */
+ public void testPrestartAllCoreThreads() {
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ assertEquals(0, p.getPoolSize());
+ p.prestartAllCoreThreads();
+ assertEquals(2, p.getPoolSize());
+ p.prestartAllCoreThreads();
+ assertEquals(2, p.getPoolSize());
+ joinPool(p);
+ }
+
+ /**
+ * getCompletedTaskCount increases, but doesn't overestimate,
+ * when tasks complete
+ */
+ public void testGetCompletedTaskCount() throws InterruptedException {
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch threadProceed = new CountDownLatch(1);
+ final CountDownLatch threadDone = new CountDownLatch(1);
+ try {
+ assertEquals(0, p.getCompletedTaskCount());
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ assertEquals(0, p.getCompletedTaskCount());
+ threadProceed.await();
+ threadDone.countDown();
+ }});
+ await(threadStarted);
+ assertEquals(0, p.getCompletedTaskCount());
+ threadProceed.countDown();
+ threadDone.await();
+ long startTime = System.nanoTime();
+ while (p.getCompletedTaskCount() != 1) {
+ if (millisElapsedSince(startTime) > LONG_DELAY_MS)
+ fail("timed out");
+ Thread.yield();
+ }
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * getCorePoolSize returns size given in constructor if not otherwise set
+ */
+ public void testGetCorePoolSize() {
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ assertEquals(1, p.getCorePoolSize());
+ joinPool(p);
+ }
+
+ /**
+ * getKeepAliveTime returns value given in constructor if not otherwise set
+ */
+ public void testGetKeepAliveTime() {
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(2, 2,
+ 1000, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ assertEquals(1, p.getKeepAliveTime(TimeUnit.SECONDS));
+ joinPool(p);
+ }
+
+ /**
+ * getThreadFactory returns factory in constructor if not set
+ */
+ public void testGetThreadFactory() {
+ ThreadFactory tf = new SimpleThreadFactory();
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10),
+ tf,
+ new NoOpREHandler());
+ assertSame(tf, p.getThreadFactory());
+ joinPool(p);
+ }
+
+ /**
+ * setThreadFactory sets the thread factory returned by getThreadFactory
+ */
+ public void testSetThreadFactory() {
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ ThreadFactory tf = new SimpleThreadFactory();
+ p.setThreadFactory(tf);
+ assertSame(tf, p.getThreadFactory());
+ joinPool(p);
+ }
+
+ /**
+ * setThreadFactory(null) throws NPE
+ */
+ public void testSetThreadFactoryNull() {
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ p.setThreadFactory(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * getRejectedExecutionHandler returns handler in constructor if not set
+ */
+ public void testGetRejectedExecutionHandler() {
+ final RejectedExecutionHandler h = new NoOpREHandler();
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10),
+ h);
+ assertSame(h, p.getRejectedExecutionHandler());
+ joinPool(p);
+ }
+
+ /**
+ * setRejectedExecutionHandler sets the handler returned by
+ * getRejectedExecutionHandler
+ */
+ public void testSetRejectedExecutionHandler() {
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ RejectedExecutionHandler h = new NoOpREHandler();
+ p.setRejectedExecutionHandler(h);
+ assertSame(h, p.getRejectedExecutionHandler());
+ joinPool(p);
+ }
+
+ /**
+ * setRejectedExecutionHandler(null) throws NPE
+ */
+ public void testSetRejectedExecutionHandlerNull() {
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ p.setRejectedExecutionHandler(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * getLargestPoolSize increases, but doesn't overestimate, when
+ * multiple threads active
+ */
+ public void testGetLargestPoolSize() throws InterruptedException {
+ final int THREADS = 3;
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(THREADS, THREADS,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ final CountDownLatch threadsStarted = new CountDownLatch(THREADS);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ assertEquals(0, p.getLargestPoolSize());
+ for (int i = 0; i < THREADS; i++)
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadsStarted.countDown();
+ done.await();
+ assertEquals(THREADS, p.getLargestPoolSize());
+ }});
+ assertTrue(threadsStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(THREADS, p.getLargestPoolSize());
+ } finally {
+ done.countDown();
+ joinPool(p);
+ assertEquals(THREADS, p.getLargestPoolSize());
+ }
+ }
+
+ /**
+ * getMaximumPoolSize returns value given in constructor if not
+ * otherwise set
+ */
+ public void testGetMaximumPoolSize() {
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(2, 3,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ assertEquals(3, p.getMaximumPoolSize());
+ joinPool(p);
+ }
+
+ /**
+ * getPoolSize increases, but doesn't overestimate, when threads
+ * become active
+ */
+ public void testGetPoolSize() throws InterruptedException {
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ assertEquals(0, p.getPoolSize());
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ assertEquals(1, p.getPoolSize());
+ done.await();
+ }});
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(1, p.getPoolSize());
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * getTaskCount increases, but doesn't overestimate, when tasks submitted
+ */
+ public void testGetTaskCount() throws InterruptedException {
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ assertEquals(0, p.getTaskCount());
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ assertEquals(1, p.getTaskCount());
+ done.await();
+ }});
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(1, p.getTaskCount());
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * isShutdown is false before shutdown, true after
+ */
+ public void testIsShutdown() {
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ assertFalse(p.isShutdown());
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ assertTrue(p.isShutdown());
+ joinPool(p);
+ }
+
+ /**
+ * awaitTermination on a non-shutdown pool times out
+ */
+ public void testAwaitTermination_timesOut() throws InterruptedException {
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ assertFalse(p.isTerminated());
+ assertFalse(p.awaitTermination(Long.MIN_VALUE, NANOSECONDS));
+ assertFalse(p.awaitTermination(Long.MIN_VALUE, MILLISECONDS));
+ assertFalse(p.awaitTermination(-1L, NANOSECONDS));
+ assertFalse(p.awaitTermination(-1L, MILLISECONDS));
+ assertFalse(p.awaitTermination(0L, NANOSECONDS));
+ assertFalse(p.awaitTermination(0L, MILLISECONDS));
+ long timeoutNanos = 999999L;
+ long startTime = System.nanoTime();
+ assertFalse(p.awaitTermination(timeoutNanos, NANOSECONDS));
+ assertTrue(System.nanoTime() - startTime >= timeoutNanos);
+ assertFalse(p.isTerminated());
+ startTime = System.nanoTime();
+ long timeoutMillis = timeoutMillis();
+ assertFalse(p.awaitTermination(timeoutMillis, MILLISECONDS));
+ assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
+ assertFalse(p.isTerminated());
+ p.shutdown();
+ assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
+ }
+
+ /**
+ * isTerminated is false before termination, true after
+ */
+ public void testIsTerminated() throws InterruptedException {
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ assertFalse(p.isTerminated());
+ try {
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(p.isTerminated());
+ threadStarted.countDown();
+ done.await();
+ }});
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertFalse(p.isTerminating());
+ done.countDown();
+ } finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ }
+ assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
+ }
+
+ /**
+ * isTerminating is not true when running or when terminated
+ */
+ public void testIsTerminating() throws InterruptedException {
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ assertFalse(p.isTerminating());
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ assertFalse(p.isTerminating());
+ threadStarted.countDown();
+ done.await();
+ }});
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertFalse(p.isTerminating());
+ done.countDown();
+ } finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ }
+ assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ assertTrue(p.isTerminated());
+ assertFalse(p.isTerminating());
+ }
+
+ /**
+ * getQueue returns the work queue, which contains queued tasks
+ */
+ public void testGetQueue() throws InterruptedException {
+ final BlockingQueue<Runnable> q = new ArrayBlockingQueue<Runnable>(10);
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ q);
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ FutureTask[] tasks = new FutureTask[5];
+ for (int i = 0; i < tasks.length; i++) {
+ Callable task = new CheckedCallable<Boolean>() {
+ public Boolean realCall() throws InterruptedException {
+ threadStarted.countDown();
+ assertSame(q, p.getQueue());
+ done.await();
+ return Boolean.TRUE;
+ }};
+ tasks[i] = new FutureTask(task);
+ p.execute(tasks[i]);
+ }
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertSame(q, p.getQueue());
+ assertFalse(q.contains(tasks[0]));
+ assertTrue(q.contains(tasks[tasks.length - 1]));
+ assertEquals(tasks.length - 1, q.size());
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * remove(task) removes queued task, and fails to remove active task
+ */
+ public void testRemove() throws InterruptedException {
+ BlockingQueue<Runnable> q = new ArrayBlockingQueue<Runnable>(10);
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ q);
+ Runnable[] tasks = new Runnable[5];
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ for (int i = 0; i < tasks.length; i++) {
+ tasks[i] = new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ done.await();
+ }};
+ p.execute(tasks[i]);
+ }
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertFalse(p.remove(tasks[0]));
+ assertTrue(q.contains(tasks[4]));
+ assertTrue(q.contains(tasks[3]));
+ assertTrue(p.remove(tasks[4]));
+ assertFalse(p.remove(tasks[4]));
+ assertFalse(q.contains(tasks[4]));
+ assertTrue(q.contains(tasks[3]));
+ assertTrue(p.remove(tasks[3]));
+ assertFalse(q.contains(tasks[3]));
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * purge removes cancelled tasks from the queue
+ */
+ public void testPurge() throws InterruptedException {
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ final BlockingQueue<Runnable> q = new ArrayBlockingQueue<Runnable>(10);
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ q);
+ FutureTask[] tasks = new FutureTask[5];
+ try {
+ for (int i = 0; i < tasks.length; i++) {
+ Callable task = new CheckedCallable<Boolean>() {
+ public Boolean realCall() throws InterruptedException {
+ threadStarted.countDown();
+ done.await();
+ return Boolean.TRUE;
+ }};
+ tasks[i] = new FutureTask(task);
+ p.execute(tasks[i]);
+ }
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ assertEquals(tasks.length, p.getTaskCount());
+ assertEquals(tasks.length - 1, q.size());
+ assertEquals(1L, p.getActiveCount());
+ assertEquals(0L, p.getCompletedTaskCount());
+ tasks[4].cancel(true);
+ tasks[3].cancel(false);
+ p.purge();
+ assertEquals(tasks.length - 3, q.size());
+ assertEquals(tasks.length - 2, p.getTaskCount());
+ p.purge(); // Nothing to do
+ assertEquals(tasks.length - 3, q.size());
+ assertEquals(tasks.length - 2, p.getTaskCount());
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * shutdownNow returns a list containing tasks that were not run
+ */
+ public void testShutdownNow() {
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ List l;
+ try {
+ for (int i = 0; i < 5; i++)
+ p.execute(new MediumPossiblyInterruptedRunnable());
+ }
+ finally {
+ try {
+ l = p.shutdownNow();
+ } catch (SecurityException ok) { return; }
+ }
+ assertTrue(p.isShutdown());
+ assertTrue(l.size() <= 4);
+ }
+
+ // Exception Tests
+
+ /**
+ * Constructor throws if corePoolSize argument is less than zero
+ */
+ public void testConstructor1() {
+ try {
+ new ThreadPoolExecutor(-1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if maximumPoolSize is less than zero
+ */
+ public void testConstructor2() {
+ try {
+ new ThreadPoolExecutor(1, -1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if maximumPoolSize is equal to zero
+ */
+ public void testConstructor3() {
+ try {
+ new ThreadPoolExecutor(1, 0,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if keepAliveTime is less than zero
+ */
+ public void testConstructor4() {
+ try {
+ new ThreadPoolExecutor(1, 2,
+ -1L, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if corePoolSize is greater than the maximumPoolSize
+ */
+ public void testConstructor5() {
+ try {
+ new ThreadPoolExecutor(2, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if workQueue is set to null
+ */
+ public void testConstructorNullPointerException() {
+ try {
+ new ThreadPoolExecutor(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ (BlockingQueue) null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Constructor throws if corePoolSize argument is less than zero
+ */
+ public void testConstructor6() {
+ try {
+ new ThreadPoolExecutor(-1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10),
+ new SimpleThreadFactory());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if maximumPoolSize is less than zero
+ */
+ public void testConstructor7() {
+ try {
+ new ThreadPoolExecutor(1, -1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10),
+ new SimpleThreadFactory());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if maximumPoolSize is equal to zero
+ */
+ public void testConstructor8() {
+ try {
+ new ThreadPoolExecutor(1, 0,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10),
+ new SimpleThreadFactory());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if keepAliveTime is less than zero
+ */
+ public void testConstructor9() {
+ try {
+ new ThreadPoolExecutor(1, 2,
+ -1L, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10),
+ new SimpleThreadFactory());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if corePoolSize is greater than the maximumPoolSize
+ */
+ public void testConstructor10() {
+ try {
+ new ThreadPoolExecutor(2, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10),
+ new SimpleThreadFactory());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if workQueue is set to null
+ */
+ public void testConstructorNullPointerException2() {
+ try {
+ new ThreadPoolExecutor(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ (BlockingQueue) null,
+ new SimpleThreadFactory());
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Constructor throws if threadFactory is set to null
+ */
+ public void testConstructorNullPointerException3() {
+ try {
+ new ThreadPoolExecutor(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10),
+ (ThreadFactory) null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Constructor throws if corePoolSize argument is less than zero
+ */
+ public void testConstructor11() {
+ try {
+ new ThreadPoolExecutor(-1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10),
+ new NoOpREHandler());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if maximumPoolSize is less than zero
+ */
+ public void testConstructor12() {
+ try {
+ new ThreadPoolExecutor(1, -1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10),
+ new NoOpREHandler());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if maximumPoolSize is equal to zero
+ */
+ public void testConstructor13() {
+ try {
+ new ThreadPoolExecutor(1, 0,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10),
+ new NoOpREHandler());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if keepAliveTime is less than zero
+ */
+ public void testConstructor14() {
+ try {
+ new ThreadPoolExecutor(1, 2,
+ -1L, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10),
+ new NoOpREHandler());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if corePoolSize is greater than the maximumPoolSize
+ */
+ public void testConstructor15() {
+ try {
+ new ThreadPoolExecutor(2, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10),
+ new NoOpREHandler());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if workQueue is set to null
+ */
+ public void testConstructorNullPointerException4() {
+ try {
+ new ThreadPoolExecutor(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ (BlockingQueue) null,
+ new NoOpREHandler());
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Constructor throws if handler is set to null
+ */
+ public void testConstructorNullPointerException5() {
+ try {
+ new ThreadPoolExecutor(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10),
+ (RejectedExecutionHandler) null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Constructor throws if corePoolSize argument is less than zero
+ */
+ public void testConstructor16() {
+ try {
+ new ThreadPoolExecutor(-1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10),
+ new SimpleThreadFactory(),
+ new NoOpREHandler());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if maximumPoolSize is less than zero
+ */
+ public void testConstructor17() {
+ try {
+ new ThreadPoolExecutor(1, -1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10),
+ new SimpleThreadFactory(),
+ new NoOpREHandler());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if maximumPoolSize is equal to zero
+ */
+ public void testConstructor18() {
+ try {
+ new ThreadPoolExecutor(1, 0,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10),
+ new SimpleThreadFactory(),
+ new NoOpREHandler());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if keepAliveTime is less than zero
+ */
+ public void testConstructor19() {
+ try {
+ new ThreadPoolExecutor(1, 2,
+ -1L, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10),
+ new SimpleThreadFactory(),
+ new NoOpREHandler());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if corePoolSize is greater than the maximumPoolSize
+ */
+ public void testConstructor20() {
+ try {
+ new ThreadPoolExecutor(2, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10),
+ new SimpleThreadFactory(),
+ new NoOpREHandler());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+
+ /**
+ * Constructor throws if workQueue is null
+ */
+ public void testConstructorNullPointerException6() {
+ try {
+ new ThreadPoolExecutor(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ (BlockingQueue) null,
+ new SimpleThreadFactory(),
+ new NoOpREHandler());
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Constructor throws if handler is null
+ */
+ public void testConstructorNullPointerException7() {
+ try {
+ new ThreadPoolExecutor(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10),
+ new SimpleThreadFactory(),
+ (RejectedExecutionHandler) null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Constructor throws if ThreadFactory is null
+ */
+ public void testConstructorNullPointerException8() {
+ try {
+ new ThreadPoolExecutor(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10),
+ (ThreadFactory) null,
+ new NoOpREHandler());
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * get of submitted callable throws InterruptedException if interrupted
+ */
+ public void testInterruptedSubmit() throws InterruptedException {
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 1,
+ 60, TimeUnit.SECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ Thread t = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws Exception {
+ Callable task = new CheckedCallable<Boolean>() {
+ public Boolean realCall() throws InterruptedException {
+ threadStarted.countDown();
+ done.await();
+ return Boolean.TRUE;
+ }};
+ p.submit(task).get();
+ }});
+
+ assertTrue(threadStarted.await(SMALL_DELAY_MS, MILLISECONDS));
+ t.interrupt();
+ awaitTermination(t, MEDIUM_DELAY_MS);
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * execute throws RejectedExecutionException if saturated.
+ */
+ public void testSaturatedExecute() {
+ ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(1));
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ Runnable task = new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ done.await();
+ }};
+ for (int i = 0; i < 2; ++i)
+ p.execute(task);
+ for (int i = 0; i < 2; ++i) {
+ try {
+ p.execute(task);
+ shouldThrow();
+ } catch (RejectedExecutionException success) {}
+ assertTrue(p.getTaskCount() <= 2);
+ }
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * submit(runnable) throws RejectedExecutionException if saturated.
+ */
+ public void testSaturatedSubmitRunnable() {
+ ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(1));
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ Runnable task = new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ done.await();
+ }};
+ for (int i = 0; i < 2; ++i)
+ p.submit(task);
+ for (int i = 0; i < 2; ++i) {
+ try {
+ p.execute(task);
+ shouldThrow();
+ } catch (RejectedExecutionException success) {}
+ assertTrue(p.getTaskCount() <= 2);
+ }
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * submit(callable) throws RejectedExecutionException if saturated.
+ */
+ public void testSaturatedSubmitCallable() {
+ ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(1));
+ final CountDownLatch done = new CountDownLatch(1);
+ try {
+ Runnable task = new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ done.await();
+ }};
+ for (int i = 0; i < 2; ++i)
+ p.submit(Executors.callable(task));
+ for (int i = 0; i < 2; ++i) {
+ try {
+ p.execute(task);
+ shouldThrow();
+ } catch (RejectedExecutionException success) {}
+ assertTrue(p.getTaskCount() <= 2);
+ }
+ } finally {
+ done.countDown();
+ joinPool(p);
+ }
+ }
+
+ /**
+ * executor using CallerRunsPolicy runs task if saturated.
+ */
+ public void testSaturatedExecute2() {
+ RejectedExecutionHandler h = new ThreadPoolExecutor.CallerRunsPolicy();
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 1,
+ LONG_DELAY_MS,
+ MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(1),
+ h);
+ try {
+ TrackedNoOpRunnable[] tasks = new TrackedNoOpRunnable[5];
+ for (int i = 0; i < tasks.length; ++i)
+ tasks[i] = new TrackedNoOpRunnable();
+ TrackedLongRunnable mr = new TrackedLongRunnable();
+ p.execute(mr);
+ for (int i = 0; i < tasks.length; ++i)
+ p.execute(tasks[i]);
+ for (int i = 1; i < tasks.length; ++i)
+ assertTrue(tasks[i].done);
+ try { p.shutdownNow(); } catch (SecurityException ok) { return; }
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * executor using DiscardPolicy drops task if saturated.
+ */
+ public void testSaturatedExecute3() {
+ RejectedExecutionHandler h = new ThreadPoolExecutor.DiscardPolicy();
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(1),
+ h);
+ try {
+ TrackedNoOpRunnable[] tasks = new TrackedNoOpRunnable[5];
+ for (int i = 0; i < tasks.length; ++i)
+ tasks[i] = new TrackedNoOpRunnable();
+ p.execute(new TrackedLongRunnable());
+ for (TrackedNoOpRunnable task : tasks)
+ p.execute(task);
+ for (TrackedNoOpRunnable task : tasks)
+ assertFalse(task.done);
+ try { p.shutdownNow(); } catch (SecurityException ok) { return; }
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * executor using DiscardOldestPolicy drops oldest task if saturated.
+ */
+ public void testSaturatedExecute4() {
+ RejectedExecutionHandler h = new ThreadPoolExecutor.DiscardOldestPolicy();
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(1),
+ h);
+ try {
+ p.execute(new TrackedLongRunnable());
+ TrackedLongRunnable r2 = new TrackedLongRunnable();
+ p.execute(r2);
+ assertTrue(p.getQueue().contains(r2));
+ TrackedNoOpRunnable r3 = new TrackedNoOpRunnable();
+ p.execute(r3);
+ assertFalse(p.getQueue().contains(r2));
+ assertTrue(p.getQueue().contains(r3));
+ try { p.shutdownNow(); } catch (SecurityException ok) { return; }
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * execute throws RejectedExecutionException if shutdown
+ */
+ public void testRejectedExecutionExceptionOnShutdown() {
+ ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(1));
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ try {
+ p.execute(new NoOpRunnable());
+ shouldThrow();
+ } catch (RejectedExecutionException success) {}
+
+ joinPool(p);
+ }
+
+ /**
+ * execute using CallerRunsPolicy drops task on shutdown
+ */
+ public void testCallerRunsOnShutdown() {
+ RejectedExecutionHandler h = new ThreadPoolExecutor.CallerRunsPolicy();
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(1), h);
+
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ try {
+ TrackedNoOpRunnable r = new TrackedNoOpRunnable();
+ p.execute(r);
+ assertFalse(r.done);
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * execute using DiscardPolicy drops task on shutdown
+ */
+ public void testDiscardOnShutdown() {
+ RejectedExecutionHandler h = new ThreadPoolExecutor.DiscardPolicy();
+ ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(1),
+ h);
+
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ try {
+ TrackedNoOpRunnable r = new TrackedNoOpRunnable();
+ p.execute(r);
+ assertFalse(r.done);
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * execute using DiscardOldestPolicy drops task on shutdown
+ */
+ public void testDiscardOldestOnShutdown() {
+ RejectedExecutionHandler h = new ThreadPoolExecutor.DiscardOldestPolicy();
+ ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 1,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(1),
+ h);
+
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ try {
+ TrackedNoOpRunnable r = new TrackedNoOpRunnable();
+ p.execute(r);
+ assertFalse(r.done);
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * execute(null) throws NPE
+ */
+ public void testExecuteNull() {
+ ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ p.execute(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+
+ joinPool(p);
+ }
+
+ /**
+ * setCorePoolSize of negative value throws IllegalArgumentException
+ */
+ public void testCorePoolSizeIllegalArgumentException() {
+ ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ p.setCorePoolSize(-1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ }
+ joinPool(p);
+ }
+
+ /**
+ * setMaximumPoolSize(int) throws IllegalArgumentException if
+ * given a value less the core pool size
+ */
+ public void testMaximumPoolSizeIllegalArgumentException() {
+ ThreadPoolExecutor p =
+ new ThreadPoolExecutor(2, 3,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ p.setMaximumPoolSize(1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ }
+ joinPool(p);
+ }
+
+ /**
+ * setMaximumPoolSize throws IllegalArgumentException
+ * if given a negative value
+ */
+ public void testMaximumPoolSizeIllegalArgumentException2() {
+ ThreadPoolExecutor p =
+ new ThreadPoolExecutor(2, 3,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ p.setMaximumPoolSize(-1);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ }
+ joinPool(p);
+ }
+
+ /**
+ * setKeepAliveTime throws IllegalArgumentException
+ * when given a negative value
+ */
+ public void testKeepAliveTimeIllegalArgumentException() {
+ ThreadPoolExecutor p =
+ new ThreadPoolExecutor(2, 3,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ p.setKeepAliveTime(-1,MILLISECONDS);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ }
+ joinPool(p);
+ }
+
+ /**
+ * terminated() is called on termination
+ */
+ public void testTerminated() {
+ ExtendedTPE p = new ExtendedTPE();
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ assertTrue(p.terminatedCalled());
+ joinPool(p);
+ }
+
+ /**
+ * beforeExecute and afterExecute are called when executing task
+ */
+ public void testBeforeAfter() throws InterruptedException {
+ ExtendedTPE p = new ExtendedTPE();
+ try {
+ final CountDownLatch done = new CountDownLatch(1);
+ final CheckedRunnable task = new CheckedRunnable() {
+ public void realRun() {
+ done.countDown();
+ }};
+ p.execute(task);
+ await(p.afterCalled);
+ assertEquals(0, done.getCount());
+ assertTrue(p.afterCalled());
+ assertTrue(p.beforeCalled());
+ try { p.shutdown(); } catch (SecurityException ok) { return; }
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * completed submit of callable returns result
+ */
+ public void testSubmitCallable() throws Exception {
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ Future<String> future = e.submit(new StringTask());
+ String result = future.get();
+ assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * completed submit of runnable returns successfully
+ */
+ public void testSubmitRunnable() throws Exception {
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ Future<?> future = e.submit(new NoOpRunnable());
+ future.get();
+ assertTrue(future.isDone());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * completed submit of (runnable, result) returns result
+ */
+ public void testSubmitRunnable2() throws Exception {
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ Future<String> future = e.submit(new NoOpRunnable(), TEST_STRING);
+ String result = future.get();
+ assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(null) throws NPE
+ */
+ public void testInvokeAny1() throws Exception {
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ e.invokeAny(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(empty collection) throws IAE
+ */
+ public void testInvokeAny2() throws Exception {
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ e.invokeAny(new ArrayList<Callable<String>>());
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(c) throws NPE if c has null elements
+ */
+ public void testInvokeAny3() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+ final ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(latchAwaitingStringTask(latch));
+ l.add(null);
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ latch.countDown();
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(c) throws ExecutionException if no task completes
+ */
+ public void testInvokeAny4() throws Exception {
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ try {
+ e.invokeAny(l);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAny(c) returns result of some task
+ */
+ public void testInvokeAny5() throws Exception {
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(new StringTask());
+ String result = e.invokeAny(l);
+ assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAll(null) throws NPE
+ */
+ public void testInvokeAll1() throws Exception {
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ e.invokeAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAll(empty collection) returns empty collection
+ */
+ public void testInvokeAll2() throws InterruptedException {
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>());
+ assertTrue(r.isEmpty());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAll(c) throws NPE if c has null elements
+ */
+ public void testInvokeAll3() throws Exception {
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(null);
+ try {
+ e.invokeAll(l);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * get of element of invokeAll(c) throws exception on failed task
+ */
+ public void testInvokeAll4() throws Exception {
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ List<Future<String>> futures = e.invokeAll(l);
+ assertEquals(1, futures.size());
+ try {
+ futures.get(0).get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ }
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * invokeAll(c) returns results of all completed tasks
+ */
+ public void testInvokeAll5() throws Exception {
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(new StringTask());
+ List<Future<String>> futures = e.invokeAll(l);
+ assertEquals(2, futures.size());
+ for (Future<String> future : futures)
+ assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(null) throws NPE
+ */
+ public void testTimedInvokeAny1() throws Exception {
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ e.invokeAny(null, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(,,null) throws NPE
+ */
+ public void testTimedInvokeAnyNullTimeUnit() throws Exception {
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(empty collection) throws IAE
+ */
+ public void testTimedInvokeAny2() throws Exception {
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ e.invokeAny(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(c) throws NPE if c has null elements
+ */
+ public void testTimedInvokeAny3() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+ final ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(latchAwaitingStringTask(latch));
+ l.add(null);
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ latch.countDown();
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(c) throws ExecutionException if no task completes
+ */
+ public void testTimedInvokeAny4() throws Exception {
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ try {
+ e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAny(c) returns result of some task
+ */
+ public void testTimedInvokeAny5() throws Exception {
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(new StringTask());
+ String result = e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ assertSame(TEST_STRING, result);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(null) throws NPE
+ */
+ public void testTimedInvokeAll1() throws Exception {
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ e.invokeAll(null, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(,,null) throws NPE
+ */
+ public void testTimedInvokeAllNullTimeUnit() throws Exception {
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ try {
+ e.invokeAll(l, MEDIUM_DELAY_MS, null);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(empty collection) returns empty collection
+ */
+ public void testTimedInvokeAll2() throws InterruptedException {
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, MILLISECONDS);
+ assertTrue(r.isEmpty());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(c) throws NPE if c has null elements
+ */
+ public void testTimedInvokeAll3() throws Exception {
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(null);
+ try {
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ shouldThrow();
+ } catch (NullPointerException success) {
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * get of element of invokeAll(c) throws exception on failed task
+ */
+ public void testTimedInvokeAll4() throws Exception {
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new NPETask());
+ List<Future<String>> futures =
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ assertEquals(1, futures.size());
+ try {
+ futures.get(0).get();
+ shouldThrow();
+ } catch (ExecutionException success) {
+ assertTrue(success.getCause() instanceof NullPointerException);
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(c) returns results of all completed tasks
+ */
+ public void testTimedInvokeAll5() throws Exception {
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(new StringTask());
+ List<Future<String>> futures =
+ e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS);
+ assertEquals(2, futures.size());
+ for (Future<String> future : futures)
+ assertSame(TEST_STRING, future.get());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * timed invokeAll(c) cancels tasks not completed by timeout
+ */
+ public void testTimedInvokeAll6() throws Exception {
+ ExecutorService e =
+ new ThreadPoolExecutor(2, 2,
+ LONG_DELAY_MS, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ try {
+ List<Callable<String>> l = new ArrayList<Callable<String>>();
+ l.add(new StringTask());
+ l.add(Executors.callable(new MediumPossiblyInterruptedRunnable(), TEST_STRING));
+ l.add(new StringTask());
+ List<Future<String>> futures =
+ e.invokeAll(l, SHORT_DELAY_MS, MILLISECONDS);
+ assertEquals(l.size(), futures.size());
+ for (Future future : futures)
+ assertTrue(future.isDone());
+ assertFalse(futures.get(0).isCancelled());
+ assertTrue(futures.get(1).isCancelled());
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * Execution continues if there is at least one thread even if
+ * thread factory fails to create more
+ */
+ public void testFailingThreadFactory() throws InterruptedException {
+ final ExecutorService e =
+ new ThreadPoolExecutor(100, 100,
+ LONG_DELAY_MS, MILLISECONDS,
+ new LinkedBlockingQueue<Runnable>(),
+ new FailingThreadFactory());
+ try {
+ final int TASKS = 100;
+ final CountDownLatch done = new CountDownLatch(TASKS);
+ for (int k = 0; k < TASKS; ++k)
+ e.execute(new CheckedRunnable() {
+ public void realRun() {
+ done.countDown();
+ }});
+ assertTrue(done.await(LONG_DELAY_MS, MILLISECONDS));
+ } finally {
+ joinPool(e);
+ }
+ }
+
+ /**
+ * allowsCoreThreadTimeOut is by default false.
+ */
+ public void testAllowsCoreThreadTimeOut() {
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(2, 2,
+ 1000, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ assertFalse(p.allowsCoreThreadTimeOut());
+ joinPool(p);
+ }
+
+ /**
+ * allowCoreThreadTimeOut(true) causes idle threads to time out
+ */
+ public void testAllowCoreThreadTimeOut_true() throws Exception {
+ long coreThreadTimeOut = SHORT_DELAY_MS;
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(2, 10,
+ coreThreadTimeOut, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ try {
+ p.allowCoreThreadTimeOut(true);
+ p.execute(new CheckedRunnable() {
+ public void realRun() {
+ threadStarted.countDown();
+ assertEquals(1, p.getPoolSize());
+ }});
+ await(threadStarted);
+ delay(coreThreadTimeOut);
+ long startTime = System.nanoTime();
+ while (p.getPoolSize() > 0
+ && millisElapsedSince(startTime) < LONG_DELAY_MS)
+ Thread.yield();
+ assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
+ assertEquals(0, p.getPoolSize());
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * allowCoreThreadTimeOut(false) causes idle threads not to time out
+ */
+ public void testAllowCoreThreadTimeOut_false() throws Exception {
+ long coreThreadTimeOut = SHORT_DELAY_MS;
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(2, 10,
+ coreThreadTimeOut, MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(10));
+ final CountDownLatch threadStarted = new CountDownLatch(1);
+ try {
+ p.allowCoreThreadTimeOut(false);
+ p.execute(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ threadStarted.countDown();
+ assertTrue(p.getPoolSize() >= 1);
+ }});
+ delay(2 * coreThreadTimeOut);
+ assertTrue(p.getPoolSize() >= 1);
+ } finally {
+ joinPool(p);
+ }
+ }
+
+ /**
+ * execute allows the same task to be submitted multiple times, even
+ * if rejected
+ */
+ public void testRejectedRecycledTask() throws InterruptedException {
+ final int nTasks = 1000;
+ final CountDownLatch done = new CountDownLatch(nTasks);
+ final Runnable recycledTask = new Runnable() {
+ public void run() {
+ done.countDown();
+ }};
+ final ThreadPoolExecutor p =
+ new ThreadPoolExecutor(1, 30, 60, TimeUnit.SECONDS,
+ new ArrayBlockingQueue(30));
+ try {
+ for (int i = 0; i < nTasks; ++i) {
+ for (;;) {
+ try {
+ p.execute(recycledTask);
+ break;
+ }
+ catch (RejectedExecutionException ignore) {}
+ }
+ }
+ // enough time to run all tasks
+ assertTrue(done.await(nTasks * SHORT_DELAY_MS, MILLISECONDS));
+ } finally {
+ joinPool(p);
+ }
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/ThreadTest.java b/jsr166-tests/src/test/java/jsr166/ThreadTest.java
new file mode 100644
index 0000000..12c2f8a
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/ThreadTest.java
@@ -0,0 +1,65 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+
+public class ThreadTest extends JSR166TestCase {
+
+ static class MyHandler implements Thread.UncaughtExceptionHandler {
+ public void uncaughtException(Thread t, Throwable e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * getUncaughtExceptionHandler returns ThreadGroup unless set,
+ * otherwise returning value of last setUncaughtExceptionHandler.
+ */
+ public void testGetAndSetUncaughtExceptionHandler() {
+ // these must be done all at once to avoid state
+ // dependencies across tests
+ Thread current = Thread.currentThread();
+ ThreadGroup tg = current.getThreadGroup();
+ MyHandler eh = new MyHandler();
+ assertEquals(tg, current.getUncaughtExceptionHandler());
+ current.setUncaughtExceptionHandler(eh);
+ assertEquals(eh, current.getUncaughtExceptionHandler());
+ current.setUncaughtExceptionHandler(null);
+ assertEquals(tg, current.getUncaughtExceptionHandler());
+ }
+
+ /**
+ * getDefaultUncaughtExceptionHandler returns value of last
+ * setDefaultUncaughtExceptionHandler.
+ */
+ public void testGetAndSetDefaultUncaughtExceptionHandler() {
+ // BEGIN android-remove (when running as cts the RuntimeInit will
+ // set a default handler)
+ // assertEquals(null, Thread.getDefaultUncaughtExceptionHandler());
+ // END android-remove
+
+ // failure due to securityException is OK.
+ // Would be nice to explicitly test both ways, but cannot yet.
+ try {
+ Thread current = Thread.currentThread();
+ ThreadGroup tg = current.getThreadGroup();
+ MyHandler eh = new MyHandler();
+ Thread.setDefaultUncaughtExceptionHandler(eh);
+ assertEquals(eh, Thread.getDefaultUncaughtExceptionHandler());
+ Thread.setDefaultUncaughtExceptionHandler(null);
+ }
+ catch (SecurityException ok) {
+ }
+ assertEquals(null, Thread.getDefaultUncaughtExceptionHandler());
+ }
+
+ // How to test actually using UEH within junit?
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/TimeUnitTest.java b/jsr166-tests/src/test/java/jsr166/TimeUnitTest.java
new file mode 100644
index 0000000..7fa9e1a
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/TimeUnitTest.java
@@ -0,0 +1,457 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class TimeUnitTest extends JSR166TestCase {
+
+ // (loops to 88888 check increments at all time divisions.)
+
+ /**
+ * convert correctly converts sample values across the units
+ */
+ public void testConvert() {
+ for (long t = 0; t < 88888; ++t) {
+ assertEquals(t*60*60*24,
+ TimeUnit.SECONDS.convert(t,
+ TimeUnit.DAYS));
+ assertEquals(t*60*60,
+ TimeUnit.SECONDS.convert(t,
+ TimeUnit.HOURS));
+ assertEquals(t*60,
+ TimeUnit.SECONDS.convert(t,
+ TimeUnit.MINUTES));
+ assertEquals(t,
+ TimeUnit.SECONDS.convert(t,
+ TimeUnit.SECONDS));
+ assertEquals(t,
+ TimeUnit.SECONDS.convert(1000L*t,
+ TimeUnit.MILLISECONDS));
+ assertEquals(t,
+ TimeUnit.SECONDS.convert(1000000L*t,
+ TimeUnit.MICROSECONDS));
+ assertEquals(t,
+ TimeUnit.SECONDS.convert(1000000000L*t,
+ TimeUnit.NANOSECONDS));
+
+ assertEquals(1000L*t*60*60*24,
+ TimeUnit.MILLISECONDS.convert(t,
+ TimeUnit.DAYS));
+ assertEquals(1000L*t*60*60,
+ TimeUnit.MILLISECONDS.convert(t,
+ TimeUnit.HOURS));
+ assertEquals(1000L*t*60,
+ TimeUnit.MILLISECONDS.convert(t,
+ TimeUnit.MINUTES));
+ assertEquals(1000L*t,
+ TimeUnit.MILLISECONDS.convert(t,
+ TimeUnit.SECONDS));
+ assertEquals(t,
+ TimeUnit.MILLISECONDS.convert(t,
+ TimeUnit.MILLISECONDS));
+ assertEquals(t,
+ TimeUnit.MILLISECONDS.convert(1000L*t,
+ TimeUnit.MICROSECONDS));
+ assertEquals(t,
+ TimeUnit.MILLISECONDS.convert(1000000L*t,
+ TimeUnit.NANOSECONDS));
+
+ assertEquals(1000000L*t*60*60*24,
+ TimeUnit.MICROSECONDS.convert(t,
+ TimeUnit.DAYS));
+ assertEquals(1000000L*t*60*60,
+ TimeUnit.MICROSECONDS.convert(t,
+ TimeUnit.HOURS));
+ assertEquals(1000000L*t*60,
+ TimeUnit.MICROSECONDS.convert(t,
+ TimeUnit.MINUTES));
+ assertEquals(1000000L*t,
+ TimeUnit.MICROSECONDS.convert(t,
+ TimeUnit.SECONDS));
+ assertEquals(1000L*t,
+ TimeUnit.MICROSECONDS.convert(t,
+ TimeUnit.MILLISECONDS));
+ assertEquals(t,
+ TimeUnit.MICROSECONDS.convert(t,
+ TimeUnit.MICROSECONDS));
+ assertEquals(t,
+ TimeUnit.MICROSECONDS.convert(1000L*t,
+ TimeUnit.NANOSECONDS));
+
+ assertEquals(1000000000L*t*60*60*24,
+ TimeUnit.NANOSECONDS.convert(t,
+ TimeUnit.DAYS));
+ assertEquals(1000000000L*t*60*60,
+ TimeUnit.NANOSECONDS.convert(t,
+ TimeUnit.HOURS));
+ assertEquals(1000000000L*t*60,
+ TimeUnit.NANOSECONDS.convert(t,
+ TimeUnit.MINUTES));
+ assertEquals(1000000000L*t,
+ TimeUnit.NANOSECONDS.convert(t,
+ TimeUnit.SECONDS));
+ assertEquals(1000000L*t,
+ TimeUnit.NANOSECONDS.convert(t,
+ TimeUnit.MILLISECONDS));
+ assertEquals(1000L*t,
+ TimeUnit.NANOSECONDS.convert(t,
+ TimeUnit.MICROSECONDS));
+ assertEquals(t,
+ TimeUnit.NANOSECONDS.convert(t,
+ TimeUnit.NANOSECONDS));
+ }
+ }
+
+ /**
+ * toNanos correctly converts sample values in different units to
+ * nanoseconds
+ */
+ public void testToNanos() {
+ for (long t = 0; t < 88888; ++t) {
+ assertEquals(t*1000000000L*60*60*24,
+ TimeUnit.DAYS.toNanos(t));
+ assertEquals(t*1000000000L*60*60,
+ TimeUnit.HOURS.toNanos(t));
+ assertEquals(t*1000000000L*60,
+ TimeUnit.MINUTES.toNanos(t));
+ assertEquals(1000000000L*t,
+ TimeUnit.SECONDS.toNanos(t));
+ assertEquals(1000000L*t,
+ TimeUnit.MILLISECONDS.toNanos(t));
+ assertEquals(1000L*t,
+ TimeUnit.MICROSECONDS.toNanos(t));
+ assertEquals(t,
+ TimeUnit.NANOSECONDS.toNanos(t));
+ }
+ }
+
+ /**
+ * toMicros correctly converts sample values in different units to
+ * microseconds
+ */
+ public void testToMicros() {
+ for (long t = 0; t < 88888; ++t) {
+ assertEquals(t*1000000L*60*60*24,
+ TimeUnit.DAYS.toMicros(t));
+ assertEquals(t*1000000L*60*60,
+ TimeUnit.HOURS.toMicros(t));
+ assertEquals(t*1000000L*60,
+ TimeUnit.MINUTES.toMicros(t));
+ assertEquals(1000000L*t,
+ TimeUnit.SECONDS.toMicros(t));
+ assertEquals(1000L*t,
+ TimeUnit.MILLISECONDS.toMicros(t));
+ assertEquals(t,
+ TimeUnit.MICROSECONDS.toMicros(t));
+ assertEquals(t,
+ TimeUnit.NANOSECONDS.toMicros(t*1000L));
+ }
+ }
+
+ /**
+ * toMillis correctly converts sample values in different units to
+ * milliseconds
+ */
+ public void testToMillis() {
+ for (long t = 0; t < 88888; ++t) {
+ assertEquals(t*1000L*60*60*24,
+ TimeUnit.DAYS.toMillis(t));
+ assertEquals(t*1000L*60*60,
+ TimeUnit.HOURS.toMillis(t));
+ assertEquals(t*1000L*60,
+ TimeUnit.MINUTES.toMillis(t));
+ assertEquals(1000L*t,
+ TimeUnit.SECONDS.toMillis(t));
+ assertEquals(t,
+ TimeUnit.MILLISECONDS.toMillis(t));
+ assertEquals(t,
+ TimeUnit.MICROSECONDS.toMillis(t*1000L));
+ assertEquals(t,
+ TimeUnit.NANOSECONDS.toMillis(t*1000000L));
+ }
+ }
+
+ /**
+ * toSeconds correctly converts sample values in different units to
+ * seconds
+ */
+ public void testToSeconds() {
+ for (long t = 0; t < 88888; ++t) {
+ assertEquals(t*60*60*24,
+ TimeUnit.DAYS.toSeconds(t));
+ assertEquals(t*60*60,
+ TimeUnit.HOURS.toSeconds(t));
+ assertEquals(t*60,
+ TimeUnit.MINUTES.toSeconds(t));
+ assertEquals(t,
+ TimeUnit.SECONDS.toSeconds(t));
+ assertEquals(t,
+ TimeUnit.MILLISECONDS.toSeconds(t*1000L));
+ assertEquals(t,
+ TimeUnit.MICROSECONDS.toSeconds(t*1000000L));
+ assertEquals(t,
+ TimeUnit.NANOSECONDS.toSeconds(t*1000000000L));
+ }
+ }
+
+ /**
+ * toMinutes correctly converts sample values in different units to
+ * minutes
+ */
+ public void testToMinutes() {
+ for (long t = 0; t < 88888; ++t) {
+ assertEquals(t*60*24,
+ TimeUnit.DAYS.toMinutes(t));
+ assertEquals(t*60,
+ TimeUnit.HOURS.toMinutes(t));
+ assertEquals(t,
+ TimeUnit.MINUTES.toMinutes(t));
+ assertEquals(t,
+ TimeUnit.SECONDS.toMinutes(t*60));
+ assertEquals(t,
+ TimeUnit.MILLISECONDS.toMinutes(t*1000L*60));
+ assertEquals(t,
+ TimeUnit.MICROSECONDS.toMinutes(t*1000000L*60));
+ assertEquals(t,
+ TimeUnit.NANOSECONDS.toMinutes(t*1000000000L*60));
+ }
+ }
+
+ /**
+ * toHours correctly converts sample values in different units to
+ * hours
+ */
+ public void testToHours() {
+ for (long t = 0; t < 88888; ++t) {
+ assertEquals(t*24,
+ TimeUnit.DAYS.toHours(t));
+ assertEquals(t,
+ TimeUnit.HOURS.toHours(t));
+ assertEquals(t,
+ TimeUnit.MINUTES.toHours(t*60));
+ assertEquals(t,
+ TimeUnit.SECONDS.toHours(t*60*60));
+ assertEquals(t,
+ TimeUnit.MILLISECONDS.toHours(t*1000L*60*60));
+ assertEquals(t,
+ TimeUnit.MICROSECONDS.toHours(t*1000000L*60*60));
+ assertEquals(t,
+ TimeUnit.NANOSECONDS.toHours(t*1000000000L*60*60));
+ }
+ }
+
+ /**
+ * toDays correctly converts sample values in different units to
+ * days
+ */
+ public void testToDays() {
+ for (long t = 0; t < 88888; ++t) {
+ assertEquals(t,
+ TimeUnit.DAYS.toDays(t));
+ assertEquals(t,
+ TimeUnit.HOURS.toDays(t*24));
+ assertEquals(t,
+ TimeUnit.MINUTES.toDays(t*60*24));
+ assertEquals(t,
+ TimeUnit.SECONDS.toDays(t*60*60*24));
+ assertEquals(t,
+ TimeUnit.MILLISECONDS.toDays(t*1000L*60*60*24));
+ assertEquals(t,
+ TimeUnit.MICROSECONDS.toDays(t*1000000L*60*60*24));
+ assertEquals(t,
+ TimeUnit.NANOSECONDS.toDays(t*1000000000L*60*60*24));
+ }
+ }
+
+ /**
+ * convert saturates positive too-large values to Long.MAX_VALUE
+ * and negative to LONG.MIN_VALUE
+ */
+ public void testConvertSaturate() {
+ assertEquals(Long.MAX_VALUE,
+ TimeUnit.NANOSECONDS.convert(Long.MAX_VALUE / 2,
+ TimeUnit.SECONDS));
+ assertEquals(Long.MIN_VALUE,
+ TimeUnit.NANOSECONDS.convert(-Long.MAX_VALUE / 4,
+ TimeUnit.SECONDS));
+ assertEquals(Long.MAX_VALUE,
+ TimeUnit.NANOSECONDS.convert(Long.MAX_VALUE / 2,
+ TimeUnit.MINUTES));
+ assertEquals(Long.MIN_VALUE,
+ TimeUnit.NANOSECONDS.convert(-Long.MAX_VALUE / 4,
+ TimeUnit.MINUTES));
+ assertEquals(Long.MAX_VALUE,
+ TimeUnit.NANOSECONDS.convert(Long.MAX_VALUE / 2,
+ TimeUnit.HOURS));
+ assertEquals(Long.MIN_VALUE,
+ TimeUnit.NANOSECONDS.convert(-Long.MAX_VALUE / 4,
+ TimeUnit.HOURS));
+ assertEquals(Long.MAX_VALUE,
+ TimeUnit.NANOSECONDS.convert(Long.MAX_VALUE / 2,
+ TimeUnit.DAYS));
+ assertEquals(Long.MIN_VALUE,
+ TimeUnit.NANOSECONDS.convert(-Long.MAX_VALUE / 4,
+ TimeUnit.DAYS));
+ }
+
+ /**
+ * toNanos saturates positive too-large values to Long.MAX_VALUE
+ * and negative to LONG.MIN_VALUE
+ */
+ public void testToNanosSaturate() {
+ assertEquals(Long.MAX_VALUE,
+ TimeUnit.MILLISECONDS.toNanos(Long.MAX_VALUE / 2));
+ assertEquals(Long.MIN_VALUE,
+ TimeUnit.MILLISECONDS.toNanos(-Long.MAX_VALUE / 3));
+ }
+
+ /**
+ * toString returns name of unit
+ */
+ public void testToString() {
+ assertEquals("SECONDS", TimeUnit.SECONDS.toString());
+ }
+
+ /**
+ * name returns name of unit
+ */
+ public void testName() {
+ assertEquals("SECONDS", TimeUnit.SECONDS.name());
+ }
+
+ /**
+ * Timed wait without holding lock throws
+ * IllegalMonitorStateException
+ */
+ public void testTimedWait_IllegalMonitorException() {
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ Object o = new Object();
+ TimeUnit tu = TimeUnit.MILLISECONDS;
+
+ try {
+ tu.timedWait(o, LONG_DELAY_MS);
+ threadShouldThrow();
+ } catch (IllegalMonitorStateException success) {}
+ }});
+
+ awaitTermination(t);
+ }
+
+ /**
+ * timedWait throws InterruptedException when interrupted
+ */
+ public void testTimedWait_Interruptible() {
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ Object o = new Object();
+ TimeUnit tu = TimeUnit.MILLISECONDS;
+
+ Thread.currentThread().interrupt();
+ try {
+ synchronized (o) {
+ tu.timedWait(o, LONG_DELAY_MS);
+ }
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ synchronized (o) {
+ tu.timedWait(o, LONG_DELAY_MS);
+ }
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * timedJoin throws InterruptedException when interrupted
+ */
+ public void testTimedJoin_Interruptible() {
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ final Thread s = newStartedThread(new CheckedInterruptedRunnable() {
+ public void realRun() throws InterruptedException {
+ Thread.sleep(LONG_DELAY_MS);
+ }});
+ final Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ TimeUnit tu = TimeUnit.MILLISECONDS;
+ Thread.currentThread().interrupt();
+ try {
+ tu.timedJoin(s, LONG_DELAY_MS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ tu.timedJoin(s, LONG_DELAY_MS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ s.interrupt();
+ awaitTermination(s);
+ }
+
+ /**
+ * timedSleep throws InterruptedException when interrupted
+ */
+ public void testTimedSleep_Interruptible() {
+ final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
+ Thread t = newStartedThread(new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ TimeUnit tu = TimeUnit.MILLISECONDS;
+ Thread.currentThread().interrupt();
+ try {
+ tu.sleep(LONG_DELAY_MS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+
+ pleaseInterrupt.countDown();
+ try {
+ tu.sleep(LONG_DELAY_MS);
+ shouldThrow();
+ } catch (InterruptedException success) {}
+ assertFalse(Thread.interrupted());
+ }});
+
+ await(pleaseInterrupt);
+ assertThreadStaysAlive(t);
+ t.interrupt();
+ awaitTermination(t);
+ }
+
+ /**
+ * a deserialized serialized unit is the same instance
+ */
+ public void testSerialization() throws Exception {
+ TimeUnit x = TimeUnit.MILLISECONDS;
+ assertSame(x, serialClone(x));
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/TreeMapTest.java b/jsr166-tests/src/test/java/jsr166/TreeMapTest.java
new file mode 100644
index 0000000..87baa1a
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/TreeMapTest.java
@@ -0,0 +1,1068 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.*;
+
+public class TreeMapTest extends JSR166TestCase {
+
+ /**
+ * Returns a new map from Integers 1-5 to Strings "A"-"E".
+ */
+ private static TreeMap map5() {
+ TreeMap map = new TreeMap();
+ assertTrue(map.isEmpty());
+ map.put(one, "A");
+ map.put(five, "E");
+ map.put(three, "C");
+ map.put(two, "B");
+ map.put(four, "D");
+ assertFalse(map.isEmpty());
+ assertEquals(5, map.size());
+ return map;
+ }
+
+ /**
+ * clear removes all pairs
+ */
+ public void testClear() {
+ TreeMap map = map5();
+ map.clear();
+ assertEquals(0, map.size());
+ }
+
+ /**
+ * copy constructor creates map equal to source map
+ */
+ public void testConstructFromSorted() {
+ TreeMap map = map5();
+ TreeMap map2 = new TreeMap(map);
+ assertEquals(map, map2);
+ }
+
+ /**
+ * Maps with same contents are equal
+ */
+ public void testEquals() {
+ TreeMap map1 = map5();
+ TreeMap map2 = map5();
+ assertEquals(map1, map2);
+ assertEquals(map2, map1);
+ map1.clear();
+ assertFalse(map1.equals(map2));
+ assertFalse(map2.equals(map1));
+ }
+
+ /**
+ * containsKey returns true for contained key
+ */
+ public void testContainsKey() {
+ TreeMap map = map5();
+ assertTrue(map.containsKey(one));
+ assertFalse(map.containsKey(zero));
+ }
+
+ /**
+ * containsValue returns true for held values
+ */
+ public void testContainsValue() {
+ TreeMap map = map5();
+ assertTrue(map.containsValue("A"));
+ assertFalse(map.containsValue("Z"));
+ }
+
+ /**
+ * get returns the correct element at the given key,
+ * or null if not present
+ */
+ public void testGet() {
+ TreeMap map = map5();
+ assertEquals("A", (String)map.get(one));
+ TreeMap empty = new TreeMap();
+ assertNull(empty.get(one));
+ }
+
+ /**
+ * isEmpty is true of empty map and false for non-empty
+ */
+ public void testIsEmpty() {
+ TreeMap empty = new TreeMap();
+ TreeMap map = map5();
+ assertTrue(empty.isEmpty());
+ assertFalse(map.isEmpty());
+ }
+
+ /**
+ * firstKey returns first key
+ */
+ public void testFirstKey() {
+ TreeMap map = map5();
+ assertEquals(one, map.firstKey());
+ }
+
+ /**
+ * lastKey returns last key
+ */
+ public void testLastKey() {
+ TreeMap map = map5();
+ assertEquals(five, map.lastKey());
+ }
+
+ /**
+ * keySet.toArray returns contains all keys
+ */
+ public void testKeySetToArray() {
+ TreeMap map = map5();
+ Set s = map.keySet();
+ Object[] ar = s.toArray();
+ assertTrue(s.containsAll(Arrays.asList(ar)));
+ assertEquals(5, ar.length);
+ ar[0] = m10;
+ assertFalse(s.containsAll(Arrays.asList(ar)));
+ }
+
+ /**
+ * descendingkeySet.toArray returns contains all keys
+ */
+ public void testDescendingKeySetToArray() {
+ TreeMap map = map5();
+ Set s = map.descendingKeySet();
+ Object[] ar = s.toArray();
+ assertEquals(5, ar.length);
+ assertTrue(s.containsAll(Arrays.asList(ar)));
+ ar[0] = m10;
+ assertFalse(s.containsAll(Arrays.asList(ar)));
+ }
+
+ /**
+ * keySet returns a Set containing all the keys
+ */
+ public void testKeySet() {
+ TreeMap map = map5();
+ Set s = map.keySet();
+ assertEquals(5, s.size());
+ assertTrue(s.contains(one));
+ assertTrue(s.contains(two));
+ assertTrue(s.contains(three));
+ assertTrue(s.contains(four));
+ assertTrue(s.contains(five));
+ }
+
+ /**
+ * keySet is ordered
+ */
+ public void testKeySetOrder() {
+ TreeMap map = map5();
+ Set s = map.keySet();
+ Iterator i = s.iterator();
+ Integer last = (Integer)i.next();
+ assertEquals(last, one);
+ int count = 1;
+ while (i.hasNext()) {
+ Integer k = (Integer)i.next();
+ assertTrue(last.compareTo(k) < 0);
+ last = k;
+ ++count;
+ }
+ assertEquals(5, count);
+ }
+
+ /**
+ * descending iterator of key set is inverse ordered
+ */
+ public void testKeySetDescendingIteratorOrder() {
+ TreeMap map = map5();
+ NavigableSet s = map.navigableKeySet();
+ Iterator i = s.descendingIterator();
+ Integer last = (Integer)i.next();
+ assertEquals(last, five);
+ int count = 1;
+ while (i.hasNext()) {
+ Integer k = (Integer)i.next();
+ assertTrue(last.compareTo(k) > 0);
+ last = k;
+ ++count;
+ }
+ assertEquals(5, count);
+ }
+
+ /**
+ * descendingKeySet is ordered
+ */
+ public void testDescendingKeySetOrder() {
+ TreeMap map = map5();
+ Set s = map.descendingKeySet();
+ Iterator i = s.iterator();
+ Integer last = (Integer)i.next();
+ assertEquals(last, five);
+ int count = 1;
+ while (i.hasNext()) {
+ Integer k = (Integer)i.next();
+ assertTrue(last.compareTo(k) > 0);
+ last = k;
+ ++count;
+ }
+ assertEquals(5, count);
+ }
+
+ /**
+ * descending iterator of descendingKeySet is ordered
+ */
+ public void testDescendingKeySetDescendingIteratorOrder() {
+ TreeMap map = map5();
+ NavigableSet s = map.descendingKeySet();
+ Iterator i = s.descendingIterator();
+ Integer last = (Integer)i.next();
+ assertEquals(last, one);
+ int count = 1;
+ while (i.hasNext()) {
+ Integer k = (Integer)i.next();
+ assertTrue(last.compareTo(k) < 0);
+ last = k;
+ ++count;
+ }
+ assertEquals(5, count);
+ }
+
+ /**
+ * values collection contains all values
+ */
+ public void testValues() {
+ TreeMap map = map5();
+ Collection s = map.values();
+ assertEquals(5, s.size());
+ assertTrue(s.contains("A"));
+ assertTrue(s.contains("B"));
+ assertTrue(s.contains("C"));
+ assertTrue(s.contains("D"));
+ assertTrue(s.contains("E"));
+ }
+
+ /**
+ * entrySet contains all pairs
+ */
+ public void testEntrySet() {
+ TreeMap map = map5();
+ Set s = map.entrySet();
+ assertEquals(5, s.size());
+ Iterator it = s.iterator();
+ while (it.hasNext()) {
+ Map.Entry e = (Map.Entry) it.next();
+ assertTrue(
+ (e.getKey().equals(one) && e.getValue().equals("A")) ||
+ (e.getKey().equals(two) && e.getValue().equals("B")) ||
+ (e.getKey().equals(three) && e.getValue().equals("C")) ||
+ (e.getKey().equals(four) && e.getValue().equals("D")) ||
+ (e.getKey().equals(five) && e.getValue().equals("E")));
+ }
+ }
+
+ /**
+ * descendingEntrySet contains all pairs
+ */
+ public void testDescendingEntrySet() {
+ TreeMap map = map5();
+ Set s = map.descendingMap().entrySet();
+ assertEquals(5, s.size());
+ Iterator it = s.iterator();
+ while (it.hasNext()) {
+ Map.Entry e = (Map.Entry) it.next();
+ assertTrue(
+ (e.getKey().equals(one) && e.getValue().equals("A")) ||
+ (e.getKey().equals(two) && e.getValue().equals("B")) ||
+ (e.getKey().equals(three) && e.getValue().equals("C")) ||
+ (e.getKey().equals(four) && e.getValue().equals("D")) ||
+ (e.getKey().equals(five) && e.getValue().equals("E")));
+ }
+ }
+
+ /**
+ * entrySet.toArray contains all entries
+ */
+ public void testEntrySetToArray() {
+ TreeMap map = map5();
+ Set s = map.entrySet();
+ Object[] ar = s.toArray();
+ assertEquals(5, ar.length);
+ for (int i = 0; i < 5; ++i) {
+ assertTrue(map.containsKey(((Map.Entry)(ar[i])).getKey()));
+ assertTrue(map.containsValue(((Map.Entry)(ar[i])).getValue()));
+ }
+ }
+
+ /**
+ * descendingEntrySet.toArray contains all entries
+ */
+ public void testDescendingEntrySetToArray() {
+ TreeMap map = map5();
+ Set s = map.descendingMap().entrySet();
+ Object[] ar = s.toArray();
+ assertEquals(5, ar.length);
+ for (int i = 0; i < 5; ++i) {
+ assertTrue(map.containsKey(((Map.Entry)(ar[i])).getKey()));
+ assertTrue(map.containsValue(((Map.Entry)(ar[i])).getValue()));
+ }
+ }
+
+ /**
+ * putAll adds all key-value pairs from the given map
+ */
+ public void testPutAll() {
+ TreeMap empty = new TreeMap();
+ TreeMap map = map5();
+ empty.putAll(map);
+ assertEquals(5, empty.size());
+ assertTrue(empty.containsKey(one));
+ assertTrue(empty.containsKey(two));
+ assertTrue(empty.containsKey(three));
+ assertTrue(empty.containsKey(four));
+ assertTrue(empty.containsKey(five));
+ }
+
+ /**
+ * remove removes the correct key-value pair from the map
+ */
+ public void testRemove() {
+ TreeMap map = map5();
+ map.remove(five);
+ assertEquals(4, map.size());
+ assertFalse(map.containsKey(five));
+ }
+
+ /**
+ * lowerEntry returns preceding entry.
+ */
+ public void testLowerEntry() {
+ TreeMap map = map5();
+ Map.Entry e1 = map.lowerEntry(three);
+ assertEquals(two, e1.getKey());
+
+ Map.Entry e2 = map.lowerEntry(six);
+ assertEquals(five, e2.getKey());
+
+ Map.Entry e3 = map.lowerEntry(one);
+ assertNull(e3);
+
+ Map.Entry e4 = map.lowerEntry(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * higherEntry returns next entry.
+ */
+ public void testHigherEntry() {
+ TreeMap map = map5();
+ Map.Entry e1 = map.higherEntry(three);
+ assertEquals(four, e1.getKey());
+
+ Map.Entry e2 = map.higherEntry(zero);
+ assertEquals(one, e2.getKey());
+
+ Map.Entry e3 = map.higherEntry(five);
+ assertNull(e3);
+
+ Map.Entry e4 = map.higherEntry(six);
+ assertNull(e4);
+ }
+
+ /**
+ * floorEntry returns preceding entry.
+ */
+ public void testFloorEntry() {
+ TreeMap map = map5();
+ Map.Entry e1 = map.floorEntry(three);
+ assertEquals(three, e1.getKey());
+
+ Map.Entry e2 = map.floorEntry(six);
+ assertEquals(five, e2.getKey());
+
+ Map.Entry e3 = map.floorEntry(one);
+ assertEquals(one, e3.getKey());
+
+ Map.Entry e4 = map.floorEntry(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * ceilingEntry returns next entry.
+ */
+ public void testCeilingEntry() {
+ TreeMap map = map5();
+ Map.Entry e1 = map.ceilingEntry(three);
+ assertEquals(three, e1.getKey());
+
+ Map.Entry e2 = map.ceilingEntry(zero);
+ assertEquals(one, e2.getKey());
+
+ Map.Entry e3 = map.ceilingEntry(five);
+ assertEquals(five, e3.getKey());
+
+ Map.Entry e4 = map.ceilingEntry(six);
+ assertNull(e4);
+ }
+
+ /**
+ * lowerKey returns preceding element
+ */
+ public void testLowerKey() {
+ TreeMap q = map5();
+ Object e1 = q.lowerKey(three);
+ assertEquals(two, e1);
+
+ Object e2 = q.lowerKey(six);
+ assertEquals(five, e2);
+
+ Object e3 = q.lowerKey(one);
+ assertNull(e3);
+
+ Object e4 = q.lowerKey(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * higherKey returns next element
+ */
+ public void testHigherKey() {
+ TreeMap q = map5();
+ Object e1 = q.higherKey(three);
+ assertEquals(four, e1);
+
+ Object e2 = q.higherKey(zero);
+ assertEquals(one, e2);
+
+ Object e3 = q.higherKey(five);
+ assertNull(e3);
+
+ Object e4 = q.higherKey(six);
+ assertNull(e4);
+ }
+
+ /**
+ * floorKey returns preceding element
+ */
+ public void testFloorKey() {
+ TreeMap q = map5();
+ Object e1 = q.floorKey(three);
+ assertEquals(three, e1);
+
+ Object e2 = q.floorKey(six);
+ assertEquals(five, e2);
+
+ Object e3 = q.floorKey(one);
+ assertEquals(one, e3);
+
+ Object e4 = q.floorKey(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * ceilingKey returns next element
+ */
+ public void testCeilingKey() {
+ TreeMap q = map5();
+ Object e1 = q.ceilingKey(three);
+ assertEquals(three, e1);
+
+ Object e2 = q.ceilingKey(zero);
+ assertEquals(one, e2);
+
+ Object e3 = q.ceilingKey(five);
+ assertEquals(five, e3);
+
+ Object e4 = q.ceilingKey(six);
+ assertNull(e4);
+ }
+
+ /**
+ * pollFirstEntry returns entries in order
+ */
+ public void testPollFirstEntry() {
+ TreeMap map = map5();
+ Map.Entry e = map.pollFirstEntry();
+ assertEquals(one, e.getKey());
+ assertEquals("A", e.getValue());
+ e = map.pollFirstEntry();
+ assertEquals(two, e.getKey());
+ map.put(one, "A");
+ e = map.pollFirstEntry();
+ assertEquals(one, e.getKey());
+ assertEquals("A", e.getValue());
+ e = map.pollFirstEntry();
+ assertEquals(three, e.getKey());
+ map.remove(four);
+ e = map.pollFirstEntry();
+ assertEquals(five, e.getKey());
+ try {
+ e.setValue("A");
+ shouldThrow();
+ } catch (UnsupportedOperationException success) {}
+ e = map.pollFirstEntry();
+ assertNull(e);
+ }
+
+ /**
+ * pollLastEntry returns entries in order
+ */
+ public void testPollLastEntry() {
+ TreeMap map = map5();
+ Map.Entry e = map.pollLastEntry();
+ assertEquals(five, e.getKey());
+ assertEquals("E", e.getValue());
+ e = map.pollLastEntry();
+ assertEquals(four, e.getKey());
+ map.put(five, "E");
+ e = map.pollLastEntry();
+ assertEquals(five, e.getKey());
+ assertEquals("E", e.getValue());
+ e = map.pollLastEntry();
+ assertEquals(three, e.getKey());
+ map.remove(two);
+ e = map.pollLastEntry();
+ assertEquals(one, e.getKey());
+ try {
+ e.setValue("E");
+ shouldThrow();
+ } catch (UnsupportedOperationException success) {}
+ e = map.pollLastEntry();
+ assertNull(e);
+ }
+
+ /**
+ * size returns the correct values
+ */
+ public void testSize() {
+ TreeMap map = map5();
+ TreeMap empty = new TreeMap();
+ assertEquals(0, empty.size());
+ assertEquals(5, map.size());
+ }
+
+ /**
+ * toString contains toString of elements
+ */
+ public void testToString() {
+ TreeMap map = map5();
+ String s = map.toString();
+ for (int i = 1; i <= 5; ++i) {
+ assertTrue(s.contains(String.valueOf(i)));
+ }
+ }
+
+ // Exception tests
+
+ /**
+ * get(null) of nonempty map throws NPE
+ */
+ public void testGet_NullPointerException() {
+ try {
+ TreeMap c = map5();
+ c.get(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * containsKey(null) of nonempty map throws NPE
+ */
+ public void testContainsKey_NullPointerException() {
+ try {
+ TreeMap c = map5();
+ c.containsKey(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * remove(null) throws NPE for nonempty map
+ */
+ public void testRemove1_NullPointerException() {
+ try {
+ TreeMap c = new TreeMap();
+ c.put("sadsdf", "asdads");
+ c.remove(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * A deserialized map equals original
+ */
+ public void testSerialization() throws Exception {
+ NavigableMap x = map5();
+ NavigableMap y = serialClone(x);
+
+ assertNotSame(x, y);
+ assertEquals(x.size(), y.size());
+ assertEquals(x.toString(), y.toString());
+ assertEquals(x, y);
+ assertEquals(y, x);
+ }
+
+ /**
+ * subMap returns map with keys in requested range
+ */
+ public void testSubMapContents() {
+ TreeMap map = map5();
+ NavigableMap sm = map.subMap(two, true, four, false);
+ assertEquals(two, sm.firstKey());
+ assertEquals(three, sm.lastKey());
+ assertEquals(2, sm.size());
+ assertFalse(sm.containsKey(one));
+ assertTrue(sm.containsKey(two));
+ assertTrue(sm.containsKey(three));
+ assertFalse(sm.containsKey(four));
+ assertFalse(sm.containsKey(five));
+ Iterator i = sm.keySet().iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ k = (Integer)(i.next());
+ assertEquals(three, k);
+ assertFalse(i.hasNext());
+ Iterator r = sm.descendingKeySet().iterator();
+ k = (Integer)(r.next());
+ assertEquals(three, k);
+ k = (Integer)(r.next());
+ assertEquals(two, k);
+ assertFalse(r.hasNext());
+
+ Iterator j = sm.keySet().iterator();
+ j.next();
+ j.remove();
+ assertFalse(map.containsKey(two));
+ assertEquals(4, map.size());
+ assertEquals(1, sm.size());
+ assertEquals(three, sm.firstKey());
+ assertEquals(three, sm.lastKey());
+ assertEquals("C", sm.remove(three));
+ assertTrue(sm.isEmpty());
+ assertEquals(3, map.size());
+ }
+
+ public void testSubMapContents2() {
+ TreeMap map = map5();
+ NavigableMap sm = map.subMap(two, true, three, false);
+ assertEquals(1, sm.size());
+ assertEquals(two, sm.firstKey());
+ assertEquals(two, sm.lastKey());
+ assertFalse(sm.containsKey(one));
+ assertTrue(sm.containsKey(two));
+ assertFalse(sm.containsKey(three));
+ assertFalse(sm.containsKey(four));
+ assertFalse(sm.containsKey(five));
+ Iterator i = sm.keySet().iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ assertFalse(i.hasNext());
+ Iterator r = sm.descendingKeySet().iterator();
+ k = (Integer)(r.next());
+ assertEquals(two, k);
+ assertFalse(r.hasNext());
+
+ Iterator j = sm.keySet().iterator();
+ j.next();
+ j.remove();
+ assertFalse(map.containsKey(two));
+ assertEquals(4, map.size());
+ assertEquals(0, sm.size());
+ assertTrue(sm.isEmpty());
+ assertSame(sm.remove(three), null);
+ assertEquals(4, map.size());
+ }
+
+ /**
+ * headMap returns map with keys in requested range
+ */
+ public void testHeadMapContents() {
+ TreeMap map = map5();
+ NavigableMap sm = map.headMap(four, false);
+ assertTrue(sm.containsKey(one));
+ assertTrue(sm.containsKey(two));
+ assertTrue(sm.containsKey(three));
+ assertFalse(sm.containsKey(four));
+ assertFalse(sm.containsKey(five));
+ Iterator i = sm.keySet().iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(one, k);
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ k = (Integer)(i.next());
+ assertEquals(three, k);
+ assertFalse(i.hasNext());
+ sm.clear();
+ assertTrue(sm.isEmpty());
+ assertEquals(2, map.size());
+ assertEquals(four, map.firstKey());
+ }
+
+ /**
+ * headMap returns map with keys in requested range
+ */
+ public void testTailMapContents() {
+ TreeMap map = map5();
+ NavigableMap sm = map.tailMap(two, true);
+ assertFalse(sm.containsKey(one));
+ assertTrue(sm.containsKey(two));
+ assertTrue(sm.containsKey(three));
+ assertTrue(sm.containsKey(four));
+ assertTrue(sm.containsKey(five));
+ Iterator i = sm.keySet().iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ k = (Integer)(i.next());
+ assertEquals(three, k);
+ k = (Integer)(i.next());
+ assertEquals(four, k);
+ k = (Integer)(i.next());
+ assertEquals(five, k);
+ assertFalse(i.hasNext());
+ Iterator r = sm.descendingKeySet().iterator();
+ k = (Integer)(r.next());
+ assertEquals(five, k);
+ k = (Integer)(r.next());
+ assertEquals(four, k);
+ k = (Integer)(r.next());
+ assertEquals(three, k);
+ k = (Integer)(r.next());
+ assertEquals(two, k);
+ assertFalse(r.hasNext());
+
+ Iterator ei = sm.entrySet().iterator();
+ Map.Entry e;
+ e = (Map.Entry)(ei.next());
+ assertEquals(two, e.getKey());
+ assertEquals("B", e.getValue());
+ e = (Map.Entry)(ei.next());
+ assertEquals(three, e.getKey());
+ assertEquals("C", e.getValue());
+ e = (Map.Entry)(ei.next());
+ assertEquals(four, e.getKey());
+ assertEquals("D", e.getValue());
+ e = (Map.Entry)(ei.next());
+ assertEquals(five, e.getKey());
+ assertEquals("E", e.getValue());
+ assertFalse(i.hasNext());
+
+ NavigableMap ssm = sm.tailMap(four, true);
+ assertEquals(four, ssm.firstKey());
+ assertEquals(five, ssm.lastKey());
+ assertEquals("D", ssm.remove(four));
+ assertEquals(1, ssm.size());
+ assertEquals(3, sm.size());
+ assertEquals(4, map.size());
+ }
+
+ Random rnd = new Random(666);
+ BitSet bs;
+
+ /**
+ * Submaps of submaps subdivide correctly
+ */
+ public void testRecursiveSubMaps() throws Exception {
+ int mapSize = expensiveTests ? 1000 : 100;
+ Class cl = TreeMap.class;
+ NavigableMap<Integer, Integer> map = newMap(cl);
+ bs = new BitSet(mapSize);
+
+ populate(map, mapSize);
+ check(map, 0, mapSize - 1, true);
+ check(map.descendingMap(), 0, mapSize - 1, false);
+
+ mutateMap(map, 0, mapSize - 1);
+ check(map, 0, mapSize - 1, true);
+ check(map.descendingMap(), 0, mapSize - 1, false);
+
+ bashSubMap(map.subMap(0, true, mapSize, false),
+ 0, mapSize - 1, true);
+ }
+
+ static NavigableMap<Integer, Integer> newMap(Class cl) throws Exception {
+ NavigableMap<Integer, Integer> result
+ = (NavigableMap<Integer, Integer>) cl.newInstance();
+ assertEquals(0, result.size());
+ assertFalse(result.keySet().iterator().hasNext());
+ return result;
+ }
+
+ void populate(NavigableMap<Integer, Integer> map, int limit) {
+ for (int i = 0, n = 2 * limit / 3; i < n; i++) {
+ int key = rnd.nextInt(limit);
+ put(map, key);
+ }
+ }
+
+ void mutateMap(NavigableMap<Integer, Integer> map, int min, int max) {
+ int size = map.size();
+ int rangeSize = max - min + 1;
+
+ // Remove a bunch of entries directly
+ for (int i = 0, n = rangeSize / 2; i < n; i++) {
+ remove(map, min - 5 + rnd.nextInt(rangeSize + 10));
+ }
+
+ // Remove a bunch of entries with iterator
+ for (Iterator<Integer> it = map.keySet().iterator(); it.hasNext(); ) {
+ if (rnd.nextBoolean()) {
+ bs.clear(it.next());
+ it.remove();
+ }
+ }
+
+ // Add entries till we're back to original size
+ while (map.size() < size) {
+ int key = min + rnd.nextInt(rangeSize);
+ assertTrue(key >= min && key<= max);
+ put(map, key);
+ }
+ }
+
+ void mutateSubMap(NavigableMap<Integer, Integer> map, int min, int max) {
+ int size = map.size();
+ int rangeSize = max - min + 1;
+
+ // Remove a bunch of entries directly
+ for (int i = 0, n = rangeSize / 2; i < n; i++) {
+ remove(map, min - 5 + rnd.nextInt(rangeSize + 10));
+ }
+
+ // Remove a bunch of entries with iterator
+ for (Iterator<Integer> it = map.keySet().iterator(); it.hasNext(); ) {
+ if (rnd.nextBoolean()) {
+ bs.clear(it.next());
+ it.remove();
+ }
+ }
+
+ // Add entries till we're back to original size
+ while (map.size() < size) {
+ int key = min - 5 + rnd.nextInt(rangeSize + 10);
+ if (key >= min && key<= max) {
+ put(map, key);
+ } else {
+ try {
+ map.put(key, 2 * key);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+ }
+ }
+
+ void put(NavigableMap<Integer, Integer> map, int key) {
+ if (map.put(key, 2 * key) == null)
+ bs.set(key);
+ }
+
+ void remove(NavigableMap<Integer, Integer> map, int key) {
+ if (map.remove(key) != null)
+ bs.clear(key);
+ }
+
+ void bashSubMap(NavigableMap<Integer, Integer> map,
+ int min, int max, boolean ascending) {
+ check(map, min, max, ascending);
+ check(map.descendingMap(), min, max, !ascending);
+
+ mutateSubMap(map, min, max);
+ check(map, min, max, ascending);
+ check(map.descendingMap(), min, max, !ascending);
+
+ // Recurse
+ if (max - min < 2)
+ return;
+ int midPoint = (min + max) / 2;
+
+ // headMap - pick direction and endpoint inclusion randomly
+ boolean incl = rnd.nextBoolean();
+ NavigableMap<Integer,Integer> hm = map.headMap(midPoint, incl);
+ if (ascending) {
+ if (rnd.nextBoolean())
+ bashSubMap(hm, min, midPoint - (incl ? 0 : 1), true);
+ else
+ bashSubMap(hm.descendingMap(), min, midPoint - (incl ? 0 : 1),
+ false);
+ } else {
+ if (rnd.nextBoolean())
+ bashSubMap(hm, midPoint + (incl ? 0 : 1), max, false);
+ else
+ bashSubMap(hm.descendingMap(), midPoint + (incl ? 0 : 1), max,
+ true);
+ }
+
+ // tailMap - pick direction and endpoint inclusion randomly
+ incl = rnd.nextBoolean();
+ NavigableMap<Integer,Integer> tm = map.tailMap(midPoint,incl);
+ if (ascending) {
+ if (rnd.nextBoolean())
+ bashSubMap(tm, midPoint + (incl ? 0 : 1), max, true);
+ else
+ bashSubMap(tm.descendingMap(), midPoint + (incl ? 0 : 1), max,
+ false);
+ } else {
+ if (rnd.nextBoolean()) {
+ bashSubMap(tm, min, midPoint - (incl ? 0 : 1), false);
+ } else {
+ bashSubMap(tm.descendingMap(), min, midPoint - (incl ? 0 : 1),
+ true);
+ }
+ }
+
+ // subMap - pick direction and endpoint inclusion randomly
+ int rangeSize = max - min + 1;
+ int[] endpoints = new int[2];
+ endpoints[0] = min + rnd.nextInt(rangeSize);
+ endpoints[1] = min + rnd.nextInt(rangeSize);
+ Arrays.sort(endpoints);
+ boolean lowIncl = rnd.nextBoolean();
+ boolean highIncl = rnd.nextBoolean();
+ if (ascending) {
+ NavigableMap<Integer,Integer> sm = map.subMap(
+ endpoints[0], lowIncl, endpoints[1], highIncl);
+ if (rnd.nextBoolean())
+ bashSubMap(sm, endpoints[0] + (lowIncl ? 0 : 1),
+ endpoints[1] - (highIncl ? 0 : 1), true);
+ else
+ bashSubMap(sm.descendingMap(), endpoints[0] + (lowIncl ? 0 : 1),
+ endpoints[1] - (highIncl ? 0 : 1), false);
+ } else {
+ NavigableMap<Integer,Integer> sm = map.subMap(
+ endpoints[1], highIncl, endpoints[0], lowIncl);
+ if (rnd.nextBoolean())
+ bashSubMap(sm, endpoints[0] + (lowIncl ? 0 : 1),
+ endpoints[1] - (highIncl ? 0 : 1), false);
+ else
+ bashSubMap(sm.descendingMap(), endpoints[0] + (lowIncl ? 0 : 1),
+ endpoints[1] - (highIncl ? 0 : 1), true);
+ }
+ }
+
+ /**
+ * min and max are both inclusive. If max < min, interval is empty.
+ */
+ void check(NavigableMap<Integer, Integer> map,
+ final int min, final int max, final boolean ascending) {
+ class ReferenceSet {
+ int lower(int key) {
+ return ascending ? lowerAscending(key) : higherAscending(key);
+ }
+ int floor(int key) {
+ return ascending ? floorAscending(key) : ceilingAscending(key);
+ }
+ int ceiling(int key) {
+ return ascending ? ceilingAscending(key) : floorAscending(key);
+ }
+ int higher(int key) {
+ return ascending ? higherAscending(key) : lowerAscending(key);
+ }
+ int first() {
+ return ascending ? firstAscending() : lastAscending();
+ }
+ int last() {
+ return ascending ? lastAscending() : firstAscending();
+ }
+ int lowerAscending(int key) {
+ return floorAscending(key - 1);
+ }
+ int floorAscending(int key) {
+ if (key < min)
+ return -1;
+ else if (key > max)
+ key = max;
+
+ // BitSet should support this! Test would run much faster
+ while (key >= min) {
+ if (bs.get(key))
+ return key;
+ key--;
+ }
+ return -1;
+ }
+ int ceilingAscending(int key) {
+ if (key < min)
+ key = min;
+ else if (key > max)
+ return -1;
+ int result = bs.nextSetBit(key);
+ return result > max ? -1 : result;
+ }
+ int higherAscending(int key) {
+ return ceilingAscending(key + 1);
+ }
+ private int firstAscending() {
+ int result = ceilingAscending(min);
+ return result > max ? -1 : result;
+ }
+ private int lastAscending() {
+ int result = floorAscending(max);
+ return result < min ? -1 : result;
+ }
+ }
+ ReferenceSet rs = new ReferenceSet();
+
+ // Test contents using containsKey
+ int size = 0;
+ for (int i = min; i <= max; i++) {
+ boolean bsContainsI = bs.get(i);
+ assertEquals(bsContainsI, map.containsKey(i));
+ if (bsContainsI)
+ size++;
+ }
+ assertEquals(size, map.size());
+
+ // Test contents using contains keySet iterator
+ int size2 = 0;
+ int previousKey = -1;
+ for (int key : map.keySet()) {
+ assertTrue(bs.get(key));
+ size2++;
+ assertTrue(previousKey < 0 ||
+ (ascending ? key - previousKey > 0 : key - previousKey < 0));
+ previousKey = key;
+ }
+ assertEquals(size2, size);
+
+ // Test navigation ops
+ for (int key = min - 1; key <= max + 1; key++) {
+ assertEq(map.lowerKey(key), rs.lower(key));
+ assertEq(map.floorKey(key), rs.floor(key));
+ assertEq(map.higherKey(key), rs.higher(key));
+ assertEq(map.ceilingKey(key), rs.ceiling(key));
+ }
+
+ // Test extrema
+ if (map.size() != 0) {
+ assertEq(map.firstKey(), rs.first());
+ assertEq(map.lastKey(), rs.last());
+ } else {
+ assertEq(rs.first(), -1);
+ assertEq(rs.last(), -1);
+ try {
+ map.firstKey();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ try {
+ map.lastKey();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+ }
+
+ static void assertEq(Integer i, int j) {
+ if (i == null)
+ assertEquals(j, -1);
+ else
+ assertEquals((int) i, j);
+ }
+
+ static boolean eq(Integer i, int j) {
+ return i == null ? j == -1 : i == j;
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/TreeSetTest.java b/jsr166-tests/src/test/java/jsr166/TreeSetTest.java
new file mode 100644
index 0000000..2957019
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/TreeSetTest.java
@@ -0,0 +1,985 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.NavigableSet;
+import java.util.NoSuchElementException;
+import java.util.Random;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+public class TreeSetTest extends JSR166TestCase {
+
+ static class MyReverseComparator implements Comparator {
+ public int compare(Object x, Object y) {
+ return ((Comparable)y).compareTo(x);
+ }
+ }
+
+ /**
+ * The number of elements to place in collections, arrays, etc.
+ */
+ static final int SIZE = 20;
+
+ /**
+ * Returns a new set of given size containing consecutive
+ * Integers 0 ... n.
+ */
+ private TreeSet<Integer> populatedSet(int n) {
+ TreeSet<Integer> q = new TreeSet<Integer>();
+ assertTrue(q.isEmpty());
+ for (int i = n-1; i >= 0; i-=2)
+ assertTrue(q.add(new Integer(i)));
+ for (int i = (n & 1); i < n; i+=2)
+ assertTrue(q.add(new Integer(i)));
+ assertFalse(q.isEmpty());
+ assertEquals(n, q.size());
+ return q;
+ }
+
+ /**
+ * Returns a new set of first 5 ints.
+ */
+ private TreeSet set5() {
+ TreeSet q = new TreeSet();
+ assertTrue(q.isEmpty());
+ q.add(one);
+ q.add(two);
+ q.add(three);
+ q.add(four);
+ q.add(five);
+ assertEquals(5, q.size());
+ return q;
+ }
+
+ /**
+ * A new set has unbounded capacity
+ */
+ public void testConstructor1() {
+ assertEquals(0, new TreeSet().size());
+ }
+
+ /**
+ * Initializing from null Collection throws NPE
+ */
+ public void testConstructor3() {
+ try {
+ TreeSet q = new TreeSet((Collection)null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing from Collection of null elements throws NPE
+ */
+ public void testConstructor4() {
+ try {
+ Integer[] ints = new Integer[SIZE];
+ TreeSet q = new TreeSet(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Initializing from Collection with some null elements throws NPE
+ */
+ public void testConstructor5() {
+ try {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
+ TreeSet q = new TreeSet(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Set contains all elements of collection used to initialize
+ */
+ public void testConstructor6() {
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(i);
+ TreeSet q = new TreeSet(Arrays.asList(ints));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(ints[i], q.pollFirst());
+ }
+
+ /**
+ * The comparator used in constructor is used
+ */
+ public void testConstructor7() {
+ MyReverseComparator cmp = new MyReverseComparator();
+ TreeSet q = new TreeSet(cmp);
+ assertEquals(cmp, q.comparator());
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(i);
+ q.addAll(Arrays.asList(ints));
+ for (int i = SIZE-1; i >= 0; --i)
+ assertEquals(ints[i], q.pollFirst());
+ }
+
+ /**
+ * isEmpty is true before add, false after
+ */
+ public void testEmpty() {
+ TreeSet q = new TreeSet();
+ assertTrue(q.isEmpty());
+ q.add(new Integer(1));
+ assertFalse(q.isEmpty());
+ q.add(new Integer(2));
+ q.pollFirst();
+ q.pollFirst();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * size changes when elements added and removed
+ */
+ public void testSize() {
+ TreeSet q = populatedSet(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(SIZE-i, q.size());
+ q.pollFirst();
+ }
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.size());
+ q.add(new Integer(i));
+ }
+ }
+
+ /**
+ * add(null) throws NPE if nonempty
+ */
+ public void testAddNull() {
+ try {
+ TreeSet q = populatedSet(SIZE);
+ q.add(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Add of comparable element succeeds
+ */
+ public void testAdd() {
+ TreeSet q = new TreeSet();
+ assertTrue(q.add(zero));
+ assertTrue(q.add(one));
+ }
+
+ /**
+ * Add of duplicate element fails
+ */
+ public void testAddDup() {
+ TreeSet q = new TreeSet();
+ assertTrue(q.add(zero));
+ assertFalse(q.add(zero));
+ }
+
+ /**
+ * Add of non-Comparable throws CCE
+ */
+ public void testAddNonComparable() {
+ try {
+ TreeSet q = new TreeSet();
+ q.add(new Object());
+ q.add(new Object());
+ q.add(new Object());
+ shouldThrow();
+ } catch (ClassCastException success) {}
+ }
+
+ /**
+ * addAll(null) throws NPE
+ */
+ public void testAddAll1() {
+ try {
+ TreeSet q = new TreeSet();
+ q.addAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll of a collection with null elements throws NPE
+ */
+ public void testAddAll2() {
+ try {
+ TreeSet q = new TreeSet();
+ Integer[] ints = new Integer[SIZE];
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll of a collection with any null elements throws NPE after
+ * possibly adding some elements
+ */
+ public void testAddAll3() {
+ try {
+ TreeSet q = new TreeSet();
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i);
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Set contains all elements of successful addAll
+ */
+ public void testAddAll5() {
+ Integer[] empty = new Integer[0];
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(SIZE-1-i);
+ TreeSet q = new TreeSet();
+ assertFalse(q.addAll(Arrays.asList(empty)));
+ assertTrue(q.addAll(Arrays.asList(ints)));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(new Integer(i), q.pollFirst());
+ }
+
+ /**
+ * pollFirst succeeds unless empty
+ */
+ public void testPollFirst() {
+ TreeSet q = populatedSet(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.pollFirst());
+ }
+ assertNull(q.pollFirst());
+ }
+
+ /**
+ * pollLast succeeds unless empty
+ */
+ public void testPollLast() {
+ TreeSet q = populatedSet(SIZE);
+ for (int i = SIZE-1; i >= 0; --i) {
+ assertEquals(i, q.pollLast());
+ }
+ assertNull(q.pollFirst());
+ }
+
+ /**
+ * remove(x) removes x and returns true if present
+ */
+ public void testRemoveElement() {
+ TreeSet q = populatedSet(SIZE);
+ for (int i = 1; i < SIZE; i+=2) {
+ assertTrue(q.contains(i));
+ assertTrue(q.remove(i));
+ assertFalse(q.contains(i));
+ assertTrue(q.contains(i-1));
+ }
+ for (int i = 0; i < SIZE; i+=2) {
+ assertTrue(q.contains(i));
+ assertTrue(q.remove(i));
+ assertFalse(q.contains(i));
+ assertFalse(q.remove(i+1));
+ assertFalse(q.contains(i+1));
+ }
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * contains(x) reports true when elements added but not yet removed
+ */
+ public void testContains() {
+ TreeSet q = populatedSet(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.contains(new Integer(i)));
+ q.pollFirst();
+ assertFalse(q.contains(new Integer(i)));
+ }
+ }
+
+ /**
+ * clear removes all elements
+ */
+ public void testClear() {
+ TreeSet q = populatedSet(SIZE);
+ q.clear();
+ assertTrue(q.isEmpty());
+ assertEquals(0, q.size());
+ q.add(new Integer(1));
+ assertFalse(q.isEmpty());
+ q.clear();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * containsAll(c) is true when c contains a subset of elements
+ */
+ public void testContainsAll() {
+ TreeSet q = populatedSet(SIZE);
+ TreeSet p = new TreeSet();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.containsAll(p));
+ assertFalse(p.containsAll(q));
+ p.add(new Integer(i));
+ }
+ assertTrue(p.containsAll(q));
+ }
+
+ /**
+ * retainAll(c) retains only those elements of c and reports true if changed
+ */
+ public void testRetainAll() {
+ TreeSet q = populatedSet(SIZE);
+ TreeSet p = populatedSet(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ boolean changed = q.retainAll(p);
+ if (i == 0)
+ assertFalse(changed);
+ else
+ assertTrue(changed);
+
+ assertTrue(q.containsAll(p));
+ assertEquals(SIZE-i, q.size());
+ p.pollFirst();
+ }
+ }
+
+ /**
+ * removeAll(c) removes only those elements of c and reports true if changed
+ */
+ public void testRemoveAll() {
+ for (int i = 1; i < SIZE; ++i) {
+ TreeSet q = populatedSet(SIZE);
+ TreeSet p = populatedSet(i);
+ assertTrue(q.removeAll(p));
+ assertEquals(SIZE-i, q.size());
+ for (int j = 0; j < i; ++j) {
+ Integer I = (Integer)(p.pollFirst());
+ assertFalse(q.contains(I));
+ }
+ }
+ }
+
+ /**
+ * lower returns preceding element
+ */
+ public void testLower() {
+ TreeSet q = set5();
+ Object e1 = q.lower(three);
+ assertEquals(two, e1);
+
+ Object e2 = q.lower(six);
+ assertEquals(five, e2);
+
+ Object e3 = q.lower(one);
+ assertNull(e3);
+
+ Object e4 = q.lower(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * higher returns next element
+ */
+ public void testHigher() {
+ TreeSet q = set5();
+ Object e1 = q.higher(three);
+ assertEquals(four, e1);
+
+ Object e2 = q.higher(zero);
+ assertEquals(one, e2);
+
+ Object e3 = q.higher(five);
+ assertNull(e3);
+
+ Object e4 = q.higher(six);
+ assertNull(e4);
+ }
+
+ /**
+ * floor returns preceding element
+ */
+ public void testFloor() {
+ TreeSet q = set5();
+ Object e1 = q.floor(three);
+ assertEquals(three, e1);
+
+ Object e2 = q.floor(six);
+ assertEquals(five, e2);
+
+ Object e3 = q.floor(one);
+ assertEquals(one, e3);
+
+ Object e4 = q.floor(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * ceiling returns next element
+ */
+ public void testCeiling() {
+ TreeSet q = set5();
+ Object e1 = q.ceiling(three);
+ assertEquals(three, e1);
+
+ Object e2 = q.ceiling(zero);
+ assertEquals(one, e2);
+
+ Object e3 = q.ceiling(five);
+ assertEquals(five, e3);
+
+ Object e4 = q.ceiling(six);
+ assertNull(e4);
+ }
+
+ /**
+ * toArray contains all elements in sorted order
+ */
+ public void testToArray() {
+ TreeSet q = populatedSet(SIZE);
+ Object[] o = q.toArray();
+ for (int i = 0; i < o.length; i++)
+ assertSame(o[i], q.pollFirst());
+ }
+
+ /**
+ * toArray(a) contains all elements in sorted order
+ */
+ public void testToArray2() {
+ TreeSet<Integer> q = populatedSet(SIZE);
+ Integer[] ints = new Integer[SIZE];
+ Integer[] array = q.toArray(ints);
+ assertSame(ints, array);
+ for (int i = 0; i < ints.length; i++)
+ assertSame(ints[i], q.pollFirst());
+ }
+
+ /**
+ * iterator iterates through all elements
+ */
+ public void testIterator() {
+ TreeSet q = populatedSet(SIZE);
+ int i = 0;
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ assertTrue(q.contains(it.next()));
+ ++i;
+ }
+ assertEquals(i, SIZE);
+ }
+
+ /**
+ * iterator of empty set has no elements
+ */
+ public void testEmptyIterator() {
+ TreeSet q = new TreeSet();
+ int i = 0;
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ assertTrue(q.contains(it.next()));
+ ++i;
+ }
+ assertEquals(0, i);
+ }
+
+ /**
+ * iterator.remove removes current element
+ */
+ public void testIteratorRemove() {
+ final TreeSet q = new TreeSet();
+ q.add(new Integer(2));
+ q.add(new Integer(1));
+ q.add(new Integer(3));
+
+ Iterator it = q.iterator();
+ it.next();
+ it.remove();
+
+ it = q.iterator();
+ assertEquals(it.next(), new Integer(2));
+ assertEquals(it.next(), new Integer(3));
+ assertFalse(it.hasNext());
+ }
+
+ /**
+ * toString contains toStrings of elements
+ */
+ public void testToString() {
+ TreeSet q = populatedSet(SIZE);
+ String s = q.toString();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(s.contains(String.valueOf(i)));
+ }
+ }
+
+ /**
+ * A deserialized serialized set has same elements
+ */
+ public void testSerialization() throws Exception {
+ NavigableSet x = populatedSet(SIZE);
+ NavigableSet y = serialClone(x);
+
+ assertNotSame(x, y);
+ assertEquals(x.size(), y.size());
+ assertEquals(x, y);
+ assertEquals(y, x);
+ while (!x.isEmpty()) {
+ assertFalse(y.isEmpty());
+ assertEquals(x.pollFirst(), y.pollFirst());
+ }
+ assertTrue(y.isEmpty());
+ }
+
+ /**
+ * subSet returns set with keys in requested range
+ */
+ public void testSubSetContents() {
+ TreeSet set = set5();
+ SortedSet sm = set.subSet(two, four);
+ assertEquals(two, sm.first());
+ assertEquals(three, sm.last());
+ assertEquals(2, sm.size());
+ assertFalse(sm.contains(one));
+ assertTrue(sm.contains(two));
+ assertTrue(sm.contains(three));
+ assertFalse(sm.contains(four));
+ assertFalse(sm.contains(five));
+ Iterator i = sm.iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ k = (Integer)(i.next());
+ assertEquals(three, k);
+ assertFalse(i.hasNext());
+ Iterator j = sm.iterator();
+ j.next();
+ j.remove();
+ assertFalse(set.contains(two));
+ assertEquals(4, set.size());
+ assertEquals(1, sm.size());
+ assertEquals(three, sm.first());
+ assertEquals(three, sm.last());
+ assertTrue(sm.remove(three));
+ assertTrue(sm.isEmpty());
+ assertEquals(3, set.size());
+ }
+
+ public void testSubSetContents2() {
+ TreeSet set = set5();
+ SortedSet sm = set.subSet(two, three);
+ assertEquals(1, sm.size());
+ assertEquals(two, sm.first());
+ assertEquals(two, sm.last());
+ assertFalse(sm.contains(one));
+ assertTrue(sm.contains(two));
+ assertFalse(sm.contains(three));
+ assertFalse(sm.contains(four));
+ assertFalse(sm.contains(five));
+ Iterator i = sm.iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ assertFalse(i.hasNext());
+ Iterator j = sm.iterator();
+ j.next();
+ j.remove();
+ assertFalse(set.contains(two));
+ assertEquals(4, set.size());
+ assertEquals(0, sm.size());
+ assertTrue(sm.isEmpty());
+ assertFalse(sm.remove(three));
+ assertEquals(4, set.size());
+ }
+
+ /**
+ * headSet returns set with keys in requested range
+ */
+ public void testHeadSetContents() {
+ TreeSet set = set5();
+ SortedSet sm = set.headSet(four);
+ assertTrue(sm.contains(one));
+ assertTrue(sm.contains(two));
+ assertTrue(sm.contains(three));
+ assertFalse(sm.contains(four));
+ assertFalse(sm.contains(five));
+ Iterator i = sm.iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(one, k);
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ k = (Integer)(i.next());
+ assertEquals(three, k);
+ assertFalse(i.hasNext());
+ sm.clear();
+ assertTrue(sm.isEmpty());
+ assertEquals(2, set.size());
+ assertEquals(four, set.first());
+ }
+
+ /**
+ * tailSet returns set with keys in requested range
+ */
+ public void testTailSetContents() {
+ TreeSet set = set5();
+ SortedSet sm = set.tailSet(two);
+ assertFalse(sm.contains(one));
+ assertTrue(sm.contains(two));
+ assertTrue(sm.contains(three));
+ assertTrue(sm.contains(four));
+ assertTrue(sm.contains(five));
+ Iterator i = sm.iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ k = (Integer)(i.next());
+ assertEquals(three, k);
+ k = (Integer)(i.next());
+ assertEquals(four, k);
+ k = (Integer)(i.next());
+ assertEquals(five, k);
+ assertFalse(i.hasNext());
+
+ SortedSet ssm = sm.tailSet(four);
+ assertEquals(four, ssm.first());
+ assertEquals(five, ssm.last());
+ assertTrue(ssm.remove(four));
+ assertEquals(1, ssm.size());
+ assertEquals(3, sm.size());
+ assertEquals(4, set.size());
+ }
+
+ Random rnd = new Random(666);
+ BitSet bs;
+
+ /**
+ * Subsets of subsets subdivide correctly
+ */
+ public void testRecursiveSubSets() throws Exception {
+ int setSize = expensiveTests ? 1000 : 100;
+ Class cl = TreeSet.class;
+
+ NavigableSet<Integer> set = newSet(cl);
+ bs = new BitSet(setSize);
+
+ populate(set, setSize);
+ check(set, 0, setSize - 1, true);
+ check(set.descendingSet(), 0, setSize - 1, false);
+
+ mutateSet(set, 0, setSize - 1);
+ check(set, 0, setSize - 1, true);
+ check(set.descendingSet(), 0, setSize - 1, false);
+
+ bashSubSet(set.subSet(0, true, setSize, false),
+ 0, setSize - 1, true);
+ }
+
+ /**
+ * addAll is idempotent
+ */
+ public void testAddAll_idempotent() throws Exception {
+ Set x = populatedSet(SIZE);
+ Set y = new TreeSet(x);
+ y.addAll(x);
+ assertEquals(x, y);
+ assertEquals(y, x);
+ }
+
+ static NavigableSet<Integer> newSet(Class cl) throws Exception {
+ NavigableSet<Integer> result = (NavigableSet<Integer>) cl.newInstance();
+ assertEquals(0, result.size());
+ assertFalse(result.iterator().hasNext());
+ return result;
+ }
+
+ void populate(NavigableSet<Integer> set, int limit) {
+ for (int i = 0, n = 2 * limit / 3; i < n; i++) {
+ int element = rnd.nextInt(limit);
+ put(set, element);
+ }
+ }
+
+ void mutateSet(NavigableSet<Integer> set, int min, int max) {
+ int size = set.size();
+ int rangeSize = max - min + 1;
+
+ // Remove a bunch of entries directly
+ for (int i = 0, n = rangeSize / 2; i < n; i++) {
+ remove(set, min - 5 + rnd.nextInt(rangeSize + 10));
+ }
+
+ // Remove a bunch of entries with iterator
+ for (Iterator<Integer> it = set.iterator(); it.hasNext(); ) {
+ if (rnd.nextBoolean()) {
+ bs.clear(it.next());
+ it.remove();
+ }
+ }
+
+ // Add entries till we're back to original size
+ while (set.size() < size) {
+ int element = min + rnd.nextInt(rangeSize);
+ assertTrue(element >= min && element<= max);
+ put(set, element);
+ }
+ }
+
+ void mutateSubSet(NavigableSet<Integer> set, int min, int max) {
+ int size = set.size();
+ int rangeSize = max - min + 1;
+
+ // Remove a bunch of entries directly
+ for (int i = 0, n = rangeSize / 2; i < n; i++) {
+ remove(set, min - 5 + rnd.nextInt(rangeSize + 10));
+ }
+
+ // Remove a bunch of entries with iterator
+ for (Iterator<Integer> it = set.iterator(); it.hasNext(); ) {
+ if (rnd.nextBoolean()) {
+ bs.clear(it.next());
+ it.remove();
+ }
+ }
+
+ // Add entries till we're back to original size
+ while (set.size() < size) {
+ int element = min - 5 + rnd.nextInt(rangeSize + 10);
+ if (element >= min && element<= max) {
+ put(set, element);
+ } else {
+ try {
+ set.add(element);
+ shouldThrow();
+ } catch (IllegalArgumentException success) {}
+ }
+ }
+ }
+
+ void put(NavigableSet<Integer> set, int element) {
+ if (set.add(element))
+ bs.set(element);
+ }
+
+ void remove(NavigableSet<Integer> set, int element) {
+ if (set.remove(element))
+ bs.clear(element);
+ }
+
+ void bashSubSet(NavigableSet<Integer> set,
+ int min, int max, boolean ascending) {
+ check(set, min, max, ascending);
+ check(set.descendingSet(), min, max, !ascending);
+
+ mutateSubSet(set, min, max);
+ check(set, min, max, ascending);
+ check(set.descendingSet(), min, max, !ascending);
+
+ // Recurse
+ if (max - min < 2)
+ return;
+ int midPoint = (min + max) / 2;
+
+ // headSet - pick direction and endpoint inclusion randomly
+ boolean incl = rnd.nextBoolean();
+ NavigableSet<Integer> hm = set.headSet(midPoint, incl);
+ if (ascending) {
+ if (rnd.nextBoolean())
+ bashSubSet(hm, min, midPoint - (incl ? 0 : 1), true);
+ else
+ bashSubSet(hm.descendingSet(), min, midPoint - (incl ? 0 : 1),
+ false);
+ } else {
+ if (rnd.nextBoolean())
+ bashSubSet(hm, midPoint + (incl ? 0 : 1), max, false);
+ else
+ bashSubSet(hm.descendingSet(), midPoint + (incl ? 0 : 1), max,
+ true);
+ }
+
+ // tailSet - pick direction and endpoint inclusion randomly
+ incl = rnd.nextBoolean();
+ NavigableSet<Integer> tm = set.tailSet(midPoint,incl);
+ if (ascending) {
+ if (rnd.nextBoolean())
+ bashSubSet(tm, midPoint + (incl ? 0 : 1), max, true);
+ else
+ bashSubSet(tm.descendingSet(), midPoint + (incl ? 0 : 1), max,
+ false);
+ } else {
+ if (rnd.nextBoolean()) {
+ bashSubSet(tm, min, midPoint - (incl ? 0 : 1), false);
+ } else {
+ bashSubSet(tm.descendingSet(), min, midPoint - (incl ? 0 : 1),
+ true);
+ }
+ }
+
+ // subSet - pick direction and endpoint inclusion randomly
+ int rangeSize = max - min + 1;
+ int[] endpoints = new int[2];
+ endpoints[0] = min + rnd.nextInt(rangeSize);
+ endpoints[1] = min + rnd.nextInt(rangeSize);
+ Arrays.sort(endpoints);
+ boolean lowIncl = rnd.nextBoolean();
+ boolean highIncl = rnd.nextBoolean();
+ if (ascending) {
+ NavigableSet<Integer> sm = set.subSet(
+ endpoints[0], lowIncl, endpoints[1], highIncl);
+ if (rnd.nextBoolean())
+ bashSubSet(sm, endpoints[0] + (lowIncl ? 0 : 1),
+ endpoints[1] - (highIncl ? 0 : 1), true);
+ else
+ bashSubSet(sm.descendingSet(), endpoints[0] + (lowIncl ? 0 : 1),
+ endpoints[1] - (highIncl ? 0 : 1), false);
+ } else {
+ NavigableSet<Integer> sm = set.subSet(
+ endpoints[1], highIncl, endpoints[0], lowIncl);
+ if (rnd.nextBoolean())
+ bashSubSet(sm, endpoints[0] + (lowIncl ? 0 : 1),
+ endpoints[1] - (highIncl ? 0 : 1), false);
+ else
+ bashSubSet(sm.descendingSet(), endpoints[0] + (lowIncl ? 0 : 1),
+ endpoints[1] - (highIncl ? 0 : 1), true);
+ }
+ }
+
+ /**
+ * min and max are both inclusive. If max < min, interval is empty.
+ */
+ void check(NavigableSet<Integer> set,
+ final int min, final int max, final boolean ascending) {
+ class ReferenceSet {
+ int lower(int element) {
+ return ascending ?
+ lowerAscending(element) : higherAscending(element);
+ }
+ int floor(int element) {
+ return ascending ?
+ floorAscending(element) : ceilingAscending(element);
+ }
+ int ceiling(int element) {
+ return ascending ?
+ ceilingAscending(element) : floorAscending(element);
+ }
+ int higher(int element) {
+ return ascending ?
+ higherAscending(element) : lowerAscending(element);
+ }
+ int first() {
+ return ascending ? firstAscending() : lastAscending();
+ }
+ int last() {
+ return ascending ? lastAscending() : firstAscending();
+ }
+ int lowerAscending(int element) {
+ return floorAscending(element - 1);
+ }
+ int floorAscending(int element) {
+ if (element < min)
+ return -1;
+ else if (element > max)
+ element = max;
+
+ // BitSet should support this! Test would run much faster
+ while (element >= min) {
+ if (bs.get(element))
+ return element;
+ element--;
+ }
+ return -1;
+ }
+ int ceilingAscending(int element) {
+ if (element < min)
+ element = min;
+ else if (element > max)
+ return -1;
+ int result = bs.nextSetBit(element);
+ return result > max ? -1 : result;
+ }
+ int higherAscending(int element) {
+ return ceilingAscending(element + 1);
+ }
+ private int firstAscending() {
+ int result = ceilingAscending(min);
+ return result > max ? -1 : result;
+ }
+ private int lastAscending() {
+ int result = floorAscending(max);
+ return result < min ? -1 : result;
+ }
+ }
+ ReferenceSet rs = new ReferenceSet();
+
+ // Test contents using containsElement
+ int size = 0;
+ for (int i = min; i <= max; i++) {
+ boolean bsContainsI = bs.get(i);
+ assertEquals(bsContainsI, set.contains(i));
+ if (bsContainsI)
+ size++;
+ }
+ assertEquals(size, set.size());
+
+ // Test contents using contains elementSet iterator
+ int size2 = 0;
+ int previousElement = -1;
+ for (int element : set) {
+ assertTrue(bs.get(element));
+ size2++;
+ assertTrue(previousElement < 0 || (ascending ?
+ element - previousElement > 0 : element - previousElement < 0));
+ previousElement = element;
+ }
+ assertEquals(size2, size);
+
+ // Test navigation ops
+ for (int element = min - 1; element <= max + 1; element++) {
+ assertEq(set.lower(element), rs.lower(element));
+ assertEq(set.floor(element), rs.floor(element));
+ assertEq(set.higher(element), rs.higher(element));
+ assertEq(set.ceiling(element), rs.ceiling(element));
+ }
+
+ // Test extrema
+ if (set.size() != 0) {
+ assertEq(set.first(), rs.first());
+ assertEq(set.last(), rs.last());
+ } else {
+ assertEq(rs.first(), -1);
+ assertEq(rs.last(), -1);
+ try {
+ set.first();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ try {
+ set.last();
+ shouldThrow();
+ } catch (NoSuchElementException success) {}
+ }
+ }
+
+ static void assertEq(Integer i, int j) {
+ if (i == null)
+ assertEquals(j, -1);
+ else
+ assertEquals((int) i, j);
+ }
+
+ static boolean eq(Integer i, int j) {
+ return i == null ? j == -1 : i == j;
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/TreeSubMapTest.java b/jsr166-tests/src/test/java/jsr166/TreeSubMapTest.java
new file mode 100644
index 0000000..17201f3
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/TreeSubMapTest.java
@@ -0,0 +1,1097 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.*;
+
+public class TreeSubMapTest extends JSR166TestCase {
+
+ /**
+ * Returns a new map from Integers 1-5 to Strings "A"-"E".
+ */
+ private static NavigableMap map5() {
+ TreeMap map = new TreeMap();
+ assertTrue(map.isEmpty());
+ map.put(zero, "Z");
+ map.put(one, "A");
+ map.put(five, "E");
+ map.put(three, "C");
+ map.put(two, "B");
+ map.put(four, "D");
+ map.put(seven, "F");
+ assertFalse(map.isEmpty());
+ assertEquals(7, map.size());
+ return map.subMap(one, true, seven, false);
+ }
+
+ private static NavigableMap map0() {
+ TreeMap map = new TreeMap();
+ assertTrue(map.isEmpty());
+ return map.tailMap(one, true);
+ }
+
+ /**
+ * Returns a new map from Integers -5 to -1 to Strings "A"-"E".
+ */
+ private static NavigableMap dmap5() {
+ TreeMap map = new TreeMap();
+ assertTrue(map.isEmpty());
+ map.put(m1, "A");
+ map.put(m5, "E");
+ map.put(m3, "C");
+ map.put(m2, "B");
+ map.put(m4, "D");
+ assertFalse(map.isEmpty());
+ assertEquals(5, map.size());
+ return map.descendingMap();
+ }
+
+ private static NavigableMap dmap0() {
+ TreeMap map = new TreeMap();
+ assertTrue(map.isEmpty());
+ return map;
+ }
+
+ /**
+ * clear removes all pairs
+ */
+ public void testClear() {
+ NavigableMap map = map5();
+ map.clear();
+ assertEquals(0, map.size());
+ }
+
+ /**
+ * Maps with same contents are equal
+ */
+ public void testEquals() {
+ NavigableMap map1 = map5();
+ NavigableMap map2 = map5();
+ assertEquals(map1, map2);
+ assertEquals(map2, map1);
+ map1.clear();
+ assertFalse(map1.equals(map2));
+ assertFalse(map2.equals(map1));
+ }
+
+ /**
+ * containsKey returns true for contained key
+ */
+ public void testContainsKey() {
+ NavigableMap map = map5();
+ assertTrue(map.containsKey(one));
+ assertFalse(map.containsKey(zero));
+ }
+
+ /**
+ * containsValue returns true for held values
+ */
+ public void testContainsValue() {
+ NavigableMap map = map5();
+ assertTrue(map.containsValue("A"));
+ assertFalse(map.containsValue("Z"));
+ }
+
+ /**
+ * get returns the correct element at the given key,
+ * or null if not present
+ */
+ public void testGet() {
+ NavigableMap map = map5();
+ assertEquals("A", (String)map.get(one));
+ NavigableMap empty = map0();
+ assertNull(empty.get(one));
+ }
+
+ /**
+ * isEmpty is true of empty map and false for non-empty
+ */
+ public void testIsEmpty() {
+ NavigableMap empty = map0();
+ NavigableMap map = map5();
+ assertTrue(empty.isEmpty());
+ assertFalse(map.isEmpty());
+ }
+
+ /**
+ * firstKey returns first key
+ */
+ public void testFirstKey() {
+ NavigableMap map = map5();
+ assertEquals(one, map.firstKey());
+ }
+
+ /**
+ * lastKey returns last key
+ */
+ public void testLastKey() {
+ NavigableMap map = map5();
+ assertEquals(five, map.lastKey());
+ }
+
+ /**
+ * keySet returns a Set containing all the keys
+ */
+ public void testKeySet() {
+ NavigableMap map = map5();
+ Set s = map.keySet();
+ assertEquals(5, s.size());
+ assertTrue(s.contains(one));
+ assertTrue(s.contains(two));
+ assertTrue(s.contains(three));
+ assertTrue(s.contains(four));
+ assertTrue(s.contains(five));
+ }
+
+ /**
+ * keySet is ordered
+ */
+ public void testKeySetOrder() {
+ NavigableMap map = map5();
+ Set s = map.keySet();
+ Iterator i = s.iterator();
+ Integer last = (Integer)i.next();
+ assertEquals(last, one);
+ while (i.hasNext()) {
+ Integer k = (Integer)i.next();
+ assertTrue(last.compareTo(k) < 0);
+ last = k;
+ }
+ }
+
+ /**
+ * values collection contains all values
+ */
+ public void testValues() {
+ NavigableMap map = map5();
+ Collection s = map.values();
+ assertEquals(5, s.size());
+ assertTrue(s.contains("A"));
+ assertTrue(s.contains("B"));
+ assertTrue(s.contains("C"));
+ assertTrue(s.contains("D"));
+ assertTrue(s.contains("E"));
+ }
+
+ /**
+ * entrySet contains all pairs
+ */
+ public void testEntrySet() {
+ NavigableMap map = map5();
+ Set s = map.entrySet();
+ assertEquals(5, s.size());
+ Iterator it = s.iterator();
+ while (it.hasNext()) {
+ Map.Entry e = (Map.Entry) it.next();
+ assertTrue(
+ (e.getKey().equals(one) && e.getValue().equals("A")) ||
+ (e.getKey().equals(two) && e.getValue().equals("B")) ||
+ (e.getKey().equals(three) && e.getValue().equals("C")) ||
+ (e.getKey().equals(four) && e.getValue().equals("D")) ||
+ (e.getKey().equals(five) && e.getValue().equals("E")));
+ }
+ }
+
+ /**
+ * putAll adds all key-value pairs from the given map
+ */
+ public void testPutAll() {
+ NavigableMap empty = map0();
+ NavigableMap map = map5();
+ empty.putAll(map);
+ assertEquals(5, empty.size());
+ assertTrue(empty.containsKey(one));
+ assertTrue(empty.containsKey(two));
+ assertTrue(empty.containsKey(three));
+ assertTrue(empty.containsKey(four));
+ assertTrue(empty.containsKey(five));
+ }
+
+ /**
+ * remove removes the correct key-value pair from the map
+ */
+ public void testRemove() {
+ NavigableMap map = map5();
+ map.remove(five);
+ assertEquals(4, map.size());
+ assertFalse(map.containsKey(five));
+ }
+
+ /**
+ * lowerEntry returns preceding entry.
+ */
+ public void testLowerEntry() {
+ NavigableMap map = map5();
+ Map.Entry e1 = map.lowerEntry(three);
+ assertEquals(two, e1.getKey());
+
+ Map.Entry e2 = map.lowerEntry(six);
+ assertEquals(five, e2.getKey());
+
+ Map.Entry e3 = map.lowerEntry(one);
+ assertNull(e3);
+
+ Map.Entry e4 = map.lowerEntry(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * higherEntry returns next entry.
+ */
+ public void testHigherEntry() {
+ NavigableMap map = map5();
+ Map.Entry e1 = map.higherEntry(three);
+ assertEquals(four, e1.getKey());
+
+ Map.Entry e2 = map.higherEntry(zero);
+ assertEquals(one, e2.getKey());
+
+ Map.Entry e3 = map.higherEntry(five);
+ assertNull(e3);
+
+ Map.Entry e4 = map.higherEntry(six);
+ assertNull(e4);
+ }
+
+ /**
+ * floorEntry returns preceding entry.
+ */
+ public void testFloorEntry() {
+ NavigableMap map = map5();
+ Map.Entry e1 = map.floorEntry(three);
+ assertEquals(three, e1.getKey());
+
+ Map.Entry e2 = map.floorEntry(six);
+ assertEquals(five, e2.getKey());
+
+ Map.Entry e3 = map.floorEntry(one);
+ assertEquals(one, e3.getKey());
+
+ Map.Entry e4 = map.floorEntry(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * ceilingEntry returns next entry.
+ */
+ public void testCeilingEntry() {
+ NavigableMap map = map5();
+ Map.Entry e1 = map.ceilingEntry(three);
+ assertEquals(three, e1.getKey());
+
+ Map.Entry e2 = map.ceilingEntry(zero);
+ assertEquals(one, e2.getKey());
+
+ Map.Entry e3 = map.ceilingEntry(five);
+ assertEquals(five, e3.getKey());
+
+ Map.Entry e4 = map.ceilingEntry(six);
+ assertNull(e4);
+ }
+
+ /**
+ * pollFirstEntry returns entries in order
+ */
+ public void testPollFirstEntry() {
+ NavigableMap map = map5();
+ Map.Entry e = map.pollFirstEntry();
+ assertEquals(one, e.getKey());
+ assertEquals("A", e.getValue());
+ e = map.pollFirstEntry();
+ assertEquals(two, e.getKey());
+ map.put(one, "A");
+ e = map.pollFirstEntry();
+ assertEquals(one, e.getKey());
+ assertEquals("A", e.getValue());
+ e = map.pollFirstEntry();
+ assertEquals(three, e.getKey());
+ map.remove(four);
+ e = map.pollFirstEntry();
+ assertEquals(five, e.getKey());
+ try {
+ e.setValue("A");
+ shouldThrow();
+ } catch (UnsupportedOperationException success) {}
+ assertTrue(map.isEmpty());
+ Map.Entry f = map.firstEntry();
+ assertNull(f);
+ e = map.pollFirstEntry();
+ assertNull(e);
+ }
+
+ /**
+ * pollLastEntry returns entries in order
+ */
+ public void testPollLastEntry() {
+ NavigableMap map = map5();
+ Map.Entry e = map.pollLastEntry();
+ assertEquals(five, e.getKey());
+ assertEquals("E", e.getValue());
+ e = map.pollLastEntry();
+ assertEquals(four, e.getKey());
+ map.put(five, "E");
+ e = map.pollLastEntry();
+ assertEquals(five, e.getKey());
+ assertEquals("E", e.getValue());
+ e = map.pollLastEntry();
+ assertEquals(three, e.getKey());
+ map.remove(two);
+ e = map.pollLastEntry();
+ assertEquals(one, e.getKey());
+ try {
+ e.setValue("E");
+ shouldThrow();
+ } catch (UnsupportedOperationException success) {}
+ e = map.pollLastEntry();
+ assertNull(e);
+ }
+
+ /**
+ * size returns the correct values
+ */
+ public void testSize() {
+ NavigableMap map = map5();
+ NavigableMap empty = map0();
+ assertEquals(0, empty.size());
+ assertEquals(5, map.size());
+ }
+
+ /**
+ * toString contains toString of elements
+ */
+ public void testToString() {
+ NavigableMap map = map5();
+ String s = map.toString();
+ for (int i = 1; i <= 5; ++i) {
+ assertTrue(s.contains(String.valueOf(i)));
+ }
+ }
+
+ // Exception tests
+
+ /**
+ * get(null) of nonempty map throws NPE
+ */
+ public void testGet_NullPointerException() {
+ try {
+ NavigableMap c = map5();
+ c.get(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * containsKey(null) of nonempty map throws NPE
+ */
+ public void testContainsKey_NullPointerException() {
+ try {
+ NavigableMap c = map5();
+ c.containsKey(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * put(null,x) throws NPE
+ */
+ public void testPut1_NullPointerException() {
+ try {
+ NavigableMap c = map5();
+ c.put(null, "whatever");
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * remove(null) throws NPE
+ */
+ public void testRemove1_NullPointerException() {
+ try {
+ NavigableMap c = map5();
+ c.remove(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * A deserialized map equals original
+ */
+ public void testSerialization() throws Exception {
+ NavigableMap x = map5();
+ NavigableMap y = serialClone(x);
+
+ assertNotSame(x, y);
+ assertEquals(x.size(), y.size());
+ assertEquals(x.toString(), y.toString());
+ assertEquals(x, y);
+ assertEquals(y, x);
+ }
+
+ /**
+ * subMap returns map with keys in requested range
+ */
+ public void testSubMapContents() {
+ NavigableMap map = map5();
+ SortedMap sm = map.subMap(two, four);
+ assertEquals(two, sm.firstKey());
+ assertEquals(three, sm.lastKey());
+ assertEquals(2, sm.size());
+ assertFalse(sm.containsKey(one));
+ assertTrue(sm.containsKey(two));
+ assertTrue(sm.containsKey(three));
+ assertFalse(sm.containsKey(four));
+ assertFalse(sm.containsKey(five));
+ Iterator i = sm.keySet().iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ k = (Integer)(i.next());
+ assertEquals(three, k);
+ assertFalse(i.hasNext());
+ Iterator j = sm.keySet().iterator();
+ j.next();
+ j.remove();
+ assertFalse(map.containsKey(two));
+ assertEquals(4, map.size());
+ assertEquals(1, sm.size());
+ assertEquals(three, sm.firstKey());
+ assertEquals(three, sm.lastKey());
+ assertEquals("C", sm.remove(three));
+ assertTrue(sm.isEmpty());
+ assertEquals(3, map.size());
+ }
+
+ public void testSubMapContents2() {
+ NavigableMap map = map5();
+ SortedMap sm = map.subMap(two, three);
+ assertEquals(1, sm.size());
+ assertEquals(two, sm.firstKey());
+ assertEquals(two, sm.lastKey());
+ assertFalse(sm.containsKey(one));
+ assertTrue(sm.containsKey(two));
+ assertFalse(sm.containsKey(three));
+ assertFalse(sm.containsKey(four));
+ assertFalse(sm.containsKey(five));
+ Iterator i = sm.keySet().iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ assertFalse(i.hasNext());
+ Iterator j = sm.keySet().iterator();
+ j.next();
+ j.remove();
+ assertFalse(map.containsKey(two));
+ assertEquals(4, map.size());
+ assertEquals(0, sm.size());
+ assertTrue(sm.isEmpty());
+ assertSame(sm.remove(three), null);
+ assertEquals(4, map.size());
+ }
+
+ /**
+ * headMap returns map with keys in requested range
+ */
+ public void testHeadMapContents() {
+ NavigableMap map = map5();
+ SortedMap sm = map.headMap(four);
+ assertTrue(sm.containsKey(one));
+ assertTrue(sm.containsKey(two));
+ assertTrue(sm.containsKey(three));
+ assertFalse(sm.containsKey(four));
+ assertFalse(sm.containsKey(five));
+ Iterator i = sm.keySet().iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(one, k);
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ k = (Integer)(i.next());
+ assertEquals(three, k);
+ assertFalse(i.hasNext());
+ sm.clear();
+ assertTrue(sm.isEmpty());
+ assertEquals(2, map.size());
+ assertEquals(four, map.firstKey());
+ }
+
+ /**
+ * headMap returns map with keys in requested range
+ */
+ public void testTailMapContents() {
+ NavigableMap map = map5();
+ SortedMap sm = map.tailMap(two);
+ assertFalse(sm.containsKey(one));
+ assertTrue(sm.containsKey(two));
+ assertTrue(sm.containsKey(three));
+ assertTrue(sm.containsKey(four));
+ assertTrue(sm.containsKey(five));
+ Iterator i = sm.keySet().iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ k = (Integer)(i.next());
+ assertEquals(three, k);
+ k = (Integer)(i.next());
+ assertEquals(four, k);
+ k = (Integer)(i.next());
+ assertEquals(five, k);
+ assertFalse(i.hasNext());
+
+ Iterator ei = sm.entrySet().iterator();
+ Map.Entry e;
+ e = (Map.Entry)(ei.next());
+ assertEquals(two, e.getKey());
+ assertEquals("B", e.getValue());
+ e = (Map.Entry)(ei.next());
+ assertEquals(three, e.getKey());
+ assertEquals("C", e.getValue());
+ e = (Map.Entry)(ei.next());
+ assertEquals(four, e.getKey());
+ assertEquals("D", e.getValue());
+ e = (Map.Entry)(ei.next());
+ assertEquals(five, e.getKey());
+ assertEquals("E", e.getValue());
+ assertFalse(i.hasNext());
+
+ SortedMap ssm = sm.tailMap(four);
+ assertEquals(four, ssm.firstKey());
+ assertEquals(five, ssm.lastKey());
+ assertEquals("D", ssm.remove(four));
+ assertEquals(1, ssm.size());
+ assertEquals(3, sm.size());
+ assertEquals(4, map.size());
+ }
+
+ /**
+ * clear removes all pairs
+ */
+ public void testDescendingClear() {
+ NavigableMap map = dmap5();
+ map.clear();
+ assertEquals(0, map.size());
+ }
+
+ /**
+ * Maps with same contents are equal
+ */
+ public void testDescendingEquals() {
+ NavigableMap map1 = dmap5();
+ NavigableMap map2 = dmap5();
+ assertEquals(map1, map2);
+ assertEquals(map2, map1);
+ map1.clear();
+ assertFalse(map1.equals(map2));
+ assertFalse(map2.equals(map1));
+ }
+
+ /**
+ * containsKey returns true for contained key
+ */
+ public void testDescendingContainsKey() {
+ NavigableMap map = dmap5();
+ assertTrue(map.containsKey(m1));
+ assertFalse(map.containsKey(zero));
+ }
+
+ /**
+ * containsValue returns true for held values
+ */
+ public void testDescendingContainsValue() {
+ NavigableMap map = dmap5();
+ assertTrue(map.containsValue("A"));
+ assertFalse(map.containsValue("Z"));
+ }
+
+ /**
+ * get returns the correct element at the given key,
+ * or null if not present
+ */
+ public void testDescendingGet() {
+ NavigableMap map = dmap5();
+ assertEquals("A", (String)map.get(m1));
+ NavigableMap empty = dmap0();
+ assertNull(empty.get(m1));
+ }
+
+ /**
+ * isEmpty is true of empty map and false for non-empty
+ */
+ public void testDescendingIsEmpty() {
+ NavigableMap empty = dmap0();
+ NavigableMap map = dmap5();
+ assertTrue(empty.isEmpty());
+ assertFalse(map.isEmpty());
+ }
+
+ /**
+ * firstKey returns first key
+ */
+ public void testDescendingFirstKey() {
+ NavigableMap map = dmap5();
+ assertEquals(m1, map.firstKey());
+ }
+
+ /**
+ * lastKey returns last key
+ */
+ public void testDescendingLastKey() {
+ NavigableMap map = dmap5();
+ assertEquals(m5, map.lastKey());
+ }
+
+ /**
+ * keySet returns a Set containing all the keys
+ */
+ public void testDescendingKeySet() {
+ NavigableMap map = dmap5();
+ Set s = map.keySet();
+ assertEquals(5, s.size());
+ assertTrue(s.contains(m1));
+ assertTrue(s.contains(m2));
+ assertTrue(s.contains(m3));
+ assertTrue(s.contains(m4));
+ assertTrue(s.contains(m5));
+ }
+
+ /**
+ * keySet is ordered
+ */
+ public void testDescendingKeySetOrder() {
+ NavigableMap map = dmap5();
+ Set s = map.keySet();
+ Iterator i = s.iterator();
+ Integer last = (Integer)i.next();
+ assertEquals(last, m1);
+ while (i.hasNext()) {
+ Integer k = (Integer)i.next();
+ assertTrue(last.compareTo(k) > 0);
+ last = k;
+ }
+ }
+
+ /**
+ * values collection contains all values
+ */
+ public void testDescendingValues() {
+ NavigableMap map = dmap5();
+ Collection s = map.values();
+ assertEquals(5, s.size());
+ assertTrue(s.contains("A"));
+ assertTrue(s.contains("B"));
+ assertTrue(s.contains("C"));
+ assertTrue(s.contains("D"));
+ assertTrue(s.contains("E"));
+ }
+
+ /**
+ * keySet.toArray returns contains all keys
+ */
+ public void testDescendingAscendingKeySetToArray() {
+ NavigableMap map = dmap5();
+ Set s = map.keySet();
+ Object[] ar = s.toArray();
+ assertTrue(s.containsAll(Arrays.asList(ar)));
+ assertEquals(5, ar.length);
+ ar[0] = m10;
+ assertFalse(s.containsAll(Arrays.asList(ar)));
+ }
+
+ /**
+ * descendingkeySet.toArray returns contains all keys
+ */
+ public void testDescendingDescendingKeySetToArray() {
+ NavigableMap map = dmap5();
+ Set s = map.descendingKeySet();
+ Object[] ar = s.toArray();
+ assertEquals(5, ar.length);
+ assertTrue(s.containsAll(Arrays.asList(ar)));
+ ar[0] = m10;
+ assertFalse(s.containsAll(Arrays.asList(ar)));
+ }
+
+ /**
+ * Values.toArray contains all values
+ */
+ public void testDescendingValuesToArray() {
+ NavigableMap map = dmap5();
+ Collection v = map.values();
+ Object[] ar = v.toArray();
+ ArrayList s = new ArrayList(Arrays.asList(ar));
+ assertEquals(5, ar.length);
+ assertTrue(s.contains("A"));
+ assertTrue(s.contains("B"));
+ assertTrue(s.contains("C"));
+ assertTrue(s.contains("D"));
+ assertTrue(s.contains("E"));
+ }
+
+ /**
+ * entrySet contains all pairs
+ */
+ public void testDescendingEntrySet() {
+ NavigableMap map = dmap5();
+ Set s = map.entrySet();
+ assertEquals(5, s.size());
+ Iterator it = s.iterator();
+ while (it.hasNext()) {
+ Map.Entry e = (Map.Entry) it.next();
+ assertTrue(
+ (e.getKey().equals(m1) && e.getValue().equals("A")) ||
+ (e.getKey().equals(m2) && e.getValue().equals("B")) ||
+ (e.getKey().equals(m3) && e.getValue().equals("C")) ||
+ (e.getKey().equals(m4) && e.getValue().equals("D")) ||
+ (e.getKey().equals(m5) && e.getValue().equals("E")));
+ }
+ }
+
+ /**
+ * putAll adds all key-value pairs from the given map
+ */
+ public void testDescendingPutAll() {
+ NavigableMap empty = dmap0();
+ NavigableMap map = dmap5();
+ empty.putAll(map);
+ assertEquals(5, empty.size());
+ assertTrue(empty.containsKey(m1));
+ assertTrue(empty.containsKey(m2));
+ assertTrue(empty.containsKey(m3));
+ assertTrue(empty.containsKey(m4));
+ assertTrue(empty.containsKey(m5));
+ }
+
+ /**
+ * remove removes the correct key-value pair from the map
+ */
+ public void testDescendingRemove() {
+ NavigableMap map = dmap5();
+ map.remove(m5);
+ assertEquals(4, map.size());
+ assertFalse(map.containsKey(m5));
+ }
+
+ /**
+ * lowerEntry returns preceding entry.
+ */
+ public void testDescendingLowerEntry() {
+ NavigableMap map = dmap5();
+ Map.Entry e1 = map.lowerEntry(m3);
+ assertEquals(m2, e1.getKey());
+
+ Map.Entry e2 = map.lowerEntry(m6);
+ assertEquals(m5, e2.getKey());
+
+ Map.Entry e3 = map.lowerEntry(m1);
+ assertNull(e3);
+
+ Map.Entry e4 = map.lowerEntry(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * higherEntry returns next entry.
+ */
+ public void testDescendingHigherEntry() {
+ NavigableMap map = dmap5();
+ Map.Entry e1 = map.higherEntry(m3);
+ assertEquals(m4, e1.getKey());
+
+ Map.Entry e2 = map.higherEntry(zero);
+ assertEquals(m1, e2.getKey());
+
+ Map.Entry e3 = map.higherEntry(m5);
+ assertNull(e3);
+
+ Map.Entry e4 = map.higherEntry(m6);
+ assertNull(e4);
+ }
+
+ /**
+ * floorEntry returns preceding entry.
+ */
+ public void testDescendingFloorEntry() {
+ NavigableMap map = dmap5();
+ Map.Entry e1 = map.floorEntry(m3);
+ assertEquals(m3, e1.getKey());
+
+ Map.Entry e2 = map.floorEntry(m6);
+ assertEquals(m5, e2.getKey());
+
+ Map.Entry e3 = map.floorEntry(m1);
+ assertEquals(m1, e3.getKey());
+
+ Map.Entry e4 = map.floorEntry(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * ceilingEntry returns next entry.
+ */
+ public void testDescendingCeilingEntry() {
+ NavigableMap map = dmap5();
+ Map.Entry e1 = map.ceilingEntry(m3);
+ assertEquals(m3, e1.getKey());
+
+ Map.Entry e2 = map.ceilingEntry(zero);
+ assertEquals(m1, e2.getKey());
+
+ Map.Entry e3 = map.ceilingEntry(m5);
+ assertEquals(m5, e3.getKey());
+
+ Map.Entry e4 = map.ceilingEntry(m6);
+ assertNull(e4);
+ }
+
+ /**
+ * pollFirstEntry returns entries in order
+ */
+ public void testDescendingPollFirstEntry() {
+ NavigableMap map = dmap5();
+ Map.Entry e = map.pollFirstEntry();
+ assertEquals(m1, e.getKey());
+ assertEquals("A", e.getValue());
+ e = map.pollFirstEntry();
+ assertEquals(m2, e.getKey());
+ map.put(m1, "A");
+ e = map.pollFirstEntry();
+ assertEquals(m1, e.getKey());
+ assertEquals("A", e.getValue());
+ e = map.pollFirstEntry();
+ assertEquals(m3, e.getKey());
+ map.remove(m4);
+ e = map.pollFirstEntry();
+ assertEquals(m5, e.getKey());
+ try {
+ e.setValue("A");
+ shouldThrow();
+ } catch (UnsupportedOperationException success) {}
+ e = map.pollFirstEntry();
+ assertNull(e);
+ }
+
+ /**
+ * pollLastEntry returns entries in order
+ */
+ public void testDescendingPollLastEntry() {
+ NavigableMap map = dmap5();
+ Map.Entry e = map.pollLastEntry();
+ assertEquals(m5, e.getKey());
+ assertEquals("E", e.getValue());
+ e = map.pollLastEntry();
+ assertEquals(m4, e.getKey());
+ map.put(m5, "E");
+ e = map.pollLastEntry();
+ assertEquals(m5, e.getKey());
+ assertEquals("E", e.getValue());
+ e = map.pollLastEntry();
+ assertEquals(m3, e.getKey());
+ map.remove(m2);
+ e = map.pollLastEntry();
+ assertEquals(m1, e.getKey());
+ try {
+ e.setValue("E");
+ shouldThrow();
+ } catch (UnsupportedOperationException success) {}
+ e = map.pollLastEntry();
+ assertNull(e);
+ }
+
+ /**
+ * size returns the correct values
+ */
+ public void testDescendingSize() {
+ NavigableMap map = dmap5();
+ NavigableMap empty = dmap0();
+ assertEquals(0, empty.size());
+ assertEquals(5, map.size());
+ }
+
+ /**
+ * toString contains toString of elements
+ */
+ public void testDescendingToString() {
+ NavigableMap map = dmap5();
+ String s = map.toString();
+ for (int i = 1; i <= 5; ++i) {
+ assertTrue(s.contains(String.valueOf(i)));
+ }
+ }
+
+ // Exception testDescendings
+
+ /**
+ * get(null) of nonempty map throws NPE
+ */
+ public void testDescendingGet_NullPointerException() {
+ try {
+ NavigableMap c = dmap5();
+ c.get(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * put(null,x) throws NPE
+ */
+ public void testDescendingPut1_NullPointerException() {
+ try {
+ NavigableMap c = dmap5();
+ c.put(null, "whatever");
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * A deserialized map equals original
+ */
+ public void testDescendingSerialization() throws Exception {
+ NavigableMap x = dmap5();
+ NavigableMap y = serialClone(x);
+
+ assertNotSame(x, y);
+ assertEquals(x.size(), y.size());
+ assertEquals(x.toString(), y.toString());
+ assertEquals(x, y);
+ assertEquals(y, x);
+ }
+
+ /**
+ * subMap returns map with keys in requested range
+ */
+ public void testDescendingSubMapContents() {
+ NavigableMap map = dmap5();
+ SortedMap sm = map.subMap(m2, m4);
+ assertEquals(m2, sm.firstKey());
+ assertEquals(m3, sm.lastKey());
+ assertEquals(2, sm.size());
+ assertFalse(sm.containsKey(m1));
+ assertTrue(sm.containsKey(m2));
+ assertTrue(sm.containsKey(m3));
+ assertFalse(sm.containsKey(m4));
+ assertFalse(sm.containsKey(m5));
+ Iterator i = sm.keySet().iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(m2, k);
+ k = (Integer)(i.next());
+ assertEquals(m3, k);
+ assertFalse(i.hasNext());
+ Iterator j = sm.keySet().iterator();
+ j.next();
+ j.remove();
+ assertFalse(map.containsKey(m2));
+ assertEquals(4, map.size());
+ assertEquals(1, sm.size());
+ assertEquals(m3, sm.firstKey());
+ assertEquals(m3, sm.lastKey());
+ assertEquals("C", sm.remove(m3));
+ assertTrue(sm.isEmpty());
+ assertEquals(3, map.size());
+ }
+
+ public void testDescendingSubMapContents2() {
+ NavigableMap map = dmap5();
+ SortedMap sm = map.subMap(m2, m3);
+ assertEquals(1, sm.size());
+ assertEquals(m2, sm.firstKey());
+ assertEquals(m2, sm.lastKey());
+ assertFalse(sm.containsKey(m1));
+ assertTrue(sm.containsKey(m2));
+ assertFalse(sm.containsKey(m3));
+ assertFalse(sm.containsKey(m4));
+ assertFalse(sm.containsKey(m5));
+ Iterator i = sm.keySet().iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(m2, k);
+ assertFalse(i.hasNext());
+ Iterator j = sm.keySet().iterator();
+ j.next();
+ j.remove();
+ assertFalse(map.containsKey(m2));
+ assertEquals(4, map.size());
+ assertEquals(0, sm.size());
+ assertTrue(sm.isEmpty());
+ assertSame(sm.remove(m3), null);
+ assertEquals(4, map.size());
+ }
+
+ /**
+ * headMap returns map with keys in requested range
+ */
+ public void testDescendingHeadMapContents() {
+ NavigableMap map = dmap5();
+ SortedMap sm = map.headMap(m4);
+ assertTrue(sm.containsKey(m1));
+ assertTrue(sm.containsKey(m2));
+ assertTrue(sm.containsKey(m3));
+ assertFalse(sm.containsKey(m4));
+ assertFalse(sm.containsKey(m5));
+ Iterator i = sm.keySet().iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(m1, k);
+ k = (Integer)(i.next());
+ assertEquals(m2, k);
+ k = (Integer)(i.next());
+ assertEquals(m3, k);
+ assertFalse(i.hasNext());
+ sm.clear();
+ assertTrue(sm.isEmpty());
+ assertEquals(2, map.size());
+ assertEquals(m4, map.firstKey());
+ }
+
+ /**
+ * headMap returns map with keys in requested range
+ */
+ public void testDescendingTailMapContents() {
+ NavigableMap map = dmap5();
+ SortedMap sm = map.tailMap(m2);
+ assertFalse(sm.containsKey(m1));
+ assertTrue(sm.containsKey(m2));
+ assertTrue(sm.containsKey(m3));
+ assertTrue(sm.containsKey(m4));
+ assertTrue(sm.containsKey(m5));
+ Iterator i = sm.keySet().iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(m2, k);
+ k = (Integer)(i.next());
+ assertEquals(m3, k);
+ k = (Integer)(i.next());
+ assertEquals(m4, k);
+ k = (Integer)(i.next());
+ assertEquals(m5, k);
+ assertFalse(i.hasNext());
+
+ Iterator ei = sm.entrySet().iterator();
+ Map.Entry e;
+ e = (Map.Entry)(ei.next());
+ assertEquals(m2, e.getKey());
+ assertEquals("B", e.getValue());
+ e = (Map.Entry)(ei.next());
+ assertEquals(m3, e.getKey());
+ assertEquals("C", e.getValue());
+ e = (Map.Entry)(ei.next());
+ assertEquals(m4, e.getKey());
+ assertEquals("D", e.getValue());
+ e = (Map.Entry)(ei.next());
+ assertEquals(m5, e.getKey());
+ assertEquals("E", e.getValue());
+ assertFalse(i.hasNext());
+
+ SortedMap ssm = sm.tailMap(m4);
+ assertEquals(m4, ssm.firstKey());
+ assertEquals(m5, ssm.lastKey());
+ assertEquals("D", ssm.remove(m4));
+ assertEquals(1, ssm.size());
+ assertEquals(3, sm.size());
+ assertEquals(4, map.size());
+ }
+
+}
diff --git a/jsr166-tests/src/test/java/jsr166/TreeSubSetTest.java b/jsr166-tests/src/test/java/jsr166/TreeSubSetTest.java
new file mode 100644
index 0000000..ba61748
--- /dev/null
+++ b/jsr166-tests/src/test/java/jsr166/TreeSubSetTest.java
@@ -0,0 +1,1116 @@
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package jsr166;
+
+import junit.framework.*;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.NavigableSet;
+import java.util.SortedSet;
+import java.util.Set;
+import java.util.TreeSet;
+
+public class TreeSubSetTest extends JSR166TestCase {
+
+ static class MyReverseComparator implements Comparator {
+ public int compare(Object x, Object y) {
+ return ((Comparable)y).compareTo(x);
+ }
+ }
+
+ /**
+ * Returns a new set of given size containing consecutive
+ * Integers 0 ... n.
+ */
+ private NavigableSet<Integer> populatedSet(int n) {
+ TreeSet<Integer> q = new TreeSet<Integer>();
+ assertTrue(q.isEmpty());
+
+ for (int i = n-1; i >= 0; i-=2)
+ assertTrue(q.add(new Integer(i)));
+ for (int i = (n & 1); i < n; i+=2)
+ assertTrue(q.add(new Integer(i)));
+ assertTrue(q.add(new Integer(-n)));
+ assertTrue(q.add(new Integer(n)));
+ NavigableSet s = q.subSet(new Integer(0), true, new Integer(n), false);
+ assertFalse(s.isEmpty());
+ assertEquals(n, s.size());
+ return s;
+ }
+
+ /**
+ * Returns a new set of first 5 ints.
+ */
+ private NavigableSet set5() {
+ TreeSet q = new TreeSet();
+ assertTrue(q.isEmpty());
+ q.add(one);
+ q.add(two);
+ q.add(three);
+ q.add(four);
+ q.add(five);
+ q.add(zero);
+ q.add(seven);
+ NavigableSet s = q.subSet(one, true, seven, false);
+ assertEquals(5, s.size());
+ return s;
+ }
+
+ private NavigableSet dset5() {
+ TreeSet q = new TreeSet();
+ assertTrue(q.isEmpty());
+ q.add(m1);
+ q.add(m2);
+ q.add(m3);
+ q.add(m4);
+ q.add(m5);
+ NavigableSet s = q.descendingSet();
+ assertEquals(5, s.size());
+ return s;
+ }
+
+ private static NavigableSet set0() {
+ TreeSet set = new TreeSet();
+ assertTrue(set.isEmpty());
+ return set.tailSet(m1, false);
+ }
+
+ private static NavigableSet dset0() {
+ TreeSet set = new TreeSet();
+ assertTrue(set.isEmpty());
+ return set;
+ }
+
+ /**
+ * A new set has unbounded capacity
+ */
+ public void testConstructor1() {
+ assertEquals(0, set0().size());
+ }
+
+ /**
+ * isEmpty is true before add, false after
+ */
+ public void testEmpty() {
+ NavigableSet q = set0();
+ assertTrue(q.isEmpty());
+ assertTrue(q.add(new Integer(1)));
+ assertFalse(q.isEmpty());
+ assertTrue(q.add(new Integer(2)));
+ q.pollFirst();
+ q.pollFirst();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * size changes when elements added and removed
+ */
+ public void testSize() {
+ NavigableSet q = populatedSet(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(SIZE-i, q.size());
+ q.pollFirst();
+ }
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.size());
+ q.add(new Integer(i));
+ }
+ }
+
+ /**
+ * add(null) throws NPE
+ */
+ public void testAddNull() {
+ try {
+ NavigableSet q = set0();
+ q.add(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Add of comparable element succeeds
+ */
+ public void testAdd() {
+ NavigableSet q = set0();
+ assertTrue(q.add(six));
+ }
+
+ /**
+ * Add of duplicate element fails
+ */
+ public void testAddDup() {
+ NavigableSet q = set0();
+ assertTrue(q.add(six));
+ assertFalse(q.add(six));
+ }
+
+ /**
+ * Add of non-Comparable throws CCE
+ */
+ public void testAddNonComparable() {
+ try {
+ NavigableSet q = set0();
+ q.add(new Object());
+ q.add(new Object());
+ q.add(new Object());
+ shouldThrow();
+ } catch (ClassCastException success) {}
+ }
+
+ /**
+ * addAll(null) throws NPE
+ */
+ public void testAddAll1() {
+ try {
+ NavigableSet q = set0();
+ q.addAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll of a collection with null elements throws NPE
+ */
+ public void testAddAll2() {
+ try {
+ NavigableSet q = set0();
+ Integer[] ints = new Integer[SIZE];
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll of a collection with any null elements throws NPE after
+ * possibly adding some elements
+ */
+ public void testAddAll3() {
+ try {
+ NavigableSet q = set0();
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i+SIZE);
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Set contains all elements of successful addAll
+ */
+ public void testAddAll5() {
+ Integer[] empty = new Integer[0];
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(SIZE-1- i);
+ NavigableSet q = set0();
+ assertFalse(q.addAll(Arrays.asList(empty)));
+ assertTrue(q.addAll(Arrays.asList(ints)));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(new Integer(i), q.pollFirst());
+ }
+
+ /**
+ * poll succeeds unless empty
+ */
+ public void testPoll() {
+ NavigableSet q = populatedSet(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.pollFirst());
+ }
+ assertNull(q.pollFirst());
+ }
+
+ /**
+ * remove(x) removes x and returns true if present
+ */
+ public void testRemoveElement() {
+ NavigableSet q = populatedSet(SIZE);
+ for (int i = 1; i < SIZE; i+=2) {
+ assertTrue(q.contains(i));
+ assertTrue(q.remove(i));
+ assertFalse(q.contains(i));
+ assertTrue(q.contains(i-1));
+ }
+ for (int i = 0; i < SIZE; i+=2) {
+ assertTrue(q.contains(i));
+ assertTrue(q.remove(i));
+ assertFalse(q.contains(i));
+ assertFalse(q.remove(i+1));
+ assertFalse(q.contains(i+1));
+ }
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * contains(x) reports true when elements added but not yet removed
+ */
+ public void testContains() {
+ NavigableSet q = populatedSet(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.contains(new Integer(i)));
+ q.pollFirst();
+ assertFalse(q.contains(new Integer(i)));
+ }
+ }
+
+ /**
+ * clear removes all elements
+ */
+ public void testClear() {
+ NavigableSet q = populatedSet(SIZE);
+ q.clear();
+ assertTrue(q.isEmpty());
+ assertEquals(0, q.size());
+ assertTrue(q.add(new Integer(1)));
+ assertFalse(q.isEmpty());
+ q.clear();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * containsAll(c) is true when c contains a subset of elements
+ */
+ public void testContainsAll() {
+ NavigableSet q = populatedSet(SIZE);
+ NavigableSet p = set0();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.containsAll(p));
+ assertFalse(p.containsAll(q));
+ p.add(new Integer(i));
+ }
+ assertTrue(p.containsAll(q));
+ }
+
+ /**
+ * retainAll(c) retains only those elements of c and reports true if changed
+ */
+ public void testRetainAll() {
+ NavigableSet q = populatedSet(SIZE);
+ NavigableSet p = populatedSet(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ boolean changed = q.retainAll(p);
+ if (i == 0)
+ assertFalse(changed);
+ else
+ assertTrue(changed);
+
+ assertTrue(q.containsAll(p));
+ assertEquals(SIZE-i, q.size());
+ p.pollFirst();
+ }
+ }
+
+ /**
+ * removeAll(c) removes only those elements of c and reports true if changed
+ */
+ public void testRemoveAll() {
+ for (int i = 1; i < SIZE; ++i) {
+ NavigableSet q = populatedSet(SIZE);
+ NavigableSet p = populatedSet(i);
+ assertTrue(q.removeAll(p));
+ assertEquals(SIZE-i, q.size());
+ for (int j = 0; j < i; ++j) {
+ Integer I = (Integer)(p.pollFirst());
+ assertFalse(q.contains(I));
+ }
+ }
+ }
+
+ /**
+ * lower returns preceding element
+ */
+ public void testLower() {
+ NavigableSet q = set5();
+ Object e1 = q.lower(three);
+ assertEquals(two, e1);
+
+ Object e2 = q.lower(six);
+ assertEquals(five, e2);
+
+ Object e3 = q.lower(one);
+ assertNull(e3);
+
+ Object e4 = q.lower(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * higher returns next element
+ */
+ public void testHigher() {
+ NavigableSet q = set5();
+ Object e1 = q.higher(three);
+ assertEquals(four, e1);
+
+ Object e2 = q.higher(zero);
+ assertEquals(one, e2);
+
+ Object e3 = q.higher(five);
+ assertNull(e3);
+
+ Object e4 = q.higher(six);
+ assertNull(e4);
+ }
+
+ /**
+ * floor returns preceding element
+ */
+ public void testFloor() {
+ NavigableSet q = set5();
+ Object e1 = q.floor(three);
+ assertEquals(three, e1);
+
+ Object e2 = q.floor(six);
+ assertEquals(five, e2);
+
+ Object e3 = q.floor(one);
+ assertEquals(one, e3);
+
+ Object e4 = q.floor(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * ceiling returns next element
+ */
+ public void testCeiling() {
+ NavigableSet q = set5();
+ Object e1 = q.ceiling(three);
+ assertEquals(three, e1);
+
+ Object e2 = q.ceiling(zero);
+ assertEquals(one, e2);
+
+ Object e3 = q.ceiling(five);
+ assertEquals(five, e3);
+
+ Object e4 = q.ceiling(six);
+ assertNull(e4);
+ }
+
+ /**
+ * toArray contains all elements in sorted order
+ */
+ public void testToArray() {
+ NavigableSet q = populatedSet(SIZE);
+ Object[] o = q.toArray();
+ for (int i = 0; i < o.length; i++)
+ assertSame(o[i], q.pollFirst());
+ }
+
+ /**
+ * toArray(a) contains all elements in sorted order
+ */
+ public void testToArray2() {
+ NavigableSet<Integer> q = populatedSet(SIZE);
+ Integer[] ints = new Integer[SIZE];
+ Integer[] array = q.toArray(ints);
+ assertSame(ints, array);
+ for (int i = 0; i < ints.length; i++)
+ assertSame(ints[i], q.pollFirst());
+ }
+
+ /**
+ * iterator iterates through all elements
+ */
+ public void testIterator() {
+ NavigableSet q = populatedSet(SIZE);
+ int i = 0;
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ assertTrue(q.contains(it.next()));
+ ++i;
+ }
+ assertEquals(i, SIZE);
+ }
+
+ /**
+ * iterator of empty set has no elements
+ */
+ public void testEmptyIterator() {
+ NavigableSet q = set0();
+ int i = 0;
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ assertTrue(q.contains(it.next()));
+ ++i;
+ }
+ assertEquals(0, i);
+ }
+
+ /**
+ * iterator.remove removes current element
+ */
+ public void testIteratorRemove() {
+ final NavigableSet q = set0();
+ q.add(new Integer(2));
+ q.add(new Integer(1));
+ q.add(new Integer(3));
+
+ Iterator it = q.iterator();
+ it.next();
+ it.remove();
+
+ it = q.iterator();
+ assertEquals(2, it.next());
+ assertEquals(3, it.next());
+ assertFalse(it.hasNext());
+ }
+
+ /**
+ * toString contains toStrings of elements
+ */
+ public void testToString() {
+ NavigableSet q = populatedSet(SIZE);
+ String s = q.toString();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(s.contains(String.valueOf(i)));
+ }
+ }
+
+ /**
+ * A deserialized serialized set has same elements
+ */
+ public void testSerialization() throws Exception {
+ NavigableSet x = populatedSet(SIZE);
+ NavigableSet y = serialClone(x);
+
+ assertNotSame(x, y);
+ assertEquals(x.size(), y.size());
+ assertEquals(x, y);
+ assertEquals(y, x);
+ while (!x.isEmpty()) {
+ assertFalse(y.isEmpty());
+ assertEquals(x.pollFirst(), y.pollFirst());
+ }
+ assertTrue(y.isEmpty());
+ }
+
+ /**
+ * subSet returns set with keys in requested range
+ */
+ public void testSubSetContents() {
+ NavigableSet set = set5();
+ SortedSet sm = set.subSet(two, four);
+ assertEquals(two, sm.first());
+ assertEquals(three, sm.last());
+ assertEquals(2, sm.size());
+ assertFalse(sm.contains(one));
+ assertTrue(sm.contains(two));
+ assertTrue(sm.contains(three));
+ assertFalse(sm.contains(four));
+ assertFalse(sm.contains(five));
+ Iterator i = sm.iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ k = (Integer)(i.next());
+ assertEquals(three, k);
+ assertFalse(i.hasNext());
+ Iterator j = sm.iterator();
+ j.next();
+ j.remove();
+ assertFalse(set.contains(two));
+ assertEquals(4, set.size());
+ assertEquals(1, sm.size());
+ assertEquals(three, sm.first());
+ assertEquals(three, sm.last());
+ assertTrue(sm.remove(three));
+ assertTrue(sm.isEmpty());
+ assertEquals(3, set.size());
+ }
+
+ public void testSubSetContents2() {
+ NavigableSet set = set5();
+ SortedSet sm = set.subSet(two, three);
+ assertEquals(1, sm.size());
+ assertEquals(two, sm.first());
+ assertEquals(two, sm.last());
+ assertFalse(sm.contains(one));
+ assertTrue(sm.contains(two));
+ assertFalse(sm.contains(three));
+ assertFalse(sm.contains(four));
+ assertFalse(sm.contains(five));
+ Iterator i = sm.iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ assertFalse(i.hasNext());
+ Iterator j = sm.iterator();
+ j.next();
+ j.remove();
+ assertFalse(set.contains(two));
+ assertEquals(4, set.size());
+ assertEquals(0, sm.size());
+ assertTrue(sm.isEmpty());
+ assertFalse(sm.remove(three));
+ assertEquals(4, set.size());
+ }
+
+ /**
+ * headSet returns set with keys in requested range
+ */
+ public void testHeadSetContents() {
+ NavigableSet set = set5();
+ SortedSet sm = set.headSet(four);
+ assertTrue(sm.contains(one));
+ assertTrue(sm.contains(two));
+ assertTrue(sm.contains(three));
+ assertFalse(sm.contains(four));
+ assertFalse(sm.contains(five));
+ Iterator i = sm.iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(one, k);
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ k = (Integer)(i.next());
+ assertEquals(three, k);
+ assertFalse(i.hasNext());
+ sm.clear();
+ assertTrue(sm.isEmpty());
+ assertEquals(2, set.size());
+ assertEquals(four, set.first());
+ }
+
+ /**
+ * tailSet returns set with keys in requested range
+ */
+ public void testTailSetContents() {
+ NavigableSet set = set5();
+ SortedSet sm = set.tailSet(two);
+ assertFalse(sm.contains(one));
+ assertTrue(sm.contains(two));
+ assertTrue(sm.contains(three));
+ assertTrue(sm.contains(four));
+ assertTrue(sm.contains(five));
+ Iterator i = sm.iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(two, k);
+ k = (Integer)(i.next());
+ assertEquals(three, k);
+ k = (Integer)(i.next());
+ assertEquals(four, k);
+ k = (Integer)(i.next());
+ assertEquals(five, k);
+ assertFalse(i.hasNext());
+
+ SortedSet ssm = sm.tailSet(four);
+ assertEquals(four, ssm.first());
+ assertEquals(five, ssm.last());
+ assertTrue(ssm.remove(four));
+ assertEquals(1, ssm.size());
+ assertEquals(3, sm.size());
+ assertEquals(4, set.size());
+ }
+
+ /**
+ * size changes when elements added and removed
+ */
+ public void testDescendingSize() {
+ NavigableSet q = populatedSet(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(SIZE-i, q.size());
+ q.pollFirst();
+ }
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.size());
+ q.add(new Integer(i));
+ }
+ }
+
+ /**
+ * Add of comparable element succeeds
+ */
+ public void testDescendingAdd() {
+ NavigableSet q = dset0();
+ assertTrue(q.add(m6));
+ }
+
+ /**
+ * Add of duplicate element fails
+ */
+ public void testDescendingAddDup() {
+ NavigableSet q = dset0();
+ assertTrue(q.add(m6));
+ assertFalse(q.add(m6));
+ }
+
+ /**
+ * Add of non-Comparable throws CCE
+ */
+ public void testDescendingAddNonComparable() {
+ try {
+ NavigableSet q = dset0();
+ q.add(new Object());
+ q.add(new Object());
+ q.add(new Object());
+ shouldThrow();
+ } catch (ClassCastException success) {}
+ }
+
+ /**
+ * addAll(null) throws NPE
+ */
+ public void testDescendingAddAll1() {
+ try {
+ NavigableSet q = dset0();
+ q.addAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll of a collection with null elements throws NPE
+ */
+ public void testDescendingAddAll2() {
+ try {
+ NavigableSet q = dset0();
+ Integer[] ints = new Integer[SIZE];
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * addAll of a collection with any null elements throws NPE after
+ * possibly adding some elements
+ */
+ public void testDescendingAddAll3() {
+ try {
+ NavigableSet q = dset0();
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE-1; ++i)
+ ints[i] = new Integer(i+SIZE);
+ q.addAll(Arrays.asList(ints));
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * Set contains all elements of successful addAll
+ */
+ public void testDescendingAddAll5() {
+ Integer[] empty = new Integer[0];
+ Integer[] ints = new Integer[SIZE];
+ for (int i = 0; i < SIZE; ++i)
+ ints[i] = new Integer(SIZE-1- i);
+ NavigableSet q = dset0();
+ assertFalse(q.addAll(Arrays.asList(empty)));
+ assertTrue(q.addAll(Arrays.asList(ints)));
+ for (int i = 0; i < SIZE; ++i)
+ assertEquals(new Integer(i), q.pollFirst());
+ }
+
+ /**
+ * poll succeeds unless empty
+ */
+ public void testDescendingPoll() {
+ NavigableSet q = populatedSet(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertEquals(i, q.pollFirst());
+ }
+ assertNull(q.pollFirst());
+ }
+
+ /**
+ * remove(x) removes x and returns true if present
+ */
+ public void testDescendingRemoveElement() {
+ NavigableSet q = populatedSet(SIZE);
+ for (int i = 1; i < SIZE; i+=2) {
+ assertTrue(q.remove(new Integer(i)));
+ }
+ for (int i = 0; i < SIZE; i+=2) {
+ assertTrue(q.remove(new Integer(i)));
+ assertFalse(q.remove(new Integer(i+1)));
+ }
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * contains(x) reports true when elements added but not yet removed
+ */
+ public void testDescendingContains() {
+ NavigableSet q = populatedSet(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.contains(new Integer(i)));
+ q.pollFirst();
+ assertFalse(q.contains(new Integer(i)));
+ }
+ }
+
+ /**
+ * clear removes all elements
+ */
+ public void testDescendingClear() {
+ NavigableSet q = populatedSet(SIZE);
+ q.clear();
+ assertTrue(q.isEmpty());
+ assertEquals(0, q.size());
+ assertTrue(q.add(new Integer(1)));
+ assertFalse(q.isEmpty());
+ q.clear();
+ assertTrue(q.isEmpty());
+ }
+
+ /**
+ * containsAll(c) is true when c contains a subset of elements
+ */
+ public void testDescendingContainsAll() {
+ NavigableSet q = populatedSet(SIZE);
+ NavigableSet p = dset0();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(q.containsAll(p));
+ assertFalse(p.containsAll(q));
+ p.add(new Integer(i));
+ }
+ assertTrue(p.containsAll(q));
+ }
+
+ /**
+ * retainAll(c) retains only those elements of c and reports true if changed
+ */
+ public void testDescendingRetainAll() {
+ NavigableSet q = populatedSet(SIZE);
+ NavigableSet p = populatedSet(SIZE);
+ for (int i = 0; i < SIZE; ++i) {
+ boolean changed = q.retainAll(p);
+ if (i == 0)
+ assertFalse(changed);
+ else
+ assertTrue(changed);
+
+ assertTrue(q.containsAll(p));
+ assertEquals(SIZE-i, q.size());
+ p.pollFirst();
+ }
+ }
+
+ /**
+ * removeAll(c) removes only those elements of c and reports true if changed
+ */
+ public void testDescendingRemoveAll() {
+ for (int i = 1; i < SIZE; ++i) {
+ NavigableSet q = populatedSet(SIZE);
+ NavigableSet p = populatedSet(i);
+ assertTrue(q.removeAll(p));
+ assertEquals(SIZE-i, q.size());
+ for (int j = 0; j < i; ++j) {
+ Integer I = (Integer)(p.pollFirst());
+ assertFalse(q.contains(I));
+ }
+ }
+ }
+
+ /**
+ * lower returns preceding element
+ */
+ public void testDescendingLower() {
+ NavigableSet q = dset5();
+ Object e1 = q.lower(m3);
+ assertEquals(m2, e1);
+
+ Object e2 = q.lower(m6);
+ assertEquals(m5, e2);
+
+ Object e3 = q.lower(m1);
+ assertNull(e3);
+
+ Object e4 = q.lower(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * higher returns next element
+ */
+ public void testDescendingHigher() {
+ NavigableSet q = dset5();
+ Object e1 = q.higher(m3);
+ assertEquals(m4, e1);
+
+ Object e2 = q.higher(zero);
+ assertEquals(m1, e2);
+
+ Object e3 = q.higher(m5);
+ assertNull(e3);
+
+ Object e4 = q.higher(m6);
+ assertNull(e4);
+ }
+
+ /**
+ * floor returns preceding element
+ */
+ public void testDescendingFloor() {
+ NavigableSet q = dset5();
+ Object e1 = q.floor(m3);
+ assertEquals(m3, e1);
+
+ Object e2 = q.floor(m6);
+ assertEquals(m5, e2);
+
+ Object e3 = q.floor(m1);
+ assertEquals(m1, e3);
+
+ Object e4 = q.floor(zero);
+ assertNull(e4);
+ }
+
+ /**
+ * ceiling returns next element
+ */
+ public void testDescendingCeiling() {
+ NavigableSet q = dset5();
+ Object e1 = q.ceiling(m3);
+ assertEquals(m3, e1);
+
+ Object e2 = q.ceiling(zero);
+ assertEquals(m1, e2);
+
+ Object e3 = q.ceiling(m5);
+ assertEquals(m5, e3);
+
+ Object e4 = q.ceiling(m6);
+ assertNull(e4);
+ }
+
+ /**
+ * toArray contains all elements
+ */
+ public void testDescendingToArray() {
+ NavigableSet q = populatedSet(SIZE);
+ Object[] o = q.toArray();
+ Arrays.sort(o);
+ for (int i = 0; i < o.length; i++)
+ assertEquals(o[i], q.pollFirst());
+ }
+
+ /**
+ * toArray(a) contains all elements
+ */
+ public void testDescendingToArray2() {
+ NavigableSet q = populatedSet(SIZE);
+ Integer[] ints = new Integer[SIZE];
+ assertSame(ints, q.toArray(ints));
+ Arrays.sort(ints);
+ for (int i = 0; i < ints.length; i++)
+ assertEquals(ints[i], q.pollFirst());
+ }
+
+ /**
+ * iterator iterates through all elements
+ */
+ public void testDescendingIterator() {
+ NavigableSet q = populatedSet(SIZE);
+ int i = 0;
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ assertTrue(q.contains(it.next()));
+ ++i;
+ }
+ assertEquals(i, SIZE);
+ }
+
+ /**
+ * iterator of empty set has no elements
+ */
+ public void testDescendingEmptyIterator() {
+ NavigableSet q = dset0();
+ int i = 0;
+ Iterator it = q.iterator();
+ while (it.hasNext()) {
+ assertTrue(q.contains(it.next()));
+ ++i;
+ }
+ assertEquals(0, i);
+ }
+
+ /**
+ * iterator.remove removes current element
+ */
+ public void testDescendingIteratorRemove() {
+ final NavigableSet q = dset0();
+ q.add(new Integer(2));
+ q.add(new Integer(1));
+ q.add(new Integer(3));
+
+ Iterator it = q.iterator();
+ it.next();
+ it.remove();
+
+ it = q.iterator();
+ assertEquals(2, it.next());
+ assertEquals(3, it.next());
+ assertFalse(it.hasNext());
+ }
+
+ /**
+ * toString contains toStrings of elements
+ */
+ public void testDescendingToString() {
+ NavigableSet q = populatedSet(SIZE);
+ String s = q.toString();
+ for (int i = 0; i < SIZE; ++i) {
+ assertTrue(s.contains(String.valueOf(i)));
+ }
+ }
+
+ /**
+ * A deserialized serialized set has same elements
+ */
+ public void testDescendingSerialization() throws Exception {
+ NavigableSet x = dset5();
+ NavigableSet y = serialClone(x);
+
+ assertNotSame(x, y);
+ assertEquals(x.size(), y.size());
+ assertEquals(x.toString(), y.toString());
+ assertEquals(x, y);
+ assertEquals(y, x);
+ while (!x.isEmpty()) {
+ assertFalse(y.isEmpty());
+ assertEquals(x.pollFirst(), y.pollFirst());
+ }
+ assertTrue(y.isEmpty());
+ }
+
+ /**
+ * subSet returns set with keys in requested range
+ */
+ public void testDescendingSubSetContents() {
+ NavigableSet set = dset5();
+ SortedSet sm = set.subSet(m2, m4);
+ assertEquals(m2, sm.first());
+ assertEquals(m3, sm.last());
+ assertEquals(2, sm.size());
+ assertFalse(sm.contains(m1));
+ assertTrue(sm.contains(m2));
+ assertTrue(sm.contains(m3));
+ assertFalse(sm.contains(m4));
+ assertFalse(sm.contains(m5));
+ Iterator i = sm.iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(m2, k);
+ k = (Integer)(i.next());
+ assertEquals(m3, k);
+ assertFalse(i.hasNext());
+ Iterator j = sm.iterator();
+ j.next();
+ j.remove();
+ assertFalse(set.contains(m2));
+ assertEquals(4, set.size());
+ assertEquals(1, sm.size());
+ assertEquals(m3, sm.first());
+ assertEquals(m3, sm.last());
+ assertTrue(sm.remove(m3));
+ assertTrue(sm.isEmpty());
+ assertEquals(3, set.size());
+ }
+
+ public void testDescendingSubSetContents2() {
+ NavigableSet set = dset5();
+ SortedSet sm = set.subSet(m2, m3);
+ assertEquals(1, sm.size());
+ assertEquals(m2, sm.first());
+ assertEquals(m2, sm.last());
+ assertFalse(sm.contains(m1));
+ assertTrue(sm.contains(m2));
+ assertFalse(sm.contains(m3));
+ assertFalse(sm.contains(m4));
+ assertFalse(sm.contains(m5));
+ Iterator i = sm.iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(m2, k);
+ assertFalse(i.hasNext());
+ Iterator j = sm.iterator();
+ j.next();
+ j.remove();
+ assertFalse(set.contains(m2));
+ assertEquals(4, set.size());
+ assertEquals(0, sm.size());
+ assertTrue(sm.isEmpty());
+ assertFalse(sm.remove(m3));
+ assertEquals(4, set.size());
+ }
+
+ /**
+ * headSet returns set with keys in requested range
+ */
+ public void testDescendingHeadSetContents() {
+ NavigableSet set = dset5();
+ SortedSet sm = set.headSet(m4);
+ assertTrue(sm.contains(m1));
+ assertTrue(sm.contains(m2));
+ assertTrue(sm.contains(m3));
+ assertFalse(sm.contains(m4));
+ assertFalse(sm.contains(m5));
+ Iterator i = sm.iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(m1, k);
+ k = (Integer)(i.next());
+ assertEquals(m2, k);
+ k = (Integer)(i.next());
+ assertEquals(m3, k);
+ assertFalse(i.hasNext());
+ sm.clear();
+ assertTrue(sm.isEmpty());
+ assertEquals(2, set.size());
+ assertEquals(m4, set.first());
+ }
+
+ /**
+ * tailSet returns set with keys in requested range
+ */
+ public void testDescendingTailSetContents() {
+ NavigableSet set = dset5();
+ SortedSet sm = set.tailSet(m2);
+ assertFalse(sm.contains(m1));
+ assertTrue(sm.contains(m2));
+ assertTrue(sm.contains(m3));
+ assertTrue(sm.contains(m4));
+ assertTrue(sm.contains(m5));
+ Iterator i = sm.iterator();
+ Object k;
+ k = (Integer)(i.next());
+ assertEquals(m2, k);
+ k = (Integer)(i.next());
+ assertEquals(m3, k);
+ k = (Integer)(i.next());
+ assertEquals(m4, k);
+ k = (Integer)(i.next());
+ assertEquals(m5, k);
+ assertFalse(i.hasNext());
+
+ SortedSet ssm = sm.tailSet(m4);
+ assertEquals(m4, ssm.first());
+ assertEquals(m5, ssm.last());
+ assertTrue(ssm.remove(m4));
+ assertEquals(1, ssm.size());
+ assertEquals(3, sm.size());
+ assertEquals(4, set.size());
+ }
+
+ /**
+ * addAll is idempotent
+ */
+ public void testAddAll_idempotent() throws Exception {
+ Set x = populatedSet(SIZE);
+ Set y = new TreeSet(x);
+ y.addAll(x);
+ assertEquals(x, y);
+ assertEquals(y, x);
+ }
+
+}