8 |
|
import static java.util.concurrent.TimeUnit.MILLISECONDS; |
9 |
|
import static java.util.concurrent.TimeUnit.SECONDS; |
10 |
|
|
11 |
+ |
import java.lang.reflect.Method; |
12 |
+ |
import java.lang.reflect.Modifier; |
13 |
+ |
|
14 |
+ |
import java.util.stream.Collectors; |
15 |
+ |
import java.util.stream.Stream; |
16 |
+ |
|
17 |
|
import java.util.ArrayList; |
18 |
+ |
import java.util.Arrays; |
19 |
|
import java.util.List; |
20 |
|
import java.util.Objects; |
21 |
+ |
import java.util.Set; |
22 |
|
import java.util.concurrent.Callable; |
23 |
|
import java.util.concurrent.CancellationException; |
24 |
|
import java.util.concurrent.CompletableFuture; |
3696 |
|
} |
3697 |
|
}} |
3698 |
|
|
3699 |
+ |
/** |
3700 |
+ |
* Minimal completion stages throw UOE for all non-CompletionStage methods |
3701 |
+ |
*/ |
3702 |
+ |
public void testMinimalCompletionStage_minimality() { |
3703 |
+ |
if (!testImplementationDetails) return; |
3704 |
+ |
Function<Method, String> toSignature = |
3705 |
+ |
(method) -> method.getName() + Arrays.toString(method.getParameterTypes()); |
3706 |
+ |
List<Method> minimalMethods = |
3707 |
+ |
Stream.of(Object.class, CompletionStage.class) |
3708 |
+ |
.map((klazz) -> Stream.of(klazz.getMethods())) |
3709 |
+ |
.reduce(Stream::concat) |
3710 |
+ |
.orElseGet(Stream::empty) |
3711 |
+ |
.filter((method) -> (method.getModifiers() & Modifier.STATIC) == 0) |
3712 |
+ |
.collect(Collectors.toList()); |
3713 |
+ |
// Methods from CompletableFuture permitted NOT to throw UOE |
3714 |
+ |
String[] signatureWhitelist = { |
3715 |
+ |
"newIncompleteFuture[]", |
3716 |
+ |
"defaultExecutor[]", |
3717 |
+ |
"minimalCompletionStage[]", |
3718 |
+ |
"copy[]", |
3719 |
+ |
}; |
3720 |
+ |
Set<String> permittedMethodSignatures = |
3721 |
+ |
Stream.concat(minimalMethods.stream().map(toSignature), |
3722 |
+ |
Stream.of(signatureWhitelist)) |
3723 |
+ |
.collect(Collectors.toSet()); |
3724 |
+ |
List<Method> allMethods = Stream.of(CompletableFuture.class.getMethods()) |
3725 |
+ |
.filter((method) -> (method.getModifiers() & Modifier.STATIC) == 0) |
3726 |
+ |
.filter((method) -> !permittedMethodSignatures.contains(toSignature.apply(method))) |
3727 |
+ |
.collect(Collectors.toList()); |
3728 |
+ |
|
3729 |
+ |
CompletionStage<Integer> minimalStage = |
3730 |
+ |
new CompletableFuture<Integer>().minimalCompletionStage(); |
3731 |
+ |
|
3732 |
+ |
List<Method> bugs = new ArrayList<>(); |
3733 |
+ |
for (Method method : allMethods) { |
3734 |
+ |
Class<?>[] parameterTypes = method.getParameterTypes(); |
3735 |
+ |
Object[] args = new Object[parameterTypes.length]; |
3736 |
+ |
// Manufacture boxed primitives for primitive params |
3737 |
+ |
for (int i = 0; i < args.length; i++) { |
3738 |
+ |
Class<?> type = parameterTypes[i]; |
3739 |
+ |
if (parameterTypes[i] == boolean.class) |
3740 |
+ |
args[i] = false; |
3741 |
+ |
else if (parameterTypes[i] == int.class) |
3742 |
+ |
args[i] = 0; |
3743 |
+ |
else if (parameterTypes[i] == long.class) |
3744 |
+ |
args[i] = 0L; |
3745 |
+ |
} |
3746 |
+ |
try { |
3747 |
+ |
method.invoke(minimalStage, args); |
3748 |
+ |
bugs.add(method); |
3749 |
+ |
} |
3750 |
+ |
catch (java.lang.reflect.InvocationTargetException expected) { |
3751 |
+ |
if (! (expected.getCause() instanceof UnsupportedOperationException)) { |
3752 |
+ |
bugs.add(method); |
3753 |
+ |
// expected.getCause().printStackTrace(); |
3754 |
+ |
} |
3755 |
+ |
} |
3756 |
+ |
catch (ReflectiveOperationException bad) { throw new Error(bad); } |
3757 |
+ |
} |
3758 |
+ |
if (!bugs.isEmpty()) |
3759 |
+ |
throw new Error("Methods did not throw UOE: " + bugs.toString()); |
3760 |
+ |
} |
3761 |
+ |
|
3762 |
+ |
// static <U> U join(CompletionStage<U> stage) { |
3763 |
+ |
// CompletableFuture<U> f = new CompletableFuture<>(); |
3764 |
+ |
// stage.whenComplete((v, ex) -> { |
3765 |
+ |
// if (ex != null) f.completeExceptionally(ex); else f.complete(v); |
3766 |
+ |
// }); |
3767 |
+ |
// return f.join(); |
3768 |
+ |
// } |
3769 |
+ |
|
3770 |
+ |
// static <U> boolean isDone(CompletionStage<U> stage) { |
3771 |
+ |
// CompletableFuture<U> f = new CompletableFuture<>(); |
3772 |
+ |
// stage.whenComplete((v, ex) -> { |
3773 |
+ |
// if (ex != null) f.completeExceptionally(ex); else f.complete(v); |
3774 |
+ |
// }); |
3775 |
+ |
// return f.isDone(); |
3776 |
+ |
// } |
3777 |
+ |
|
3778 |
+ |
// static <U> U join2(CompletionStage<U> stage) { |
3779 |
+ |
// return stage.toCompletableFuture().copy().join(); |
3780 |
+ |
// } |
3781 |
+ |
|
3782 |
+ |
// static <U> boolean isDone2(CompletionStage<U> stage) { |
3783 |
+ |
// return stage.toCompletableFuture().copy().isDone(); |
3784 |
+ |
// } |
3785 |
+ |
|
3786 |
|
} |