Add required sender checking and add more tests

This commit is contained in:
Alexander Söderberg 2020-09-16 21:22:46 +02:00
parent f5e230945d
commit bc261676e7
No known key found for this signature in database
GPG key ID: C0207FF7EA146678
7 changed files with 194 additions and 17 deletions

View file

@ -29,6 +29,7 @@ import com.intellectualsites.commands.components.parser.ComponentParseResult;
import com.intellectualsites.commands.context.CommandContext;
import com.intellectualsites.commands.exceptions.AmbiguousNodeException;
import com.intellectualsites.commands.exceptions.ComponentParseException;
import com.intellectualsites.commands.exceptions.InvalidCommandSenderException;
import com.intellectualsites.commands.exceptions.InvalidSyntaxException;
import com.intellectualsites.commands.exceptions.NoCommandInLeafException;
import com.intellectualsites.commands.exceptions.NoPermissionException;
@ -101,7 +102,13 @@ public final class CommandTree<C extends CommandSender, M extends CommandMeta> {
public Optional<Command<C, M>> parse(@Nonnull final CommandContext<C> commandContext,
@Nonnull final Queue<String> args) throws
NoSuchCommandException, NoPermissionException, InvalidSyntaxException {
return parseCommand(commandContext, args, this.internalTree);
final Optional<Command<C, M>> commandOptional = parseCommand(commandContext, args, this.internalTree);
commandOptional.flatMap(Command::getSenderType).ifPresent(requiredType -> {
if (!requiredType.isAssignableFrom(commandContext.getSender().getClass())) {
throw new InvalidCommandSenderException(commandContext.getSender(), requiredType, Collections.emptyList());
}
});
return commandOptional;
}
private Optional<Command<C, M>> parseCommand(@Nonnull final CommandContext<C> commandContext,

View file

@ -0,0 +1,69 @@
//
// MIT License
//
// Copyright (c) 2020 Alexander Söderberg
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package com.intellectualsites.commands.exceptions;
import com.intellectualsites.commands.components.CommandComponent;
import com.intellectualsites.commands.sender.CommandSender;
import javax.annotation.Nonnull;
import java.util.List;
/**
* Exception thrown when an invalid command sender tries to execute a command
*/
public final class InvalidCommandSenderException extends CommandParseException {
private final Class<?> requiredSender;
/**
* Construct a new command parse exception
*
* @param commandSender Sender who executed the command
* @param requiredSender The sender type that is required
* @param currentChain Chain leading up to the exception
*/
public InvalidCommandSenderException(@Nonnull final CommandSender commandSender,
@Nonnull final Class<?> requiredSender,
@Nonnull final List<CommandComponent<?, ?>> currentChain) {
super(commandSender, currentChain);
this.requiredSender = requiredSender;
}
/**
* Get the required sender type
*
* @return Required sender type
*/
@Nonnull
public Class<?> getRequiredSender() {
return this.requiredSender;
}
@Override
public String getMessage() {
return String.format("%s is not allowed to execute that command. Must be of type %s",
getCommandSender().toString(),
requiredSender.getSimpleName());
}
}

View file

@ -0,0 +1,89 @@
//
// MIT License
//
// Copyright (c) 2020 Alexander Söderberg
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package com.intellectualsites.commands;
import com.intellectualsites.commands.components.StaticComponent;
import com.intellectualsites.commands.components.standard.EnumComponent;
import com.intellectualsites.commands.components.standard.StringComponent;
import com.intellectualsites.commands.meta.SimpleCommandMeta;
import com.intellectualsites.commands.sender.CommandSender;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class CommandSuggestionsTest {
private static CommandManager<CommandSender, SimpleCommandMeta> manager;
@BeforeAll
static void setupManager() {
manager = new TestCommandManager();
manager.command(manager.commandBuilder("test").component(StaticComponent.required("one")).build());
manager.command(manager.commandBuilder("test").component(StaticComponent.required("two")).build());
manager.command(manager.commandBuilder("test")
.component(StaticComponent.required("var"))
.component(StringComponent.newBuilder("str")
.withSuggestionsProvider((c, s) -> Arrays.asList("one", "two"))
.build())
.component(EnumComponent.required(TestEnum.class, "enum"))
.build());
}
@Test
void testSimple() {
final String input = "test";
final List<String> suggestions = manager.suggest(new TestCommandSender(), input);
Assertions.assertEquals(Arrays.asList("one", "two", "var"), suggestions);
}
@Test
void testVar() {
final String input = "test var";
final List<String> suggestions = manager.suggest(new TestCommandSender(), input);
Assertions.assertEquals(Arrays.asList("one", "two"), suggestions);
final String input2 = "test var one";
final List<String> suggestions2 = manager.suggest(new TestCommandSender(), input2);
Assertions.assertEquals(Arrays.asList("foo", "bar"), suggestions2);
final String input3 = "test var one f";
final List<String> suggestions3 = manager.suggest(new TestCommandSender(), input3);
Assertions.assertEquals(Collections.singletonList("foo"), suggestions3);
}
@Test
void testEmpty() {
final String input = "kenny";
final List<String> suggestions = manager.suggest(new TestCommandSender(), input);
Assertions.assertTrue(suggestions.isEmpty());
}
public enum TestEnum {
FOO, BAR
}
}

View file

@ -37,6 +37,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Optional;
import java.util.concurrent.CompletionException;
class CommandTreeTest {
@ -47,15 +48,16 @@ class CommandTreeTest {
static void newTree() {
commandManager = new TestCommandManager();
commandManager.command(commandManager.commandBuilder("test", SimpleCommandMeta.empty())
.component(StaticComponent.required("one")).build())
.component(StaticComponent.required("one")).build())
.command(commandManager.commandBuilder("test", SimpleCommandMeta.empty())
.component(StaticComponent.required("two")).withPermission("no").build())
.component(StaticComponent.required("two")).withPermission("no").build())
.command(commandManager.commandBuilder("test", Collections.singleton("other"),
SimpleCommandMeta.empty())
.component(StaticComponent.required("opt", "öpt"))
.component(IntegerComponent
.optional("num", EXPECTED_INPUT_NUMBER))
.build());
SimpleCommandMeta.empty())
.component(StaticComponent.required("opt", "öpt"))
.component(IntegerComponent
.optional("num", EXPECTED_INPUT_NUMBER))
.build())
.command(commandManager.commandBuilder("req").withSenderType(SpecificCommandSender.class).build());
}
@Test
@ -94,4 +96,13 @@ class CommandTreeTest {
Collections.singletonList("test"))).isEmpty());
}
@Test
void testRequiredSender() {
Assertions.assertThrows(CompletionException.class, () ->
commandManager.executeCommand(new TestCommandSender(), "req").join());
}
public static final class SpecificCommandSender extends TestCommandSender {
}
}