--- jsr166/src/test/tck/CompletableFutureTest.java 2018/09/17 11:50:55 1.198 +++ jsr166/src/test/tck/CompletableFutureTest.java 2018/09/24 18:09:30 1.214 @@ -551,9 +551,7 @@ public class CompletableFutureTest exten public CompletableFuture apply(Integer x) { invoked(); value = x; - CompletableFuture f = new CompletableFuture<>(); - assertTrue(f.complete(inc(x))); - return f; + return CompletableFuture.completedFuture(inc(x)); } } @@ -574,9 +572,7 @@ public class CompletableFutureTest exten ExceptionalCompletableFutureFunction(ExecutionMode m) { super(m); } public CompletionStage apply(Throwable x) { invoked(); - CompletableFuture d = new CompletableFuture(); - d.complete(value); - return d; + return CompletableFuture.completedFuture(value); } } @@ -930,12 +926,10 @@ public class CompletableFutureTest exten for (boolean createIncomplete : new boolean[] { true, false }) for (Integer v1 : new Integer[] { 1, null }) { - final AtomicInteger a = new AtomicInteger(0); final CompletableFuture f = new CompletableFuture<>(); if (!createIncomplete) assertTrue(f.complete(v1)); final CompletableFuture g = m.exceptionally (f, (Throwable t) -> { - a.getAndIncrement(); threadFail("should not be called"); return null; // unreached }); @@ -943,7 +937,6 @@ public class CompletableFutureTest exten checkCompletedNormally(g, v1); checkCompletedNormally(f, v1); - assertEquals(0, a.get()); }} /** @@ -3206,7 +3199,6 @@ public class CompletableFutureTest exten public void testExceptionallyCompose_actionFailed() { for (ExecutionMode m : ExecutionMode.values()) for (boolean createIncomplete : new boolean[] { true, false }) - for (Integer v1 : new Integer[] { 1, null }) { final CFException ex = new CFException(); final CompletableFuture f = new CompletableFuture<>(); @@ -3221,6 +3213,58 @@ public class CompletableFutureTest exten r.assertInvoked(); }} + /** + * exceptionallyCompose result completes exceptionally if the + * result of the action does + */ + public void testExceptionallyCompose_actionReturnsFailingFuture() { + for (ExecutionMode m : ExecutionMode.values()) + for (int order = 0; order < 6; order++) + { + final CFException ex0 = new CFException(); + final CFException ex = new CFException(); + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final CompletableFuture h; + // Test all permutations of orders + switch (order) { + case 0: + assertTrue(f.completeExceptionally(ex0)); + assertTrue(g.completeExceptionally(ex)); + h = m.exceptionallyCompose(f, (x -> g)); + break; + case 1: + assertTrue(f.completeExceptionally(ex0)); + h = m.exceptionallyCompose(f, (x -> g)); + assertTrue(g.completeExceptionally(ex)); + break; + case 2: + assertTrue(g.completeExceptionally(ex)); + assertTrue(f.completeExceptionally(ex0)); + h = m.exceptionallyCompose(f, (x -> g)); + break; + case 3: + assertTrue(g.completeExceptionally(ex)); + h = m.exceptionallyCompose(f, (x -> g)); + assertTrue(f.completeExceptionally(ex0)); + break; + case 4: + h = m.exceptionallyCompose(f, (x -> g)); + assertTrue(f.completeExceptionally(ex0)); + assertTrue(g.completeExceptionally(ex)); + break; + case 5: + h = m.exceptionallyCompose(f, (x -> g)); + assertTrue(f.completeExceptionally(ex0)); + assertTrue(g.completeExceptionally(ex)); + break; + default: throw new AssertionError(); + } + + checkCompletedExceptionally(g, ex); + checkCompletedWithWrappedException(h, ex); + checkCompletedExceptionally(f, ex0); + }} // other static methods @@ -4633,4 +4677,429 @@ public class CompletableFutureTest exten // return stage.toCompletableFuture().copy().isDone(); // } + // For testing default implementations + // Only non-default interface methods defined. + static final class DelegatedCompletionStage implements CompletionStage { + final CompletableFuture cf; + DelegatedCompletionStage(CompletableFuture cf) { this.cf = cf; } + public CompletableFuture toCompletableFuture() { + return cf; } + public CompletionStage thenRun + (Runnable action) { + return cf.thenRun(action); } + public CompletionStage thenRunAsync + (Runnable action) { + return cf.thenRunAsync(action); } + public CompletionStage thenRunAsync + (Runnable action, + Executor executor) { + return cf.thenRunAsync(action, executor); } + public CompletionStage thenAccept + (Consumer action) { + return cf.thenAccept(action); } + public CompletionStage thenAcceptAsync + (Consumer action) { + return cf.thenAcceptAsync(action); } + public CompletionStage thenAcceptAsync + (Consumer action, + Executor executor) { + return cf.thenAcceptAsync(action, executor); } + public CompletionStage thenApply + (Function a) { + return cf.thenApply(a); } + public CompletionStage thenApplyAsync + (Function fn) { + return cf.thenApplyAsync(fn); } + public CompletionStage thenApplyAsync + (Function fn, + Executor executor) { + return cf.thenApplyAsync(fn, executor); } + public CompletionStage thenCombine + (CompletionStage other, + BiFunction fn) { + return cf.thenCombine(other, fn); } + public CompletionStage thenCombineAsync + (CompletionStage other, + BiFunction fn) { + return cf.thenCombineAsync(other, fn); } + public CompletionStage thenCombineAsync + (CompletionStage other, + BiFunction fn, + Executor executor) { + return cf.thenCombineAsync(other, fn, executor); } + public CompletionStage thenAcceptBoth + (CompletionStage other, + BiConsumer action) { + return cf.thenAcceptBoth(other, action); } + public CompletionStage thenAcceptBothAsync + (CompletionStage other, + BiConsumer action) { + return cf.thenAcceptBothAsync(other, action); } + public CompletionStage thenAcceptBothAsync + (CompletionStage other, + BiConsumer action, + Executor executor) { + return cf.thenAcceptBothAsync(other, action, executor); } + public CompletionStage runAfterBoth + (CompletionStage other, + Runnable action) { + return cf.runAfterBoth(other, action); } + public CompletionStage runAfterBothAsync + (CompletionStage other, + Runnable action) { + return cf.runAfterBothAsync(other, action); } + public CompletionStage runAfterBothAsync + (CompletionStage other, + Runnable action, + Executor executor) { + return cf.runAfterBothAsync(other, action, executor); } + public CompletionStage applyToEither + (CompletionStage other, + Function fn) { + return cf.applyToEither(other, fn); } + public CompletionStage applyToEitherAsync + (CompletionStage other, + Function fn) { + return cf.applyToEitherAsync(other, fn); } + public CompletionStage applyToEitherAsync + (CompletionStage other, + Function fn, + Executor executor) { + return cf.applyToEitherAsync(other, fn, executor); } + public CompletionStage acceptEither + (CompletionStage other, + Consumer action) { + return cf.acceptEither(other, action); } + public CompletionStage acceptEitherAsync + (CompletionStage other, + Consumer action) { + return cf.acceptEitherAsync(other, action); } + public CompletionStage acceptEitherAsync + (CompletionStage other, + Consumer action, + Executor executor) { + return cf.acceptEitherAsync(other, action, executor); } + public CompletionStage runAfterEither + (CompletionStage other, + Runnable action) { + return cf.runAfterEither(other, action); } + public CompletionStage runAfterEitherAsync + (CompletionStage other, + Runnable action) { + return cf.runAfterEitherAsync(other, action); } + public CompletionStage runAfterEitherAsync + (CompletionStage other, + Runnable action, + Executor executor) { + return cf.runAfterEitherAsync(other, action, executor); } + public CompletionStage thenCompose + (Function> fn) { + return cf.thenCompose(fn); } + public CompletionStage thenComposeAsync + (Function> fn) { + return cf.thenComposeAsync(fn); } + public CompletionStage thenComposeAsync + (Function> fn, + Executor executor) { + return cf.thenComposeAsync(fn, executor); } + public CompletionStage handle + (BiFunction fn) { + return cf.handle(fn); } + public CompletionStage handleAsync + (BiFunction fn) { + return cf.handleAsync(fn); } + public CompletionStage handleAsync + (BiFunction fn, + Executor executor) { + return cf.handleAsync(fn, executor); } + public CompletionStage whenComplete + (BiConsumer action) { + return cf.whenComplete(action); } + public CompletionStage whenCompleteAsync + (BiConsumer action) { + return cf.whenCompleteAsync(action); } + public CompletionStage whenCompleteAsync + (BiConsumer action, + Executor executor) { + return cf.whenCompleteAsync(action, executor); } + public CompletionStage exceptionally + (Function fn) { + return cf.exceptionally(fn); } + } + + /** + * default-implemented exceptionallyAsync action is not invoked when + * source completes normally, and source result is propagated + */ + public void testDefaultExceptionallyAsync_normalCompletion() { + for (boolean createIncomplete : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final DelegatedCompletionStage d = + new DelegatedCompletionStage(f); + if (!createIncomplete) assertTrue(f.complete(v1)); + final CompletionStage g = d.exceptionallyAsync + ((Throwable t) -> { + threadFail("should not be called"); + return null; // unreached + }); + if (createIncomplete) assertTrue(f.complete(v1)); + + checkCompletedNormally(g.toCompletableFuture(), v1); + }} + + /** + * default-implemented exceptionallyAsync action completes with + * function value on source exception + */ + public void testDefaultExceptionallyAsync_exceptionalCompletion() { + for (boolean createIncomplete : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final AtomicInteger a = new AtomicInteger(0); + final CFException ex = new CFException(); + final CompletableFuture f = new CompletableFuture<>(); + final DelegatedCompletionStage d = + new DelegatedCompletionStage(f); + if (!createIncomplete) f.completeExceptionally(ex); + final CompletionStage g = d.exceptionallyAsync + ((Throwable t) -> { + threadAssertSame(t, ex); + a.getAndIncrement(); + return v1; + }); + if (createIncomplete) f.completeExceptionally(ex); + + checkCompletedNormally(g.toCompletableFuture(), v1); + assertEquals(1, a.get()); + }} + + /** + * Under default implementation, if an "exceptionally action" + * throws an exception, it completes exceptionally with that + * exception + */ + public void testDefaultExceptionallyAsync_exceptionalCompletionActionFailed() { + for (boolean createIncomplete : new boolean[] { true, false }) + { + final AtomicInteger a = new AtomicInteger(0); + final CFException ex1 = new CFException(); + final CFException ex2 = new CFException(); + final CompletableFuture f = new CompletableFuture<>(); + final DelegatedCompletionStage d = + new DelegatedCompletionStage(f); + if (!createIncomplete) f.completeExceptionally(ex1); + final CompletionStage g = d.exceptionallyAsync + ((Throwable t) -> { + threadAssertSame(t, ex1); + a.getAndIncrement(); + throw ex2; + }); + if (createIncomplete) f.completeExceptionally(ex1); + + checkCompletedWithWrappedException(g.toCompletableFuture(), ex2); + checkCompletedExceptionally(f, ex1); + checkCompletedExceptionally(d.toCompletableFuture(), ex1); + assertEquals(1, a.get()); + }} + + /** + * default-implemented exceptionallyCompose result completes + * normally after normal completion of source + */ + public void testDefaultExceptionallyCompose_normalCompletion() { + for (boolean createIncomplete : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final ExceptionalCompletableFutureFunction r = + new ExceptionalCompletableFutureFunction(ExecutionMode.SYNC); + final DelegatedCompletionStage d = + new DelegatedCompletionStage(f); + if (!createIncomplete) assertTrue(f.complete(v1)); + final CompletionStage g = d.exceptionallyCompose(r); + if (createIncomplete) assertTrue(f.complete(v1)); + + checkCompletedNormally(f, v1); + checkCompletedNormally(g.toCompletableFuture(), v1); + r.assertNotInvoked(); + }} + + /** + * default-implemented exceptionallyCompose result completes + * normally after exceptional completion of source + */ + public void testDefaultExceptionallyCompose_exceptionalCompletion() { + for (boolean createIncomplete : new boolean[] { true, false }) + { + final CFException ex = new CFException(); + final ExceptionalCompletableFutureFunction r = + new ExceptionalCompletableFutureFunction(ExecutionMode.SYNC); + final CompletableFuture f = new CompletableFuture<>(); + final DelegatedCompletionStage d = + new DelegatedCompletionStage(f); + if (!createIncomplete) f.completeExceptionally(ex); + final CompletionStage g = d.exceptionallyCompose(r); + if (createIncomplete) f.completeExceptionally(ex); + + checkCompletedExceptionally(f, ex); + checkCompletedNormally(g.toCompletableFuture(), r.value); + r.assertInvoked(); + }} + + /** + * default-implemented exceptionallyCompose completes + * exceptionally on exception if action does + */ + public void testDefaultExceptionallyCompose_actionFailed() { + for (boolean createIncomplete : new boolean[] { true, false }) + { + final CFException ex = new CFException(); + final CompletableFuture f = new CompletableFuture<>(); + final FailingExceptionalCompletableFutureFunction r + = new FailingExceptionalCompletableFutureFunction(ExecutionMode.SYNC); + final DelegatedCompletionStage d = + new DelegatedCompletionStage(f); + if (!createIncomplete) f.completeExceptionally(ex); + final CompletionStage g = d.exceptionallyCompose(r); + if (createIncomplete) f.completeExceptionally(ex); + + checkCompletedExceptionally(f, ex); + checkCompletedWithWrappedException(g.toCompletableFuture(), r.ex); + r.assertInvoked(); + }} + + /** + * default-implemented exceptionallyComposeAsync result completes + * normally after normal completion of source + */ + public void testDefaultExceptionallyComposeAsync_normalCompletion() { + for (boolean createIncomplete : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final ExceptionalCompletableFutureFunction r = + new ExceptionalCompletableFutureFunction(ExecutionMode.ASYNC); + final DelegatedCompletionStage d = + new DelegatedCompletionStage(f); + if (!createIncomplete) assertTrue(f.complete(v1)); + final CompletionStage g = d.exceptionallyComposeAsync(r); + if (createIncomplete) assertTrue(f.complete(v1)); + + checkCompletedNormally(f, v1); + checkCompletedNormally(g.toCompletableFuture(), v1); + r.assertNotInvoked(); + }} + + /** + * default-implemented exceptionallyComposeAsync result completes + * normally after exceptional completion of source + */ + public void testDefaultExceptionallyComposeAsync_exceptionalCompletion() { + for (boolean createIncomplete : new boolean[] { true, false }) + { + final CFException ex = new CFException(); + final ExceptionalCompletableFutureFunction r = + new ExceptionalCompletableFutureFunction(ExecutionMode.ASYNC); + final CompletableFuture f = new CompletableFuture<>(); + final DelegatedCompletionStage d = + new DelegatedCompletionStage(f); + if (!createIncomplete) f.completeExceptionally(ex); + final CompletionStage g = d.exceptionallyComposeAsync(r); + if (createIncomplete) f.completeExceptionally(ex); + + checkCompletedExceptionally(f, ex); + checkCompletedNormally(g.toCompletableFuture(), r.value); + r.assertInvoked(); + }} + + /** + * default-implemented exceptionallyComposeAsync completes + * exceptionally on exception if action does + */ + public void testDefaultExceptionallyComposeAsync_actionFailed() { + for (boolean createIncomplete : new boolean[] { true, false }) + { + final CFException ex = new CFException(); + final CompletableFuture f = new CompletableFuture<>(); + final FailingExceptionalCompletableFutureFunction r + = new FailingExceptionalCompletableFutureFunction(ExecutionMode.ASYNC); + final DelegatedCompletionStage d = + new DelegatedCompletionStage(f); + if (!createIncomplete) f.completeExceptionally(ex); + final CompletionStage g = d.exceptionallyComposeAsync(r); + if (createIncomplete) f.completeExceptionally(ex); + + checkCompletedExceptionally(f, ex); + checkCompletedWithWrappedException(g.toCompletableFuture(), r.ex); + r.assertInvoked(); + }} + + /** + * default-implemented exceptionallyComposeAsync result completes + * normally after normal completion of source + */ + public void testDefaultExceptionallyComposeAsyncExecutor_normalCompletion() { + for (boolean createIncomplete : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final ExceptionalCompletableFutureFunction r = + new ExceptionalCompletableFutureFunction(ExecutionMode.EXECUTOR); + final DelegatedCompletionStage d = + new DelegatedCompletionStage(f); + if (!createIncomplete) assertTrue(f.complete(v1)); + final CompletionStage g = d.exceptionallyComposeAsync(r, new ThreadExecutor()); + if (createIncomplete) assertTrue(f.complete(v1)); + + checkCompletedNormally(f, v1); + checkCompletedNormally(g.toCompletableFuture(), v1); + r.assertNotInvoked(); + }} + + /** + * default-implemented exceptionallyComposeAsync result completes + * normally after exceptional completion of source + */ + public void testDefaultExceptionallyComposeAsyncExecutor_exceptionalCompletion() { + for (boolean createIncomplete : new boolean[] { true, false }) + { + final CFException ex = new CFException(); + final ExceptionalCompletableFutureFunction r = + new ExceptionalCompletableFutureFunction(ExecutionMode.EXECUTOR); + final CompletableFuture f = new CompletableFuture<>(); + final DelegatedCompletionStage d = + new DelegatedCompletionStage(f); + if (!createIncomplete) f.completeExceptionally(ex); + final CompletionStage g = d.exceptionallyComposeAsync(r, new ThreadExecutor()); + if (createIncomplete) f.completeExceptionally(ex); + + checkCompletedExceptionally(f, ex); + checkCompletedNormally(g.toCompletableFuture(), r.value); + r.assertInvoked(); + }} + + /** + * default-implemented exceptionallyComposeAsync completes + * exceptionally on exception if action does + */ + public void testDefaultExceptionallyComposeAsyncExecutor_actionFailed() { + for (boolean createIncomplete : new boolean[] { true, false }) + { + final CFException ex = new CFException(); + final CompletableFuture f = new CompletableFuture<>(); + final FailingExceptionalCompletableFutureFunction r + = new FailingExceptionalCompletableFutureFunction(ExecutionMode.EXECUTOR); + final DelegatedCompletionStage d = + new DelegatedCompletionStage(f); + if (!createIncomplete) f.completeExceptionally(ex); + final CompletionStage g = d.exceptionallyComposeAsync(r, new ThreadExecutor()); + if (createIncomplete) f.completeExceptionally(ex); + + checkCompletedExceptionally(f, ex); + checkCompletedWithWrappedException(g.toCompletableFuture(), r.ex); + r.assertInvoked(); + }} + }