--- jsr166/src/test/tck/CompletableFutureTest.java 2013/03/27 21:28:13 1.10 +++ jsr166/src/test/tck/CompletableFutureTest.java 2013/04/08 16:58:17 1.21 @@ -53,7 +53,10 @@ public class CompletableFutureTest exten catch (Throwable fail) { threadUnexpectedException(fail); } } - void checkCompletedNormally(CompletableFuture f, Object value) { + void checkCompletedNormally(CompletableFuture f, T value) { + try { + assertEquals(value, f.get(LONG_DELAY_MS, MILLISECONDS)); + } catch (Throwable fail) { threadUnexpectedException(fail); } try { assertEquals(value, f.join()); } catch (Throwable fail) { threadUnexpectedException(fail); } @@ -63,9 +66,6 @@ public class CompletableFutureTest exten try { assertEquals(value, f.get()); } catch (Throwable fail) { threadUnexpectedException(fail); } - try { - assertEquals(value, f.get(0L, SECONDS)); - } catch (Throwable fail) { threadUnexpectedException(fail); } assertTrue(f.isDone()); assertFalse(f.isCancelled()); assertTrue(f.toString().contains("[Completed normally]")); @@ -73,6 +73,12 @@ public class CompletableFutureTest exten void checkCompletedWithWrappedCFException(CompletableFuture f) { try { + f.get(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof CFException); + } catch (Throwable fail) { threadUnexpectedException(fail); } + try { f.join(); shouldThrow(); } catch (CompletionException success) { @@ -90,18 +96,18 @@ public class CompletableFutureTest exten } catch (ExecutionException success) { assertTrue(success.getCause() instanceof CFException); } catch (Throwable fail) { threadUnexpectedException(fail); } - try { - f.get(0L, SECONDS); - shouldThrow(); - } catch (ExecutionException success) { - assertTrue(success.getCause() instanceof CFException); - } catch (Throwable fail) { threadUnexpectedException(fail); } assertTrue(f.isDone()); assertFalse(f.isCancelled()); + assertTrue(f.toString().contains("[Completed exceptionally]")); } void checkCancelled(CompletableFuture f) { try { + f.get(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (CancellationException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + try { f.join(); shouldThrow(); } catch (CancellationException success) {} @@ -114,17 +120,19 @@ public class CompletableFutureTest exten shouldThrow(); } catch (CancellationException success) { } catch (Throwable fail) { threadUnexpectedException(fail); } - try { - f.get(0L, SECONDS); - shouldThrow(); - } catch (CancellationException success) { - } catch (Throwable fail) { threadUnexpectedException(fail); } assertTrue(f.isDone()); assertTrue(f.isCancelled()); + assertTrue(f.toString().contains("[Completed exceptionally]")); } void checkCompletedWithWrappedCancellationException(CompletableFuture f) { try { + f.get(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertTrue(success.getCause() instanceof CancellationException); + } catch (Throwable fail) { threadUnexpectedException(fail); } + try { f.join(); shouldThrow(); } catch (CompletionException success) { @@ -142,14 +150,9 @@ public class CompletableFutureTest exten } catch (ExecutionException success) { assertTrue(success.getCause() instanceof CancellationException); } catch (Throwable fail) { threadUnexpectedException(fail); } - try { - f.get(0L, SECONDS); - shouldThrow(); - } catch (ExecutionException success) { - assertTrue(success.getCause() instanceof CancellationException); - } catch (Throwable fail) { threadUnexpectedException(fail); } assertTrue(f.isDone()); assertFalse(f.isCancelled()); + assertTrue(f.toString().contains("[Completed exceptionally]")); } /** @@ -279,12 +282,14 @@ public class CompletableFutureTest exten checkCompletedNormally(f, "test"); } + // Choose non-commutative actions for better coverage + static final Supplier supplyOne = () -> Integer.valueOf(1); static final Function inc = (Integer x) -> Integer.valueOf(x.intValue() + 1); - static final BiFunction add = - (Integer x, Integer y) -> Integer.valueOf(x.intValue() + y.intValue()); + static final BiFunction subtract = + (Integer x, Integer y) -> Integer.valueOf(x.intValue() - y.intValue()); static final class IncAction implements Consumer { int value; public void accept(Integer x) { value = x.intValue() + 1; } @@ -325,15 +330,19 @@ public class CompletableFutureTest exten public void run() { ran = true; throw new CFException(); } } - static final class CompletableFutureInc implements Function> { + static final class CompletableFutureInc + implements Function> { + boolean ran; public CompletableFuture apply(Integer x) { + ran = true; CompletableFuture f = new CompletableFuture(); f.complete(Integer.valueOf(x.intValue() + 1)); return f; } } - static final class FailingCompletableFutureFunction implements Function> { + static final class FailingCompletableFutureFunction + implements Function> { boolean ran; public CompletableFuture apply(Integer x) { ran = true; throw new CFException(); @@ -342,7 +351,10 @@ public class CompletableFutureTest exten // Used for explicit executor tests static final class ThreadExecutor implements Executor { + AtomicInteger count = new AtomicInteger(0); + public void execute(Runnable r) { + count.getAndIncrement(); new Thread(r).start(); } } @@ -352,7 +364,9 @@ public class CompletableFutureTest exten } static final class IntegerHandler implements BiFunction { + boolean ran; public Integer apply(Integer x, Throwable t) { + ran = true; return (t == null) ? two : three; } } @@ -381,16 +395,33 @@ public class CompletableFutureTest exten * normal or exceptional completion of source */ public void testHandle() { - CompletableFuture f = new CompletableFuture(); - IntegerHandler r = new IntegerHandler(); - CompletableFuture g = f.handle(r); + CompletableFuture f, g; + IntegerHandler r; + + f = new CompletableFuture(); + f.completeExceptionally(new CFException()); + g = f.handle(r = new IntegerHandler()); + assertTrue(r.ran); + checkCompletedNormally(g, three); + + f = new CompletableFuture(); + g = f.handle(r = new IntegerHandler()); + assertFalse(r.ran); f.completeExceptionally(new CFException()); checkCompletedNormally(g, three); + assertTrue(r.ran); + + f = new CompletableFuture(); + f.complete(one); + g = f.handle(r = new IntegerHandler()); + assertTrue(r.ran); + checkCompletedNormally(g, two); f = new CompletableFuture(); - r = new IntegerHandler(); - g = f.handle(r); + g = f.handle(r = new IntegerHandler()); + assertFalse(r.ran); f.complete(one); + assertTrue(r.ran); checkCompletedNormally(g, two); } @@ -402,6 +433,7 @@ public class CompletableFutureTest exten CompletableFuture f = CompletableFuture.runAsync(r); assertNull(f.join()); assertTrue(r.ran); + checkCompletedNormally(f, null); } /** @@ -409,9 +441,12 @@ public class CompletableFutureTest exten */ public void testRunAsync2() { Noop r = new Noop(); - CompletableFuture f = CompletableFuture.runAsync(r, new ThreadExecutor()); + ThreadExecutor exec = new ThreadExecutor(); + CompletableFuture f = CompletableFuture.runAsync(r, exec); assertNull(f.join()); assertTrue(r.ran); + checkCompletedNormally(f, null); + assertEquals(1, exec.count.get()); } /** @@ -428,16 +463,20 @@ public class CompletableFutureTest exten * supplyAsync completes with result of supplier */ public void testSupplyAsync() { - CompletableFuture f = CompletableFuture.supplyAsync(supplyOne); + CompletableFuture f; + f = CompletableFuture.supplyAsync(supplyOne); assertEquals(f.join(), one); + checkCompletedNormally(f, one); } /** * supplyAsync with executor completes with result of supplier */ public void testSupplyAsync2() { - CompletableFuture f = CompletableFuture.supplyAsync(supplyOne, new ThreadExecutor()); + CompletableFuture f; + f = CompletableFuture.supplyAsync(supplyOne, new ThreadExecutor()); assertEquals(f.join(), one); + checkCompletedNormally(f, one); } /** @@ -593,24 +632,34 @@ public class CompletableFutureTest exten /** - * thenCombine result completes normally after normal completion of sources + * thenCombine result completes normally after normal completion + * of sources */ public void testThenCombine() { - CompletableFuture f = new CompletableFuture(); - CompletableFuture f2 = new CompletableFuture(); - CompletableFuture g = f.thenCombine(f2, add); - f.complete(one); - checkIncomplete(g); - f2.complete(two); - checkCompletedNormally(g, three); + CompletableFuture f, g, h; f = new CompletableFuture(); - f.complete(one); - f2 = new CompletableFuture(); - g = f.thenCombine(f2, add); - checkIncomplete(g); - f2.complete(two); - checkCompletedNormally(g, three); + g = new CompletableFuture(); + h = f.thenCombine(g, subtract); + f.complete(3); + checkIncomplete(h); + g.complete(1); + checkCompletedNormally(h, 2); + + f = new CompletableFuture(); + g = new CompletableFuture(); + h = f.thenCombine(g, subtract); + g.complete(1); + checkIncomplete(h); + f.complete(3); + checkCompletedNormally(h, 2); + + f = new CompletableFuture(); + g = new CompletableFuture(); + g.complete(1); + f.complete(3); + h = f.thenCombine(g, subtract); + checkCompletedNormally(h, 2); } /** @@ -618,19 +667,37 @@ public class CompletableFutureTest exten * completion of either source */ public void testThenCombine2() { - CompletableFuture f = new CompletableFuture(); - CompletableFuture f2 = new CompletableFuture(); - CompletableFuture g = f.thenCombine(f2, add); + CompletableFuture f, g, h; + + f = new CompletableFuture(); + g = new CompletableFuture(); + h = f.thenCombine(g, subtract); f.completeExceptionally(new CFException()); - f2.complete(two); - checkCompletedWithWrappedCFException(g); + checkIncomplete(h); + g.complete(1); + checkCompletedWithWrappedCFException(h); f = new CompletableFuture(); - f.complete(one); - f2 = new CompletableFuture(); - g = f.thenCombine(f2, add); - f2.completeExceptionally(new CFException()); - checkCompletedWithWrappedCFException(g); + g = new CompletableFuture(); + h = f.thenCombine(g, subtract); + g.completeExceptionally(new CFException()); + checkIncomplete(h); + f.complete(3); + checkCompletedWithWrappedCFException(h); + + f = new CompletableFuture(); + g = new CompletableFuture(); + f.complete(3); + g.completeExceptionally(new CFException()); + h = f.thenCombine(g, subtract); + checkCompletedWithWrappedCFException(h); + + f = new CompletableFuture(); + g = new CompletableFuture(); + f.completeExceptionally(new CFException()); + g.complete(3); + h = f.thenCombine(g, subtract); + checkCompletedWithWrappedCFException(h); } /** @@ -643,26 +710,40 @@ public class CompletableFutureTest exten CompletableFuture g = f.thenCombine(f2, r); f.complete(one); checkIncomplete(g); + assertFalse(r.ran); f2.complete(two); checkCompletedWithWrappedCFException(g); + assertTrue(r.ran); } /** * thenCombine result completes exceptionally if either source cancelled */ public void testThenCombine4() { - CompletableFuture f = new CompletableFuture(); - CompletableFuture f2 = new CompletableFuture(); - CompletableFuture g = f.thenCombine(f2, add); + CompletableFuture f, g, h; + + f = new CompletableFuture(); + g = new CompletableFuture(); + h = f.thenCombine(g, subtract); assertTrue(f.cancel(true)); - f2.complete(two); - checkCompletedWithWrappedCancellationException(g); + checkIncomplete(h); + g.complete(1); + checkCompletedWithWrappedCancellationException(h); + f = new CompletableFuture(); - f2 = new CompletableFuture(); - g = f.thenCombine(f2, add); - f.complete(one); - assertTrue(f2.cancel(true)); - checkCompletedWithWrappedCancellationException(g); + g = new CompletableFuture(); + h = f.thenCombine(g, subtract); + assertTrue(g.cancel(true)); + checkIncomplete(h); + f.complete(3); + checkCompletedWithWrappedCancellationException(h); + + f = new CompletableFuture(); + g = new CompletableFuture(); + assertTrue(f.cancel(true)); + assertTrue(g.cancel(true)); + h = f.thenCombine(g, subtract); + checkCompletedWithWrappedCancellationException(h); } /** @@ -1046,11 +1127,20 @@ public class CompletableFutureTest exten * thenCompose result completes normally after normal completion of source */ public void testThenCompose() { - CompletableFuture f = new CompletableFuture(); - CompletableFutureInc r = new CompletableFutureInc(); - CompletableFuture g = f.thenCompose(r); + CompletableFuture f, g; + CompletableFutureInc r; + + f = new CompletableFuture(); + g = f.thenCompose(r = new CompletableFutureInc()); + f.complete(one); + checkCompletedNormally(g, two); + assertTrue(r.ran); + + f = new CompletableFuture(); f.complete(one); + g = f.thenCompose(r = new CompletableFutureInc()); checkCompletedNormally(g, two); + assertTrue(r.ran); } /** @@ -1058,21 +1148,35 @@ public class CompletableFutureTest exten * completion of source */ public void testThenCompose2() { - CompletableFuture f = new CompletableFuture(); - CompletableFutureInc r = new CompletableFutureInc(); - CompletableFuture g = f.thenCompose(r); + CompletableFuture f, g; + CompletableFutureInc r; + + f = new CompletableFuture(); + g = f.thenCompose(r = new CompletableFutureInc()); f.completeExceptionally(new CFException()); checkCompletedWithWrappedCFException(g); + + f = new CompletableFuture(); + f.completeExceptionally(new CFException()); + g = f.thenCompose(r = new CompletableFutureInc()); + checkCompletedWithWrappedCFException(g); } /** * thenCompose result completes exceptionally if action does */ public void testThenCompose3() { - CompletableFuture f = new CompletableFuture(); - FailingCompletableFutureFunction r = new FailingCompletableFutureFunction(); - CompletableFuture g = f.thenCompose(r); + CompletableFuture f, g; + FailingCompletableFutureFunction r; + + f = new CompletableFuture(); + g = f.thenCompose(r = new FailingCompletableFutureFunction()); + f.complete(one); + checkCompletedWithWrappedCFException(g); + + f = new CompletableFuture(); f.complete(one); + g = f.thenCompose(r = new FailingCompletableFutureFunction()); checkCompletedWithWrappedCFException(g); } @@ -1080,10 +1184,17 @@ public class CompletableFutureTest exten * thenCompose result completes exceptionally if source cancelled */ public void testThenCompose4() { - CompletableFuture f = new CompletableFuture(); - CompletableFutureInc r = new CompletableFutureInc(); - CompletableFuture g = f.thenCompose(r); + CompletableFuture f, g; + CompletableFutureInc r; + + f = new CompletableFuture(); + g = f.thenCompose(r = new CompletableFutureInc()); + assertTrue(f.cancel(true)); + checkCompletedWithWrappedCancellationException(g); + + f = new CompletableFuture(); assertTrue(f.cancel(true)); + g = f.thenCompose(r = new CompletableFutureInc()); checkCompletedWithWrappedCancellationException(g); } @@ -1235,38 +1346,67 @@ public class CompletableFutureTest exten assertTrue(f.cancel(true)); checkCompletedWithWrappedCancellationException(g); } + /** * thenCombineAsync result completes normally after normal * completion of sources */ public void testThenCombineAsync() { - CompletableFuture f = new CompletableFuture(); - CompletableFuture f2 = new CompletableFuture(); - CompletableFuture g = f.thenCombineAsync(f2, add); - f.complete(one); - checkIncomplete(g); - f2.complete(two); - checkCompletedNormally(g, three); + CompletableFuture f, g, h; + + f = new CompletableFuture(); + g = new CompletableFuture(); + h = f.thenCombineAsync(g, subtract); + f.complete(3); + checkIncomplete(h); + g.complete(1); + checkCompletedNormally(h, 2); + + f = new CompletableFuture(); + g = new CompletableFuture(); + h = f.thenCombineAsync(g, subtract); + g.complete(1); + checkIncomplete(h); + f.complete(3); + checkCompletedNormally(h, 2); + + f = new CompletableFuture(); + g = new CompletableFuture(); + g.complete(1); + f.complete(3); + h = f.thenCombineAsync(g, subtract); + checkCompletedNormally(h, 2); } /** * thenCombineAsync result completes exceptionally after exceptional - * completion of source + * completion of either source */ public void testThenCombineAsync2() { - CompletableFuture f = new CompletableFuture(); - CompletableFuture f2 = new CompletableFuture(); - CompletableFuture g = f.thenCombineAsync(f2, add); + CompletableFuture f, g, h; + + f = new CompletableFuture(); + g = new CompletableFuture(); + h = f.thenCombineAsync(g, subtract); f.completeExceptionally(new CFException()); - f2.complete(two); - checkCompletedWithWrappedCFException(g); + checkIncomplete(h); + g.complete(1); + checkCompletedWithWrappedCFException(h); f = new CompletableFuture(); - f2 = new CompletableFuture(); - g = f.thenCombineAsync(f2, add); - f.complete(one); - f2.completeExceptionally(new CFException()); - checkCompletedWithWrappedCFException(g); + g = new CompletableFuture(); + h = f.thenCombineAsync(g, subtract); + g.completeExceptionally(new CFException()); + checkIncomplete(h); + f.complete(3); + checkCompletedWithWrappedCFException(h); + + f = new CompletableFuture(); + g = new CompletableFuture(); + g.completeExceptionally(new CFException()); + f.complete(3); + h = f.thenCombineAsync(g, subtract); + checkCompletedWithWrappedCFException(h); } /** @@ -1279,27 +1419,47 @@ public class CompletableFutureTest exten CompletableFuture g = f.thenCombineAsync(f2, r); f.complete(one); checkIncomplete(g); + assertFalse(r.ran); f2.complete(two); checkCompletedWithWrappedCFException(g); + assertTrue(r.ran); } /** * thenCombineAsync result completes exceptionally if either source cancelled */ public void testThenCombineAsync4() { - CompletableFuture f = new CompletableFuture(); - CompletableFuture f2 = new CompletableFuture(); - CompletableFuture g = f.thenCombineAsync(f2, add); + CompletableFuture f, g, h; + + f = new CompletableFuture(); + g = new CompletableFuture(); + h = f.thenCombineAsync(g, subtract); assertTrue(f.cancel(true)); - f2.complete(two); - checkCompletedWithWrappedCancellationException(g); + checkIncomplete(h); + g.complete(1); + checkCompletedWithWrappedCancellationException(h); f = new CompletableFuture(); - f2 = new CompletableFuture(); - g = f.thenCombineAsync(f2, add); - f.complete(one); - assertTrue(f2.cancel(true)); - checkCompletedWithWrappedCancellationException(g); + g = new CompletableFuture(); + h = f.thenCombineAsync(g, subtract); + assertTrue(g.cancel(true)); + checkIncomplete(h); + f.complete(3); + checkCompletedWithWrappedCancellationException(h); + + f = new CompletableFuture(); + g = new CompletableFuture(); + g.complete(3); + assertTrue(f.cancel(true)); + h = f.thenCombineAsync(g, subtract); + checkCompletedWithWrappedCancellationException(h); + + f = new CompletableFuture(); + g = new CompletableFuture(); + f.complete(3); + assertTrue(g.cancel(true)); + h = f.thenCombineAsync(g, subtract); + checkCompletedWithWrappedCancellationException(h); } /** @@ -1669,11 +1829,18 @@ public class CompletableFutureTest exten * completion of source */ public void testThenComposeAsync() { - CompletableFuture f = new CompletableFuture(); - CompletableFutureInc r = new CompletableFutureInc(); - CompletableFuture g = f.thenComposeAsync(r); + CompletableFuture f, g; + CompletableFutureInc r; + + f = new CompletableFuture(); + g = f.thenComposeAsync(r = new CompletableFutureInc()); f.complete(one); checkCompletedNormally(g, two); + + f = new CompletableFuture(); + f.complete(one); + g = f.thenComposeAsync(r = new CompletableFutureInc()); + checkCompletedNormally(g, two); } /** @@ -1681,21 +1848,37 @@ public class CompletableFutureTest exten * exceptional completion of source */ public void testThenComposeAsync2() { - CompletableFuture f = new CompletableFuture(); - CompletableFutureInc r = new CompletableFutureInc(); - CompletableFuture g = f.thenComposeAsync(r); + CompletableFuture f, g; + CompletableFutureInc r; + + f = new CompletableFuture(); + g = f.thenComposeAsync(r = new CompletableFutureInc()); + f.completeExceptionally(new CFException()); + checkCompletedWithWrappedCFException(g); + assertFalse(r.ran); + + f = new CompletableFuture(); f.completeExceptionally(new CFException()); + g = f.thenComposeAsync(r = new CompletableFutureInc()); checkCompletedWithWrappedCFException(g); + assertFalse(r.ran); } /** * thenComposeAsync result completes exceptionally if action does */ public void testThenComposeAsync3() { - CompletableFuture f = new CompletableFuture(); - FailingCompletableFutureFunction r = new FailingCompletableFutureFunction(); - CompletableFuture g = f.thenComposeAsync(r); + CompletableFuture f, g; + FailingCompletableFutureFunction r; + + f = new CompletableFuture(); + g = f.thenComposeAsync(r = new FailingCompletableFutureFunction()); + f.complete(one); + checkCompletedWithWrappedCFException(g); + + f = new CompletableFuture(); f.complete(one); + g = f.thenComposeAsync(r = new FailingCompletableFutureFunction()); checkCompletedWithWrappedCFException(g); } @@ -1703,10 +1886,17 @@ public class CompletableFutureTest exten * thenComposeAsync result completes exceptionally if source cancelled */ public void testThenComposeAsync4() { - CompletableFuture f = new CompletableFuture(); - CompletableFutureInc r = new CompletableFutureInc(); - CompletableFuture g = f.thenComposeAsync(r); + CompletableFuture f, g; + CompletableFutureInc r; + + f = new CompletableFuture(); + g = f.thenComposeAsync(r = new CompletableFutureInc()); + assertTrue(f.cancel(true)); + checkCompletedWithWrappedCancellationException(g); + + f = new CompletableFuture(); assertTrue(f.cancel(true)); + g = f.thenComposeAsync(r = new CompletableFutureInc()); checkCompletedWithWrappedCancellationException(g); } @@ -1858,38 +2048,77 @@ public class CompletableFutureTest exten assertTrue(f.cancel(true)); checkCompletedWithWrappedCancellationException(g); } + /** * thenCombineAsync result completes normally after normal * completion of sources */ public void testThenCombineAsyncE() { - CompletableFuture f = new CompletableFuture(); - CompletableFuture f2 = new CompletableFuture(); - CompletableFuture g = f.thenCombineAsync(f2, add, new ThreadExecutor()); - f.complete(one); - checkIncomplete(g); - f2.complete(two); - checkCompletedNormally(g, three); + CompletableFuture f, g, h; + ThreadExecutor e = new ThreadExecutor(); + int count = 0; + + f = new CompletableFuture(); + g = new CompletableFuture(); + h = f.thenCombineAsync(g, subtract, e); + f.complete(3); + checkIncomplete(h); + g.complete(1); + checkCompletedNormally(h, 2); + assertEquals(++count, e.count.get()); + + f = new CompletableFuture(); + g = new CompletableFuture(); + h = f.thenCombineAsync(g, subtract, e); + g.complete(1); + checkIncomplete(h); + f.complete(3); + checkCompletedNormally(h, 2); + assertEquals(++count, e.count.get()); + + f = new CompletableFuture(); + g = new CompletableFuture(); + g.complete(1); + f.complete(3); + h = f.thenCombineAsync(g, subtract, e); + checkCompletedNormally(h, 2); + assertEquals(++count, e.count.get()); } /** * thenCombineAsync result completes exceptionally after exceptional - * completion of source + * completion of either source */ public void testThenCombineAsync2E() { - CompletableFuture f = new CompletableFuture(); - CompletableFuture f2 = new CompletableFuture(); - CompletableFuture g = f.thenCombineAsync(f2, add, new ThreadExecutor()); + CompletableFuture f, g, h; + ThreadExecutor e = new ThreadExecutor(); + int count = 0; + + f = new CompletableFuture(); + g = new CompletableFuture(); + h = f.thenCombineAsync(g, subtract, e); f.completeExceptionally(new CFException()); - f2.complete(two); - checkCompletedWithWrappedCFException(g); + checkIncomplete(h); + g.complete(1); + checkCompletedWithWrappedCFException(h); f = new CompletableFuture(); - f2 = new CompletableFuture(); - g = f.thenCombineAsync(f2, add, new ThreadExecutor()); - f.complete(one); - f2.completeExceptionally(new CFException()); - checkCompletedWithWrappedCFException(g); + g = new CompletableFuture(); + h = f.thenCombineAsync(g, subtract, e); + g.completeExceptionally(new CFException()); + checkIncomplete(h); + f.complete(3); + checkCompletedWithWrappedCFException(h); + + f = new CompletableFuture(); + g = new CompletableFuture(); + g.completeExceptionally(new CFException()); + h = f.thenCombineAsync(g, subtract, e); + checkIncomplete(h); + f.complete(3); + checkCompletedWithWrappedCFException(h); + + assertEquals(0, e.count.get()); } /** @@ -1902,27 +2131,51 @@ public class CompletableFutureTest exten CompletableFuture g = f.thenCombineAsync(f2, r, new ThreadExecutor()); f.complete(one); checkIncomplete(g); + assertFalse(r.ran); f2.complete(two); checkCompletedWithWrappedCFException(g); + assertTrue(r.ran); } /** * thenCombineAsync result completes exceptionally if either source cancelled */ public void testThenCombineAsync4E() { - CompletableFuture f = new CompletableFuture(); - CompletableFuture f2 = new CompletableFuture(); - CompletableFuture g = f.thenCombineAsync(f2, add, new ThreadExecutor()); + CompletableFuture f, g, h; + ThreadExecutor e = new ThreadExecutor(); + + f = new CompletableFuture(); + g = new CompletableFuture(); + h = f.thenCombineAsync(g, subtract, e); assertTrue(f.cancel(true)); - f2.complete(two); - checkCompletedWithWrappedCancellationException(g); + checkIncomplete(h); + g.complete(1); + checkCompletedWithWrappedCancellationException(h); f = new CompletableFuture(); - f2 = new CompletableFuture(); - g = f.thenCombineAsync(f2, add, new ThreadExecutor()); - f.complete(one); - assertTrue(f2.cancel(true)); - checkCompletedWithWrappedCancellationException(g); + g = new CompletableFuture(); + h = f.thenCombineAsync(g, subtract, e); + assertTrue(g.cancel(true)); + checkIncomplete(h); + f.complete(3); + checkCompletedWithWrappedCancellationException(h); + + f = new CompletableFuture(); + g = new CompletableFuture(); + assertTrue(g.cancel(true)); + h = f.thenCombineAsync(g, subtract, e); + checkIncomplete(h); + f.complete(3); + checkCompletedWithWrappedCancellationException(h); + + f = new CompletableFuture(); + g = new CompletableFuture(); + assertTrue(f.cancel(true)); + assertTrue(g.cancel(true)); + h = f.thenCombineAsync(g, subtract, e); + checkCompletedWithWrappedCancellationException(h); + + assertEquals(0, e.count.get()); } /** @@ -2370,7 +2623,7 @@ public class CompletableFutureTest exten } /** - * allOf returns a future completed when any components complete + * anyOf returns a future completed when any components complete */ public void testAnyOf() throws Exception { for (int k = 1; k < 20; ++k) { @@ -2392,39 +2645,106 @@ public class CompletableFutureTest exten public void testNPE() { CompletableFuture f = new CompletableFuture(); CompletableFuture g = new CompletableFuture(); - CompletableFuture h; - try { h = f.thenApply(null); } catch (NullPointerException ok) {} - try { h = f.thenAccept(null); } catch (NullPointerException ok) {} - try { h = f.thenRun(null); } catch (NullPointerException ok) {} - try { h = f.thenCombine(g, null); } catch (NullPointerException ok) {} - try { h = f.thenCombine(null, null); } catch (NullPointerException ok) {} - try { h = f.applyToEither(g, null); } catch (NullPointerException ok) {} - try { h = f.applyToEither(null, null); } catch (NullPointerException ok) {} - try { h = f.thenAcceptBoth(g, null); } catch (NullPointerException ok) {} - try { h = f.thenAcceptBoth(null, null); } catch (NullPointerException ok) {} - try { h = f.runAfterEither(g, null); } catch (NullPointerException ok) {} - try { h = f.runAfterEither(null, null); } catch (NullPointerException ok) {} - try { h = f.runAfterBoth(g, null); } catch (NullPointerException ok) {} - try { h = f.runAfterBoth(null, null); } catch (NullPointerException ok) {} - try { h = f.exceptionally(null); } catch (NullPointerException ok) {} - try { h = f.handle(null); } catch (NullPointerException ok) {} - try { h = f.thenCompose(null); } catch (NullPointerException ok) {} - - try { h = f.thenApplyAsync(null); } catch (NullPointerException ok) {} - try { h = f.thenAcceptAsync(null); } catch (NullPointerException ok) {} - try { h = f.thenRunAsync(null); } catch (NullPointerException ok) {} - try { h = f.thenCombineAsync(g, null); } catch (NullPointerException ok) {} - try { h = f.thenCombineAsync(null, null); } catch (NullPointerException ok) {} - try { h = f.applyToEitherAsync(g, null); } catch (NullPointerException ok) {} - try { h = f.applyToEitherAsync(null, null); } catch (NullPointerException ok) {} - try { h = f.thenAcceptBothAsync(g, null); } catch (NullPointerException ok) {} - try { h = f.thenAcceptBothAsync(null, null); } catch (NullPointerException ok) {} - try { h = f.runAfterEitherAsync(g, null); } catch (NullPointerException ok) {} - try { h = f.runAfterEitherAsync(null, null); } catch (NullPointerException ok) {} - try { h = f.runAfterBothAsync(g, null); } catch (NullPointerException ok) {} - try { h = f.runAfterBothAsync(null, null); } catch (NullPointerException ok) {} + CompletableFuture nullFuture = (CompletableFuture)null; + CompletableFuture h; + ThreadExecutor exec = new ThreadExecutor(); + + Runnable[] throwingActions = { + () -> { CompletableFuture.supplyAsync(null); }, + () -> { CompletableFuture.supplyAsync(null, exec); }, + () -> { CompletableFuture.supplyAsync(supplyOne, null); }, + + () -> { CompletableFuture.runAsync(null); }, + () -> { CompletableFuture.runAsync(null, exec); }, + () -> { CompletableFuture.runAsync(() -> {}, null); }, + + () -> { f.completeExceptionally(null); }, + + () -> { f.thenApply(null); }, + () -> { f.thenApplyAsync(null); }, + () -> { f.thenApplyAsync((x) -> x, null); }, + () -> { f.thenApplyAsync(null, exec); }, + + () -> { f.thenAccept(null); }, + () -> { f.thenAcceptAsync(null); }, + () -> { f.thenAcceptAsync((x) -> { ; }, null); }, + () -> { f.thenAcceptAsync(null, exec); }, + + () -> { f.thenRun(null); }, + () -> { f.thenRunAsync(null); }, + () -> { f.thenRunAsync(() -> { ; }, null); }, + () -> { f.thenRunAsync(null, exec); }, + + () -> { f.thenCombine(g, null); }, + () -> { f.thenCombineAsync(g, null); }, + () -> { f.thenCombineAsync(g, null, exec); }, + () -> { f.thenCombine(nullFuture, (x, y) -> x); }, + () -> { f.thenCombineAsync(nullFuture, (x, y) -> x); }, + () -> { f.thenCombineAsync(nullFuture, (x, y) -> x, exec); }, + () -> { f.thenCombineAsync(g, (x, y) -> x, null); }, + + () -> { f.thenAcceptBoth(g, null); }, + () -> { f.thenAcceptBothAsync(g, null); }, + () -> { f.thenAcceptBothAsync(g, null, exec); }, + () -> { f.thenAcceptBoth(nullFuture, (x, y) -> {}); }, + () -> { f.thenAcceptBothAsync(nullFuture, (x, y) -> {}); }, + () -> { f.thenAcceptBothAsync(nullFuture, (x, y) -> {}, exec); }, + () -> { f.thenAcceptBothAsync(g, (x, y) -> {}, null); }, + + () -> { f.runAfterBoth(g, null); }, + () -> { f.runAfterBothAsync(g, null); }, + () -> { f.runAfterBothAsync(g, null, exec); }, + () -> { f.runAfterBoth(nullFuture, () -> {}); }, + () -> { f.runAfterBothAsync(nullFuture, () -> {}); }, + () -> { f.runAfterBothAsync(nullFuture, () -> {}, exec); }, + () -> { f.runAfterBothAsync(g, () -> {}, null); }, + + () -> { f.applyToEither(g, null); }, + () -> { f.applyToEitherAsync(g, null); }, + () -> { f.applyToEitherAsync(g, null, exec); }, + () -> { f.applyToEither(nullFuture, (x) -> x); }, + () -> { f.applyToEitherAsync(nullFuture, (x) -> x); }, + () -> { f.applyToEitherAsync(nullFuture, (x) -> x, exec); }, + () -> { f.applyToEitherAsync(g, (x) -> x, null); }, + + () -> { f.acceptEither(g, null); }, + () -> { f.acceptEitherAsync(g, null); }, + () -> { f.acceptEitherAsync(g, null, exec); }, + () -> { f.acceptEither(nullFuture, (x) -> {}); }, + () -> { f.acceptEitherAsync(nullFuture, (x) -> {}); }, + () -> { f.acceptEitherAsync(nullFuture, (x) -> {}, exec); }, + () -> { f.acceptEitherAsync(g, (x) -> {}, null); }, + + () -> { f.runAfterEither(g, null); }, + () -> { f.runAfterEitherAsync(g, null); }, + () -> { f.runAfterEitherAsync(g, null, exec); }, + () -> { f.runAfterEither(nullFuture, () -> {}); }, + () -> { f.runAfterEitherAsync(nullFuture, () -> {}); }, + () -> { f.runAfterEitherAsync(nullFuture, () -> {}, exec); }, + () -> { f.runAfterEitherAsync(g, () -> {}, null); }, + + () -> { f.thenCompose(null); }, + () -> { f.thenComposeAsync(null); }, + () -> { f.thenComposeAsync(new CompletableFutureInc(), null); }, + () -> { f.thenComposeAsync(null, exec); }, + + () -> { f.exceptionally(null); }, + + () -> { f.handle(null); }, + + () -> { CompletableFuture.allOf((CompletableFuture)null); }, + () -> { CompletableFuture.allOf((CompletableFuture[])null); }, + () -> { CompletableFuture.allOf(f, null); }, + () -> { CompletableFuture.allOf(null, f); }, + + () -> { CompletableFuture.anyOf((CompletableFuture)null); }, + () -> { CompletableFuture.anyOf((CompletableFuture[])null); }, + () -> { CompletableFuture.anyOf(f, null); }, + () -> { CompletableFuture.anyOf(null, f); }, + }; + assertThrows(NullPointerException.class, throwingActions); + assertEquals(0, exec.count.get()); } - }