13
0
geforkt von Mirrors/Velocity

Test suggestion exception handling

Dieser Commit ist enthalten in:
Hugo Manrique 2021-06-09 21:00:17 +02:00
Ursprung a9d40f3ca3
Commit bcb68c8d0f
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: A60730A4A4ACE782
2 geänderte Dateien mit 154 neuen und 5 gelöschten Zeilen

Datei anzeigen

@ -182,6 +182,7 @@ final class SuggestionsProvider<S> {
final LiteralCommandNode<S> alias, final StringReader reader, final LiteralCommandNode<S> alias, final StringReader reader,
final CommandContextBuilder<S> contextSoFar) { final CommandContextBuilder<S> contextSoFar) {
final S source = contextSoFar.getSource(); final S source = contextSoFar.getSource();
final String fullInput = reader.getString();
final VelocityArgumentCommandNode<S, ?> argsNode = VelocityCommands.getArgumentsNode(alias); final VelocityArgumentCommandNode<S, ?> argsNode = VelocityCommands.getArgumentsNode(alias);
if (argsNode == null) { if (argsNode == null) {
// This is a BrigadierCommand, fallback to regular suggestions // This is a BrigadierCommand, fallback to regular suggestions
@ -212,15 +213,13 @@ final class SuggestionsProvider<S> {
this.getArgumentsNodeSuggestions(argsNode, reader, context); this.getArgumentsNodeSuggestions(argsNode, reader, context);
final boolean hasHints = alias.getChildren().size() > 1; final boolean hasHints = alias.getChildren().size() > 1;
if (!hasHints) { if (!hasHints) {
return cmdSuggestions; return this.merge(fullInput, cmdSuggestions);
} }
// Parse the hint nodes to get remaining suggestions // Parse the hint nodes to get remaining suggestions
reader.setCursor(start); reader.setCursor(start);
final CompletableFuture<Suggestions> hintSuggestions = final CompletableFuture<Suggestions> hintSuggestions =
this.getHintSuggestions(alias, reader, contextSoFar); this.getHintSuggestions(alias, reader, contextSoFar);
final String fullInput = reader.getString();
return this.merge(fullInput, cmdSuggestions, hintSuggestions); return this.merge(fullInput, cmdSuggestions, hintSuggestions);
} }
@ -245,7 +244,7 @@ final class SuggestionsProvider<S> {
return node.listSuggestions(built, new SuggestionsBuilder(fullInput, start)); return node.listSuggestions(built, new SuggestionsBuilder(fullInput, start));
} catch (final Throwable e) { } catch (final Throwable e) {
// Ugly, ugly swallowing of everything Throwable, because plugins are naughty. // Ugly, ugly swallowing of everything Throwable, because plugins are naughty.
LOGGER.error("Arguments node cannot provide suggestions, skipping", e); LOGGER.error("Arguments node cannot provide suggestions", e);
return Suggestions.empty(); return Suggestions.empty();
} }
} }
@ -264,7 +263,13 @@ final class SuggestionsProvider<S> {
final LiteralCommandNode<S> alias, final StringReader reader, final LiteralCommandNode<S> alias, final StringReader reader,
final CommandContextBuilder<S> context) { final CommandContextBuilder<S> context) {
final ParseResults<S> parse = this.parseHints(alias, reader, context); final ParseResults<S> parse = this.parseHints(alias, reader, context);
try {
return this.dispatcher.getCompletionSuggestions(parse); return this.dispatcher.getCompletionSuggestions(parse);
} catch (final Throwable e) {
// Again, plugins are naughty.
LOGGER.error("Hint node cannot provide suggestions", e);
return Suggestions.empty();
}
} }
/** /**

Datei anzeigen

@ -23,10 +23,13 @@ import static org.junit.jupiter.api.Assertions.fail;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder; import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.spotify.futures.CompletableFutures;
import com.velocitypowered.api.command.Command; import com.velocitypowered.api.command.Command;
import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.command.RawCommand; import com.velocitypowered.api.command.RawCommand;
import com.velocitypowered.api.command.SimpleCommand;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
/** /**
@ -65,6 +68,51 @@ public class SuggestionsProviderTests extends CommandTestSuite {
assertSuggestions("bar"); assertSuggestions("bar");
} }
@Test
void testDoesNotSuggestForPartialIncorrectAlias() {
final var meta = manager.metaBuilder("hello").build();
manager.register(meta, NoSuggestionsCommand.INSTANCE);
assertSuggestions("yo");
assertSuggestions("welcome");
}
@Test
void testDoesNotSuggestArgumentsForPartialAlias() {
final var meta = manager.metaBuilder("hello").build();
manager.register(meta, new SimpleCommand() {
@Override
public void execute(final Invocation invocation) {
fail();
}
@Override
public List<String> suggest(final Invocation invocation) {
return fail();
}
});
assertSuggestions("hell ");
}
@Test
void testSuggestsArgumentsIgnoresAliasCase() {
final var meta = manager.metaBuilder("hello").build();
manager.register(meta, new SimpleCommand() {
@Override
public void execute(final Invocation invocation) {
fail();
}
@Override
public List<String> suggest(final Invocation invocation) {
return ImmutableList.of("world");
}
});
assertSuggestions("Hello ", "world");
}
@Test @Test
void testSuggestsHintLiteral() { void testSuggestsHintLiteral() {
final var hint = LiteralArgumentBuilder final var hint = LiteralArgumentBuilder
@ -123,6 +171,102 @@ public class SuggestionsProviderTests extends CommandTestSuite {
assertSuggestions("foo bar", "baz", "qux"); assertSuggestions("foo bar", "baz", "qux");
} }
// Exception handling
@Test
void testSkipsSuggestionWhenNodeSuggestionProviderFutureCompletesExceptionally() {
final var meta = manager.metaBuilder("hello").build();
manager.register(meta, new RawCommand() {
@Override
public void execute(final Invocation invocation) {
fail();
}
@Override
public CompletableFuture<List<String>> suggestAsync(final Invocation invocation) {
return CompletableFutures.exceptionallyCompletedFuture(new RuntimeException());
}
});
assertSuggestions("hello ");
}
@Test
void testSkipsSuggestionWhenNodeSuggestionProviderThrows() {
final var meta = manager.metaBuilder("hello").build();
manager.register(meta, new RawCommand() {
@Override
public void execute(final Invocation invocation) {
fail();
}
@Override
public CompletableFuture<List<String>> suggestAsync(final Invocation invocation) {
throw new RuntimeException();
}
});
// Also logs an error to the console, but testing this is quite involved
assertSuggestions("hello ");
}
@Test
void testSkipsSuggestionWhenHintSuggestionProviderFutureCompletesExceptionally() {
final var hint = RequiredArgumentBuilder
.<CommandSource, String>argument("hint", word())
.suggests((context, builder) ->
CompletableFutures.exceptionallyCompletedFuture(new RuntimeException()))
.build();
final var meta = manager.metaBuilder("hello")
.hint(hint)
.build();
manager.register(meta, NoSuggestionsCommand.INSTANCE);
assertSuggestions("hello ");
}
@Test
void testSkipsSuggestionWhenHintSuggestionProviderThrows() {
final var hint = RequiredArgumentBuilder
.<CommandSource, String>argument("hint", word())
.suggests((context, builder) -> {
throw new RuntimeException();
})
.build();
final var meta = manager.metaBuilder("hello")
.hint(hint)
.build();
manager.register(meta, NoSuggestionsCommand.INSTANCE);
// Also logs an error to the console, but testing this is quite involved
assertSuggestions("hello ");
}
@Test
void testSuggestionMergingIgnoresExceptionallyCompletedSuggestionFutures() {
final var hint = RequiredArgumentBuilder
.<CommandSource, String>argument("hint", word())
.suggests((context, builder) ->
CompletableFutures.exceptionallyCompletedFuture(new RuntimeException()))
.build();
final var meta = manager.metaBuilder("hello")
.hint(hint)
.build();
manager.register(meta, new RawCommand() {
@Override
public void execute(final Invocation invocation) {
fail();
}
@Override
public List<String> suggest(final Invocation invocation) {
return ImmutableList.of("world");
}
});
assertSuggestions("hello ", "world");
}
static final class NoSuggestionsCommand implements RawCommand { static final class NoSuggestionsCommand implements RawCommand {
static final NoSuggestionsCommand INSTANCE = new NoSuggestionsCommand(); static final NoSuggestionsCommand INSTANCE = new NoSuggestionsCommand();