--- jsr166/src/test/tck/CompletableFutureTest.java 2017/03/18 20:42:20 1.184 +++ jsr166/src/test/tck/CompletableFutureTest.java 2018/11/24 21:23:31 1.220 @@ -41,7 +41,6 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; -import junit.framework.AssertionFailedError; import junit.framework.Test; import junit.framework.TestSuite; @@ -59,34 +58,38 @@ public class CompletableFutureTest exten void checkIncomplete(CompletableFuture f) { assertFalse(f.isDone()); assertFalse(f.isCancelled()); - assertTrue(f.toString().contains("Not completed")); + assertTrue(f.toString().matches(".*\\[.*Not completed.*\\]")); + + Object result = null; try { - assertNull(f.getNow(null)); + result = f.getNow(null); } catch (Throwable fail) { threadUnexpectedException(fail); } + assertNull(result); + try { - f.get(0L, SECONDS); + f.get(randomExpiredTimeout(), randomTimeUnit()); shouldThrow(); } catch (TimeoutException success) {} catch (Throwable fail) { threadUnexpectedException(fail); } } - void checkCompletedNormally(CompletableFuture f, T value) { - checkTimedGet(f, value); + void checkCompletedNormally(CompletableFuture f, T expectedValue) { + checkTimedGet(f, expectedValue); + assertEquals(expectedValue, f.join()); + assertEquals(expectedValue, f.getNow(null)); + + T result = null; try { - assertEquals(value, f.join()); - } catch (Throwable fail) { threadUnexpectedException(fail); } - try { - assertEquals(value, f.getNow(null)); - } catch (Throwable fail) { threadUnexpectedException(fail); } - try { - assertEquals(value, f.get()); + result = f.get(); } catch (Throwable fail) { threadUnexpectedException(fail); } + assertEquals(expectedValue, result); + assertTrue(f.isDone()); assertFalse(f.isCancelled()); assertFalse(f.isCompletedExceptionally()); - assertTrue(f.toString().contains("[Completed normally]")); + assertTrue(f.toString().matches(".*\\[.*Completed normally.*\\]")); } /** @@ -142,7 +145,7 @@ public class CompletableFutureTest exten assertFalse(f.isCancelled()); assertTrue(f.isDone()); assertTrue(f.isCompletedExceptionally()); - assertTrue(f.toString().contains("[Completed exceptionally]")); + assertTrue(f.toString().matches(".*\\[.*Completed exceptionally.*\\]")); } void checkCompletedWithWrappedCFException(CompletableFuture f) { @@ -197,7 +200,7 @@ public class CompletableFutureTest exten assertTrue(f.isDone()); assertTrue(f.isCompletedExceptionally()); assertTrue(f.isCancelled()); - assertTrue(f.toString().contains("[Completed exceptionally]")); + assertTrue(f.toString().matches(".*\\[.*Completed exceptionally.*\\]")); } /** @@ -296,7 +299,7 @@ public class CompletableFutureTest exten } f = new CompletableFuture<>(); - f.completeExceptionally(ex = new CFException()); + f.completeExceptionally(new CFException()); f.obtrudeValue(v1); checkCompletedNormally(f, v1); f.obtrudeException(ex = new CFException()); @@ -333,23 +336,40 @@ public class CompletableFutureTest exten /** * toString indicates current completion state */ - public void testToString() { - CompletableFuture f; - - f = new CompletableFuture(); - assertTrue(f.toString().contains("[Not completed]")); + public void testToString_incomplete() { + CompletableFuture f = new CompletableFuture<>(); + assertTrue(f.toString().matches(".*\\[.*Not completed.*\\]")); + if (testImplementationDetails) + assertEquals(identityString(f) + "[Not completed]", + f.toString()); + } + public void testToString_normal() { + CompletableFuture f = new CompletableFuture<>(); assertTrue(f.complete("foo")); - assertTrue(f.toString().contains("[Completed normally]")); + assertTrue(f.toString().matches(".*\\[.*Completed normally.*\\]")); + if (testImplementationDetails) + assertEquals(identityString(f) + "[Completed normally]", + f.toString()); + } - f = new CompletableFuture(); + public void testToString_exception() { + CompletableFuture f = new CompletableFuture<>(); assertTrue(f.completeExceptionally(new IndexOutOfBoundsException())); - assertTrue(f.toString().contains("[Completed exceptionally]")); + assertTrue(f.toString().matches(".*\\[.*Completed exceptionally.*\\]")); + if (testImplementationDetails) + assertTrue(f.toString().startsWith( + identityString(f) + "[Completed exceptionally: ")); + } + public void testToString_cancelled() { for (boolean mayInterruptIfRunning : new boolean[] { true, false }) { - f = new CompletableFuture(); + CompletableFuture f = new CompletableFuture<>(); assertTrue(f.cancel(mayInterruptIfRunning)); - assertTrue(f.toString().contains("[Completed exceptionally]")); + assertTrue(f.toString().matches(".*\\[.*Completed exceptionally.*\\]")); + if (testImplementationDetails) + assertTrue(f.toString().startsWith( + identityString(f) + "[Completed exceptionally: ")); } } @@ -531,9 +551,28 @@ 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)); + } + } + + static class FailingExceptionalCompletableFutureFunction extends CheckedAction + implements Function> + { + final CFException ex; + FailingExceptionalCompletableFutureFunction(ExecutionMode m) { super(m); ex = new CFException(); } + public CompletableFuture apply(Throwable x) { + invoked(); + throw ex; + } + } + + static class ExceptionalCompletableFutureFunction extends CheckedAction + implements Function> { + final Integer value = 3; + ExceptionalCompletableFutureFunction(ExecutionMode m) { super(m); } + public CompletionStage apply(Throwable x) { + invoked(); + return CompletableFuture.completedFuture(value); } } @@ -652,8 +691,16 @@ public class CompletableFutureTest exten Function a) { return f.applyToEither(g, a); } + public CompletableFuture exceptionally + (CompletableFuture f, + Function fn) { + return f.exceptionally(fn); + } + public CompletableFuture exceptionallyCompose + (CompletableFuture f, Function> fn) { + return f.exceptionallyCompose(fn); + } }, - ASYNC { public void checkExecutionMode() { assertEquals(defaultExecutorIsCommonPool, @@ -726,6 +773,17 @@ public class CompletableFutureTest exten Function a) { return f.applyToEitherAsync(g, a); } + public CompletableFuture exceptionally + (CompletableFuture f, + Function fn) { + return f.exceptionallyAsync(fn); + } + + public CompletableFuture exceptionallyCompose + (CompletableFuture f, Function> fn) { + return f.exceptionallyComposeAsync(fn); + } + }, EXECUTOR { @@ -799,6 +857,16 @@ public class CompletableFutureTest exten Function a) { return f.applyToEitherAsync(g, a, new ThreadExecutor()); } + public CompletableFuture exceptionally + (CompletableFuture f, + Function fn) { + return f.exceptionallyAsync(fn, new ThreadExecutor()); + } + public CompletableFuture exceptionallyCompose + (CompletableFuture f, Function> fn) { + return f.exceptionallyComposeAsync(fn, new ThreadExecutor()); + } + }; public abstract void checkExecutionMode(); @@ -841,6 +909,12 @@ public class CompletableFutureTest exten (CompletableFuture f, CompletionStage g, Function a); + public abstract CompletableFuture exceptionally + (CompletableFuture f, + Function fn); + public abstract CompletableFuture exceptionallyCompose + (CompletableFuture f, + Function> fn); } /** @@ -848,23 +922,23 @@ public class CompletableFutureTest exten * normally, and source result is propagated */ public void testExceptionally_normalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) for (boolean createIncomplete : new boolean[] { true, false }) for (Integer v1 : new Integer[] { 1, null }) { - final AtomicInteger a = new AtomicInteger(0); + final AtomicInteger ran = new AtomicInteger(0); final CompletableFuture f = new CompletableFuture<>(); if (!createIncomplete) assertTrue(f.complete(v1)); - final CompletableFuture g = f.exceptionally - ((Throwable t) -> { - a.getAndIncrement(); - threadFail("should not be called"); - return null; // unreached + final CompletableFuture g = m.exceptionally + (f, (Throwable t) -> { + ran.getAndIncrement(); + throw new AssertionError("should not be called"); }); if (createIncomplete) assertTrue(f.complete(v1)); checkCompletedNormally(g, v1); checkCompletedNormally(f, v1); - assertEquals(0, a.get()); + assertEquals(0, ran.get()); }} /** @@ -872,24 +946,25 @@ public class CompletableFutureTest exten * exception */ public void testExceptionally_exceptionalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) for (boolean createIncomplete : new boolean[] { true, false }) for (Integer v1 : new Integer[] { 1, null }) { - final AtomicInteger a = new AtomicInteger(0); + final AtomicInteger ran = new AtomicInteger(0); final CFException ex = new CFException(); final CompletableFuture f = new CompletableFuture<>(); if (!createIncomplete) f.completeExceptionally(ex); - final CompletableFuture g = f.exceptionally - ((Throwable t) -> { - ExecutionMode.SYNC.checkExecutionMode(); - threadAssertSame(t, ex); - a.getAndIncrement(); + final CompletableFuture g = m.exceptionally + (f, (Throwable t) -> { + m.checkExecutionMode(); + assertSame(t, ex); + ran.getAndIncrement(); return v1; }); if (createIncomplete) f.completeExceptionally(ex); checkCompletedNormally(g, v1); - assertEquals(1, a.get()); + assertEquals(1, ran.get()); }} /** @@ -897,25 +972,26 @@ public class CompletableFutureTest exten * exceptionally with that exception */ public void testExceptionally_exceptionalCompletionActionFailed() { + for (ExecutionMode m : ExecutionMode.values()) for (boolean createIncomplete : new boolean[] { true, false }) { - final AtomicInteger a = new AtomicInteger(0); + final AtomicInteger ran = new AtomicInteger(0); final CFException ex1 = new CFException(); final CFException ex2 = new CFException(); final CompletableFuture f = new CompletableFuture<>(); if (!createIncomplete) f.completeExceptionally(ex1); - final CompletableFuture g = f.exceptionally - ((Throwable t) -> { - ExecutionMode.SYNC.checkExecutionMode(); - threadAssertSame(t, ex1); - a.getAndIncrement(); + final CompletableFuture g = m.exceptionally + (f, (Throwable t) -> { + m.checkExecutionMode(); + assertSame(t, ex1); + ran.getAndIncrement(); throw ex2; }); if (createIncomplete) f.completeExceptionally(ex1); checkCompletedWithWrappedException(g, ex2); checkCompletedExceptionally(f, ex1); - assertEquals(1, a.get()); + assertEquals(1, ran.get()); }} /** @@ -927,22 +1003,22 @@ 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 AtomicInteger ran = new AtomicInteger(0); final CompletableFuture f = new CompletableFuture<>(); if (!createIncomplete) assertTrue(f.complete(v1)); final CompletableFuture g = m.whenComplete (f, (Integer result, Throwable t) -> { m.checkExecutionMode(); - threadAssertSame(result, v1); - threadAssertNull(t); - a.getAndIncrement(); + assertSame(result, v1); + assertNull(t); + ran.getAndIncrement(); }); if (createIncomplete) assertTrue(f.complete(v1)); checkCompletedNormally(g, v1); checkCompletedNormally(f, v1); - assertEquals(1, a.get()); + assertEquals(1, ran.get()); }} /** @@ -953,7 +1029,7 @@ public class CompletableFutureTest exten for (ExecutionMode m : ExecutionMode.values()) for (boolean createIncomplete : new boolean[] { true, false }) { - final AtomicInteger a = new AtomicInteger(0); + final AtomicInteger ran = new AtomicInteger(0); final CFException ex = new CFException(); final CompletableFuture f = new CompletableFuture<>(); if (!createIncomplete) f.completeExceptionally(ex); @@ -961,15 +1037,15 @@ public class CompletableFutureTest exten (f, (Integer result, Throwable t) -> { m.checkExecutionMode(); - threadAssertNull(result); - threadAssertSame(t, ex); - a.getAndIncrement(); + assertNull(result); + assertSame(t, ex); + ran.getAndIncrement(); }); if (createIncomplete) f.completeExceptionally(ex); checkCompletedWithWrappedException(g, ex); checkCompletedExceptionally(f, ex); - assertEquals(1, a.get()); + assertEquals(1, ran.get()); }} /** @@ -981,22 +1057,22 @@ public class CompletableFutureTest exten for (boolean mayInterruptIfRunning : new boolean[] { true, false }) for (boolean createIncomplete : new boolean[] { true, false }) { - final AtomicInteger a = new AtomicInteger(0); + final AtomicInteger ran = new AtomicInteger(0); final CompletableFuture f = new CompletableFuture<>(); if (!createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning)); final CompletableFuture g = m.whenComplete (f, (Integer result, Throwable t) -> { m.checkExecutionMode(); - threadAssertNull(result); - threadAssertTrue(t instanceof CancellationException); - a.getAndIncrement(); + assertNull(result); + assertTrue(t instanceof CancellationException); + ran.getAndIncrement(); }); if (createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning)); checkCompletedWithWrappedCancellationException(g); checkCancelled(f); - assertEquals(1, a.get()); + assertEquals(1, ran.get()); }} /** @@ -1008,7 +1084,7 @@ public class CompletableFutureTest exten for (ExecutionMode m : ExecutionMode.values()) for (Integer v1 : new Integer[] { 1, null }) { - final AtomicInteger a = new AtomicInteger(0); + final AtomicInteger ran = new AtomicInteger(0); final CFException ex = new CFException(); final CompletableFuture f = new CompletableFuture<>(); if (!createIncomplete) assertTrue(f.complete(v1)); @@ -1016,16 +1092,16 @@ public class CompletableFutureTest exten (f, (Integer result, Throwable t) -> { m.checkExecutionMode(); - threadAssertSame(result, v1); - threadAssertNull(t); - a.getAndIncrement(); + assertSame(result, v1); + assertNull(t); + ran.getAndIncrement(); throw ex; }); if (createIncomplete) assertTrue(f.complete(v1)); checkCompletedWithWrappedException(g, ex); checkCompletedNormally(f, v1); - assertEquals(1, a.get()); + assertEquals(1, ran.get()); }} /** @@ -1037,7 +1113,7 @@ public class CompletableFutureTest exten for (boolean createIncomplete : new boolean[] { true, false }) for (ExecutionMode m : ExecutionMode.values()) { - final AtomicInteger a = new AtomicInteger(0); + final AtomicInteger ran = new AtomicInteger(0); final CFException ex1 = new CFException(); final CFException ex2 = new CFException(); final CompletableFuture f = new CompletableFuture<>(); @@ -1047,9 +1123,9 @@ public class CompletableFutureTest exten (f, (Integer result, Throwable t) -> { m.checkExecutionMode(); - threadAssertSame(t, ex1); - threadAssertNull(result); - a.getAndIncrement(); + assertSame(t, ex1); + assertNull(result); + ran.getAndIncrement(); throw ex2; }); if (createIncomplete) f.completeExceptionally(ex1); @@ -1060,7 +1136,7 @@ public class CompletableFutureTest exten assertEquals(1, ex1.getSuppressed().length); assertSame(ex2, ex1.getSuppressed()[0]); } - assertEquals(1, a.get()); + assertEquals(1, ran.get()); }} /** @@ -1073,22 +1149,22 @@ public class CompletableFutureTest exten for (Integer v1 : new Integer[] { 1, null }) { final CompletableFuture f = new CompletableFuture<>(); - final AtomicInteger a = new AtomicInteger(0); + final AtomicInteger ran = new AtomicInteger(0); if (!createIncomplete) assertTrue(f.complete(v1)); final CompletableFuture g = m.handle (f, (Integer result, Throwable t) -> { m.checkExecutionMode(); - threadAssertSame(result, v1); - threadAssertNull(t); - a.getAndIncrement(); + assertSame(result, v1); + assertNull(t); + ran.getAndIncrement(); return inc(v1); }); if (createIncomplete) assertTrue(f.complete(v1)); checkCompletedNormally(g, inc(v1)); checkCompletedNormally(f, v1); - assertEquals(1, a.get()); + assertEquals(1, ran.get()); }} /** @@ -1101,23 +1177,23 @@ public class CompletableFutureTest exten for (Integer v1 : new Integer[] { 1, null }) { final CompletableFuture f = new CompletableFuture<>(); - final AtomicInteger a = new AtomicInteger(0); + final AtomicInteger ran = new AtomicInteger(0); final CFException ex = new CFException(); if (!createIncomplete) f.completeExceptionally(ex); final CompletableFuture g = m.handle (f, (Integer result, Throwable t) -> { m.checkExecutionMode(); - threadAssertNull(result); - threadAssertSame(t, ex); - a.getAndIncrement(); + assertNull(result); + assertSame(t, ex); + ran.getAndIncrement(); return v1; }); if (createIncomplete) f.completeExceptionally(ex); checkCompletedNormally(g, v1); checkCompletedExceptionally(f, ex); - assertEquals(1, a.get()); + assertEquals(1, ran.get()); }} /** @@ -1131,22 +1207,22 @@ public class CompletableFutureTest exten for (Integer v1 : new Integer[] { 1, null }) { final CompletableFuture f = new CompletableFuture<>(); - final AtomicInteger a = new AtomicInteger(0); + final AtomicInteger ran = new AtomicInteger(0); if (!createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning)); final CompletableFuture g = m.handle (f, (Integer result, Throwable t) -> { m.checkExecutionMode(); - threadAssertNull(result); - threadAssertTrue(t instanceof CancellationException); - a.getAndIncrement(); + assertNull(result); + assertTrue(t instanceof CancellationException); + ran.getAndIncrement(); return v1; }); if (createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning)); checkCompletedNormally(g, v1); checkCancelled(f); - assertEquals(1, a.get()); + assertEquals(1, ran.get()); }} /** @@ -1159,23 +1235,23 @@ public class CompletableFutureTest exten for (Integer v1 : new Integer[] { 1, null }) { final CompletableFuture f = new CompletableFuture<>(); - final AtomicInteger a = new AtomicInteger(0); + final AtomicInteger ran = new AtomicInteger(0); final CFException ex = new CFException(); if (!createIncomplete) assertTrue(f.complete(v1)); final CompletableFuture g = m.handle (f, (Integer result, Throwable t) -> { m.checkExecutionMode(); - threadAssertSame(result, v1); - threadAssertNull(t); - a.getAndIncrement(); + assertSame(result, v1); + assertNull(t); + ran.getAndIncrement(); throw ex; }); if (createIncomplete) assertTrue(f.complete(v1)); checkCompletedWithWrappedException(g, ex); checkCompletedNormally(f, v1); - assertEquals(1, a.get()); + assertEquals(1, ran.get()); }} /** @@ -1187,7 +1263,7 @@ public class CompletableFutureTest exten for (boolean createIncomplete : new boolean[] { true, false }) for (ExecutionMode m : ExecutionMode.values()) { - final AtomicInteger a = new AtomicInteger(0); + final AtomicInteger ran = new AtomicInteger(0); final CFException ex1 = new CFException(); final CFException ex2 = new CFException(); final CompletableFuture f = new CompletableFuture<>(); @@ -1197,16 +1273,16 @@ public class CompletableFutureTest exten (f, (Integer result, Throwable t) -> { m.checkExecutionMode(); - threadAssertNull(result); - threadAssertSame(ex1, t); - a.getAndIncrement(); + assertNull(result); + assertSame(ex1, t); + ran.getAndIncrement(); throw ex2; }); if (createIncomplete) f.completeExceptionally(ex1); checkCompletedWithWrappedException(g, ex2); checkCompletedExceptionally(f, ex1); - assertEquals(1, a.get()); + assertEquals(1, ran.get()); }} /** @@ -1242,6 +1318,7 @@ public class CompletableFutureTest exten r.assertInvoked(); }} + @SuppressWarnings("FutureReturnValueIgnored") public void testRunAsync_rejectingExecutor() { CountingRejectingExecutor e = new CountingRejectingExecutor(); try { @@ -1288,6 +1365,7 @@ public class CompletableFutureTest exten r.assertInvoked(); }} + @SuppressWarnings("FutureReturnValueIgnored") public void testSupplyAsync_rejectingExecutor() { CountingRejectingExecutor e = new CountingRejectingExecutor(); try { @@ -3040,30 +3118,30 @@ public class CompletableFutureTest exten case 0: assertTrue(f.complete(v1)); assertTrue(g.completeExceptionally(ex)); - h = m.thenCompose(f, (x -> g)); + h = m.thenCompose(f, x -> g); break; case 1: assertTrue(f.complete(v1)); - h = m.thenCompose(f, (x -> g)); + h = m.thenCompose(f, x -> g); assertTrue(g.completeExceptionally(ex)); break; case 2: assertTrue(g.completeExceptionally(ex)); assertTrue(f.complete(v1)); - h = m.thenCompose(f, (x -> g)); + h = m.thenCompose(f, x -> g); break; case 3: assertTrue(g.completeExceptionally(ex)); - h = m.thenCompose(f, (x -> g)); + h = m.thenCompose(f, x -> g); assertTrue(f.complete(v1)); break; case 4: - h = m.thenCompose(f, (x -> g)); + h = m.thenCompose(f, x -> g); assertTrue(f.complete(v1)); assertTrue(g.completeExceptionally(ex)); break; case 5: - h = m.thenCompose(f, (x -> g)); + h = m.thenCompose(f, x -> g); assertTrue(f.complete(v1)); assertTrue(g.completeExceptionally(ex)); break; @@ -3075,6 +3153,121 @@ public class CompletableFutureTest exten checkCompletedNormally(f, v1); }} + /** + * exceptionallyCompose result completes normally after normal + * completion of source + */ + public void testExceptionallyCompose_normalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean createIncomplete : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final ExceptionalCompletableFutureFunction r = + new ExceptionalCompletableFutureFunction(m); + if (!createIncomplete) assertTrue(f.complete(v1)); + final CompletableFuture g = m.exceptionallyCompose(f, r); + if (createIncomplete) assertTrue(f.complete(v1)); + + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v1); + r.assertNotInvoked(); + }} + + /** + * exceptionallyCompose result completes normally after exceptional + * completion of source + */ + public void testExceptionallyCompose_exceptionalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean createIncomplete : new boolean[] { true, false }) + { + final CFException ex = new CFException(); + final ExceptionalCompletableFutureFunction r = + new ExceptionalCompletableFutureFunction(m); + final CompletableFuture f = new CompletableFuture<>(); + if (!createIncomplete) f.completeExceptionally(ex); + final CompletableFuture g = m.exceptionallyCompose(f, r); + if (createIncomplete) f.completeExceptionally(ex); + + checkCompletedExceptionally(f, ex); + checkCompletedNormally(g, r.value); + r.assertInvoked(); + }} + + /** + * exceptionallyCompose completes exceptionally on exception if action does + */ + public void testExceptionallyCompose_actionFailed() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean createIncomplete : new boolean[] { true, false }) + { + final CFException ex = new CFException(); + final CompletableFuture f = new CompletableFuture<>(); + final FailingExceptionalCompletableFutureFunction r + = new FailingExceptionalCompletableFutureFunction(m); + if (!createIncomplete) f.completeExceptionally(ex); + final CompletableFuture g = m.exceptionallyCompose(f, r); + if (createIncomplete) f.completeExceptionally(ex); + + checkCompletedExceptionally(f, ex); + checkCompletedWithWrappedException(g, r.ex); + 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 /** @@ -3238,6 +3431,7 @@ public class CompletableFutureTest exten /** * Completion methods throw NullPointerException with null arguments */ + @SuppressWarnings("FutureReturnValueIgnored") public void testNPE() { CompletableFuture f = new CompletableFuture<>(); CompletableFuture g = new CompletableFuture<>(); @@ -3453,12 +3647,6 @@ public class CompletableFutureTest exten final CompletableFuture complete = CompletableFuture.completedFuture(v); final CompletableFuture incomplete = new CompletableFuture<>(); - List> futures = new ArrayList<>(); - - List> srcs = new ArrayList<>(); - srcs.add(complete); - srcs.add(incomplete); - List> fs = new ArrayList<>(); fs.add(incomplete.thenRunAsync(() -> {}, e)); fs.add(incomplete.thenAcceptAsync(z -> {}, e)); @@ -4174,7 +4362,7 @@ public class CompletableFutureTest exten static void assertZero(CompletableFuture f) { try { f.getNow(null); - throw new AssertionFailedError("should throw"); + throw new AssertionError("should throw"); } catch (CompletionException success) { assertTrue(success.getCause() instanceof ZeroException); } @@ -4299,6 +4487,7 @@ public class CompletableFutureTest exten } /** Test long recursive chains of CompletableFutures with cascading completions */ + @SuppressWarnings("FutureReturnValueIgnored") public void testRecursiveChains() throws Throwable { for (ExecutionMode m : ExecutionMode.values()) for (boolean addDeadEnds : new boolean[] { true, false }) @@ -4323,6 +4512,7 @@ public class CompletableFutureTest exten * A single CompletableFuture with many dependents. * A demo of scalability - runtime is O(n). */ + @SuppressWarnings("FutureReturnValueIgnored") public void testManyDependents() throws Throwable { final int n = expensiveTests ? 1_000_000 : 10; final CompletableFuture head = new CompletableFuture<>(); @@ -4352,6 +4542,7 @@ public class CompletableFutureTest exten } /** ant -Dvmoptions=-Xmx8m -Djsr166.expensiveTests=true -Djsr166.tckTestClass=CompletableFutureTest tck */ + @SuppressWarnings("FutureReturnValueIgnored") public void testCoCompletionGarbageRetention() throws Throwable { final int n = expensiveTests ? 1_000_000 : 10; final CompletableFuture incomplete = new CompletableFuture<>(); @@ -4370,7 +4561,7 @@ public class CompletableFutureTest exten f.complete(null); f = new CompletableFuture<>(); - CompletableFuture.anyOf(new CompletableFuture[] { f, incomplete }); + CompletableFuture.anyOf(f, incomplete); f.complete(null); } @@ -4388,7 +4579,7 @@ public class CompletableFutureTest exten f.complete(null); f = new CompletableFuture<>(); - CompletableFuture.anyOf(new CompletableFuture[] { incomplete, f }); + CompletableFuture.anyOf(incomplete, f); f.complete(null); } } @@ -4482,4 +4673,433 @@ 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 AtomicInteger ran = new AtomicInteger(0); + final CompletableFuture f = new CompletableFuture<>(); + final DelegatedCompletionStage d = + new DelegatedCompletionStage(f); + if (!createIncomplete) assertTrue(f.complete(v1)); + final CompletionStage g = d.exceptionallyAsync + ((Throwable t) -> { + ran.getAndIncrement(); + throw new AssertionError("should not be called"); + }); + if (createIncomplete) assertTrue(f.complete(v1)); + + checkCompletedNormally(g.toCompletableFuture(), v1); + checkCompletedNormally(f, v1); + assertEquals(0, ran.get()); + }} + + /** + * 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 ran = 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) -> { + assertSame(t, ex); + ran.getAndIncrement(); + return v1; + }); + if (createIncomplete) f.completeExceptionally(ex); + + checkCompletedNormally(g.toCompletableFuture(), v1); + checkCompletedExceptionally(f, ex); + assertEquals(1, ran.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 ran = 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) -> { + assertSame(t, ex1); + ran.getAndIncrement(); + throw ex2; + }); + if (createIncomplete) f.completeExceptionally(ex1); + + checkCompletedWithWrappedException(g.toCompletableFuture(), ex2); + checkCompletedExceptionally(f, ex1); + checkCompletedExceptionally(d.toCompletableFuture(), ex1); + assertEquals(1, ran.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(); + }} + }