--- jsr166/src/test/tck/CompletableFutureTest.java 2013/04/20 23:28:35 1.25 +++ jsr166/src/test/tck/CompletableFutureTest.java 2014/05/26 17:25:36 1.32 @@ -68,6 +68,7 @@ public class CompletableFutureTest exten } catch (Throwable fail) { threadUnexpectedException(fail); } assertTrue(f.isDone()); assertFalse(f.isCancelled()); + assertFalse(f.isCompletedExceptionally()); assertTrue(f.toString().contains("[Completed normally]")); } @@ -121,6 +122,7 @@ public class CompletableFutureTest exten } catch (CancellationException success) { } catch (Throwable fail) { threadUnexpectedException(fail); } assertTrue(f.isDone()); + assertTrue(f.isCompletedExceptionally()); assertTrue(f.isCancelled()); assertTrue(f.toString().contains("[Completed exceptionally]")); } @@ -152,6 +154,7 @@ public class CompletableFutureTest exten } catch (Throwable fail) { threadUnexpectedException(fail); } assertTrue(f.isDone()); assertFalse(f.isCancelled()); + assertTrue(f.isCompletedExceptionally()); assertTrue(f.toString().contains("[Completed exceptionally]")); } @@ -256,7 +259,6 @@ public class CompletableFutureTest exten assertEquals(g.getNumberOfDependents(), 0); } - /** * toString indicates current completion state */ @@ -371,10 +373,9 @@ public class CompletableFutureTest exten } } - /** * exceptionally action completes with function value on source - * exception; otherwise with source value + * exception; otherwise with source value */ public void testExceptionally() { CompletableFuture f = new CompletableFuture<>(); @@ -660,7 +661,6 @@ public class CompletableFutureTest exten checkCompletedWithWrappedCancellationException(g); } - /** * thenCombine result completes normally after normal completion * of sources @@ -1168,7 +1168,6 @@ public class CompletableFutureTest exten checkCompletedWithWrappedCancellationException(g); } - /** * runAfterEither result completes normally after normal completion * of either source @@ -1317,7 +1316,6 @@ public class CompletableFutureTest exten checkCompletedWithWrappedCancellationException(g); } - // asyncs /** @@ -1350,8 +1348,7 @@ public class CompletableFutureTest exten try { g.join(); shouldThrow(); - } catch (Exception ok) { - } + } catch (CompletionException success) {} checkCompletedWithWrappedCFException(g); } @@ -2085,7 +2082,6 @@ public class CompletableFutureTest exten checkCompletedWithWrappedCancellationException(g); } - // async with explicit executors /** @@ -2118,8 +2114,7 @@ public class CompletableFutureTest exten try { g.join(); shouldThrow(); - } catch (Exception ok) { - } + } catch (CompletionException success) {} checkCompletedWithWrappedCFException(g); } @@ -2936,101 +2931,332 @@ public class CompletableFutureTest exten 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); }, + () -> 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), + + () -> f.obtrudeException(null), }; assertThrows(NullPointerException.class, throwingActions); assertEquals(0, exec.count.get()); } + /** + * toCompletableFuture returns this CompletableFuture. + */ + public void testToCompletableFuture() { + CompletableFuture f = new CompletableFuture<>(); + assertSame(f, f.toCompletableFuture()); + } + + /** + * whenComplete action executes on normal completion, propagating + * source result. + */ + public void testWhenComplete1() { + final AtomicInteger a = new AtomicInteger(); + CompletableFuture f = new CompletableFuture<>(); + CompletableFuture g = + f.whenComplete((Integer x, Throwable t) -> a.getAndIncrement()); + f.complete(three); + checkCompletedNormally(f, three); + checkCompletedNormally(g, three); + assertEquals(a.get(), 1); + } + + /** + * whenComplete action executes on exceptional completion, propagating + * source result. + */ + public void testWhenComplete2() { + final AtomicInteger a = new AtomicInteger(); + CompletableFuture f = new CompletableFuture<>(); + CompletableFuture g = + f.whenComplete((Integer x, Throwable t) -> a.getAndIncrement()); + f.completeExceptionally(new CFException()); + assertTrue(f.isCompletedExceptionally()); + assertTrue(g.isCompletedExceptionally()); + assertEquals(a.get(), 1); + } + + /** + * If a whenComplete action throws an exception when triggered by + * a normal completion, it completes exceptionally + */ + public void testWhenComplete3() { + CompletableFuture f = new CompletableFuture<>(); + CompletableFuture g = + f.whenComplete((Integer x, Throwable t) -> + { throw new CFException(); } ); + f.complete(three); + checkCompletedNormally(f, three); + assertTrue(g.isCompletedExceptionally()); + checkCompletedWithWrappedCFException(g); + } + + /** + * whenCompleteAsync action executes on normal completion, propagating + * source result. + */ + public void testWhenCompleteAsync1() { + final AtomicInteger a = new AtomicInteger(); + CompletableFuture f = new CompletableFuture<>(); + CompletableFuture g = + f.whenCompleteAsync((Integer x, Throwable t) -> a.getAndIncrement()); + f.complete(three); + checkCompletedNormally(f, three); + checkCompletedNormally(g, three); + assertEquals(a.get(), 1); + } + + /** + * whenCompleteAsync action executes on exceptional completion, propagating + * source result. + */ + public void testWhenCompleteAsync2() { + final AtomicInteger a = new AtomicInteger(); + CompletableFuture f = new CompletableFuture<>(); + CompletableFuture g = + f.whenCompleteAsync((Integer x, Throwable t) -> a.getAndIncrement()); + f.completeExceptionally(new CFException()); + checkCompletedWithWrappedCFException(f); + checkCompletedWithWrappedCFException(g); + } + + /** + * If a whenCompleteAsync action throws an exception when + * triggered by a normal completion, it completes exceptionally + */ + public void testWhenCompleteAsync3() { + CompletableFuture f = new CompletableFuture<>(); + CompletableFuture g = + f.whenCompleteAsync((Integer x, Throwable t) -> + { throw new CFException(); } ); + f.complete(three); + checkCompletedNormally(f, three); + checkCompletedWithWrappedCFException(g); + } + + /** + * whenCompleteAsync action executes on normal completion, propagating + * source result. + */ + public void testWhenCompleteAsync1e() { + final AtomicInteger a = new AtomicInteger(); + ThreadExecutor exec = new ThreadExecutor(); + CompletableFuture f = new CompletableFuture<>(); + CompletableFuture g = + f.whenCompleteAsync((Integer x, Throwable t) -> a.getAndIncrement(), + exec); + f.complete(three); + checkCompletedNormally(f, three); + checkCompletedNormally(g, three); + assertEquals(a.get(), 1); + } + + /** + * whenCompleteAsync action executes on exceptional completion, propagating + * source result. + */ + public void testWhenCompleteAsync2e() { + final AtomicInteger a = new AtomicInteger(); + ThreadExecutor exec = new ThreadExecutor(); + CompletableFuture f = new CompletableFuture<>(); + CompletableFuture g = + f.whenCompleteAsync((Integer x, Throwable t) -> a.getAndIncrement(), + exec); + f.completeExceptionally(new CFException()); + checkCompletedWithWrappedCFException(f); + checkCompletedWithWrappedCFException(g); + } + + /** + * If a whenCompleteAsync action throws an exception when triggered + * by a normal completion, it completes exceptionally + */ + public void testWhenCompleteAsync3e() { + ThreadExecutor exec = new ThreadExecutor(); + CompletableFuture f = new CompletableFuture<>(); + CompletableFuture g = + f.whenCompleteAsync((Integer x, Throwable t) -> + { throw new CFException(); }, + exec); + f.complete(three); + checkCompletedNormally(f, three); + checkCompletedWithWrappedCFException(g); + } + + /** + * handleAsync action completes normally with function value on + * either normal or exceptional completion of source + */ + public void testHandleAsync() { + CompletableFuture f, g; + IntegerHandler r; + + f = new CompletableFuture<>(); + g = f.handleAsync(r = new IntegerHandler()); + assertFalse(r.ran); + f.completeExceptionally(new CFException()); + checkCompletedWithWrappedCFException(f); + checkCompletedNormally(g, three); + assertTrue(r.ran); + + f = new CompletableFuture<>(); + g = f.handleAsync(r = new IntegerHandler()); + assertFalse(r.ran); + f.completeExceptionally(new CFException()); + checkCompletedWithWrappedCFException(f); + checkCompletedNormally(g, three); + assertTrue(r.ran); + + f = new CompletableFuture<>(); + g = f.handleAsync(r = new IntegerHandler()); + assertFalse(r.ran); + f.complete(one); + checkCompletedNormally(f, one); + checkCompletedNormally(g, two); + assertTrue(r.ran); + + f = new CompletableFuture<>(); + g = f.handleAsync(r = new IntegerHandler()); + assertFalse(r.ran); + f.complete(one); + checkCompletedNormally(f, one); + checkCompletedNormally(g, two); + assertTrue(r.ran); + } + + /** + * handleAsync action with Executor completes normally with + * function value on either normal or exceptional completion of + * source + */ + public void testHandleAsync2() { + CompletableFuture f, g; + ThreadExecutor exec = new ThreadExecutor(); + IntegerHandler r; + + f = new CompletableFuture<>(); + g = f.handleAsync(r = new IntegerHandler(), exec); + assertFalse(r.ran); + f.completeExceptionally(new CFException()); + checkCompletedWithWrappedCFException(f); + checkCompletedNormally(g, three); + assertTrue(r.ran); + + f = new CompletableFuture<>(); + g = f.handleAsync(r = new IntegerHandler(), exec); + assertFalse(r.ran); + f.completeExceptionally(new CFException()); + checkCompletedWithWrappedCFException(f); + checkCompletedNormally(g, three); + assertTrue(r.ran); + + f = new CompletableFuture<>(); + g = f.handleAsync(r = new IntegerHandler(), exec); + assertFalse(r.ran); + f.complete(one); + checkCompletedNormally(f, one); + checkCompletedNormally(g, two); + assertTrue(r.ran); + + f = new CompletableFuture<>(); + g = f.handleAsync(r = new IntegerHandler(), exec); + assertFalse(r.ran); + f.complete(one); + checkCompletedNormally(f, one); + checkCompletedNormally(g, two); + assertTrue(r.ran); + } + }