--- jsr166/src/test/tck/CompletableFutureTest.java 2013/07/15 03:50:08 1.29 +++ jsr166/src/test/tck/CompletableFutureTest.java 2014/06/02 19:20:51 1.49 @@ -16,6 +16,9 @@ import java.util.concurrent.ExecutionExc import java.util.concurrent.Future; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import static java.util.concurrent.TimeUnit.MILLISECONDS; @@ -102,6 +105,37 @@ public class CompletableFutureTest exten assertTrue(f.toString().contains("[Completed exceptionally]")); } + void checkCompletedWithWrappedCFException(CompletableFuture f, + CFException ex) { + try { + f.get(LONG_DELAY_MS, MILLISECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertSame(ex, success.getCause()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + try { + f.join(); + shouldThrow(); + } catch (CompletionException success) { + assertSame(ex, success.getCause()); + } + try { + f.getNow(null); + shouldThrow(); + } catch (CompletionException success) { + assertSame(ex, success.getCause()); + } + try { + f.get(); + shouldThrow(); + } catch (ExecutionException success) { + assertSame(ex, success.getCause()); + } 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); @@ -215,6 +249,8 @@ public class CompletableFutureTest exten f = new CompletableFuture<>(); f.obtrudeValue(three); checkCompletedNormally(f, three); + f.obtrudeValue(null); + checkCompletedNormally(f, null); f = new CompletableFuture<>(); f.completeExceptionally(new CFException()); f.obtrudeValue(four); @@ -247,16 +283,16 @@ public class CompletableFutureTest exten */ public void testGetNumberOfDependents() { CompletableFuture f = new CompletableFuture<>(); - assertEquals(f.getNumberOfDependents(), 0); + assertEquals(0, f.getNumberOfDependents()); CompletableFuture g = f.thenRun(new Noop()); - assertEquals(f.getNumberOfDependents(), 1); - assertEquals(g.getNumberOfDependents(), 0); + assertEquals(1, f.getNumberOfDependents()); + assertEquals(0, g.getNumberOfDependents()); CompletableFuture h = f.thenRun(new Noop()); - assertEquals(f.getNumberOfDependents(), 2); + assertEquals(2, f.getNumberOfDependents()); f.complete(1); checkCompletedNormally(g, null); - assertEquals(f.getNumberOfDependents(), 0); - assertEquals(g.getNumberOfDependents(), 0); + assertEquals(0, f.getNumberOfDependents()); + assertEquals(0, g.getNumberOfDependents()); } /** @@ -286,68 +322,125 @@ public class CompletableFutureTest exten // Choose non-commutative actions for better coverage + // A non-commutative function that handles and produces null values as well. + static Integer subtract(Integer x, Integer y) { + return (x == null && y == null) ? null : + ((x == null) ? 42 : x.intValue()) + - ((y == null) ? 99 : y.intValue()); + } + + // A function that handles and produces null values as well. + static Integer inc(Integer x) { + return (x == null) ? null : x + 1; + } + static final Supplier supplyOne = () -> Integer.valueOf(1); static final Function inc = (Integer x) -> Integer.valueOf(x.intValue() + 1); static final BiFunction subtract = - (Integer x, Integer y) -> Integer.valueOf(x.intValue() - y.intValue()); + (Integer x, Integer y) -> subtract(x, y); static final class IncAction implements Consumer { - int value; - public void accept(Integer x) { value = x.intValue() + 1; } + int invocationCount = 0; + Integer value; + public void accept(Integer x) { + invocationCount++; + value = inc(x); + } + } + static final class IncFunction implements Function { + int invocationCount = 0; + Integer value; + public Integer apply(Integer x) { + invocationCount++; + return value = inc(x); + } } static final class SubtractAction implements BiConsumer { - int value; + int invocationCount = 0; + Integer value; + // Check this action was invoked exactly once when result is computed. public void accept(Integer x, Integer y) { - value = x.intValue() - y.intValue(); + invocationCount++; + value = subtract(x, y); + } + } + static final class SubtractFunction implements BiFunction { + int invocationCount = 0; + Integer value; + // Check this action was invoked exactly once when result is computed. + public Integer apply(Integer x, Integer y) { + invocationCount++; + return value = subtract(x, y); } } static final class Noop implements Runnable { - boolean ran; - public void run() { ran = true; } + int invocationCount = 0; + public void run() { + invocationCount++; + } } static final class FailingSupplier implements Supplier { - boolean ran; - public Integer get() { ran = true; throw new CFException(); } + int invocationCount = 0; + public Integer get() { + invocationCount++; + throw new CFException(); + } } static final class FailingConsumer implements Consumer { - boolean ran; - public void accept(Integer x) { ran = true; throw new CFException(); } + int invocationCount = 0; + public void accept(Integer x) { + invocationCount++; + throw new CFException(); + } } static final class FailingBiConsumer implements BiConsumer { - boolean ran; - public void accept(Integer x, Integer y) { ran = true; throw new CFException(); } + int invocationCount = 0; + public void accept(Integer x, Integer y) { + invocationCount++; + throw new CFException(); + } } static final class FailingFunction implements Function { - boolean ran; - public Integer apply(Integer x) { ran = true; throw new CFException(); } + int invocationCount = 0; + public Integer apply(Integer x) { + invocationCount++; + throw new CFException(); + } } static final class FailingBiFunction implements BiFunction { - boolean ran; - public Integer apply(Integer x, Integer y) { ran = true; throw new CFException(); } + int invocationCount = 0; + public Integer apply(Integer x, Integer y) { + invocationCount++; + throw new CFException(); + } } static final class FailingNoop implements Runnable { - boolean ran; - public void run() { ran = true; throw new CFException(); } + int invocationCount = 0; + public void run() { + invocationCount++; + throw new CFException(); + } } static final class CompletableFutureInc implements Function> { - boolean ran; + int invocationCount = 0; public CompletableFuture apply(Integer x) { - ran = true; + invocationCount++; CompletableFuture f = new CompletableFuture<>(); - f.complete(Integer.valueOf(x.intValue() + 1)); + f.complete(inc(x)); return f; } } static final class FailingCompletableFutureFunction implements Function> { - boolean ran; + int invocationCount = 0; public CompletableFuture apply(Integer x) { - ran = true; throw new CFException(); + invocationCount++; + throw new CFException(); } } @@ -361,70 +454,456 @@ public class CompletableFutureTest exten } } - static final class ExceptionToInteger implements Function { - public Integer apply(Throwable x) { return Integer.valueOf(3); } - } + /** + * Permits the testing of parallel code for the 3 different + * execution modes without repeating all the testing code. + */ + enum ExecutionMode { + DEFAULT { + public void checkExecutionMode() { + assertNull(ForkJoinTask.getPool()); + } + public CompletableFuture thenRun + (CompletableFuture f, Runnable a) { + return f.thenRun(a); + } + public CompletableFuture thenAccept + (CompletableFuture f, Consumer a) { + return f.thenAccept(a); + } + public CompletableFuture thenApply + (CompletableFuture f, Function a) { + return f.thenApply(a); + } + public CompletableFuture thenCompose + (CompletableFuture f, + Function> a) { + return f.thenCompose(a); + } + public CompletableFuture handle + (CompletableFuture f, + BiFunction a) { + return f.handle(a); + } + public CompletableFuture whenComplete + (CompletableFuture f, + BiConsumer a) { + return f.whenComplete(a); + } + public CompletableFuture runAfterBoth + (CompletableFuture f, CompletableFuture g, Runnable a) { + return f.runAfterBoth(g, a); + } + public CompletableFuture thenAcceptBoth + (CompletableFuture f, + CompletionStage g, + BiConsumer a) { + return f.thenAcceptBoth(g, a); + } + public CompletableFuture thenCombine + (CompletableFuture f, + CompletionStage g, + BiFunction a) { + return f.thenCombine(g, a); + } + public CompletableFuture runAfterEither + (CompletableFuture f, + CompletionStage g, + java.lang.Runnable a) { + return f.runAfterEither(g, a); + } + public CompletableFuture acceptEither + (CompletableFuture f, + CompletionStage g, + Consumer a) { + return f.acceptEither(g, a); + } + public CompletableFuture applyToEither + (CompletableFuture f, + CompletionStage g, + Function a) { + return f.applyToEither(g, a); + } + }, - static final class IntegerHandler implements BiFunction { - boolean ran; - public Integer apply(Integer x, Throwable t) { - ran = true; - return (t == null) ? two : three; - } + ASYNC { + public void checkExecutionMode() { + assertSame(ForkJoinPool.commonPool(), + ForkJoinTask.getPool()); + } + public CompletableFuture thenRun + (CompletableFuture f, Runnable a) { + return f.thenRunAsync(a); + } + public CompletableFuture thenAccept + (CompletableFuture f, Consumer a) { + return f.thenAcceptAsync(a); + } + public CompletableFuture thenApply + (CompletableFuture f, Function a) { + return f.thenApplyAsync(a); + } + public CompletableFuture thenCompose + (CompletableFuture f, + Function> a) { + return f.thenComposeAsync(a); + } + public CompletableFuture handle + (CompletableFuture f, + BiFunction a) { + return f.handleAsync(a); + } + public CompletableFuture whenComplete + (CompletableFuture f, + BiConsumer a) { + return f.whenCompleteAsync(a); + } + public CompletableFuture runAfterBoth + (CompletableFuture f, CompletableFuture g, Runnable a) { + return f.runAfterBothAsync(g, a); + } + public CompletableFuture thenAcceptBoth + (CompletableFuture f, + CompletionStage g, + BiConsumer a) { + return f.thenAcceptBothAsync(g, a); + } + public CompletableFuture thenCombine + (CompletableFuture f, + CompletionStage g, + BiFunction a) { + return f.thenCombineAsync(g, a); + } + public CompletableFuture runAfterEither + (CompletableFuture f, + CompletionStage g, + java.lang.Runnable a) { + return f.runAfterEitherAsync(g, a); + } + public CompletableFuture acceptEither + (CompletableFuture f, + CompletionStage g, + Consumer a) { + return f.acceptEitherAsync(g, a); + } + public CompletableFuture applyToEither + (CompletableFuture f, + CompletionStage g, + Function a) { + return f.applyToEitherAsync(g, a); + } + }, + + EXECUTOR { + public void checkExecutionMode() { + //TODO + } + public CompletableFuture thenRun + (CompletableFuture f, Runnable a) { + return f.thenRunAsync(a, new ThreadExecutor()); + } + public CompletableFuture thenAccept + (CompletableFuture f, Consumer a) { + return f.thenAcceptAsync(a, new ThreadExecutor()); + } + public CompletableFuture thenApply + (CompletableFuture f, Function a) { + return f.thenApplyAsync(a, new ThreadExecutor()); + } + public CompletableFuture thenCompose + (CompletableFuture f, + Function> a) { + return f.thenComposeAsync(a, new ThreadExecutor()); + } + public CompletableFuture handle + (CompletableFuture f, + BiFunction a) { + return f.handleAsync(a, new ThreadExecutor()); + } + public CompletableFuture whenComplete + (CompletableFuture f, + BiConsumer a) { + return f.whenCompleteAsync(a, new ThreadExecutor()); + } + public CompletableFuture runAfterBoth + (CompletableFuture f, CompletableFuture g, Runnable a) { + return f.runAfterBothAsync(g, a, new ThreadExecutor()); + } + public CompletableFuture thenAcceptBoth + (CompletableFuture f, + CompletionStage g, + BiConsumer a) { + return f.thenAcceptBothAsync(g, a, new ThreadExecutor()); + } + public CompletableFuture thenCombine + (CompletableFuture f, + CompletionStage g, + BiFunction a) { + return f.thenCombineAsync(g, a, new ThreadExecutor()); + } + public CompletableFuture runAfterEither + (CompletableFuture f, + CompletionStage g, + java.lang.Runnable a) { + return f.runAfterEitherAsync(g, a, new ThreadExecutor()); + } + public CompletableFuture acceptEither + (CompletableFuture f, + CompletionStage g, + Consumer a) { + return f.acceptEitherAsync(g, a, new ThreadExecutor()); + } + public CompletableFuture applyToEither + (CompletableFuture f, + CompletionStage g, + Function a) { + return f.applyToEitherAsync(g, a, new ThreadExecutor()); + } + }; + + public abstract void checkExecutionMode(); + public abstract CompletableFuture thenRun + (CompletableFuture f, Runnable a); + public abstract CompletableFuture thenAccept + (CompletableFuture f, Consumer a); + public abstract CompletableFuture thenApply + (CompletableFuture f, Function a); + public abstract CompletableFuture thenCompose + (CompletableFuture f, + Function> a); + public abstract CompletableFuture handle + (CompletableFuture f, + BiFunction a); + public abstract CompletableFuture whenComplete + (CompletableFuture f, + BiConsumer a); + public abstract CompletableFuture runAfterBoth + (CompletableFuture f, CompletableFuture g, Runnable a); + public abstract CompletableFuture thenAcceptBoth + (CompletableFuture f, + CompletionStage g, + BiConsumer a); + public abstract CompletableFuture thenCombine + (CompletableFuture f, + CompletionStage g, + BiFunction a); + public abstract CompletableFuture runAfterEither + (CompletableFuture f, + CompletionStage g, + java.lang.Runnable a); + public abstract CompletableFuture acceptEither + (CompletableFuture f, + CompletionStage g, + Consumer a); + public abstract CompletableFuture applyToEither + (CompletableFuture f, + CompletionStage g, + Function a); } /** - * exceptionally action completes with function value on source - * exception; otherwise with source value - */ - public void testExceptionally() { - CompletableFuture f = new CompletableFuture<>(); - ExceptionToInteger r = new ExceptionToInteger(); - CompletableFuture g = f.exceptionally(r); - f.completeExceptionally(new CFException()); - checkCompletedNormally(g, three); + * exceptionally action is not invoked when source completes + * normally, and source result is propagated + */ + public void testExceptionally_normalCompletion() { + 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) f.complete(v1); + final CompletableFuture g = f.exceptionally + ((Throwable t) -> { + // Should not be called + a.getAndIncrement(); + throw new AssertionError(); + }); + if (createIncomplete) f.complete(v1); + + checkCompletedNormally(g, v1); + checkCompletedNormally(f, v1); + assertEquals(0, a.get()); + }} - f = new CompletableFuture<>(); - r = new ExceptionToInteger(); - g = f.exceptionally(r); - f.complete(one); - checkCompletedNormally(g, one); - } /** - * handle action completes normally with function value on either - * normal or exceptional completion of source + * exceptionally action completes with function value on source + * exception */ - public void testHandle() { - CompletableFuture f, g; - IntegerHandler r; - - f = new CompletableFuture<>(); - f.completeExceptionally(new CFException()); - g = f.handle(r = new IntegerHandler()); - assertTrue(r.ran); - checkCompletedNormally(g, three); + public void testExceptionally_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<>(); + if (!createIncomplete) f.completeExceptionally(ex); + final CompletableFuture g = f.exceptionally + ((Throwable t) -> { + threadAssertSame(t, ex); + a.getAndIncrement(); + return v1; + }); + if (createIncomplete) f.completeExceptionally(ex); + + checkCompletedNormally(g, v1); + assertEquals(1, a.get()); + }} + + public void testExceptionally_exceptionalCompletionActionFailed() { + for (boolean createIncomplete : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final AtomicInteger a = 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) -> { + threadAssertSame(t, ex1); + a.getAndIncrement(); + throw ex2; + }); + if (createIncomplete) f.completeExceptionally(ex1); + + checkCompletedWithWrappedCFException(g, ex2); + assertEquals(1, a.get()); + }} + + /** + * handle action completes normally with function value on normal + * completion of source + */ + public void testHandle_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 AtomicInteger a = new AtomicInteger(0); + if (!createIncomplete) f.complete(v1); + final CompletableFuture g = m.handle + (f, + (Integer x, Throwable t) -> { + threadAssertSame(x, v1); + threadAssertNull(t); + a.getAndIncrement(); + return inc(v1); + }); + if (createIncomplete) f.complete(v1); + + checkCompletedNormally(g, inc(v1)); + checkCompletedNormally(f, v1); + assertEquals(1, a.get()); + }} - f = new CompletableFuture<>(); - g = f.handle(r = new IntegerHandler()); - assertFalse(r.ran); - f.completeExceptionally(new CFException()); - checkCompletedNormally(g, three); - assertTrue(r.ran); + /** + * handle action completes normally with function value on + * exceptional completion of source + */ + public void testHandle_exceptionalCompletion() { + 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 AtomicInteger a = new AtomicInteger(0); + final CFException ex = new CFException(); + if (!createIncomplete) f.completeExceptionally(ex); + final CompletableFuture g = m.handle + (f, + (Integer x, Throwable t) -> { + threadAssertNull(x); + threadAssertSame(t, ex); + a.getAndIncrement(); + return v1; + }); + if (createIncomplete) f.completeExceptionally(ex); + + checkCompletedNormally(g, v1); + checkCompletedWithWrappedCFException(f, ex); + assertEquals(1, a.get()); + }} + + /** + * handle action completes normally with function value on + * cancelled source + */ + public void testHandle_sourceCancelled() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (boolean createIncomplete : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final AtomicInteger a = new AtomicInteger(0); + if (!createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning)); + final CompletableFuture g = m.handle + (f, + (Integer x, Throwable t) -> { + threadAssertNull(x); + threadAssertTrue(t instanceof CancellationException); + a.getAndIncrement(); + return v1; + }); + if (createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning)); - f = new CompletableFuture<>(); - f.complete(one); - g = f.handle(r = new IntegerHandler()); - assertTrue(r.ran); - checkCompletedNormally(g, two); + checkCompletedNormally(g, v1); + checkCancelled(f); + assertEquals(1, a.get()); + }} - f = new CompletableFuture<>(); - g = f.handle(r = new IntegerHandler()); - assertFalse(r.ran); - f.complete(one); - assertTrue(r.ran); - checkCompletedNormally(g, two); - } + /** + * handle result completes exceptionally if action does + */ + public void testHandle_sourceFailedActionFailed() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean createIncomplete : new boolean[] { true, false }) + { + final CompletableFuture f = new CompletableFuture<>(); + final AtomicInteger a = new AtomicInteger(0); + final CFException ex1 = new CFException(); + final CFException ex2 = new CFException(); + if (!createIncomplete) f.completeExceptionally(ex1); + final CompletableFuture g = m.handle + (f, + (Integer x, Throwable t) -> { + threadAssertNull(x); + threadAssertSame(ex1, t); + a.getAndIncrement(); + throw ex2; + }); + if (createIncomplete) f.completeExceptionally(ex1); + + checkCompletedWithWrappedCFException(g, ex2); + checkCompletedWithWrappedCFException(f, ex1); + assertEquals(1, a.get()); + }} + + public void testHandle_sourceCompletedNormallyActionFailed() { + 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 AtomicInteger a = new AtomicInteger(0); + final CFException ex = new CFException(); + if (!createIncomplete) f.complete(v1); + final CompletableFuture g = m.handle + (f, + (Integer x, Throwable t) -> { + threadAssertSame(x, v1); + threadAssertNull(t); + a.getAndIncrement(); + throw ex; + }); + if (createIncomplete) f.complete(v1); + + checkCompletedWithWrappedCFException(g, ex); + checkCompletedNormally(f, v1); + assertEquals(1, a.get()); + }} /** * runAsync completes after running Runnable @@ -433,7 +912,7 @@ public class CompletableFutureTest exten Noop r = new Noop(); CompletableFuture f = CompletableFuture.runAsync(r); assertNull(f.join()); - assertTrue(r.ran); + assertEquals(1, r.invocationCount); checkCompletedNormally(f, null); } @@ -445,7 +924,7 @@ public class CompletableFutureTest exten ThreadExecutor exec = new ThreadExecutor(); CompletableFuture f = CompletableFuture.runAsync(r, exec); assertNull(f.join()); - assertTrue(r.ran); + assertEquals(1, r.invocationCount); checkCompletedNormally(f, null); assertEquals(1, exec.count.get()); } @@ -457,7 +936,7 @@ public class CompletableFutureTest exten FailingNoop r = new FailingNoop(); CompletableFuture f = CompletableFuture.runAsync(r); checkCompletedWithWrappedCFException(f); - assertTrue(r.ran); + assertEquals(1, r.invocationCount); } /** @@ -487,7 +966,7 @@ public class CompletableFutureTest exten FailingSupplier r = new FailingSupplier(); CompletableFuture f = CompletableFuture.supplyAsync(r); checkCompletedWithWrappedCFException(f); - assertTrue(r.ran); + assertEquals(1, r.invocationCount); } // seq completion methods @@ -495,124 +974,157 @@ public class CompletableFutureTest exten /** * thenRun result completes normally after normal completion of source */ - public void testThenRun() { - CompletableFuture f; - CompletableFuture g; - Noop r; + public void testThenRun_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 Noop r = new Noop(); + if (!createIncomplete) f.complete(v1); + final CompletableFuture g = m.thenRun(f, r); + if (createIncomplete) f.complete(v1); - f = new CompletableFuture<>(); - g = f.thenRun(r = new Noop()); - f.complete(null); checkCompletedNormally(g, null); - assertTrue(r.ran); - - f = new CompletableFuture<>(); - f.complete(null); - g = f.thenRun(r = new Noop()); - checkCompletedNormally(g, null); - assertTrue(r.ran); - } + checkCompletedNormally(f, v1); + assertEquals(1, r.invocationCount); + }} /** * thenRun result completes exceptionally after exceptional * completion of source */ - public void testThenRun2() { - CompletableFuture f; - CompletableFuture g; - Noop r; - - f = new CompletableFuture<>(); - g = f.thenRun(r = new Noop()); - f.completeExceptionally(new CFException()); - checkCompletedWithWrappedCFException(g); - assertFalse(r.ran); - - f = new CompletableFuture<>(); - f.completeExceptionally(new CFException()); - g = f.thenRun(r = new Noop()); - checkCompletedWithWrappedCFException(g); - assertFalse(r.ran); - } + public void testThenRun_exceptionalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean createIncomplete : new boolean[] { true, false }) + { + final CFException ex = new CFException(); + final CompletableFuture f = new CompletableFuture<>(); + final Noop r = new Noop(); + if (!createIncomplete) f.completeExceptionally(ex); + final CompletableFuture g = m.thenRun(f, r); + if (createIncomplete) f.completeExceptionally(ex); + + checkCompletedWithWrappedCFException(g, ex); + checkCompletedWithWrappedCFException(f, ex); + assertEquals(0, r.invocationCount); + }} /** - * thenRun result completes exceptionally if action does + * thenRun result completes exceptionally if source cancelled */ - public void testThenRun3() { - CompletableFuture f; - CompletableFuture g; - FailingNoop r; - - f = new CompletableFuture<>(); - g = f.thenRun(r = new FailingNoop()); - f.complete(null); - checkCompletedWithWrappedCFException(g); + public void testThenRun_sourceCancelled() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean createIncomplete : new boolean[] { true, false }) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + { + final CompletableFuture f = new CompletableFuture<>(); + final Noop r = new Noop(); + if (!createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning)); + final CompletableFuture g = f.thenRun(r); + if (createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning)); - f = new CompletableFuture<>(); - f.complete(null); - g = f.thenRun(r = new FailingNoop()); - checkCompletedWithWrappedCFException(g); - } + checkCompletedWithWrappedCancellationException(g); + checkCancelled(f); + assertEquals(0, r.invocationCount); + }} /** - * thenRun result completes exceptionally if source cancelled + * thenRun result completes exceptionally if action does */ - public void testThenRun4() { - CompletableFuture f; - CompletableFuture g; - Noop r; + public void testThenRun_actionFailed() { + 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 FailingNoop r = new FailingNoop(); + if (!createIncomplete) f.complete(v1); + final CompletableFuture g = f.thenRun(r); + if (createIncomplete) f.complete(v1); - f = new CompletableFuture<>(); - g = f.thenRun(r = new Noop()); - assertTrue(f.cancel(true)); - checkCompletedWithWrappedCancellationException(g); - - f = new CompletableFuture<>(); - assertTrue(f.cancel(true)); - g = f.thenRun(r = new Noop()); - checkCompletedWithWrappedCancellationException(g); - } + checkCompletedWithWrappedCFException(g); + checkCompletedNormally(f, v1); + }} /** * thenApply result completes normally after normal completion of source */ - public void testThenApply() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture g = f.thenApply(inc); - f.complete(one); - checkCompletedNormally(g, two); - } + public void testThenApply_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 IncFunction r = new IncFunction(); + if (!createIncomplete) f.complete(v1); + final CompletableFuture g = m.thenApply(f, r); + if (createIncomplete) { + checkIncomplete(g); + f.complete(v1); + } + + checkCompletedNormally(g, inc(v1)); + checkCompletedNormally(f, v1); + assertEquals(1, r.invocationCount); + }} /** * thenApply result completes exceptionally after exceptional * completion of source */ - public void testThenApply2() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture g = f.thenApply(inc); - f.completeExceptionally(new CFException()); - checkCompletedWithWrappedCFException(g); - } + public void testThenApply_exceptionalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean createIncomplete : new boolean[] { true, false }) + { + final CFException ex = new CFException(); + final CompletableFuture f = new CompletableFuture<>(); + final IncFunction r = new IncFunction(); + if (!createIncomplete) f.completeExceptionally(ex); + final CompletableFuture g = m.thenApply(f, r); + if (createIncomplete) f.completeExceptionally(ex); + + checkCompletedWithWrappedCFException(g, ex); + checkCompletedWithWrappedCFException(f, ex); + assertEquals(0, r.invocationCount); + }} /** - * thenApply result completes exceptionally if action does + * thenApply result completes exceptionally if source cancelled */ - public void testThenApply3() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture g = f.thenApply(new FailingFunction()); - f.complete(one); - checkCompletedWithWrappedCFException(g); - } + public void testThenApply_sourceCancelled() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean createIncomplete : new boolean[] { true, false }) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + { + final CompletableFuture f = new CompletableFuture<>(); + final IncFunction r = new IncFunction(); + if (!createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning)); + final CompletableFuture g = f.thenApply(r); + if (createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning)); + + checkCompletedWithWrappedCancellationException(g); + checkCancelled(f); + assertEquals(0, r.invocationCount); + }} /** - * thenApply result completes exceptionally if source cancelled + * thenApply result completes exceptionally if action does */ - public void testThenApply4() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture g = f.thenApply(inc); - assertTrue(f.cancel(true)); - checkCompletedWithWrappedCancellationException(g); - } + public void testThenApply_actionFailed() { + 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 FailingFunction r = new FailingFunction(); + if (!createIncomplete) f.complete(v1); + final CompletableFuture g = f.thenApply(r); + if (createIncomplete) f.complete(v1); + + checkCompletedWithWrappedCFException(g); + checkCompletedNormally(f, v1); + }} /** * thenAccept result completes normally after normal completion of source @@ -623,7 +1135,7 @@ public class CompletableFutureTest exten CompletableFuture g = f.thenAccept(r); f.complete(one); checkCompletedNormally(g, null); - assertEquals(r.value, 2); + assertEquals(r.value, (Integer) 2); } /** @@ -647,7 +1159,7 @@ public class CompletableFutureTest exten CompletableFuture g = f.thenAccept(r); f.complete(one); checkCompletedWithWrappedCFException(g); - assertTrue(r.ran); + assertEquals(1, r.invocationCount); } /** @@ -665,1524 +1177,1840 @@ public class CompletableFutureTest exten * thenCombine result completes normally after normal completion * of sources */ - public void testThenCombine() { - CompletableFuture f, g, h; - - f = new CompletableFuture<>(); - 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); - } + public void testThenCombine_normalCompletion1() { + for (boolean createIncomplete : new boolean[] { true, false }) + for (boolean fFirst : new boolean[] { true, false }) + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractFunction r = new SubtractFunction(); + CompletableFuture h = null; + if (createIncomplete) h = m.thenCombine(f, g, r); + + if (fFirst) + f.complete(v1); + else + g.complete(v2); + if (createIncomplete) checkIncomplete(h); + assertEquals(0, r.invocationCount); + if (!fFirst) + f.complete(v1); + else + g.complete(v2); + if (!createIncomplete) h = m.thenCombine(f, g, r); + + checkCompletedNormally(h, subtract(v1, v2)); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + assertEquals(1, r.invocationCount); + }} /** * thenCombine result completes exceptionally after exceptional * completion of either source */ - public void testThenCombine2() { - CompletableFuture f, g, h; - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenCombine(g, subtract); - f.completeExceptionally(new CFException()); - checkIncomplete(h); - g.complete(1); - checkCompletedWithWrappedCFException(h); - - f = new CompletableFuture<>(); - 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); - } + public void testThenCombine_exceptionalCompletion1() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractFunction r = new SubtractFunction(); + final CompletableFuture h = m.thenCombine(f, g, r); + final CFException ex = new CFException(); + + f.completeExceptionally(ex); + checkIncomplete(h); + g.complete(v1); + + checkCompletedWithWrappedCFException(h, ex); + checkCompletedWithWrappedCFException(f, ex); + assertEquals(0, r.invocationCount); + checkCompletedNormally(g, v1); + }} + + public void testThenCombine_exceptionalCompletion2() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractFunction r = new SubtractFunction(); + final CompletableFuture h = m.thenCombine(f, g, r); + final CFException ex = new CFException(); + + g.completeExceptionally(ex); + checkIncomplete(h); + f.complete(v1); + + checkCompletedWithWrappedCFException(h, ex); + checkCompletedWithWrappedCFException(g, ex); + assertEquals(0, r.invocationCount); + checkCompletedNormally(f, v1); + }} + + public void testThenCombine_exceptionalCompletion3() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractFunction r = new SubtractFunction(); + final CFException ex = new CFException(); + + g.completeExceptionally(ex); + f.complete(v1); + final CompletableFuture h = m.thenCombine(f, g, r); + + checkCompletedWithWrappedCFException(h, ex); + checkCompletedWithWrappedCFException(g, ex); + assertEquals(0, r.invocationCount); + checkCompletedNormally(f, v1); + }} + + public void testThenCombine_exceptionalCompletion4() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractFunction r = new SubtractFunction(); + final CFException ex = new CFException(); + + f.completeExceptionally(ex); + g.complete(v1); + final CompletableFuture h = m.thenCombine(f, g, r); + + checkCompletedWithWrappedCFException(h, ex); + checkCompletedWithWrappedCFException(f, ex); + assertEquals(0, r.invocationCount); + checkCompletedNormally(g, v1); + }} /** * thenCombine result completes exceptionally if action does */ - public void testThenCombine3() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - FailingBiFunction r = new FailingBiFunction(); - CompletableFuture g = f.thenCombine(f2, r); - f.complete(one); - checkIncomplete(g); - assertFalse(r.ran); - f2.complete(two); - checkCompletedWithWrappedCFException(g); - assertTrue(r.ran); - } + public void testThenCombine_actionFailed1() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final FailingBiFunction r = new FailingBiFunction(); + final CompletableFuture h = m.thenCombine(f, g, r); + + f.complete(v1); + checkIncomplete(h); + g.complete(v2); + + checkCompletedWithWrappedCFException(h); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} + + public void testThenCombine_actionFailed2() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final FailingBiFunction r = new FailingBiFunction(); + final CompletableFuture h = m.thenCombine(f, g, r); + + g.complete(v2); + checkIncomplete(h); + f.complete(v1); + + checkCompletedWithWrappedCFException(h); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} /** * thenCombine result completes exceptionally if either source cancelled */ - public void testThenCombine4() { - CompletableFuture f, g, h; + public void testThenCombine_sourceCancelled1() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractFunction r = new SubtractFunction(); + final CompletableFuture h = m.thenCombine(f, g, r); - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenCombine(g, subtract); - assertTrue(f.cancel(true)); + assertTrue(f.cancel(mayInterruptIfRunning)); checkIncomplete(h); - g.complete(1); - checkCompletedWithWrappedCancellationException(h); + g.complete(v1); - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenCombine(g, subtract); - assertTrue(g.cancel(true)); - checkIncomplete(h); - f.complete(3); checkCompletedWithWrappedCancellationException(h); + checkCancelled(f); + assertEquals(0, r.invocationCount); + checkCompletedNormally(g, v1); + }} + + public void testThenCombine_sourceCancelled2() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractFunction r = new SubtractFunction(); + final CompletableFuture h = m.thenCombine(f, g, r); + + assertTrue(g.cancel(mayInterruptIfRunning)); + checkIncomplete(h); + f.complete(v1); + + checkCompletedWithWrappedCancellationException(h); + checkCancelled(g); + assertEquals(0, r.invocationCount); + checkCompletedNormally(f, v1); + }} + + public void testThenCombine_sourceCancelled3() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractFunction r = new SubtractFunction(); + + assertTrue(g.cancel(mayInterruptIfRunning)); + f.complete(v1); + final CompletableFuture h = m.thenCombine(f, g, r); + + checkCompletedWithWrappedCancellationException(h); + checkCancelled(g); + assertEquals(0, r.invocationCount); + checkCompletedNormally(f, v1); + }} + + public void testThenCombine_sourceCancelled4() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractFunction r = new SubtractFunction(); + + assertTrue(f.cancel(mayInterruptIfRunning)); + g.complete(v1); + final CompletableFuture h = m.thenCombine(f, g, r); - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - assertTrue(f.cancel(true)); - assertTrue(g.cancel(true)); - h = f.thenCombine(g, subtract); checkCompletedWithWrappedCancellationException(h); - } + checkCancelled(f); + assertEquals(0, r.invocationCount); + checkCompletedNormally(g, v1); + }} /** * thenAcceptBoth result completes normally after normal * completion of sources */ - public void testThenAcceptBoth() { - CompletableFuture f, g; - CompletableFuture h; - SubtractAction r; + public void testThenAcceptBoth_normalCompletion1() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractAction r = new SubtractAction(); + final CompletableFuture h = m.thenAcceptBoth(f, g, r); - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenAcceptBoth(g, r = new SubtractAction()); - f.complete(3); + f.complete(v1); checkIncomplete(h); - g.complete(1); + assertEquals(0, r.invocationCount); + g.complete(v2); + checkCompletedNormally(h, null); - assertEquals(r.value, 2); + assertEquals(subtract(v1, v2), r.value); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} + + public void testThenAcceptBoth_normalCompletion2() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractAction r = new SubtractAction(); + final CompletableFuture h = m.thenAcceptBoth(f, g, r); - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenAcceptBoth(g, r = new SubtractAction()); - g.complete(1); + g.complete(v2); checkIncomplete(h); - f.complete(3); + assertEquals(0, r.invocationCount); + f.complete(v1); + checkCompletedNormally(h, null); - assertEquals(r.value, 2); + assertEquals(subtract(v1, v2), r.value); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} + + public void testThenAcceptBoth_normalCompletion3() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractAction r = new SubtractAction(); + + g.complete(v2); + f.complete(v1); + final CompletableFuture h = m.thenAcceptBoth(f, g, r); - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - g.complete(1); - f.complete(3); - h = f.thenAcceptBoth(g, r = new SubtractAction()); checkCompletedNormally(h, null); - assertEquals(r.value, 2); - } + assertEquals(subtract(v1, v2), r.value); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} + + public void testThenAcceptBoth_normalCompletion4() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractAction r = new SubtractAction(); + + f.complete(v1); + g.complete(v2); + final CompletableFuture h = m.thenAcceptBoth(f, g, r); + + checkCompletedNormally(h, null); + assertEquals(subtract(v1, v2), r.value); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} /** * thenAcceptBoth result completes exceptionally after exceptional * completion of either source */ - public void testThenAcceptBoth2() { - CompletableFuture f, g; - CompletableFuture h; - SubtractAction r; - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenAcceptBoth(g, r = new SubtractAction()); - f.completeExceptionally(new CFException()); - checkIncomplete(h); - g.complete(1); - checkCompletedWithWrappedCFException(h); - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenAcceptBoth(g, r = new SubtractAction()); - 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.thenAcceptBoth(g, r = new SubtractAction()); - checkCompletedWithWrappedCFException(h); - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - f.completeExceptionally(new CFException()); - g.complete(3); - h = f.thenAcceptBoth(g, r = new SubtractAction()); - checkCompletedWithWrappedCFException(h); - } + public void testThenAcceptBoth_exceptionalCompletion1() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractAction r = new SubtractAction(); + final CompletableFuture h = m.thenAcceptBoth(f, g, r); + final CFException ex = new CFException(); + + f.completeExceptionally(ex); + checkIncomplete(h); + g.complete(v1); + + checkCompletedWithWrappedCFException(h, ex); + checkCompletedWithWrappedCFException(f, ex); + assertEquals(0, r.invocationCount); + checkCompletedNormally(g, v1); + }} + + public void testThenAcceptBoth_exceptionalCompletion2() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractAction r = new SubtractAction(); + final CompletableFuture h = m.thenAcceptBoth(f, g, r); + final CFException ex = new CFException(); + + g.completeExceptionally(ex); + checkIncomplete(h); + f.complete(v1); + + checkCompletedWithWrappedCFException(h, ex); + checkCompletedWithWrappedCFException(g, ex); + assertEquals(0, r.invocationCount); + checkCompletedNormally(f, v1); + }} + + public void testThenAcceptBoth_exceptionalCompletion3() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractAction r = new SubtractAction(); + final CFException ex = new CFException(); + + g.completeExceptionally(ex); + f.complete(v1); + final CompletableFuture h = m.thenAcceptBoth(f, g, r); + + checkCompletedWithWrappedCFException(h, ex); + checkCompletedWithWrappedCFException(g, ex); + assertEquals(0, r.invocationCount); + checkCompletedNormally(f, v1); + }} + + public void testThenAcceptBoth_exceptionalCompletion4() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractAction r = new SubtractAction(); + final CFException ex = new CFException(); + + f.completeExceptionally(ex); + g.complete(v1); + final CompletableFuture h = m.thenAcceptBoth(f, g, r); + + checkCompletedWithWrappedCFException(h, ex); + checkCompletedWithWrappedCFException(f, ex); + assertEquals(0, r.invocationCount); + checkCompletedNormally(g, v1); + }} /** * thenAcceptBoth result completes exceptionally if action does */ - public void testThenAcceptBoth3() { - CompletableFuture f, g; - CompletableFuture h; - FailingBiConsumer r; - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenAcceptBoth(g, r = new FailingBiConsumer()); - f.complete(3); - checkIncomplete(h); - g.complete(1); - checkCompletedWithWrappedCFException(h); - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - f.complete(3); - g.complete(1); - h = f.thenAcceptBoth(g, r = new FailingBiConsumer()); - checkCompletedWithWrappedCFException(h); - } + public void testThenAcceptBoth_actionFailed1() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final FailingBiConsumer r = new FailingBiConsumer(); + final CompletableFuture h = m.thenAcceptBoth(f, g, r); + + f.complete(v1); + checkIncomplete(h); + g.complete(v2); + + checkCompletedWithWrappedCFException(h); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} + + public void testThenAcceptBoth_actionFailed2() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final FailingBiConsumer r = new FailingBiConsumer(); + final CompletableFuture h = m.thenAcceptBoth(f, g, r); + + g.complete(v2); + checkIncomplete(h); + f.complete(v1); + + checkCompletedWithWrappedCFException(h); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} /** * thenAcceptBoth result completes exceptionally if either source cancelled */ - public void testThenAcceptBoth4() { - CompletableFuture f, g; - CompletableFuture h; - SubtractAction r; - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenAcceptBoth(g, r = new SubtractAction()); - assertTrue(f.cancel(true)); - checkIncomplete(h); - g.complete(1); - checkCompletedWithWrappedCancellationException(h); + public void testThenAcceptBoth_sourceCancelled1() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractAction r = new SubtractAction(); + final CompletableFuture h = m.thenAcceptBoth(f, g, r); - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenAcceptBoth(g, r = new SubtractAction()); - assertTrue(g.cancel(true)); + assertTrue(f.cancel(mayInterruptIfRunning)); checkIncomplete(h); - f.complete(3); - checkCompletedWithWrappedCancellationException(h); + g.complete(v1); - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - f.complete(3); - assertTrue(g.cancel(true)); - h = f.thenAcceptBoth(g, r = new SubtractAction()); checkCompletedWithWrappedCancellationException(h); + checkCancelled(f); + assertEquals(0, r.invocationCount); + checkCompletedNormally(g, v1); + }} + + public void testThenAcceptBoth_sourceCancelled2() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractAction r = new SubtractAction(); + final CompletableFuture h = m.thenAcceptBoth(f, g, r); + + assertTrue(g.cancel(mayInterruptIfRunning)); + checkIncomplete(h); + f.complete(v1); + + checkCompletedWithWrappedCancellationException(h); + checkCancelled(g); + assertEquals(0, r.invocationCount); + checkCompletedNormally(f, v1); + }} + + public void testThenAcceptBoth_sourceCancelled3() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractAction r = new SubtractAction(); + + assertTrue(g.cancel(mayInterruptIfRunning)); + f.complete(v1); + final CompletableFuture h = m.thenAcceptBoth(f, g, r); + + checkCompletedWithWrappedCancellationException(h); + checkCancelled(g); + assertEquals(0, r.invocationCount); + checkCompletedNormally(f, v1); + }} + + public void testThenAcceptBoth_sourceCancelled4() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final SubtractAction r = new SubtractAction(); + + assertTrue(f.cancel(mayInterruptIfRunning)); + g.complete(v1); + final CompletableFuture h = m.thenAcceptBoth(f, g, r); - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - assertTrue(f.cancel(true)); - g.complete(3); - h = f.thenAcceptBoth(g, r = new SubtractAction()); checkCompletedWithWrappedCancellationException(h); - } + checkCancelled(f); + assertEquals(0, r.invocationCount); + checkCompletedNormally(g, v1); + }} /** * runAfterBoth result completes normally after normal * completion of sources */ - public void testRunAfterBoth() { - CompletableFuture f, g; - CompletableFuture h; - Noop r; + public void testRunAfterBoth_normalCompletion1() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r = new Noop(); + final CompletableFuture h = m.runAfterBoth(f, g, r); - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.runAfterBoth(g, r = new Noop()); - f.complete(3); + f.complete(v1); checkIncomplete(h); - g.complete(1); + assertEquals(0, r.invocationCount); + g.complete(v2); + checkCompletedNormally(h, null); - assertTrue(r.ran); + assertEquals(1, r.invocationCount); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} + + public void testRunAfterBoth_normalCompletion2() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r = new Noop(); + final CompletableFuture h = m.runAfterBoth(f, g, r); - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.runAfterBoth(g, r = new Noop()); - g.complete(1); + g.complete(v2); checkIncomplete(h); - f.complete(3); + assertEquals(0, r.invocationCount); + f.complete(v1); + checkCompletedNormally(h, null); - assertTrue(r.ran); + assertEquals(1, r.invocationCount); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} + + public void testRunAfterBoth_normalCompletion3() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r = new Noop(); + + g.complete(v2); + f.complete(v1); + final CompletableFuture h = m.runAfterBoth(f, g, r); - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - g.complete(1); - f.complete(3); - h = f.runAfterBoth(g, r = new Noop()); checkCompletedNormally(h, null); - assertTrue(r.ran); - } + assertEquals(1, r.invocationCount); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} + + public void testRunAfterBoth_normalCompletion4() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r = new Noop(); + + f.complete(v1); + g.complete(v2); + final CompletableFuture h = m.runAfterBoth(f, g, r); + + checkCompletedNormally(h, null); + assertEquals(1, r.invocationCount); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} /** * runAfterBoth result completes exceptionally after exceptional * completion of either source */ - public void testRunAfterBoth2() { - CompletableFuture f, g; - CompletableFuture h; - Noop r; - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.runAfterBoth(g, r = new Noop()); - f.completeExceptionally(new CFException()); - checkIncomplete(h); - g.complete(1); - checkCompletedWithWrappedCFException(h); - assertFalse(r.ran); - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.runAfterBoth(g, r = new Noop()); - g.completeExceptionally(new CFException()); - checkIncomplete(h); - f.complete(3); - checkCompletedWithWrappedCFException(h); - assertFalse(r.ran); - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - g.completeExceptionally(new CFException()); - f.complete(3); - h = f.runAfterBoth(g, r = new Noop()); - checkCompletedWithWrappedCFException(h); - assertFalse(r.ran); - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - f.completeExceptionally(new CFException()); - g.complete(1); - h = f.runAfterBoth(g, r = new Noop()); - checkCompletedWithWrappedCFException(h); - assertFalse(r.ran); - } + public void testRunAfterBoth_exceptionalCompletion1() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r = new Noop(); + final CompletableFuture h = m.runAfterBoth(f, g, r); + final CFException ex = new CFException(); + + f.completeExceptionally(ex); + checkIncomplete(h); + g.complete(v1); + + checkCompletedWithWrappedCFException(h, ex); + checkCompletedWithWrappedCFException(f, ex); + assertEquals(0, r.invocationCount); + checkCompletedNormally(g, v1); + }} + + public void testRunAfterBoth_exceptionalCompletion2() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r = new Noop(); + final CompletableFuture h = m.runAfterBoth(f, g, r); + final CFException ex = new CFException(); + + g.completeExceptionally(ex); + checkIncomplete(h); + f.complete(v1); + + checkCompletedWithWrappedCFException(h, ex); + checkCompletedWithWrappedCFException(g, ex); + assertEquals(0, r.invocationCount); + checkCompletedNormally(f, v1); + }} + + public void testRunAfterBoth_exceptionalCompletion3() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r = new Noop(); + final CFException ex = new CFException(); + + g.completeExceptionally(ex); + f.complete(v1); + final CompletableFuture h = m.runAfterBoth(f, g, r); + + checkCompletedWithWrappedCFException(h, ex); + checkCompletedWithWrappedCFException(g, ex); + assertEquals(0, r.invocationCount); + checkCompletedNormally(f, v1); + }} + + public void testRunAfterBoth_exceptionalCompletion4() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r = new Noop(); + final CFException ex = new CFException(); + + f.completeExceptionally(ex); + g.complete(v1); + final CompletableFuture h = m.runAfterBoth(f, g, r); + + checkCompletedWithWrappedCFException(h, ex); + checkCompletedWithWrappedCFException(f, ex); + assertEquals(0, r.invocationCount); + checkCompletedNormally(g, v1); + }} /** * runAfterBoth result completes exceptionally if action does */ - public void testRunAfterBoth3() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - FailingNoop r = new FailingNoop(); - CompletableFuture g = f.runAfterBoth(f2, r); - f.complete(one); - checkIncomplete(g); - f2.complete(two); - checkCompletedWithWrappedCFException(g); - } + public void testRunAfterBoth_actionFailed1() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final FailingNoop r = new FailingNoop(); + final CompletableFuture h = m.runAfterBoth(f, g, r); + + f.complete(v1); + checkIncomplete(h); + g.complete(v2); + + checkCompletedWithWrappedCFException(h); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} + + public void testRunAfterBoth_actionFailed2() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final FailingNoop r = new FailingNoop(); + final CompletableFuture h = m.runAfterBoth(f, g, r); + + g.complete(v2); + checkIncomplete(h); + f.complete(v1); + + checkCompletedWithWrappedCFException(h); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} /** * runAfterBoth result completes exceptionally if either source cancelled */ - public void testRunAfterBoth4() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - Noop r = new Noop(); - CompletableFuture g = f.runAfterBoth(f2, r); - assertTrue(f.cancel(true)); - f2.complete(two); - checkCompletedWithWrappedCancellationException(g); - f = new CompletableFuture<>(); - f2 = new CompletableFuture<>(); - r = new Noop(); - g = f.runAfterBoth(f2, r); - f.complete(one); - assertTrue(f2.cancel(true)); - checkCompletedWithWrappedCancellationException(g); - } + public void testRunAfterBoth_sourceCancelled1() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r = new Noop(); + final CompletableFuture h = m.runAfterBoth(f, g, r); - /** - * applyToEither result completes normally after normal completion - * of either source - */ - public void testApplyToEither() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - CompletableFuture g = f.applyToEither(f2, inc); - f.complete(one); - checkCompletedNormally(g, two); - f2.complete(one); - checkCompletedNormally(g, two); - - f = new CompletableFuture<>(); - f.complete(one); - f2 = new CompletableFuture<>(); - g = f.applyToEither(f2, inc); - checkCompletedNormally(g, two); - } - - /** - * applyToEither result completes exceptionally after exceptional - * completion of either source - */ - public void testApplyToEither2() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - CompletableFuture g = f.applyToEither(f2, inc); - f.completeExceptionally(new CFException()); - f2.complete(one); - checkCompletedWithWrappedCFException(g); - - f = new CompletableFuture<>(); - f2 = new CompletableFuture<>(); - f2.completeExceptionally(new CFException()); - g = f.applyToEither(f2, inc); - checkCompletedWithWrappedCFException(g); - } + assertTrue(f.cancel(mayInterruptIfRunning)); + checkIncomplete(h); + g.complete(v1); - /** - * applyToEither result completes exceptionally if action does - */ - public void testApplyToEither3() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - FailingFunction r = new FailingFunction(); - CompletableFuture g = f.applyToEither(f2, r); - f2.complete(two); - checkCompletedWithWrappedCFException(g); - } + checkCompletedWithWrappedCancellationException(h); + checkCancelled(f); + assertEquals(0, r.invocationCount); + checkCompletedNormally(g, v1); + }} + + public void testRunAfterBoth_sourceCancelled2() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r = new Noop(); + final CompletableFuture h = m.runAfterBoth(f, g, r); + + assertTrue(g.cancel(mayInterruptIfRunning)); + checkIncomplete(h); + f.complete(v1); + + checkCompletedWithWrappedCancellationException(h); + checkCancelled(g); + assertEquals(0, r.invocationCount); + checkCompletedNormally(f, v1); + }} + + public void testRunAfterBoth_sourceCancelled3() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r = new Noop(); + + assertTrue(g.cancel(mayInterruptIfRunning)); + f.complete(v1); + final CompletableFuture h = m.runAfterBoth(f, g, r); + + checkCompletedWithWrappedCancellationException(h); + checkCancelled(g); + assertEquals(0, r.invocationCount); + checkCompletedNormally(f, v1); + }} + + public void testRunAfterBoth_sourceCancelled4() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r = new Noop(); + + assertTrue(f.cancel(mayInterruptIfRunning)); + g.complete(v1); + final CompletableFuture h = m.runAfterBoth(f, g, r); - /** - * applyToEither result completes exceptionally if either source cancelled - */ - public void testApplyToEither4() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - CompletableFuture g = f.applyToEither(f2, inc); - assertTrue(f.cancel(true)); - checkCompletedWithWrappedCancellationException(g); - f = new CompletableFuture<>(); - f2 = new CompletableFuture<>(); - assertTrue(f2.cancel(true)); - checkCompletedWithWrappedCancellationException(g); - } + checkCompletedWithWrappedCancellationException(h); + checkCancelled(f); + assertEquals(0, r.invocationCount); + checkCompletedNormally(g, v1); + }} /** - * acceptEither result completes normally after normal completion + * applyToEither result completes normally after normal completion * of either source */ - public void testAcceptEither() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - IncAction r = new IncAction(); - CompletableFuture g = f.acceptEither(f2, r); - f.complete(one); - checkCompletedNormally(g, null); - f2.complete(one); - checkCompletedNormally(g, null); - assertEquals(r.value, 2); - - r = new IncAction(); - f = new CompletableFuture<>(); - f.complete(one); - f2 = new CompletableFuture<>(); - g = f.acceptEither(f2, r); - checkCompletedNormally(g, null); - assertEquals(r.value, 2); - } + public void testApplyToEither_normalCompletion1() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncFunction r = new IncFunction(); + final CompletableFuture h = m.applyToEither(f, g, r); + + f.complete(v1); + checkCompletedNormally(h, inc(v1)); + g.complete(v2); + + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + checkCompletedNormally(h, inc(v1)); + }} + + public void testApplyToEither_normalCompletion2() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncFunction r = new IncFunction(); + final CompletableFuture h = m.applyToEither(f, g, r); + + g.complete(v2); + checkCompletedNormally(h, inc(v2)); + f.complete(v1); + + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + checkCompletedNormally(h, inc(v2)); + }} + + public void testApplyToEither_normalCompletion3() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncFunction r = new IncFunction(); + + f.complete(v1); + g.complete(v2); + final CompletableFuture h = m.applyToEither(f, g, r); + + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + + // unspecified behavior + assertTrue(Objects.equals(h.join(), inc(v1)) || + Objects.equals(h.join(), inc(v2))); + assertEquals(1, r.invocationCount); + }} /** - * acceptEither result completes exceptionally after exceptional + * applyToEither result completes exceptionally after exceptional * completion of either source */ - public void testAcceptEither2() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - IncAction r = new IncAction(); - CompletableFuture g = f.acceptEither(f2, r); - f.completeExceptionally(new CFException()); - f2.complete(one); - checkCompletedWithWrappedCFException(g); - - r = new IncAction(); - f = new CompletableFuture<>(); - f2 = new CompletableFuture<>(); - f2.completeExceptionally(new CFException()); - g = f.acceptEither(f2, r); - checkCompletedWithWrappedCFException(g); - } - - /** - * acceptEither result completes exceptionally if action does - */ - public void testAcceptEither3() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - FailingConsumer r = new FailingConsumer(); - CompletableFuture g = f.acceptEither(f2, r); - f2.complete(two); - checkCompletedWithWrappedCFException(g); - } - - /** - * acceptEither result completes exceptionally if either source cancelled - */ - public void testAcceptEither4() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - IncAction r = new IncAction(); - CompletableFuture g = f.acceptEither(f2, r); - assertTrue(f.cancel(true)); - checkCompletedWithWrappedCancellationException(g); - f = new CompletableFuture<>(); - f2 = new CompletableFuture<>(); - assertTrue(f2.cancel(true)); - checkCompletedWithWrappedCancellationException(g); - } + public void testApplyToEither_exceptionalCompletion1() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncFunction r = new IncFunction(); + final CompletableFuture h = m.applyToEither(f, g, r); + final CFException ex = new CFException(); + + f.completeExceptionally(ex); + checkCompletedWithWrappedCFException(h, ex); + g.complete(v1); + + assertEquals(0, r.invocationCount); + checkCompletedNormally(g, v1); + checkCompletedWithWrappedCFException(f, ex); + checkCompletedWithWrappedCFException(h, ex); + }} + + public void testApplyToEither_exceptionalCompletion2() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncFunction r = new IncFunction(); + final CompletableFuture h = m.applyToEither(f, g, r); + final CFException ex = new CFException(); + + g.completeExceptionally(ex); + checkCompletedWithWrappedCFException(h, ex); + f.complete(v1); + + assertEquals(0, r.invocationCount); + checkCompletedNormally(f, v1); + checkCompletedWithWrappedCFException(g, ex); + checkCompletedWithWrappedCFException(h, ex); + }} + + public void testApplyToEither_exceptionalCompletion3() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncFunction r = new IncFunction(); + final CFException ex = new CFException(); + + g.completeExceptionally(ex); + f.complete(v1); + final CompletableFuture h = m.applyToEither(f, g, r); - /** - * runAfterEither result completes normally after normal completion - * of either source - */ - public void testRunAfterEither() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - Noop r = new Noop(); - CompletableFuture g = f.runAfterEither(f2, r); - f.complete(one); - checkCompletedNormally(g, null); - f2.complete(one); - checkCompletedNormally(g, null); - assertTrue(r.ran); - - r = new Noop(); - f = new CompletableFuture<>(); - f.complete(one); - f2 = new CompletableFuture<>(); - g = f.runAfterEither(f2, r); - checkCompletedNormally(g, null); - assertTrue(r.ran); - } + // unspecified behavior + Integer v; + try { + assertEquals(inc(v1), h.join()); + assertEquals(1, r.invocationCount); + } catch (CompletionException ok) { + checkCompletedWithWrappedCFException(h, ex); + assertEquals(0, r.invocationCount); + } - /** - * runAfterEither result completes exceptionally after exceptional - * completion of either source - */ - public void testRunAfterEither2() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - Noop r = new Noop(); - CompletableFuture g = f.runAfterEither(f2, r); - f.completeExceptionally(new CFException()); - f2.complete(one); - checkCompletedWithWrappedCFException(g); + checkCompletedWithWrappedCFException(g, ex); + checkCompletedNormally(f, v1); + }} + + public void testApplyToEither_exceptionalCompletion4() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncFunction r = new IncFunction(); + final CFException ex = new CFException(); + + f.completeExceptionally(ex); + g.complete(v1); + final CompletableFuture h = m.applyToEither(f, g, r); - r = new Noop(); - f = new CompletableFuture<>(); - f2 = new CompletableFuture<>(); - f2.completeExceptionally(new CFException()); - g = f.runAfterEither(f2, r); - checkCompletedWithWrappedCFException(g); - } + // unspecified behavior + Integer v; + try { + assertEquals(inc(v1), h.join()); + assertEquals(1, r.invocationCount); + } catch (CompletionException ok) { + checkCompletedWithWrappedCFException(h, ex); + assertEquals(0, r.invocationCount); + } - /** - * runAfterEither result completes exceptionally if action does - */ - public void testRunAfterEither3() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - FailingNoop r = new FailingNoop(); - CompletableFuture g = f.runAfterEither(f2, r); - f2.complete(two); - checkCompletedWithWrappedCFException(g); - } + checkCompletedWithWrappedCFException(f, ex); + checkCompletedNormally(g, v1); + }} /** - * runAfterEither result completes exceptionally if either source cancelled + * applyToEither result completes exceptionally if action does */ - public void testRunAfterEither4() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - Noop r = new Noop(); - CompletableFuture g = f.runAfterEither(f2, r); - assertTrue(f.cancel(true)); - checkCompletedWithWrappedCancellationException(g); - f = new CompletableFuture<>(); - f2 = new CompletableFuture<>(); - assertTrue(f2.cancel(true)); - checkCompletedWithWrappedCancellationException(g); - } + public void testApplyToEither_actionFailed1() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final FailingFunction r = new FailingFunction(); + final CompletableFuture h = m.applyToEither(f, g, r); + + f.complete(v1); + checkCompletedWithWrappedCFException(h); + g.complete(v2); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} + + public void testApplyToEither_actionFailed2() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final FailingFunction r = new FailingFunction(); + final CompletableFuture h = m.applyToEither(f, g, r); + + g.complete(v2); + checkCompletedWithWrappedCFException(h); + f.complete(v1); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} /** - * thenCompose result completes normally after normal completion of source + * applyToEither result completes exceptionally if either source cancelled */ - public void testThenCompose() { - CompletableFuture f, g; - CompletableFutureInc r; + public void testApplyToEither_sourceCancelled1() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncFunction r = new IncFunction(); + final CompletableFuture h = m.applyToEither(f, g, 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); - } + assertTrue(f.cancel(mayInterruptIfRunning)); + checkCompletedWithWrappedCancellationException(h); + g.complete(v1); - /** - * thenCompose result completes exceptionally after exceptional - * completion of source - */ - public void testThenCompose2() { - CompletableFuture f, g; - CompletableFutureInc r; + checkCancelled(f); + assertEquals(0, r.invocationCount); + checkCompletedNormally(g, v1); + checkCompletedWithWrappedCancellationException(h); + }} - f = new CompletableFuture<>(); - g = f.thenCompose(r = new CompletableFutureInc()); - f.completeExceptionally(new CFException()); - checkCompletedWithWrappedCFException(g); + public void testApplyToEither_sourceCancelled2() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncFunction r = new IncFunction(); + final CompletableFuture h = m.applyToEither(f, g, r); + + assertTrue(g.cancel(mayInterruptIfRunning)); + checkCompletedWithWrappedCancellationException(h); + f.complete(v1); + + checkCancelled(g); + assertEquals(0, r.invocationCount); + checkCompletedNormally(f, v1); + checkCompletedWithWrappedCancellationException(h); + }} + + public void testApplyToEither_sourceCancelled3() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncFunction r = new IncFunction(); + + assertTrue(g.cancel(mayInterruptIfRunning)); + f.complete(v1); + final CompletableFuture h = m.applyToEither(f, g, r); - f = new CompletableFuture<>(); - f.completeExceptionally(new CFException()); - g = f.thenCompose(r = new CompletableFutureInc()); - checkCompletedWithWrappedCFException(g); - } + // unspecified behavior + Integer v; + try { + assertEquals(inc(v1), h.join()); + assertEquals(1, r.invocationCount); + } catch (CompletionException ok) { + checkCompletedWithWrappedCancellationException(h); + assertEquals(0, r.invocationCount); + } - /** - * thenCompose result completes exceptionally if action does - */ - public void testThenCompose3() { - CompletableFuture f, g; - FailingCompletableFutureFunction r; + checkCancelled(g); + checkCompletedNormally(f, v1); + }} + + public void testApplyToEither_sourceCancelled4() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncFunction r = new IncFunction(); + + assertTrue(f.cancel(mayInterruptIfRunning)); + g.complete(v1); + final CompletableFuture h = m.applyToEither(f, g, r); - f = new CompletableFuture<>(); - g = f.thenCompose(r = new FailingCompletableFutureFunction()); - f.complete(one); - checkCompletedWithWrappedCFException(g); + // unspecified behavior + Integer v; + try { + assertEquals(inc(v1), h.join()); + assertEquals(1, r.invocationCount); + } catch (CompletionException ok) { + checkCompletedWithWrappedCancellationException(h); + assertEquals(0, r.invocationCount); + } - f = new CompletableFuture<>(); - f.complete(one); - g = f.thenCompose(r = new FailingCompletableFutureFunction()); - checkCompletedWithWrappedCFException(g); - } + checkCancelled(f); + checkCompletedNormally(g, v1); + }} /** - * thenCompose result completes exceptionally if source cancelled + * acceptEither result completes normally after normal completion + * of either source */ - public void testThenCompose4() { - CompletableFuture f, g; - CompletableFutureInc r; + public void testAcceptEither_normalCompletion1() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncAction r = new IncAction(); + final CompletableFuture h = m.acceptEither(f, g, 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); - } - - // asyncs + f.complete(v1); + checkCompletedNormally(h, null); + assertEquals(inc(v1), r.value); + g.complete(v2); - /** - * thenRunAsync result completes normally after normal completion of source - */ - public void testThenRunAsync() { - CompletableFuture f = new CompletableFuture<>(); - Noop r = new Noop(); - CompletableFuture g = f.thenRunAsync(r); - f.complete(null); - checkCompletedNormally(g, null); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + checkCompletedNormally(h, null); + }} - // reordered version - f = new CompletableFuture<>(); - f.complete(null); - r = new Noop(); - g = f.thenRunAsync(r); - checkCompletedNormally(g, null); - } + public void testAcceptEither_normalCompletion2() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncAction r = new IncAction(); + final CompletableFuture h = m.acceptEither(f, g, r); - /** - * thenRunAsync result completes exceptionally after exceptional - * completion of source - */ - public void testThenRunAsync2() { - CompletableFuture f = new CompletableFuture<>(); - Noop r = new Noop(); - CompletableFuture g = f.thenRunAsync(r); - f.completeExceptionally(new CFException()); - try { - g.join(); - shouldThrow(); - } catch (CompletionException success) {} - checkCompletedWithWrappedCFException(g); - } + g.complete(v2); + checkCompletedNormally(h, null); + assertEquals(inc(v2), r.value); + f.complete(v1); - /** - * thenRunAsync result completes exceptionally if action does - */ - public void testThenRunAsync3() { - CompletableFuture f = new CompletableFuture<>(); - FailingNoop r = new FailingNoop(); - CompletableFuture g = f.thenRunAsync(r); - f.complete(null); - checkCompletedWithWrappedCFException(g); - } + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + checkCompletedNormally(h, null); + }} - /** - * thenRunAsync result completes exceptionally if source cancelled - */ - public void testThenRunAsync4() { - CompletableFuture f = new CompletableFuture<>(); - Noop r = new Noop(); - CompletableFuture g = f.thenRunAsync(r); - assertTrue(f.cancel(true)); - checkCompletedWithWrappedCancellationException(g); - } + public void testAcceptEither_normalCompletion3() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncAction r = new IncAction(); + + f.complete(v1); + g.complete(v2); + final CompletableFuture h = m.acceptEither(f, g, r); - /** - * thenApplyAsync result completes normally after normal completion of source - */ - public void testThenApplyAsync() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture g = f.thenApplyAsync(inc); - f.complete(one); - checkCompletedNormally(g, two); - } + checkCompletedNormally(h, null); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); - /** - * thenApplyAsync result completes exceptionally after exceptional - * completion of source - */ - public void testThenApplyAsync2() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture g = f.thenApplyAsync(inc); - f.completeExceptionally(new CFException()); - checkCompletedWithWrappedCFException(g); - } + // unspecified behavior + assertTrue(Objects.equals(r.value, inc(v1)) || + Objects.equals(r.value, inc(v2))); + }} /** - * thenApplyAsync result completes exceptionally if action does + * acceptEither result completes exceptionally after exceptional + * completion of either source */ - public void testThenApplyAsync3() { - CompletableFuture f = new CompletableFuture<>(); - FailingFunction r = new FailingFunction(); - CompletableFuture g = f.thenApplyAsync(r); - f.complete(null); - checkCompletedWithWrappedCFException(g); - } + public void testAcceptEither_exceptionalCompletion1() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncAction r = new IncAction(); + final CompletableFuture h = m.acceptEither(f, g, r); + final CFException ex = new CFException(); + + f.completeExceptionally(ex); + checkCompletedWithWrappedCFException(h, ex); + g.complete(v1); + + assertEquals(0, r.invocationCount); + checkCompletedNormally(g, v1); + checkCompletedWithWrappedCFException(f, ex); + checkCompletedWithWrappedCFException(h, ex); + }} + + public void testAcceptEither_exceptionalCompletion2() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncAction r = new IncAction(); + final CompletableFuture h = m.acceptEither(f, g, r); + final CFException ex = new CFException(); + + g.completeExceptionally(ex); + checkCompletedWithWrappedCFException(h, ex); + f.complete(v1); + + assertEquals(0, r.invocationCount); + checkCompletedNormally(f, v1); + checkCompletedWithWrappedCFException(g, ex); + checkCompletedWithWrappedCFException(h, ex); + }} + + public void testAcceptEither_exceptionalCompletion3() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncAction r = new IncAction(); + final CFException ex = new CFException(); + + g.completeExceptionally(ex); + f.complete(v1); + final CompletableFuture h = m.acceptEither(f, g, r); - /** - * thenApplyAsync result completes exceptionally if source cancelled - */ - public void testThenApplyAsync4() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture g = f.thenApplyAsync(inc); - assertTrue(f.cancel(true)); - checkCompletedWithWrappedCancellationException(g); - } + // unspecified behavior + Integer v; + try { + assertNull(h.join()); + assertEquals(1, r.invocationCount); + assertEquals(inc(v1), r.value); + } catch (CompletionException ok) { + checkCompletedWithWrappedCFException(h, ex); + assertEquals(0, r.invocationCount); + } - /** - * thenAcceptAsync result completes normally after normal - * completion of source - */ - public void testThenAcceptAsync() { - CompletableFuture f = new CompletableFuture<>(); - IncAction r = new IncAction(); - CompletableFuture g = f.thenAcceptAsync(r); - f.complete(one); - checkCompletedNormally(g, null); - assertEquals(r.value, 2); - } + checkCompletedWithWrappedCFException(g, ex); + checkCompletedNormally(f, v1); + }} + + public void testAcceptEither_exceptionalCompletion4() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncAction r = new IncAction(); + final CFException ex = new CFException(); + + f.completeExceptionally(ex); + g.complete(v1); + final CompletableFuture h = m.acceptEither(f, g, r); - /** - * thenAcceptAsync result completes exceptionally after exceptional - * completion of source - */ - public void testThenAcceptAsync2() { - CompletableFuture f = new CompletableFuture<>(); - IncAction r = new IncAction(); - CompletableFuture g = f.thenAcceptAsync(r); - f.completeExceptionally(new CFException()); - checkCompletedWithWrappedCFException(g); - } + // unspecified behavior + Integer v; + try { + assertNull(h.join()); + assertEquals(1, r.invocationCount); + assertEquals(inc(v1), r.value); + } catch (CompletionException ok) { + checkCompletedWithWrappedCFException(h, ex); + assertEquals(0, r.invocationCount); + } - /** - * thenAcceptAsync result completes exceptionally if action does - */ - public void testThenAcceptAsync3() { - CompletableFuture f = new CompletableFuture<>(); - FailingConsumer r = new FailingConsumer(); - CompletableFuture g = f.thenAcceptAsync(r); - f.complete(null); - checkCompletedWithWrappedCFException(g); - } + checkCompletedWithWrappedCFException(f, ex); + checkCompletedNormally(g, v1); + }} /** - * thenAcceptAsync result completes exceptionally if source cancelled + * acceptEither result completes exceptionally if action does */ - public void testThenAcceptAsync4() { - CompletableFuture f = new CompletableFuture<>(); - IncAction r = new IncAction(); - CompletableFuture g = f.thenAcceptAsync(r); - assertTrue(f.cancel(true)); - checkCompletedWithWrappedCancellationException(g); - } + public void testAcceptEither_actionFailed1() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final FailingConsumer r = new FailingConsumer(); + final CompletableFuture h = m.acceptEither(f, g, r); + + f.complete(v1); + checkCompletedWithWrappedCFException(h); + g.complete(v2); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} + + public void testAcceptEither_actionFailed2() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final FailingConsumer r = new FailingConsumer(); + final CompletableFuture h = m.acceptEither(f, g, r); + + g.complete(v2); + checkCompletedWithWrappedCFException(h); + f.complete(v1); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} /** - * thenCombineAsync result completes normally after normal - * completion of sources + * acceptEither result completes exceptionally if either source cancelled */ - public void testThenCombineAsync() { - CompletableFuture f, g, h; + public void testAcceptEither_sourceCancelled1() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncAction r = new IncAction(); + final CompletableFuture h = m.acceptEither(f, g, r); - 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); + assertTrue(f.cancel(mayInterruptIfRunning)); + checkCompletedWithWrappedCancellationException(h); + g.complete(v1); - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - g.complete(1); - f.complete(3); - h = f.thenCombineAsync(g, subtract); - checkCompletedNormally(h, 2); - } + checkCancelled(f); + assertEquals(0, r.invocationCount); + checkCompletedNormally(g, v1); + checkCompletedWithWrappedCancellationException(h); + }} - /** - * thenCombineAsync result completes exceptionally after exceptional - * completion of either source - */ - public void testThenCombineAsync2() { - CompletableFuture f, g, h; + public void testAcceptEither_sourceCancelled2() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncAction r = new IncAction(); + final CompletableFuture h = m.acceptEither(f, g, r); + + assertTrue(g.cancel(mayInterruptIfRunning)); + checkCompletedWithWrappedCancellationException(h); + f.complete(v1); + + checkCancelled(g); + assertEquals(0, r.invocationCount); + checkCompletedNormally(f, v1); + checkCompletedWithWrappedCancellationException(h); + }} + + public void testAcceptEither_sourceCancelled3() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncAction r = new IncAction(); + + assertTrue(g.cancel(mayInterruptIfRunning)); + f.complete(v1); + final CompletableFuture h = m.acceptEither(f, g, r); - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenCombineAsync(g, subtract); - f.completeExceptionally(new CFException()); - checkIncomplete(h); - g.complete(1); - checkCompletedWithWrappedCFException(h); + // unspecified behavior + Integer v; + try { + assertNull(h.join()); + assertEquals(1, r.invocationCount); + assertEquals(inc(v1), r.value); + } catch (CompletionException ok) { + checkCompletedWithWrappedCancellationException(h); + assertEquals(0, r.invocationCount); + } - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenCombineAsync(g, subtract); - g.completeExceptionally(new CFException()); - checkIncomplete(h); - f.complete(3); - checkCompletedWithWrappedCFException(h); + checkCancelled(g); + checkCompletedNormally(f, v1); + }} + + public void testAcceptEither_sourceCancelled4() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final IncAction r = new IncAction(); + + assertTrue(f.cancel(mayInterruptIfRunning)); + g.complete(v1); + final CompletableFuture h = m.acceptEither(f, g, r); - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - g.completeExceptionally(new CFException()); - f.complete(3); - h = f.thenCombineAsync(g, subtract); - checkCompletedWithWrappedCFException(h); - } + // unspecified behavior + Integer v; + try { + assertNull(h.join()); + assertEquals(1, r.invocationCount); + assertEquals(inc(v1), r.value); + } catch (CompletionException ok) { + checkCompletedWithWrappedCancellationException(h); + assertEquals(0, r.invocationCount); + } - /** - * thenCombineAsync result completes exceptionally if action does - */ - public void testThenCombineAsync3() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - FailingBiFunction r = new FailingBiFunction(); - CompletableFuture g = f.thenCombineAsync(f2, r); - f.complete(one); - checkIncomplete(g); - assertFalse(r.ran); - f2.complete(two); - checkCompletedWithWrappedCFException(g); - assertTrue(r.ran); - } + checkCancelled(f); + checkCompletedNormally(g, v1); + }} /** - * thenCombineAsync result completes exceptionally if either source cancelled + * runAfterEither result completes normally after normal completion + * of either source */ - public void testThenCombineAsync4() { - CompletableFuture f, g, h; - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenCombineAsync(g, subtract); - assertTrue(f.cancel(true)); - checkIncomplete(h); - g.complete(1); - checkCompletedWithWrappedCancellationException(h); + public void testRunAfterEither_normalCompletion1() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r = new Noop(); + final CompletableFuture h = m.runAfterEither(f, g, r); - f = new CompletableFuture<>(); - 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.complete(v1); + checkCompletedNormally(h, null); + assertEquals(1, r.invocationCount); + g.complete(v2); - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - f.complete(3); - assertTrue(g.cancel(true)); - h = f.thenCombineAsync(g, subtract); - checkCompletedWithWrappedCancellationException(h); - } + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + checkCompletedNormally(h, null); + assertEquals(1, r.invocationCount); + }} - /** - * thenAcceptBothAsync result completes normally after normal - * completion of sources - */ - public void testThenAcceptBothAsync() { - CompletableFuture f, g; - CompletableFuture h; - SubtractAction r; + public void testRunAfterEither_normalCompletion2() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r = new Noop(); + final CompletableFuture h = m.runAfterEither(f, g, r); - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenAcceptBothAsync(g, r = new SubtractAction()); - f.complete(3); - checkIncomplete(h); - g.complete(1); + g.complete(v2); checkCompletedNormally(h, null); - assertEquals(r.value, 2); + assertEquals(1, r.invocationCount); + f.complete(v1); - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenAcceptBothAsync(g, r = new SubtractAction()); - g.complete(1); - checkIncomplete(h); - f.complete(3); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); checkCompletedNormally(h, null); - assertEquals(r.value, 2); + assertEquals(1, r.invocationCount); + }} + + public void testRunAfterEither_normalCompletion3() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r = new Noop(); + + f.complete(v1); + g.complete(v2); + final CompletableFuture h = m.runAfterEither(f, g, r); - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - g.complete(1); - f.complete(3); - h = f.thenAcceptBothAsync(g, r = new SubtractAction()); checkCompletedNormally(h, null); - assertEquals(r.value, 2); - } + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + assertEquals(1, r.invocationCount); + }} /** - * thenAcceptBothAsync result completes exceptionally after exceptional - * completion of source + * runAfterEither result completes exceptionally after exceptional + * completion of either source */ - public void testThenAcceptBothAsync2() { - CompletableFuture f, g; - CompletableFuture h; - SubtractAction r; + public void testRunAfterEither_exceptionalCompletion1() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r = new Noop(); + final CompletableFuture h = m.runAfterEither(f, g, r); + final CFException ex = new CFException(); + + f.completeExceptionally(ex); + checkCompletedWithWrappedCFException(h, ex); + g.complete(v1); + + assertEquals(0, r.invocationCount); + checkCompletedNormally(g, v1); + checkCompletedWithWrappedCFException(f, ex); + checkCompletedWithWrappedCFException(h, ex); + }} + + public void testRunAfterEither_exceptionalCompletion2() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r = new Noop(); + final CompletableFuture h = m.runAfterEither(f, g, r); + final CFException ex = new CFException(); + + g.completeExceptionally(ex); + checkCompletedWithWrappedCFException(h, ex); + f.complete(v1); + + assertEquals(0, r.invocationCount); + checkCompletedNormally(f, v1); + checkCompletedWithWrappedCFException(g, ex); + checkCompletedWithWrappedCFException(h, ex); + }} + + public void testRunAfterEither_exceptionalCompletion3() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r = new Noop(); + final CFException ex = new CFException(); + + g.completeExceptionally(ex); + f.complete(v1); + final CompletableFuture h = m.runAfterEither(f, g, r); - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenAcceptBothAsync(g, r = new SubtractAction()); - f.completeExceptionally(new CFException()); - checkIncomplete(h); - g.complete(1); - checkCompletedWithWrappedCFException(h); + // unspecified behavior + Integer v; + try { + assertNull(h.join()); + assertEquals(1, r.invocationCount); + } catch (CompletionException ok) { + checkCompletedWithWrappedCFException(h, ex); + assertEquals(0, r.invocationCount); + } - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenAcceptBothAsync(g, r = new SubtractAction()); - g.completeExceptionally(new CFException()); - checkIncomplete(h); - f.complete(3); - checkCompletedWithWrappedCFException(h); + checkCompletedWithWrappedCFException(g, ex); + checkCompletedNormally(f, v1); + }} + + public void testRunAfterEither_exceptionalCompletion4() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r = new Noop(); + final CFException ex = new CFException(); + + f.completeExceptionally(ex); + g.complete(v1); + final CompletableFuture h = m.runAfterEither(f, g, r); - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - f.complete(3); - g.completeExceptionally(new CFException()); - h = f.thenAcceptBothAsync(g, r = new SubtractAction()); - checkCompletedWithWrappedCFException(h); + // unspecified behavior + Integer v; + try { + assertNull(h.join()); + assertEquals(1, r.invocationCount); + } catch (CompletionException ok) { + checkCompletedWithWrappedCFException(h, ex); + assertEquals(0, r.invocationCount); + } - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - f.completeExceptionally(new CFException()); - g.complete(3); - h = f.thenAcceptBothAsync(g, r = new SubtractAction()); - checkCompletedWithWrappedCFException(h); - } + checkCompletedWithWrappedCFException(f, ex); + checkCompletedNormally(g, v1); + }} /** - * thenAcceptBothAsync result completes exceptionally if action does + * runAfterEither result completes exceptionally if action does */ - public void testThenAcceptBothAsync3() { - CompletableFuture f, g; - CompletableFuture h; - FailingBiConsumer r; - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenAcceptBothAsync(g, r = new FailingBiConsumer()); - f.complete(3); - checkIncomplete(h); - g.complete(1); - checkCompletedWithWrappedCFException(h); - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - f.complete(3); - g.complete(1); - h = f.thenAcceptBothAsync(g, r = new FailingBiConsumer()); - checkCompletedWithWrappedCFException(h); - } + public void testRunAfterEither_actionFailed1() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final FailingNoop r = new FailingNoop(); + final CompletableFuture h = m.runAfterEither(f, g, r); + + f.complete(v1); + checkCompletedWithWrappedCFException(h); + g.complete(v2); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} + + public void testRunAfterEither_actionFailed2() { + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + for (Integer v2 : new Integer[] { 2, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final FailingNoop r = new FailingNoop(); + final CompletableFuture h = m.runAfterEither(f, g, r); + + g.complete(v2); + checkCompletedWithWrappedCFException(h); + f.complete(v1); + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v2); + }} /** - * thenAcceptBothAsync result completes exceptionally if either source cancelled + * runAfterEither result completes exceptionally if either source cancelled */ - public void testThenAcceptBothAsync4() { - CompletableFuture f, g; - CompletableFuture h; - SubtractAction r; + public void testRunAfterEither_sourceCancelled1() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r = new Noop(); + final CompletableFuture h = m.runAfterEither(f, g, r); - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenAcceptBothAsync(g, r = new SubtractAction()); - assertTrue(f.cancel(true)); - checkIncomplete(h); - g.complete(1); + assertTrue(f.cancel(mayInterruptIfRunning)); checkCompletedWithWrappedCancellationException(h); + g.complete(v1); - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenAcceptBothAsync(g, r = new SubtractAction()); - assertTrue(g.cancel(true)); - checkIncomplete(h); - f.complete(3); + checkCancelled(f); + assertEquals(0, r.invocationCount); + checkCompletedNormally(g, v1); checkCompletedWithWrappedCancellationException(h); + }} - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - f.complete(3); - assertTrue(g.cancel(true)); - h = f.thenAcceptBothAsync(g, r = new SubtractAction()); - checkCompletedWithWrappedCancellationException(h); + public void testRunAfterEither_sourceCancelled2() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r = new Noop(); + final CompletableFuture h = m.runAfterEither(f, g, r); + + assertTrue(g.cancel(mayInterruptIfRunning)); + checkCompletedWithWrappedCancellationException(h); + f.complete(v1); + + checkCancelled(g); + assertEquals(0, r.invocationCount); + checkCompletedNormally(f, v1); + checkCompletedWithWrappedCancellationException(h); + }} + + public void testRunAfterEither_sourceCancelled3() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r = new Noop(); + + assertTrue(g.cancel(mayInterruptIfRunning)); + f.complete(v1); + final CompletableFuture h = m.runAfterEither(f, g, r); - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - assertTrue(f.cancel(true)); - g.complete(3); - h = f.thenAcceptBothAsync(g, r = new SubtractAction()); - checkCompletedWithWrappedCancellationException(h); - } - - /** - * runAfterBothAsync result completes normally after normal - * completion of sources - */ - public void testRunAfterBothAsync() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - Noop r = new Noop(); - CompletableFuture g = f.runAfterBothAsync(f2, r); - f.complete(one); - checkIncomplete(g); - f2.complete(two); - checkCompletedNormally(g, null); - assertTrue(r.ran); - } + // unspecified behavior + Integer v; + try { + assertNull(h.join()); + assertEquals(1, r.invocationCount); + } catch (CompletionException ok) { + checkCompletedWithWrappedCancellationException(h); + assertEquals(0, r.invocationCount); + } - /** - * runAfterBothAsync result completes exceptionally after exceptional - * completion of source - */ - public void testRunAfterBothAsync2() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - Noop r = new Noop(); - CompletableFuture g = f.runAfterBothAsync(f2, r); - f.completeExceptionally(new CFException()); - f2.complete(two); - checkCompletedWithWrappedCFException(g); + checkCancelled(g); + checkCompletedNormally(f, v1); + }} + + public void testRunAfterEither_sourceCancelled4() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFuture g = new CompletableFuture<>(); + final Noop r = new Noop(); + + assertTrue(f.cancel(mayInterruptIfRunning)); + g.complete(v1); + final CompletableFuture h = m.runAfterEither(f, g, r); - r = new Noop(); - f = new CompletableFuture<>(); - f2 = new CompletableFuture<>(); - g = f.runAfterBothAsync(f2, r); - f.complete(one); - f2.completeExceptionally(new CFException()); - checkCompletedWithWrappedCFException(g); - } + // unspecified behavior + Integer v; + try { + assertNull(h.join()); + assertEquals(1, r.invocationCount); + } catch (CompletionException ok) { + checkCompletedWithWrappedCancellationException(h); + assertEquals(0, r.invocationCount); + } - /** - * runAfterBothAsync result completes exceptionally if action does - */ - public void testRunAfterBothAsync3() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - FailingNoop r = new FailingNoop(); - CompletableFuture g = f.runAfterBothAsync(f2, r); - f.complete(one); - checkIncomplete(g); - f2.complete(two); - checkCompletedWithWrappedCFException(g); - } + checkCancelled(f); + checkCompletedNormally(g, v1); + }} /** - * runAfterBothAsync result completes exceptionally if either source cancelled + * thenCompose result completes normally after normal completion of source */ - public void testRunAfterBothAsync4() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - Noop r = new Noop(); - CompletableFuture g = f.runAfterBothAsync(f2, r); - assertTrue(f.cancel(true)); - f2.complete(two); - checkCompletedWithWrappedCancellationException(g); - - r = new Noop(); - f = new CompletableFuture<>(); - f2 = new CompletableFuture<>(); - g = f.runAfterBothAsync(f2, r); - f.complete(one); - assertTrue(f2.cancel(true)); - checkCompletedWithWrappedCancellationException(g); - } + public void testThenCompose_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 CompletableFutureInc r = new CompletableFutureInc(); + if (!createIncomplete) f.complete(v1); + final CompletableFuture g = f.thenCompose(r); + if (createIncomplete) f.complete(v1); + + checkCompletedNormally(g, inc(v1)); + checkCompletedNormally(f, v1); + assertEquals(1, r.invocationCount); + }} /** - * applyToEitherAsync result completes normally after normal - * completion of sources + * thenCompose result completes exceptionally after exceptional + * completion of source */ - public void testApplyToEitherAsync() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - CompletableFuture g = f.applyToEitherAsync(f2, inc); - f.complete(one); - checkCompletedNormally(g, two); - - f = new CompletableFuture<>(); - f.complete(one); - f2 = new CompletableFuture<>(); - g = f.applyToEitherAsync(f2, inc); - checkCompletedNormally(g, two); - } + public void testThenCompose_exceptionalCompletion() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean createIncomplete : new boolean[] { true, false }) + { + final CFException ex = new CFException(); + final CompletableFutureInc r = new CompletableFutureInc(); + final CompletableFuture f = new CompletableFuture<>(); + if (!createIncomplete) f.completeExceptionally(ex); + final CompletableFuture g = f.thenCompose(r); + if (createIncomplete) f.completeExceptionally(ex); + + checkCompletedWithWrappedCFException(g, ex); + checkCompletedWithWrappedCFException(f, ex); + assertEquals(0, r.invocationCount); + }} /** - * applyToEitherAsync result completes exceptionally after exceptional - * completion of source + * thenCompose result completes exceptionally if action does */ - public void testApplyToEitherAsync2() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - CompletableFuture g = f.applyToEitherAsync(f2, inc); - f.completeExceptionally(new CFException()); - checkCompletedWithWrappedCFException(g); + public void testThenCompose_actionFailed() { + 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 FailingCompletableFutureFunction r + = new FailingCompletableFutureFunction(); + if (!createIncomplete) f.complete(v1); + final CompletableFuture g = f.thenCompose(r); + if (createIncomplete) f.complete(v1); - f = new CompletableFuture<>(); - f2 = new CompletableFuture<>(); - f2.completeExceptionally(new CFException()); - g = f.applyToEitherAsync(f2, inc); - f.complete(one); checkCompletedWithWrappedCFException(g); - } + checkCompletedNormally(f, v1); + }} /** - * applyToEitherAsync result completes exceptionally if action does + * thenCompose result completes exceptionally if source cancelled */ - public void testApplyToEitherAsync3() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - FailingFunction r = new FailingFunction(); - CompletableFuture g = f.applyToEitherAsync(f2, r); - f.complete(one); - checkCompletedWithWrappedCFException(g); - } + public void testThenCompose_sourceCancelled() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean createIncomplete : new boolean[] { true, false }) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + { + final CompletableFuture f = new CompletableFuture<>(); + final CompletableFutureInc r = new CompletableFutureInc(); + if (!createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning)); + final CompletableFuture g = f.thenCompose(r); + if (createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning)); - /** - * applyToEitherAsync result completes exceptionally if either source cancelled - */ - public void testApplyToEitherAsync4() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - CompletableFuture g = f.applyToEitherAsync(f2, inc); - assertTrue(f.cancel(true)); checkCompletedWithWrappedCancellationException(g); + checkCancelled(f); + }} - f = new CompletableFuture<>(); - f2 = new CompletableFuture<>(); - assertTrue(f2.cancel(true)); - g = f.applyToEitherAsync(f2, inc); - checkCompletedWithWrappedCancellationException(g); - } + // asyncs /** - * acceptEitherAsync result completes normally after normal - * completion of sources + * thenAcceptAsync result completes normally after normal + * completion of source */ - public void testAcceptEitherAsync() { + public void testThenAcceptAsync() { CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); IncAction r = new IncAction(); - CompletableFuture g = f.acceptEitherAsync(f2, r); - f.complete(one); - checkCompletedNormally(g, null); - assertEquals(r.value, 2); - - r = new IncAction(); - f = new CompletableFuture<>(); + CompletableFuture g = f.thenAcceptAsync(r); f.complete(one); - f2 = new CompletableFuture<>(); - g = f.acceptEitherAsync(f2, r); checkCompletedNormally(g, null); - assertEquals(r.value, 2); + assertEquals(r.value, (Integer) 2); } /** - * acceptEitherAsync result completes exceptionally after exceptional + * thenAcceptAsync result completes exceptionally after exceptional * completion of source */ - public void testAcceptEitherAsync2() { + public void testThenAcceptAsync2() { CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); IncAction r = new IncAction(); - CompletableFuture g = f.acceptEitherAsync(f2, r); + CompletableFuture g = f.thenAcceptAsync(r); f.completeExceptionally(new CFException()); checkCompletedWithWrappedCFException(g); - - r = new IncAction(); - f = new CompletableFuture<>(); - f2 = new CompletableFuture<>(); - f2.completeExceptionally(new CFException()); - g = f.acceptEitherAsync(f2, r); - f.complete(one); - checkCompletedWithWrappedCFException(g); } /** - * acceptEitherAsync result completes exceptionally if action does + * thenAcceptAsync result completes exceptionally if action does */ - public void testAcceptEitherAsync3() { + public void testThenAcceptAsync3() { CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); FailingConsumer r = new FailingConsumer(); - CompletableFuture g = f.acceptEitherAsync(f2, r); - f.complete(one); + CompletableFuture g = f.thenAcceptAsync(r); + f.complete(null); checkCompletedWithWrappedCFException(g); } /** - * acceptEitherAsync result completes exceptionally if either - * source cancelled + * thenAcceptAsync result completes exceptionally if source cancelled */ - public void testAcceptEitherAsync4() { + public void testThenAcceptAsync4() { CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); IncAction r = new IncAction(); - CompletableFuture g = f.acceptEitherAsync(f2, r); - assertTrue(f.cancel(true)); - checkCompletedWithWrappedCancellationException(g); - - r = new IncAction(); - f = new CompletableFuture<>(); - f2 = new CompletableFuture<>(); - assertTrue(f2.cancel(true)); - g = f.acceptEitherAsync(f2, r); - checkCompletedWithWrappedCancellationException(g); - } - - /** - * runAfterEitherAsync result completes normally after normal - * completion of sources - */ - public void testRunAfterEitherAsync() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - Noop r = new Noop(); - CompletableFuture g = f.runAfterEitherAsync(f2, r); - f.complete(one); - checkCompletedNormally(g, null); - assertTrue(r.ran); - - r = new Noop(); - f = new CompletableFuture<>(); - f.complete(one); - f2 = new CompletableFuture<>(); - g = f.runAfterEitherAsync(f2, r); - checkCompletedNormally(g, null); - assertTrue(r.ran); - } - - /** - * runAfterEitherAsync result completes exceptionally after exceptional - * completion of source - */ - public void testRunAfterEitherAsync2() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - Noop r = new Noop(); - CompletableFuture g = f.runAfterEitherAsync(f2, r); - f.completeExceptionally(new CFException()); - checkCompletedWithWrappedCFException(g); - - r = new Noop(); - f = new CompletableFuture<>(); - f2 = new CompletableFuture<>(); - f2.completeExceptionally(new CFException()); - g = f.runAfterEitherAsync(f2, r); - f.complete(one); - checkCompletedWithWrappedCFException(g); - } - - /** - * runAfterEitherAsync result completes exceptionally if action does - */ - public void testRunAfterEitherAsync3() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - FailingNoop r = new FailingNoop(); - CompletableFuture g = f.runAfterEitherAsync(f2, r); - f.complete(one); - checkCompletedWithWrappedCFException(g); - } - - /** - * runAfterEitherAsync result completes exceptionally if either - * source cancelled - */ - public void testRunAfterEitherAsync4() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - Noop r = new Noop(); - CompletableFuture g = f.runAfterEitherAsync(f2, r); - assertTrue(f.cancel(true)); - checkCompletedWithWrappedCancellationException(g); - - r = new Noop(); - f = new CompletableFuture<>(); - f2 = new CompletableFuture<>(); - assertTrue(f2.cancel(true)); - g = f.runAfterEitherAsync(f2, r); - checkCompletedWithWrappedCancellationException(g); - } - - /** - * thenComposeAsync result completes normally after normal - * completion of source - */ - public void testThenComposeAsync() { - 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); - } - - /** - * thenComposeAsync result completes exceptionally after - * exceptional completion of source - */ - public void testThenComposeAsync2() { - 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, 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); - } - - /** - * thenComposeAsync result completes exceptionally if source cancelled - */ - public void testThenComposeAsync4() { - CompletableFuture f, g; - CompletableFutureInc r; - - f = new CompletableFuture<>(); - g = f.thenComposeAsync(r = new CompletableFutureInc()); - assertTrue(f.cancel(true)); - checkCompletedWithWrappedCancellationException(g); - - f = new CompletableFuture<>(); + CompletableFuture g = f.thenAcceptAsync(r); assertTrue(f.cancel(true)); - g = f.thenComposeAsync(r = new CompletableFutureInc()); checkCompletedWithWrappedCancellationException(g); } // async with explicit executors /** - * thenRunAsync result completes normally after normal completion of source - */ - public void testThenRunAsyncE() { - CompletableFuture f = new CompletableFuture<>(); - Noop r = new Noop(); - CompletableFuture g = f.thenRunAsync(r, new ThreadExecutor()); - f.complete(null); - checkCompletedNormally(g, null); - - // reordered version - f = new CompletableFuture<>(); - f.complete(null); - r = new Noop(); - g = f.thenRunAsync(r, new ThreadExecutor()); - checkCompletedNormally(g, null); - } - - /** - * thenRunAsync result completes exceptionally after exceptional - * completion of source - */ - public void testThenRunAsync2E() { - CompletableFuture f = new CompletableFuture<>(); - Noop r = new Noop(); - CompletableFuture g = f.thenRunAsync(r, new ThreadExecutor()); - f.completeExceptionally(new CFException()); - try { - g.join(); - shouldThrow(); - } catch (CompletionException success) {} - checkCompletedWithWrappedCFException(g); - } - - /** - * thenRunAsync result completes exceptionally if action does - */ - public void testThenRunAsync3E() { - CompletableFuture f = new CompletableFuture<>(); - FailingNoop r = new FailingNoop(); - CompletableFuture g = f.thenRunAsync(r, new ThreadExecutor()); - f.complete(null); - checkCompletedWithWrappedCFException(g); - } - - /** - * thenRunAsync result completes exceptionally if source cancelled - */ - public void testThenRunAsync4E() { - CompletableFuture f = new CompletableFuture<>(); - Noop r = new Noop(); - CompletableFuture g = f.thenRunAsync(r, new ThreadExecutor()); - assertTrue(f.cancel(true)); - checkCompletedWithWrappedCancellationException(g); - } - - /** - * thenApplyAsync result completes normally after normal completion of source - */ - public void testThenApplyAsyncE() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture g = f.thenApplyAsync(inc, new ThreadExecutor()); - f.complete(one); - checkCompletedNormally(g, two); - } - - /** - * thenApplyAsync result completes exceptionally after exceptional - * completion of source - */ - public void testThenApplyAsync2E() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture g = f.thenApplyAsync(inc, new ThreadExecutor()); - f.completeExceptionally(new CFException()); - checkCompletedWithWrappedCFException(g); - } - - /** - * thenApplyAsync result completes exceptionally if action does - */ - public void testThenApplyAsync3E() { - CompletableFuture f = new CompletableFuture<>(); - FailingFunction r = new FailingFunction(); - CompletableFuture g = f.thenApplyAsync(r, new ThreadExecutor()); - f.complete(null); - checkCompletedWithWrappedCFException(g); - } - - /** - * thenApplyAsync result completes exceptionally if source cancelled - */ - public void testThenApplyAsync4E() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture g = f.thenApplyAsync(inc, new ThreadExecutor()); - assertTrue(f.cancel(true)); - checkCompletedWithWrappedCancellationException(g); - } - - /** * thenAcceptAsync result completes normally after normal * completion of source */ @@ -2192,7 +3020,7 @@ public class CompletableFutureTest exten CompletableFuture g = f.thenAcceptAsync(r, new ThreadExecutor()); f.complete(one); checkCompletedNormally(g, null); - assertEquals(r.value, 2); + assertEquals(r.value, (Integer) 2); } /** @@ -2229,621 +3057,6 @@ public class CompletableFutureTest exten checkCompletedWithWrappedCancellationException(g); } - /** - * thenCombineAsync result completes normally after normal - * completion of sources - */ - public void testThenCombineAsyncE() { - 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 either source - */ - public void testThenCombineAsync2E() { - 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()); - checkIncomplete(h); - g.complete(1); - checkCompletedWithWrappedCFException(h); - - f = new CompletableFuture<>(); - 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()); - } - - /** - * thenCombineAsync result completes exceptionally if action does - */ - public void testThenCombineAsync3E() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - FailingBiFunction r = new FailingBiFunction(); - 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, g, h; - ThreadExecutor e = new ThreadExecutor(); - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenCombineAsync(g, subtract, e); - assertTrue(f.cancel(true)); - checkIncomplete(h); - g.complete(1); - checkCompletedWithWrappedCancellationException(h); - - f = new CompletableFuture<>(); - 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()); - } - - /** - * thenAcceptBothAsync result completes normally after normal - * completion of sources - */ - public void testThenAcceptBothAsyncE() { - CompletableFuture f, g; - CompletableFuture h; - SubtractAction r; - ThreadExecutor e = new ThreadExecutor(); - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenAcceptBothAsync(g, r = new SubtractAction(), e); - f.complete(3); - checkIncomplete(h); - g.complete(1); - checkCompletedNormally(h, null); - assertEquals(r.value, 2); - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenAcceptBothAsync(g, r = new SubtractAction(), e); - g.complete(1); - checkIncomplete(h); - f.complete(3); - checkCompletedNormally(h, null); - assertEquals(r.value, 2); - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - g.complete(1); - f.complete(3); - h = f.thenAcceptBothAsync(g, r = new SubtractAction(), e); - checkCompletedNormally(h, null); - assertEquals(r.value, 2); - - assertEquals(3, e.count.get()); - } - - /** - * thenAcceptBothAsync result completes exceptionally after exceptional - * completion of source - */ - public void testThenAcceptBothAsync2E() { - CompletableFuture f, g; - CompletableFuture h; - SubtractAction r; - ThreadExecutor e = new ThreadExecutor(); - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenAcceptBothAsync(g, r = new SubtractAction(), e); - f.completeExceptionally(new CFException()); - checkIncomplete(h); - g.complete(1); - checkCompletedWithWrappedCFException(h); - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenAcceptBothAsync(g, r = new SubtractAction(), e); - 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.thenAcceptBothAsync(g, r = new SubtractAction(), e); - checkCompletedWithWrappedCFException(h); - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - f.completeExceptionally(new CFException()); - g.complete(3); - h = f.thenAcceptBothAsync(g, r = new SubtractAction(), e); - checkCompletedWithWrappedCFException(h); - - assertEquals(0, e.count.get()); - } - - /** - * thenAcceptBothAsync result completes exceptionally if action does - */ - public void testThenAcceptBothAsync3E() { - CompletableFuture f, g; - CompletableFuture h; - FailingBiConsumer r; - ThreadExecutor e = new ThreadExecutor(); - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenAcceptBothAsync(g, r = new FailingBiConsumer(), e); - f.complete(3); - checkIncomplete(h); - g.complete(1); - checkCompletedWithWrappedCFException(h); - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - f.complete(3); - g.complete(1); - h = f.thenAcceptBothAsync(g, r = new FailingBiConsumer(), e); - checkCompletedWithWrappedCFException(h); - - assertEquals(2, e.count.get()); - } - - /** - * thenAcceptBothAsync result completes exceptionally if either source cancelled - */ - public void testThenAcceptBothAsync4E() { - CompletableFuture f, g; - CompletableFuture h; - SubtractAction r; - ThreadExecutor e = new ThreadExecutor(); - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenAcceptBothAsync(g, r = new SubtractAction(), e); - assertTrue(f.cancel(true)); - checkIncomplete(h); - g.complete(1); - checkCompletedWithWrappedCancellationException(h); - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - h = f.thenAcceptBothAsync(g, r = new SubtractAction(), e); - assertTrue(g.cancel(true)); - checkIncomplete(h); - f.complete(3); - checkCompletedWithWrappedCancellationException(h); - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - f.complete(3); - assertTrue(g.cancel(true)); - h = f.thenAcceptBothAsync(g, r = new SubtractAction(), e); - checkCompletedWithWrappedCancellationException(h); - - f = new CompletableFuture<>(); - g = new CompletableFuture<>(); - assertTrue(f.cancel(true)); - g.complete(3); - h = f.thenAcceptBothAsync(g, r = new SubtractAction(), e); - checkCompletedWithWrappedCancellationException(h); - - assertEquals(0, e.count.get()); - } - - /** - * runAfterBothAsync result completes normally after normal - * completion of sources - */ - public void testRunAfterBothAsyncE() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - Noop r = new Noop(); - CompletableFuture g = f.runAfterBothAsync(f2, r, new ThreadExecutor()); - f.complete(one); - checkIncomplete(g); - f2.complete(two); - checkCompletedNormally(g, null); - assertTrue(r.ran); - } - - /** - * runAfterBothAsync result completes exceptionally after exceptional - * completion of source - */ - public void testRunAfterBothAsync2E() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - Noop r = new Noop(); - CompletableFuture g = f.runAfterBothAsync(f2, r, new ThreadExecutor()); - f.completeExceptionally(new CFException()); - f2.complete(two); - checkCompletedWithWrappedCFException(g); - - r = new Noop(); - f = new CompletableFuture<>(); - f2 = new CompletableFuture<>(); - g = f.runAfterBothAsync(f2, r, new ThreadExecutor()); - f.complete(one); - f2.completeExceptionally(new CFException()); - checkCompletedWithWrappedCFException(g); - } - - /** - * runAfterBothAsync result completes exceptionally if action does - */ - public void testRunAfterBothAsync3E() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - FailingNoop r = new FailingNoop(); - CompletableFuture g = f.runAfterBothAsync(f2, r, new ThreadExecutor()); - f.complete(one); - checkIncomplete(g); - f2.complete(two); - checkCompletedWithWrappedCFException(g); - } - - /** - * runAfterBothAsync result completes exceptionally if either source cancelled - */ - public void testRunAfterBothAsync4E() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - Noop r = new Noop(); - CompletableFuture g = f.runAfterBothAsync(f2, r, new ThreadExecutor()); - assertTrue(f.cancel(true)); - f2.complete(two); - checkCompletedWithWrappedCancellationException(g); - - r = new Noop(); - f = new CompletableFuture<>(); - f2 = new CompletableFuture<>(); - g = f.runAfterBothAsync(f2, r, new ThreadExecutor()); - f.complete(one); - assertTrue(f2.cancel(true)); - checkCompletedWithWrappedCancellationException(g); - } - - /** - * applyToEitherAsync result completes normally after normal - * completion of sources - */ - public void testApplyToEitherAsyncE() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - CompletableFuture g = f.applyToEitherAsync(f2, inc, new ThreadExecutor()); - f.complete(one); - checkCompletedNormally(g, two); - - f = new CompletableFuture<>(); - f.complete(one); - f2 = new CompletableFuture<>(); - g = f.applyToEitherAsync(f2, inc, new ThreadExecutor()); - checkCompletedNormally(g, two); - } - - /** - * applyToEitherAsync result completes exceptionally after exceptional - * completion of source - */ - public void testApplyToEitherAsync2E() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - CompletableFuture g = f.applyToEitherAsync(f2, inc, new ThreadExecutor()); - f.completeExceptionally(new CFException()); - checkCompletedWithWrappedCFException(g); - - f = new CompletableFuture<>(); - f2 = new CompletableFuture<>(); - f2.completeExceptionally(new CFException()); - g = f.applyToEitherAsync(f2, inc, new ThreadExecutor()); - f.complete(one); - checkCompletedWithWrappedCFException(g); - } - - /** - * applyToEitherAsync result completes exceptionally if action does - */ - public void testApplyToEitherAsync3E() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - FailingFunction r = new FailingFunction(); - CompletableFuture g = f.applyToEitherAsync(f2, r, new ThreadExecutor()); - f.complete(one); - checkCompletedWithWrappedCFException(g); - } - - /** - * applyToEitherAsync result completes exceptionally if either source cancelled - */ - public void testApplyToEitherAsync4E() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - CompletableFuture g = f.applyToEitherAsync(f2, inc, new ThreadExecutor()); - assertTrue(f.cancel(true)); - checkCompletedWithWrappedCancellationException(g); - - f = new CompletableFuture<>(); - f2 = new CompletableFuture<>(); - assertTrue(f2.cancel(true)); - g = f.applyToEitherAsync(f2, inc, new ThreadExecutor()); - checkCompletedWithWrappedCancellationException(g); - } - - /** - * acceptEitherAsync result completes normally after normal - * completion of sources - */ - public void testAcceptEitherAsyncE() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - IncAction r = new IncAction(); - CompletableFuture g = f.acceptEitherAsync(f2, r, new ThreadExecutor()); - f.complete(one); - checkCompletedNormally(g, null); - assertEquals(r.value, 2); - - r = new IncAction(); - f = new CompletableFuture<>(); - f.complete(one); - f2 = new CompletableFuture<>(); - g = f.acceptEitherAsync(f2, r, new ThreadExecutor()); - checkCompletedNormally(g, null); - assertEquals(r.value, 2); - } - - /** - * acceptEitherAsync result completes exceptionally after exceptional - * completion of source - */ - public void testAcceptEitherAsync2E() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - IncAction r = new IncAction(); - CompletableFuture g = f.acceptEitherAsync(f2, r, new ThreadExecutor()); - f.completeExceptionally(new CFException()); - checkCompletedWithWrappedCFException(g); - - r = new IncAction(); - f = new CompletableFuture<>(); - f2 = new CompletableFuture<>(); - f2.completeExceptionally(new CFException()); - g = f.acceptEitherAsync(f2, r, new ThreadExecutor()); - f.complete(one); - checkCompletedWithWrappedCFException(g); - } - - /** - * acceptEitherAsync result completes exceptionally if action does - */ - public void testAcceptEitherAsync3E() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - FailingConsumer r = new FailingConsumer(); - CompletableFuture g = f.acceptEitherAsync(f2, r, new ThreadExecutor()); - f.complete(one); - checkCompletedWithWrappedCFException(g); - } - - /** - * acceptEitherAsync result completes exceptionally if either - * source cancelled - */ - public void testAcceptEitherAsync4E() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - IncAction r = new IncAction(); - CompletableFuture g = f.acceptEitherAsync(f2, r, new ThreadExecutor()); - assertTrue(f.cancel(true)); - checkCompletedWithWrappedCancellationException(g); - - r = new IncAction(); - f = new CompletableFuture<>(); - f2 = new CompletableFuture<>(); - assertTrue(f2.cancel(true)); - g = f.acceptEitherAsync(f2, r, new ThreadExecutor()); - checkCompletedWithWrappedCancellationException(g); - } - - /** - * runAfterEitherAsync result completes normally after normal - * completion of sources - */ - public void testRunAfterEitherAsyncE() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - Noop r = new Noop(); - CompletableFuture g = f.runAfterEitherAsync(f2, r, new ThreadExecutor()); - f.complete(one); - checkCompletedNormally(g, null); - assertTrue(r.ran); - - r = new Noop(); - f = new CompletableFuture<>(); - f.complete(one); - f2 = new CompletableFuture<>(); - g = f.runAfterEitherAsync(f2, r, new ThreadExecutor()); - checkCompletedNormally(g, null); - assertTrue(r.ran); - } - - /** - * runAfterEitherAsync result completes exceptionally after exceptional - * completion of source - */ - public void testRunAfterEitherAsync2E() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - Noop r = new Noop(); - CompletableFuture g = f.runAfterEitherAsync(f2, r, new ThreadExecutor()); - f.completeExceptionally(new CFException()); - checkCompletedWithWrappedCFException(g); - - r = new Noop(); - f = new CompletableFuture<>(); - f2 = new CompletableFuture<>(); - f2.completeExceptionally(new CFException()); - g = f.runAfterEitherAsync(f2, r, new ThreadExecutor()); - f.complete(one); - checkCompletedWithWrappedCFException(g); - } - - /** - * runAfterEitherAsync result completes exceptionally if action does - */ - public void testRunAfterEitherAsync3E() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - FailingNoop r = new FailingNoop(); - CompletableFuture g = f.runAfterEitherAsync(f2, r, new ThreadExecutor()); - f.complete(one); - checkCompletedWithWrappedCFException(g); - } - - /** - * runAfterEitherAsync result completes exceptionally if either - * source cancelled - */ - public void testRunAfterEitherAsync4E() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFuture f2 = new CompletableFuture<>(); - Noop r = new Noop(); - CompletableFuture g = f.runAfterEitherAsync(f2, r, new ThreadExecutor()); - assertTrue(f.cancel(true)); - checkCompletedWithWrappedCancellationException(g); - - r = new Noop(); - f = new CompletableFuture<>(); - f2 = new CompletableFuture<>(); - assertTrue(f2.cancel(true)); - g = f.runAfterEitherAsync(f2, r, new ThreadExecutor()); - checkCompletedWithWrappedCancellationException(g); - } - - /** - * thenComposeAsync result completes normally after normal - * completion of source - */ - public void testThenComposeAsyncE() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFutureInc r = new CompletableFutureInc(); - CompletableFuture g = f.thenComposeAsync(r, new ThreadExecutor()); - f.complete(one); - checkCompletedNormally(g, two); - } - - /** - * thenComposeAsync result completes exceptionally after - * exceptional completion of source - */ - public void testThenComposeAsync2E() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFutureInc r = new CompletableFutureInc(); - CompletableFuture g = f.thenComposeAsync(r, new ThreadExecutor()); - f.completeExceptionally(new CFException()); - checkCompletedWithWrappedCFException(g); - } - - /** - * thenComposeAsync result completes exceptionally if action does - */ - public void testThenComposeAsync3E() { - CompletableFuture f = new CompletableFuture<>(); - FailingCompletableFutureFunction r = new FailingCompletableFutureFunction(); - CompletableFuture g = f.thenComposeAsync(r, new ThreadExecutor()); - f.complete(one); - checkCompletedWithWrappedCFException(g); - } - - /** - * thenComposeAsync result completes exceptionally if source cancelled - */ - public void testThenComposeAsync4E() { - CompletableFuture f = new CompletableFuture<>(); - CompletableFutureInc r = new CompletableFutureInc(); - CompletableFuture g = f.thenComposeAsync(r, new ThreadExecutor()); - assertTrue(f.cancel(true)); - checkCompletedWithWrappedCancellationException(g); - } - // other static methods /** @@ -2931,97 +3144,99 @@ 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); @@ -3040,221 +3255,137 @@ public class CompletableFutureTest exten * 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); - } + public void testWhenComplete_normalCompletion1() { + 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 CompletableFuture f = new CompletableFuture<>(); + if (!createIncomplete) f.complete(v1); + final CompletableFuture g = m.whenComplete + (f, + (Integer x, Throwable t) -> { + threadAssertSame(x, v1); + threadAssertNull(t); + a.getAndIncrement(); + }); + if (createIncomplete) f.complete(v1); + + checkCompletedNormally(g, v1); + checkCompletedNormally(f, v1); + assertEquals(1, a.get()); + }} /** * 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); - } + public void testWhenComplete_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 CFException ex = new CFException(); + final CompletableFuture f = new CompletableFuture<>(); + if (!createIncomplete) f.completeExceptionally(ex); + final CompletableFuture g = m.whenComplete + (f, + (Integer x, Throwable t) -> { + threadAssertNull(x); + threadAssertSame(t, ex); + a.getAndIncrement(); + }); + if (createIncomplete) f.completeExceptionally(ex); + checkCompletedWithWrappedCFException(f, ex); + checkCompletedWithWrappedCFException(g, ex); + assertEquals(1, a.get()); + }} + + /** + * whenComplete action executes on cancelled source, propagating + * CancellationException. + */ + public void testWhenComplete_sourceCancelled() { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean mayInterruptIfRunning : new boolean[] { true, false }) + for (boolean createIncomplete : new boolean[] { true, false }) + { + final AtomicInteger a = new AtomicInteger(0); + final CompletableFuture f = new CompletableFuture<>(); + if (!createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning)); + final CompletableFuture g = m.whenComplete + (f, + (Integer x, Throwable t) -> { + threadAssertNull(x); + threadAssertTrue(t instanceof CancellationException); + a.getAndIncrement(); + }); + if (createIncomplete) assertTrue(f.cancel(mayInterruptIfRunning)); + + //try { g.join(); } catch (Throwable t) { throw new Error(t); } + checkCompletedWithWrappedCancellationException(g); + checkCancelled(f); + assertEquals(1, a.get()); + }} /** * 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); - } + public void testWhenComplete_actionFailed() { + for (boolean createIncomplete : new boolean[] { true, false }) + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final AtomicInteger a = new AtomicInteger(0); + final CFException ex = new CFException(); + final CompletableFuture f = new CompletableFuture<>(); + if (!createIncomplete) f.complete(v1); + final CompletableFuture g = m.whenComplete + (f, + (Integer x, Throwable t) -> { + threadAssertSame(x, v1); + threadAssertNull(t); + a.getAndIncrement(); + throw ex; + }); + if (createIncomplete) f.complete(v1); + checkCompletedNormally(f, v1); + checkCompletedWithWrappedCFException(g, ex); + assertEquals(1, a.get()); + }} /** - * 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 + * If a whenComplete action throws an exception when triggered by + * a source completion that also throws an exception, the source + * exception takes precedence. */ - 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); - } + public void testWhenComplete_actionFailedSourceFailed() { + for (boolean createIncomplete : new boolean[] { true, false }) + for (ExecutionMode m : ExecutionMode.values()) + for (Integer v1 : new Integer[] { 1, null }) + { + final AtomicInteger a = 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 = m.whenComplete + (f, + (Integer x, Throwable t) -> { + threadAssertSame(t, ex1); + threadAssertNull(x); + a.getAndIncrement(); + throw ex2; + }); + if (createIncomplete) f.completeExceptionally(ex1); + + checkCompletedWithWrappedCFException(f, ex1); + checkCompletedWithWrappedCFException(g, ex1); + assertEquals(1, a.get()); + }} }