--- jsr166/src/test/tck/CompletableFutureTest.java 2016/07/03 15:27:28 1.162 +++ jsr166/src/test/tck/CompletableFutureTest.java 2016/07/03 19:38:19 1.166 @@ -3852,19 +3852,23 @@ public class CompletableFutureTest exten final CompletableFuture v42 = CompletableFuture.completedFuture(42); final CompletableFuture incomplete = new CompletableFuture<>(); + final Runnable noopRunnable = new Noop(m); + final Consumer noopConsumer = new NoopConsumer(m); + final Function incFunction = new IncFunction(m); + List, CompletableFuture>> funs = new ArrayList<>(); - funs.add((y) -> m.thenRun(y, new Noop(m))); - funs.add((y) -> m.thenAccept(y, new NoopConsumer(m))); - funs.add((y) -> m.thenApply(y, new IncFunction(m))); - - funs.add((y) -> m.runAfterEither(y, incomplete, new Noop(m))); - funs.add((y) -> m.acceptEither(y, incomplete, new NoopConsumer(m))); - funs.add((y) -> m.applyToEither(y, incomplete, new IncFunction(m))); + funs.add((y) -> m.thenRun(y, noopRunnable)); + funs.add((y) -> m.thenAccept(y, noopConsumer)); + funs.add((y) -> m.thenApply(y, incFunction)); + + funs.add((y) -> m.runAfterEither(y, incomplete, noopRunnable)); + funs.add((y) -> m.acceptEither(y, incomplete, noopConsumer)); + funs.add((y) -> m.applyToEither(y, incomplete, incFunction)); - funs.add((y) -> m.runAfterBoth(y, v42, new Noop(m))); - funs.add((y) -> m.runAfterBoth(v42, y, new Noop(m))); + funs.add((y) -> m.runAfterBoth(y, v42, noopRunnable)); + funs.add((y) -> m.runAfterBoth(v42, y, noopRunnable)); funs.add((y) -> m.thenAcceptBoth(y, v42, new SubtractAction(m))); funs.add((y) -> m.thenAcceptBoth(v42, y, new SubtractAction(m))); funs.add((y) -> m.thenCombine(y, v42, new SubtractFunction(m))); @@ -3874,18 +3878,18 @@ public class CompletableFutureTest exten funs.add((y) -> m.thenCompose(y, new CompletableFutureInc(m))); - funs.add((y) -> CompletableFuture.allOf(new CompletableFuture[] {y})); - funs.add((y) -> CompletableFuture.allOf(new CompletableFuture[] {y, v42})); - funs.add((y) -> CompletableFuture.allOf(new CompletableFuture[] {v42, y})); - funs.add((y) -> CompletableFuture.anyOf(new CompletableFuture[] {y})); - funs.add((y) -> CompletableFuture.anyOf(new CompletableFuture[] {y, incomplete})); - funs.add((y) -> CompletableFuture.anyOf(new CompletableFuture[] {incomplete, y})); + funs.add((y) -> CompletableFuture.allOf(y)); + funs.add((y) -> CompletableFuture.allOf(y, v42)); + funs.add((y) -> CompletableFuture.allOf(v42, y)); + funs.add((y) -> CompletableFuture.anyOf(y)); + funs.add((y) -> CompletableFuture.anyOf(y, incomplete)); + funs.add((y) -> CompletableFuture.anyOf(incomplete, y)); for (Function, CompletableFuture> fun : funs) { CompletableFuture f = new CompletableFuture<>(); f.completeExceptionally(ex); - CompletableFuture src = m.thenApply(f, new IncFunction(m)); + CompletableFuture src = m.thenApply(f, incFunction); checkCompletedWithWrappedException(src, ex); CompletableFuture dep = fun.apply(src); checkCompletedWithWrappedException(dep, ex); @@ -3895,7 +3899,7 @@ public class CompletableFutureTest exten for (Function, CompletableFuture> fun : funs) { CompletableFuture f = new CompletableFuture<>(); - CompletableFuture src = m.thenApply(f, new IncFunction(m)); + CompletableFuture src = m.thenApply(f, incFunction); CompletableFuture dep = fun.apply(src); f.completeExceptionally(ex); checkCompletedWithWrappedException(src, ex); @@ -3909,7 +3913,7 @@ public class CompletableFutureTest exten CompletableFuture f = new CompletableFuture<>(); f.cancel(mayInterruptIfRunning); checkCancelled(f); - CompletableFuture src = m.thenApply(f, new IncFunction(m)); + CompletableFuture src = m.thenApply(f, incFunction); checkCompletedWithWrappedCancellationException(src); CompletableFuture dep = fun.apply(src); checkCompletedWithWrappedCancellationException(dep); @@ -3920,7 +3924,7 @@ public class CompletableFutureTest exten for (Function, CompletableFuture> fun : funs) { CompletableFuture f = new CompletableFuture<>(); - CompletableFuture src = m.thenApply(f, new IncFunction(m)); + CompletableFuture src = m.thenApply(f, incFunction); CompletableFuture dep = fun.apply(src); f.cancel(mayInterruptIfRunning); checkCancelled(f); @@ -3931,7 +3935,7 @@ public class CompletableFutureTest exten }} /** - * Minimal completion stages throw UOE for all non-CompletionStage methods + * Minimal completion stages throw UOE for most non-CompletionStage methods */ public void testMinimalCompletionStage_minimality() { if (!testImplementationDetails) return; @@ -3960,8 +3964,10 @@ public class CompletableFutureTest exten .filter((method) -> !permittedMethodSignatures.contains(toSignature.apply(method))) .collect(Collectors.toList()); - CompletionStage minimalStage = - new CompletableFuture().minimalCompletionStage(); + List> stages = new ArrayList<>(); + stages.add(new CompletableFuture().minimalCompletionStage()); + stages.add(CompletableFuture.completedStage(1)); + stages.add(CompletableFuture.failedStage(new CFException())); List bugs = new ArrayList<>(); for (Method method : allMethods) { @@ -3977,20 +3983,22 @@ public class CompletableFutureTest exten else if (parameterTypes[i] == long.class) args[i] = 0L; } - try { - method.invoke(minimalStage, args); - bugs.add(method); - } - catch (java.lang.reflect.InvocationTargetException expected) { - if (! (expected.getCause() instanceof UnsupportedOperationException)) { + for (CompletionStage stage : stages) { + try { + method.invoke(stage, args); bugs.add(method); - // expected.getCause().printStackTrace(); } + catch (java.lang.reflect.InvocationTargetException expected) { + if (! (expected.getCause() instanceof UnsupportedOperationException)) { + bugs.add(method); + // expected.getCause().printStackTrace(); + } + } + catch (ReflectiveOperationException bad) { throw new Error(bad); } } - catch (ReflectiveOperationException bad) { throw new Error(bad); } } if (!bugs.isEmpty()) - throw new Error("Methods did not throw UOE: " + bugs.toString()); + throw new Error("Methods did not throw UOE: " + bugs); } static class Monad { @@ -4139,6 +4147,27 @@ public class CompletableFutureTest exten Monad.plus(godot, Monad.unit(5L))); } + /** Test long recursive chains of CompletableFutures with cascading completions */ + public void testRecursiveChains() throws Throwable { + for (ExecutionMode m : ExecutionMode.values()) + for (boolean addDeadEnds : new boolean[] { true, false }) + { + final int val = 42; + final int n = expensiveTests ? 1_000 : 2; + CompletableFuture head = new CompletableFuture<>(); + CompletableFuture tail = head; + for (int i = 0; i < n; i++) { + if (addDeadEnds) m.thenApply(tail, v -> v + 1); + tail = m.thenApply(tail, v -> v + 1); + if (addDeadEnds) m.applyToEither(tail, tail, v -> v + 1); + tail = m.applyToEither(tail, tail, v -> v + 1); + if (addDeadEnds) m.thenCombine(tail, tail, (v, w) -> v + 1); + tail = m.thenCombine(tail, tail, (v, w) -> v + 1); + } + head.complete(val); + assertEquals(val + 3 * n, (int) tail.join()); + }} + /** * A single CompletableFuture with many dependents. * A demo of scalability - runtime is O(n).