Ensure that the CompletableFuture returned by getCompletionSuggestions is always completed

fix
https://github.com/Mojang/brigadier/pull/81
This commit is contained in:
2024-08-13 03:28:27 +08:00
parent 48ab1ab497
commit 8d48b13cdf
2 changed files with 29 additions and 6 deletions
@@ -560,16 +560,15 @@ public class CommandDispatcher<S> {
futures[i++] = future;
}
final CompletableFuture<Suggestions> result = new CompletableFuture<>();
CompletableFuture.allOf(futures).thenRun(() -> {
return CompletableFuture.allOf(futures).handle((voidResult, exception) -> {
final List<Suggestions> suggestions = new ArrayList<>();
for (final CompletableFuture<Suggestions> future : futures) {
if (!future.isCompletedExceptionally()) {
suggestions.add(future.join());
}
result.complete(Suggestions.merge(fullInput, suggestions));
}
return Suggestions.merge(fullInput, suggestions);
});
return result;
}
/**
@@ -10,6 +10,8 @@ import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.context.CommandContextBuilder;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.Suggestion;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.tree.LiteralCommandNode;
import com.mojang.brigadier.tree.RootCommandNode;
@@ -22,7 +24,10 @@ import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import static com.mojang.brigadier.arguments.IntegerArgumentType.getInteger;
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
@@ -495,6 +500,25 @@ public class CommandDispatcherTest {
assertThat(subject.findNode(Lists.newArrayList("foo", "bar")), is(nullValue()));
}
@SuppressWarnings("unchecked")
@Test
public void testCompletionWithErroredFutureReturnsCompletedFuture() {
final LiteralCommandNode<Object> bar = literal("bar").build();
final LiteralCommandNode<Object> baz = mock(LiteralCommandNode.class);
when(baz.getLiteral()).thenReturn("baz");
when(baz.listSuggestions(any(), any())).thenAnswer(x -> {
final CompletableFuture<Suggestions> future = new CompletableFuture<>();
future.completeExceptionally(new IllegalArgumentException());
return future;
});
subject.register(literal("foo").then(bar).then(baz));
final ParseResults<Object> parseResults = subject.parse("foo b", source);
final Suggestions suggestions = subject.getCompletionSuggestions(parseResults).join();
final Collection<String> suggestionCollection = suggestions.getList().stream().map(Suggestion::getText).collect(Collectors.toList());
assertThat(Lists.newArrayList("bar"), is(suggestionCollection));
}
@Test
public void testResultConsumerInNonErrorRun() throws CommandSyntaxException {
subject.setConsumer(consumer);