SteamWar/SpigotCore
Archiviert
13
0

CMD #141

Zusammengeführt
YoyoNow hat 29 Commits von CMD nach master 2021-12-12 15:58:20 +01:00 zusammengeführt
16 geänderte Dateien mit 1044 neuen und 271 gelöschten Zeilen

Datei anzeigen

@ -40,6 +40,16 @@ sourceSets {
exclude '**/*.java', '**/*.kt'
}
}
test {
java {
srcDirs = ['testsrc']
}
resources {
srcDirs = ['testsrc']
exclude '**/*.java', '**/*.kt'
}
}
}
dependencies {
@ -51,6 +61,12 @@ dependencies {
testCompileOnly 'org.projectlombok:lombok:1.18.22'
annotationProcessor 'org.projectlombok:lombok:1.18.22'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.22'
testImplementation files("${project.rootDir}/lib/Spigot-1.15.jar")
testImplementation files("${project.rootDir}/lib/WorldEdit-1.12.jar")
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.hamcrest:hamcrest:2.2'
}
processResources {

Datei anzeigen

@ -19,7 +19,7 @@
package de.steamwar.command;
public class CommandParseException extends Exception {
public class CommandParseException extends RuntimeException {
public CommandParseException() {
}

Datei anzeigen

@ -0,0 +1,217 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2020 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
import lombok.AllArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.bukkit.command.CommandSender;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.List;
@ToString
public class CommandPart {
private static final String[] EMPTY_ARRAY = new String[0];
@AllArgsConstructor
private static class CheckArgumentResult {
private final boolean success;
private final Object value;
}
private TypeMapper<?> typeMapper;
private GuardChecker guard;
private Class<?> varArgType;
private String optional;
private GuardCheckType guardCheckType;
private CommandPart next = null;
@Setter
private boolean ignoreAsArgument = false;
public CommandPart(TypeMapper<?> typeMapper, GuardChecker guard, Class<?> varArgType, String optional, GuardCheckType guardCheckType) {
this.typeMapper = typeMapper;
this.guard = guard;
this.varArgType = varArgType;
this.optional = optional;
this.guardCheckType = guardCheckType;
validatePart();
}
public void setNext(CommandPart next) {
if (varArgType != null) {
throw new IllegalArgumentException("There can't be a next part if this is a vararg part!");
}
this.next = next;
}
private void validatePart() {
if (guardCheckType == GuardCheckType.TAB_COMPLETE) {
throw new IllegalArgumentException("Tab complete is not allowed as a guard check type!");
}
if (optional != null && varArgType != null) {
throw new IllegalArgumentException("A vararg part can't have an optional part!");
}
if (optional != null) {
try {
typeMapper.map(null, EMPTY_ARRAY, optional);
} catch (Exception e) {
throw new IllegalArgumentException("The optional part is not valid!");
}
}
}
public void generateArgumentArray(List<Object> current, CommandSender commandSender, String[] args, int startIndex) {
if (startIndex >= args.length && varArgType == null) {
throw new CommandParseException();
}
if (varArgType != null) {
Object array = Array.newInstance(varArgType, args.length - startIndex);
for (int i = startIndex; i < args.length; i++) {
CheckArgumentResult validArgument = checkArgument(null, commandSender, args, i);
if (!validArgument.success) {
throw new CommandParseException();
}
Array.set(array, i - startIndex, validArgument.value);
}
current.add(array);
return;
}
CheckArgumentResult validArgument = checkArgument(null, commandSender, args, startIndex);
if (!validArgument.success && optional == null) {
throw new CommandParseException();
}
if (!validArgument.success) {
if (!ignoreAsArgument) {
current.add(typeMapper.map(commandSender, EMPTY_ARRAY, optional));
}
if (next != null) {
next.generateArgumentArray(current, commandSender, args, startIndex);
}
return;
}
if (!ignoreAsArgument) {
current.add(validArgument.value);
}
if (next != null) {
next.generateArgumentArray(current, commandSender, args, startIndex + 1);
}
}
public boolean guardCheck(CommandSender commandSender, String[] args, int startIndex) {
if (varArgType != null) {
for (int i = startIndex; i < args.length; i++) {
GuardResult guardResult = checkGuard(guardCheckType, commandSender, args, i);
if (guardResult == GuardResult.DENIED) {
throw new CommandNoHelpException();
}
if (guardResult == GuardResult.DENIED_WITH_HELP) {
return false;
}
}
return true;
}
GuardResult guardResult = checkGuard(guardCheckType, commandSender, args, startIndex);
if (guardResult == GuardResult.DENIED) {
if (optional != null && next != null) {
return next.guardCheck(commandSender, args, startIndex);
}
throw new CommandNoHelpException();
}
if (guardResult == GuardResult.DENIED_WITH_HELP) {
if (optional != null && next != null) {
return next.guardCheck(commandSender, args, startIndex);
}
return false;
}
if (next != null) {
return next.guardCheck(commandSender, args, startIndex + 1);
}
return true;
}
public void generateTabComplete(List<String> current, CommandSender commandSender, String[] args, int startIndex) {
if (varArgType != null) {
for (int i = startIndex; i < args.length - 1; i++) {
CheckArgumentResult validArgument = checkArgument(null, commandSender, args, i);
if (!validArgument.success) {
return;
}
}
List<String> strings = typeMapper.tabCompletes(commandSender, Arrays.copyOf(args, args.length - 1), args[args.length - 1]);
if (strings != null) {
current.addAll(strings);
}
return;
}
if (args.length - 1 > startIndex) {
CheckArgumentResult checkArgumentResult = checkArgument(GuardCheckType.TAB_COMPLETE, commandSender, args, startIndex);
if (checkArgumentResult.success && next != null) {
next.generateTabComplete(current, commandSender, args, startIndex + 1);
}
return;
}
List<String> strings = typeMapper.tabCompletes(commandSender, Arrays.copyOf(args, startIndex), args[startIndex]);
if (strings != null) {
current.addAll(strings);
}
if (optional != null && next != null) {
next.generateTabComplete(current, commandSender, args, startIndex);
}
}
private CheckArgumentResult checkArgument(GuardCheckType guardCheckType, CommandSender commandSender, String[] args, int index) {
try {
Object value = typeMapper.map(commandSender, Arrays.copyOf(args, index), args[index]);
if (value == null) {
return new CheckArgumentResult(false, null);
}
GuardResult guardResult = checkGuard(guardCheckType, commandSender, args, index);
switch (guardResult) {
case ALLOWED:
return new CheckArgumentResult(true, value);
case DENIED:
throw new CommandNoHelpException();
case DENIED_WITH_HELP:
default:
return new CheckArgumentResult(false, null);
}
} catch (Exception e) {
return new CheckArgumentResult(false, null);
}
}
private GuardResult checkGuard(GuardCheckType guardCheckType, CommandSender commandSender, String[] args, int index) {
if (guard != null && guardCheckType != null) {
return guard.guard(commandSender, guardCheckType, Arrays.copyOf(args, index), args[index]);
}
return GuardResult.ALLOWED;
}
}

Datei anzeigen

@ -0,0 +1,65 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2020 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
import lombok.experimental.UtilityClass;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandMap;
import org.bukkit.command.SimpleCommandMap;
import java.lang.reflect.Field;
import java.util.Map;
@UtilityClass
class CommandRegistering {
private static final CommandMap commandMap;
private static final Map<String, Command> knownCommandMap;
static {
try {
final Field commandMapField = Bukkit.getServer().getClass().getDeclaredField("commandMap");
commandMapField.setAccessible(true);
commandMap = (CommandMap) commandMapField.get(Bukkit.getServer());
} catch (NoSuchFieldException | IllegalAccessException exception) {
Bukkit.shutdown();
throw new SecurityException("Oh shit. Commands cannot be registered.", exception);
}
try {
final Field knownCommandsField = SimpleCommandMap.class.getDeclaredField("knownCommands");
knownCommandsField.setAccessible(true);
knownCommandMap = (Map<String, Command>) knownCommandsField.get(commandMap);
} catch (NoSuchFieldException | IllegalAccessException exception) {
Bukkit.shutdown();
throw new SecurityException("Oh shit. Commands cannot be registered.", exception);
}
}
static void unregister(Command command) {
knownCommandMap.remove(command.getName());
command.getAliases().forEach(knownCommandMap::remove);
command.unregister(commandMap);
}
static void register(Command command) {
commandMap.register("steamwar", command);
}
}

Datei anzeigen

@ -61,13 +61,7 @@ public abstract class SWCommand {
if (!initialized) {
createMapping();
}
try {
if (!commandList.stream().anyMatch(s -> s.invoke(sender, args))) {
commandHelpList.stream().anyMatch(s -> s.invoke(sender, args));
}
} catch (CommandNoHelpException e) {
// Ignored
}
SWCommand.this.execute(sender, alias, args);
return false;
}
@ -76,21 +70,52 @@ public abstract class SWCommand {
if (!initialized) {
createMapping();
}
String string = args[args.length - 1].toLowerCase();
return commandList.stream()
.filter(s -> !s.noTabComplete)
.map(s -> s.tabComplete(sender, args))
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.filter(s -> !s.isEmpty())
.filter(s -> s.toLowerCase().startsWith(string))
.collect(Collectors.toList());
return SWCommand.this.tabComplete(sender, alias, args);
}
};
unregister();
register();
}
// This is used for the tests!
SWCommand(boolean noRegister, String command, String... aliases) {
this.command = new Command(command, "", "/" + command, Arrays.asList(aliases)) {
@Override
public boolean execute(CommandSender sender, String alias, String[] args) {
SWCommand.this.execute(sender, alias, args);
return false;
}
@Override
public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
return SWCommand.this.tabComplete(sender, alias, args);
}
};
createMapping();
}
void execute(CommandSender sender, String alias, String[] args) {
try {
if (!commandList.stream().anyMatch(s -> s.invoke(sender, args))) {
commandHelpList.stream().anyMatch(s -> s.invoke(sender, args));
}
} catch (CommandNoHelpException e) {
// Ignored
}
}
List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
String string = args[args.length - 1].toLowerCase();
return commandList.stream()
.filter(s -> !s.noTabComplete)
.map(s -> s.tabComplete(sender, args))
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.filter(s -> !s.isEmpty())
.filter(s -> s.toLowerCase().startsWith(string))
.collect(Collectors.toList());
}
private synchronized void createMapping() {
List<Method> methods = methods();
for (Method method : methods) {
@ -149,8 +174,7 @@ public abstract class SWCommand {
if (compare != 0) {
return compare;
} else {
return Integer.compare(o1.varArgType != null ? Integer.MAX_VALUE : o1.arguments.length,
o2.varArgType != null ? Integer.MAX_VALUE : o2.arguments.length);
return Integer.compare(o1.comparableValue, o2.comparableValue);
}
});
commandHelpList.sort((o1, o2) -> {
@ -219,13 +243,11 @@ public abstract class SWCommand {
}
public void unregister() {
SWCommandUtils.knownCommandMap.remove(command.getName());
command.getAliases().forEach(SWCommandUtils.knownCommandMap::remove);
command.unregister(SWCommandUtils.commandMap);
CommandRegistering.unregister(command);
}
public void register() {
SWCommandUtils.commandMap.register("steamwar", this.command);
CommandRegistering.register(command);
}
@Register(help = true)
@ -332,6 +354,15 @@ public abstract class SWCommand {
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
protected @interface StaticValue {
String[] value() default {};
String[] value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
protected @interface OptionalValue {
/**
* Will pe parsed against the TypeMapper specified by the parameter or annotation.
*/
String value();
}
}

Datei anzeigen

@ -19,20 +19,17 @@
package de.steamwar.command;
import de.steamwar.sql.BauweltMember;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SteamwarUser;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.command.Command;
import org.bukkit.command.CommandMap;
import org.bukkit.command.CommandSender;
import org.bukkit.command.SimpleCommandMap;
import org.bukkit.entity.Player;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
@ -47,15 +44,6 @@ public class SWCommandUtils {
static final Map<String, TypeMapper<?>> MAPPER_FUNCTIONS = new HashMap<>();
static final Map<String, GuardChecker> GUARD_FUNCTIONS = new HashMap<>();
static final TypeMapper<?> ERROR_FUNCTION = createMapper(s -> {
throw new SecurityException();
}, s -> Collections.emptyList());
static final BiFunction<Class<Enum<?>>, String, Enum<?>> ENUM_MAPPER = (enumClass, s) -> {
Enum<?>[] enums = enumClass.getEnumConstants();
return Arrays.stream(enums).filter(e -> e.name().equalsIgnoreCase(s)).findFirst().orElse(null);
};
static {
addMapper(boolean.class, Boolean.class, createMapper(Boolean::parseBoolean, s -> Arrays.asList("true", "false")));
addMapper(float.class, Float.class, createMapper(numberMapper(Float::parseFloat), numberCompleter(Float::parseFloat)));
@ -75,13 +63,39 @@ public class SWCommandUtils {
MAPPER_FUNCTIONS.put(SteamwarUser.class.getTypeName(), createMapper(SteamwarUser::get, s -> Bukkit.getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList())));
MAPPER_FUNCTIONS.put(SchematicNode.class.getTypeName(), new TypeMapper<SchematicNode>() {
@Override
public List<String> tabCompletes(CommandSender commandSender, String[] strings, String s) {
return SchematicNode.getNodeTabcomplete(SteamwarUser.get(((Player) commandSender).getUniqueId()), s);
public SchematicNode map(CommandSender commandSender, String[] previousArguments, String s) {
return SchematicNode.getNodeFromPath(SteamwarUser.get(((Player) commandSender).getUniqueId()), s);
}
@Override
public SchematicNode map(CommandSender commandSender, String[] previousArguments, String s) {
return SchematicNode.getNodeFromPath(SteamwarUser.get(((Player) commandSender).getUniqueId()), s);
public List<String> tabCompletes(CommandSender commandSender, String[] strings, String s) {
return SchematicNode.getNodeTabcomplete(SteamwarUser.get(((Player) commandSender).getUniqueId()), s);
}
});
MAPPER_FUNCTIONS.put(BauweltMember.class.getTypeName(), new TypeMapper<BauweltMember>() {
@Override
public BauweltMember map(CommandSender commandSender, String[] previousArguments, String s) {
if (!(commandSender instanceof Player)) {
return null;
}
Player player = (Player) commandSender;
return BauweltMember.getMembers(player.getUniqueId())
.stream()
.filter(member -> SteamwarUser.get(member.getMemberID()).getUserName().equalsIgnoreCase(s))
.findAny()
.orElse(null);
}
@Override
public List<String> tabCompletes(CommandSender commandSender, String[] previousArguments, String s) {
if (!(commandSender instanceof Player)) {
return new ArrayList<>();
}
Player player = (Player) commandSender;
return BauweltMember.getMembers(player.getUniqueId())
.stream()
.map(m -> SteamwarUser.get(m.getMemberID()).getUserName())
.collect(Collectors.toList());
}
});
}
@ -91,60 +105,99 @@ public class SWCommandUtils {
MAPPER_FUNCTIONS.put(alternativeClazz.getTypeName(), mapper);
}
static final CommandMap commandMap;
static final Map<String, Command> knownCommandMap;
static {
try {
final Field commandMapField = Bukkit.getServer().getClass().getDeclaredField("commandMap");
commandMapField.setAccessible(true);
commandMap = (CommandMap) commandMapField.get(Bukkit.getServer());
} catch (NoSuchFieldException | IllegalAccessException exception) {
Bukkit.shutdown();
throw new SecurityException("Oh shit. Commands cannot be registered.", exception);
}
try {
final Field knownCommandsField = SimpleCommandMap.class.getDeclaredField("knownCommands");
knownCommandsField.setAccessible(true);
knownCommandMap = (Map<String, Command>) knownCommandsField.get(commandMap);
} catch (NoSuchFieldException | IllegalAccessException exception) {
Bukkit.shutdown();
throw new SecurityException("Oh shit. Commands cannot be registered.", exception);
}
}
static Object[] generateArgumentArray(CommandSender commandSender, TypeMapper<?>[] parameters, GuardChecker[] guards, String[] args, Class<?> varArgType, String[] subCommand) throws CommandParseException {
Object[] arguments = new Object[parameters.length + 1];
int index = 0;
while (index < subCommand.length) {
if (!args[index].equalsIgnoreCase(subCommand[index])) throw new CommandParseException();
index++;
}
int length = 0;
if (varArgType != null) {
length = args.length - parameters.length - subCommand.length + 1;
arguments[arguments.length - 1] = Array.newInstance(varArgType, length);
if (index > args.length - 1) return arguments;
}
for (int i = 0; i < parameters.length - (varArgType != null ? 1 : 0); i++) {
arguments[i + 1] = parameters[i].map(commandSender, Arrays.copyOf(args, index), args[index]);
index++;
if (arguments[i + 1] == null) throw new CommandParseException();
}
if (varArgType != null) {
Object varArgument = arguments[arguments.length - 1];
for (int i = 0; i < length; i++) {
Object value = parameters[parameters.length - 1].map(commandSender, Arrays.copyOf(args, index), args[index]);
if (value == null) throw new CommandParseException();
Array.set(varArgument, i, value);
index++;
static CommandPart generateCommandPart(boolean help, String[] subCommand, Parameter[] parameters, Map<String, TypeMapper<?>> localTypeMapper, Map<String, GuardChecker> localGuardChecker) {
CommandPart first = null;
CommandPart current = null;
for (String s : subCommand) {
CommandPart commandPart = new CommandPart(createMapper(s), null, null, null, help ? GuardCheckType.HELP_COMMAND : GuardCheckType.COMMAND);
commandPart.setIgnoreAsArgument(true);
if (current != null) {
current.setNext(commandPart);
}
current = commandPart;
if (first == null) {
first = current;
}
}
return arguments;
for (int i = 1; i < parameters.length; i++) {
Parameter parameter = parameters[i];
TypeMapper<?> typeMapper = getTypeMapper(parameter, localTypeMapper);
GuardChecker guardChecker = getGuardChecker(parameter, localGuardChecker);
Class<?> varArgType = parameter.isVarArgs() ? parameter.getType().getComponentType() : null;
SWCommand.OptionalValue optionalValue = parameter.getAnnotation(SWCommand.OptionalValue.class);
CommandPart commandPart = new CommandPart(typeMapper, guardChecker, varArgType, optionalValue != null ? optionalValue.value() : null, help ? GuardCheckType.HELP_COMMAND : GuardCheckType.COMMAND);
if (current != null) {
current.setNext(commandPart);
}
current = commandPart;
if (first == null) {
first = current;
}
}
return first;
}
static TypeMapper<?> getTypeMapper(Parameter parameter, Map<String, TypeMapper<?>> localTypeMapper) {
Class<?> clazz = parameter.getType();
if (parameter.isVarArgs()) {
clazz = clazz.getComponentType();
}
SWCommand.ClassMapper classMapper = parameter.getAnnotation(SWCommand.ClassMapper.class);
SWCommand.Mapper mapper = parameter.getAnnotation(SWCommand.Mapper.class);
if (clazz.isEnum() && classMapper == null && mapper == null && !MAPPER_FUNCTIONS.containsKey(clazz.getTypeName()) && !localTypeMapper.containsKey(clazz.getTypeName())) {
return createEnumMapper((Class<Enum<?>>) clazz);
}
String name = clazz.getTypeName();
if (classMapper != null) {
name = classMapper.value().getTypeName();
} else if (mapper != null) {
name = mapper.value();
} else {
SWCommand.StaticValue staticValue = parameter.getAnnotation(SWCommand.StaticValue.class);
if (staticValue != null && parameter.getType() == String.class) {
return createMapper(staticValue.value());
}
}
TypeMapper<?> typeMapper = localTypeMapper.getOrDefault(name, MAPPER_FUNCTIONS.getOrDefault(name, null));
if (typeMapper == null) {
throw new IllegalArgumentException("No mapper found for " + name);
}
return typeMapper;
}
static GuardChecker getGuardChecker(Parameter parameter, Map<String, GuardChecker> localGuardChecker) {
Class<?> clazz = parameter.getType();
if (parameter.isVarArgs()) {
clazz = clazz.getComponentType();
}
SWCommand.ClassGuard classGuard = parameter.getAnnotation(SWCommand.ClassGuard.class);
if (classGuard != null) {
if (classGuard.value() != null) {
return getGuardChecker(classGuard.value().getTypeName(), localGuardChecker);
}
return getGuardChecker(clazz.getTypeName(), localGuardChecker);
}
SWCommand.Guard guard = parameter.getAnnotation(SWCommand.Guard.class);
if (guard != null) {
if (guard.value() != null && !guard.value().isEmpty()) {
return getGuardChecker(guard.value(), localGuardChecker);
}
return getGuardChecker(clazz.getTypeName(), localGuardChecker);
}
return null;
}
private static GuardChecker getGuardChecker(String s, Map<String, GuardChecker> localGuardChecker) {
GuardChecker guardChecker = localGuardChecker.getOrDefault(s, GUARD_FUNCTIONS.getOrDefault(s, null));
if (guardChecker == null) {
throw new IllegalArgumentException("No guard found for " + s);
}
return guardChecker;
}
public static <T> void addMapper(Class<T> clazz, TypeMapper<T> mapper) {
@ -186,6 +239,25 @@ public class SWCommandUtils {
};
}
public static TypeMapper<Enum<?>> createEnumMapper(Class<Enum<?>> enumClass) {
Enum<?>[] enums = enumClass.getEnumConstants();
List<String> strings = Arrays.stream(enums).map(Enum::name).map(String::toLowerCase).collect(Collectors.toList());
return new TypeMapper<Enum<?>>() {
@Override
public Enum<?> map(CommandSender commandSender, String[] previousArguments, String s) {
for (Enum<?> e : enums) {
if (e.name().equalsIgnoreCase(s)) return e;
}
return null;
}
@Override
public List<String> tabCompletes(CommandSender commandSender, String[] previousArguments, String s) {
return strings;
}
};
}
private static <T> Function<String, T> numberMapper(Function<String, T> mapper) {
return s -> {
try {

Datei anzeigen

@ -19,18 +19,16 @@
package de.steamwar.command;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.logging.Level;
import static de.steamwar.command.SWCommandUtils.*;
class SubCommand {
@ -38,214 +36,82 @@ class SubCommand {
Method method;
String[] description;
String[] subCommand;
TypeMapper<?>[] arguments;
GuardChecker[] guards;
private Predicate<CommandSender> commandSenderPredicate;
private Function<CommandSender, ?> commandSenderFunction;
GuardChecker guardChecker;
Class<?> varArgType = null;
private boolean help;
boolean noTabComplete;
int comparableValue;
private CommandPart commandPart;
SubCommand(SWCommand swCommand, Method method, String[] subCommand, Map<String, TypeMapper<?>> localTypeMapper, Map<String, GuardChecker> localGuardChecker, boolean help, String[] description, boolean noTabComplete) {
this.swCommand = swCommand;
this.method = method;
this.help = help;
this.description = description;
this.noTabComplete = noTabComplete;
this.subCommand = subCommand;
Parameter[] parameters = method.getParameters();
comparableValue = parameters[parameters.length - 1].isVarArgs() ? Integer.MAX_VALUE : subCommand.length;
guardChecker = SWCommandUtils.getGuardChecker(parameters[0], localGuardChecker);
commandPart = SWCommandUtils.generateCommandPart(help, subCommand, parameters, localTypeMapper, localGuardChecker);
commandSenderPredicate = sender -> parameters[0].getType().isAssignableFrom(sender.getClass());
commandSenderFunction = sender -> parameters[0].getType().cast(sender);
this.subCommand = subCommand;
guardChecker = getGuardChecker(parameters[0], localGuardChecker);
arguments = new TypeMapper[parameters.length - 1];
guards = new GuardChecker[parameters.length - 1];
for (int i = 1; i < parameters.length; i++) {
Parameter parameter = parameters[i];
Class<?> clazz = parameter.getType();
if (parameter.isVarArgs()) {
clazz = clazz.getComponentType();
varArgType = clazz;
}
SWCommand.Mapper mapper = parameter.getAnnotation(SWCommand.Mapper.class);
SWCommand.ClassMapper classMapper = parameter.getAnnotation(SWCommand.ClassMapper.class);
if (clazz.isEnum() && mapper == null && classMapper == null && !MAPPER_FUNCTIONS.containsKey(clazz.getTypeName()) && !localTypeMapper.containsKey(clazz.getTypeName())) {
Class<Enum<?>> enumClass = (Class<Enum<?>>) clazz;
List<String> tabCompletes = new ArrayList<>();
for (Enum<?> enumConstant : enumClass.getEnumConstants()) {
tabCompletes.add(enumConstant.name().toLowerCase());
}
arguments[i - 1] = SWCommandUtils.createMapper(s -> ENUM_MAPPER.apply(enumClass, s), s -> tabCompletes);
continue;
}
String name = clazz.getTypeName();
if (classMapper != null) {
name = classMapper.value().getTypeName();
} else if (mapper != null) {
name = mapper.value();
} else {
SWCommand.StaticValue staticValue = parameter.getAnnotation(SWCommand.StaticValue.class);
if (staticValue != null && parameter.getType() == String.class) {
arguments[i - 1] = SWCommandUtils.createMapper(staticValue.value());
guards[i - 1] = getGuardChecker(parameter, localGuardChecker);
continue;
}
}
arguments[i - 1] = localTypeMapper.containsKey(name)
? localTypeMapper.get(name)
: MAPPER_FUNCTIONS.getOrDefault(name, ERROR_FUNCTION);
guards[i - 1] = getGuardChecker(parameter, localGuardChecker);
}
}
private GuardChecker getGuardChecker(Parameter parameter, Map<String, GuardChecker> localGuardChecker) {
SWCommand.ClassGuard classGuard = parameter.getAnnotation(SWCommand.ClassGuard.class);
if (classGuard != null) {
if (classGuard.value() == null) {
String s = parameter.getType().getTypeName();
if (parameter.isVarArgs()) {
s = parameter.getType().getComponentType().getTypeName();
}
return localGuardChecker.getOrDefault(s, GUARD_FUNCTIONS.getOrDefault(s, null));
}
GuardChecker current = localGuardChecker.getOrDefault(classGuard.value().getTypeName(), GUARD_FUNCTIONS.getOrDefault(classGuard.value().getTypeName(), null));
if (current == null) {
Bukkit.getLogger().log(Level.WARNING, () -> "The guard checker with name '" + classGuard.value().getTypeName() + "' is neither a local guard checker nor a global one");
}
return current;
}
SWCommand.Guard guard = parameter.getAnnotation(SWCommand.Guard.class);
if (guard != null) {
if (guard.value() == null || guard.value().isEmpty()) {
String s = parameter.getType().getTypeName();
if (parameter.isVarArgs()) {
s = parameter.getType().getComponentType().getTypeName();
}
return localGuardChecker.getOrDefault(s, GUARD_FUNCTIONS.getOrDefault(s, null));
}
GuardChecker current = localGuardChecker.getOrDefault(guard.value(), GUARD_FUNCTIONS.getOrDefault(guard.value(), null));
if (current == null) {
Bukkit.getLogger().log(Level.WARNING, () -> "The guard checker with name '" + guard.value() + "' is neither a local guard checker nor a global one");
}
return current;
}
return null;
}
boolean invoke(CommandSender commandSender, String[] args) {
if (args.length < arguments.length + subCommand.length - (varArgType != null ? 1 : 0)) {
return false;
}
if (varArgType == null && args.length > arguments.length + subCommand.length) {
return false;
}
try {
if (!commandSenderPredicate.test(commandSender)) {
return false;
}
Object[] objects = SWCommandUtils.generateArgumentArray(commandSender, arguments, guards, args, varArgType, subCommand);
objects[0] = commandSenderFunction.apply(commandSender);
for (int i = subCommand.length; i < args.length; i++) {
GuardChecker current;
if (i == subCommand.length) {
current = guardChecker;
} else {
if (i >= objects.length + subCommand.length) {
current = guards[guards.length - 1];
} else {
current = guards[i - 1 - subCommand.length];
}
if (commandPart == null) {
if (args.length != 0) {
return false;
}
if (current != null) {
GuardResult guardResult;
if (i == 0) {
guardResult = current.guard(commandSender, help ? GuardCheckType.HELP_COMMAND : GuardCheckType.COMMAND, new String[0], null);
} else {
guardResult = current.guard(commandSender, help ? GuardCheckType.HELP_COMMAND : GuardCheckType.COMMAND, Arrays.copyOf(args, i - 1), args[i - 1]);
}
if (guardResult != GuardResult.ALLOWED) {
if (guardResult == GuardResult.DENIED) {
method.setAccessible(true);
method.invoke(swCommand, commandSenderFunction.apply(commandSender));
} else {
List<Object> objects = new ArrayList<>();
commandPart.generateArgumentArray(objects, commandSender, args, 0);
if (guardChecker != null) {
GuardResult guardResult = guardChecker.guard(commandSender, GuardCheckType.COMMAND, new String[0], null);
switch (guardResult) {
case ALLOWED:
break;
case DENIED:
throw new CommandNoHelpException();
}
return false;
case DENIED_WITH_HELP:
default:
return true;
}
}
commandPart.guardCheck(commandSender, args, 0);
objects.add(0, commandSenderFunction.apply(commandSender));
method.setAccessible(true);
method.invoke(swCommand, objects.toArray());
}
method.setAccessible(true);
method.invoke(swCommand, objects);
} catch (CommandNoHelpException e) {
throw e;
} catch (IllegalAccessException | RuntimeException | InvocationTargetException e) {
throw new SecurityException(e.getMessage(), e);
} catch (CommandParseException e) {
return false;
} catch (IllegalAccessException | RuntimeException | InvocationTargetException e) {
throw new SecurityException(e.getMessage(), e);
}
return true;
}
List<String> tabComplete(CommandSender commandSender, String[] args) {
if (varArgType == null && args.length > arguments.length + subCommand.length) {
return null;
}
if (guardChecker != null && guardChecker.guard(commandSender, GuardCheckType.TAB_COMPLETE, new String[0], null) != GuardResult.ALLOWED) {
return null;
}
int index = 0;
List<String> argsList = new LinkedList<>(Arrays.asList(args));
for (String value : subCommand) {
String s = argsList.remove(0);
if (argsList.isEmpty()) return Collections.singletonList(value);
if (!value.equalsIgnoreCase(s)) return null;
index++;
if (commandPart == null) {
return null;
}
int guardIndex = 0;
for (TypeMapper<?> argument : arguments) {
String s = argsList.remove(0);
if (argsList.isEmpty()) {
if (guards[guardIndex] != null && guards[guardIndex].guard(commandSender, GuardCheckType.TAB_COMPLETE, Arrays.copyOf(args, args.length - 1), s) != GuardResult.ALLOWED) {
return null;
}
return argument.tabCompletes(commandSender, Arrays.copyOf(args, args.length - 1), s);
}
try {
if (guards[guardIndex] != null && guards[guardIndex].guard(commandSender, GuardCheckType.TAB_COMPLETE, Arrays.copyOf(args, index), s) != GuardResult.ALLOWED) {
return null;
}
if (argument.map(commandSender, Arrays.copyOf(args, index), s) == null) {
return null;
}
} catch (Exception e) {
return null;
}
index++;
guardIndex++;
}
if (varArgType != null && !argsList.isEmpty()) {
while (!argsList.isEmpty()) {
String s = argsList.remove(0);
if (argsList.isEmpty()) {
if (guards[guards.length - 1] != null && guards[guards.length - 1].guard(commandSender, GuardCheckType.TAB_COMPLETE, Arrays.copyOf(args, args.length - 1), s) != GuardResult.ALLOWED) {
return null;
}
return arguments[arguments.length - 1].tabCompletes(commandSender, Arrays.copyOf(args, args.length - 1), s);
}
try {
if (guards[guards.length - 1] != null && guards[guards.length - 1].guard(commandSender, GuardCheckType.TAB_COMPLETE, Arrays.copyOf(args, index), s) != GuardResult.ALLOWED) {
return null;
}
if (arguments[arguments.length - 1].map(commandSender, Arrays.copyOf(args, index), s) == null) {
return null;
}
} catch (Exception e) {
return null;
}
index++;
}
}
return null;
List<String> list = new ArrayList<>();
commandPart.generateTabComplete(list, commandSender, args, 0);
return list;
}
}

Datei anzeigen

@ -24,6 +24,9 @@ import org.bukkit.command.CommandSender;
import java.util.List;
public interface TypeMapper<T> {
/**
* The CommandSender can be null!
*/
default T map(CommandSender commandSender, String[] previousArguments, String s) {
return map(previousArguments, s);
}

Datei anzeigen

@ -38,7 +38,6 @@ import java.util.logging.Level;
public class Core extends JavaPlugin{
private static Core instance;
private static final int version;
public static Message MESSAGE;

Datei anzeigen

@ -25,7 +25,9 @@ import org.bukkit.entity.Player;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.HashMap;
import java.util.Map;
YoyoNow markierte diese Unterhaltung als gelöst Veraltet
Veraltet
Review

Du und deine Import-Sauberkeit ;).

Du und deine Import-Sauberkeit ;).
import java.util.UUID;
public class SteamwarUser {

Datei anzeigen

@ -0,0 +1,122 @@
/*
YoyoNow markierte diese Unterhaltung als gelöst
Review

Die testsrc/.gitkeep kann doch mittlerweile eigentlich weg, oder?

Die testsrc/.gitkeep kann doch mittlerweile eigentlich weg, oder?
Review

Da hast du recht.

Da hast du recht.
* This file is a part of the SteamWar software.
*
* Copyright (C) 2020 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar;
import org.bukkit.Server;
import org.bukkit.command.CommandSender;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.Plugin;
import java.util.Set;
public class TestCommandSender implements CommandSender {
@Override
public void sendMessage(String s) {
}
@Override
public void sendMessage(String[] strings) {
}
@Override
public Server getServer() {
return null;
}
@Override
public String getName() {
return null;
}
@Override
public Spigot spigot() {
return null;
}
@Override
public boolean isPermissionSet(String s) {
return false;
}
@Override
public boolean isPermissionSet(Permission permission) {
return false;
}
@Override
public boolean hasPermission(String s) {
return false;
}
@Override
public boolean hasPermission(Permission permission) {
return false;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin, String s, boolean b) {
return null;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin) {
return null;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin, String s, boolean b, int i) {
return null;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin, int i) {
return null;
}
@Override
public void removeAttachment(PermissionAttachment permissionAttachment) {
}
@Override
public void recalculatePermissions() {
}
@Override
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
return null;
}
@Override
public boolean isOp() {
return false;
}
@Override
public void setOp(boolean b) {
}
}

Datei anzeigen

@ -0,0 +1,41 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2020 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
public class ExecutionIdentifier extends RuntimeException {
YoyoNow markierte diese Unterhaltung als gelöst
Review

Brauchst du den wirklich, oder hast du andernfalls silent-exceptions die irgendwo gecatcht und verworfen werden? Das wäre dann nämlich eher ein Zeichen davon, dass die Codearchitektur bescheiden ist. Eigentlich sollte man eine korrekte Ausführung daran erkennen, dass der Code ordnungsgemäß terminiert und Werte, welche sich ändern sollten, auf den korrekten Wert geändert wurden.

Brauchst du den wirklich, oder hast du andernfalls silent-exceptions die irgendwo gecatcht und verworfen werden? Das wäre dann nämlich eher ein Zeichen davon, dass die Codearchitektur bescheiden ist. Eigentlich sollte man eine korrekte Ausführung daran erkennen, dass der Code ordnungsgemäß terminiert und Werte, welche sich ändern sollten, auf den korrekten Wert geändert wurden.
Review

Naja ich will im test wissen, ob die methode wirklich ausgeführt wird, und das geht am besten indem ich wenn es ausgeführt wird eine Exception werfe und diese überprüfe.

Naja ich will im test wissen, ob die methode wirklich ausgeführt wird, und das geht am besten indem ich wenn es ausgeführt wird eine Exception werfe und diese überprüfe.
Review

Dann weißt du aber nie, ob der Code, welcher danach noch ausgeführt wird, nicht den Wert wieder zurücksetzen würde/fehler werfen würde.

Dann weißt du aber nie, ob der Code, welcher danach noch ausgeführt wird, nicht den Wert wieder zurücksetzen würde/fehler werfen würde.
Review

Das brauche ich mit dem Test nicht prüfen, ich will dort erstmal nur prüfen ob an sich die methode ausgeführt wird, andere Tests werden noch folgen. Aber soweit tut das Framework

Das brauche ich mit dem Test nicht prüfen, ich will dort erstmal nur prüfen ob an sich die methode ausgeführt wird, andere Tests werden noch folgen. Aber soweit tut das Framework
public ExecutionIdentifier() {
}
public ExecutionIdentifier(String message) {
super(message);
}
public ExecutionIdentifier(String message, Throwable cause) {
super(message, cause);
}
public ExecutionIdentifier(Throwable cause) {
super(cause);
}
public ExecutionIdentifier(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

Datei anzeigen

@ -0,0 +1,34 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2020 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
import org.bukkit.command.CommandSender;
public class SimpleCommand extends SWCommand {
public SimpleCommand() {
super(true, "simple");
}
@Register
public void execute(CommandSender sender) {
throw new ExecutionIdentifier("Simple execute without any parameters");
}
}

Datei anzeigen

@ -0,0 +1,243 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2020 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
import de.steamwar.TestCommandSender;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
public class SimpleCommandPartTest {
private CommandPart stringCommandPart;
private CommandPart intCommandPart;
private CommandPart chainedCommandPart;
private CommandPart varArgCommandPart;
private CommandPart simpleGuardPart;
private CommandPart optionalCommandPart;
@Before
public void setUp() throws Exception {
stringCommandPart = new CommandPart(SWCommandUtils.createMapper("hello", "world"), null, null, null, GuardCheckType.COMMAND);
intCommandPart = new CommandPart(SWCommandUtils.MAPPER_FUNCTIONS.get("int"), null, null, null, GuardCheckType.COMMAND);
chainedCommandPart = new CommandPart(SWCommandUtils.createMapper("hello", "world"), null, null, null, GuardCheckType.COMMAND);
chainedCommandPart.setNext(new CommandPart(SWCommandUtils.MAPPER_FUNCTIONS.get("int"), null, null, null, GuardCheckType.COMMAND));
varArgCommandPart = new CommandPart(SWCommandUtils.createMapper("hello", "world"), null, String.class, null, GuardCheckType.COMMAND);
simpleGuardPart = new CommandPart(SWCommandUtils.createMapper("hello", "world"), (commandSender, guardCheckType, previousArguments, s) -> s.equals("hello") ? GuardResult.DENIED : GuardResult.ALLOWED, null, null, GuardCheckType.COMMAND);
optionalCommandPart = new CommandPart(SWCommandUtils.createMapper("hello", "world"), null, null, "hello", GuardCheckType.COMMAND);
optionalCommandPart.setNext(new CommandPart(SWCommandUtils.createMapper("hello2", "world2"), null, null, null, GuardCheckType.COMMAND));
}
@Test
public void testCommandPartTabCompleteNoArguments() {
List<String> tabComplete = new ArrayList<>();
stringCommandPart.generateTabComplete(tabComplete, new TestCommandSender(), new String[]{""}, 0);
assertThat(tabComplete.size(), is(2));
assertThat(tabComplete.get(0), is("hello"));
assertThat(tabComplete.get(1), is("world"));
}
@Test(expected = CommandParseException.class)
public void testCommandExecuteInvalidArgument() {
stringCommandPart.generateArgumentArray(new ArrayList<>(), new TestCommandSender(), new String[]{""}, 0);
}
@Test
public void testCommandExecuteValidArgument() {
List<Object> argumentArray = new ArrayList<>();
stringCommandPart.generateArgumentArray(argumentArray, new TestCommandSender(), new String[]{"hello"}, 0);
assertThat(argumentArray.size(), is(1));
assertThat(argumentArray.get(0), instanceOf(String.class));
assertThat(argumentArray.get(0), is("hello"));
}
@Test
public void testCommandExecuteValidOtherArgument() {
List<Object> argumentArray = new ArrayList<>();
stringCommandPart.generateArgumentArray(argumentArray, new TestCommandSender(), new String[]{"world"}, 0);
assertThat(argumentArray.size(), is(1));
assertThat(argumentArray.get(0), instanceOf(String.class));
assertThat(argumentArray.get(0), is("world"));
}
@Test(expected = CommandParseException.class)
public void testCommandExecuteNonNumberArgument() {
intCommandPart.generateArgumentArray(new ArrayList<>(), new TestCommandSender(), new String[]{"world"}, 0);
}
@Test
public void testCommandExecuteValidNumberArgument() {
List<Object> argumentArray = new ArrayList<>();
intCommandPart.generateArgumentArray(argumentArray, new TestCommandSender(), new String[]{"0"}, 0);
assertThat(argumentArray.size(), is(1));
assertThat(argumentArray.get(0), instanceOf(int.class));
assertThat(argumentArray.get(0), is(0));
}
@Test
public void testChainedCommandExecuteValidArgument() {
List<Object> argumentArray = new ArrayList<>();
chainedCommandPart.generateArgumentArray(argumentArray, new TestCommandSender(), new String[]{"hello", "0"}, 0);
assertThat(argumentArray.size(), is(2));
assertThat(argumentArray.get(0), instanceOf(String.class));
assertThat(argumentArray.get(0), is("hello"));
assertThat(argumentArray.get(1), instanceOf(int.class));
assertThat(argumentArray.get(1), is(0));
}
@Test
public void testChainedCommandTabComplete() {
List<String> tabCompletes = new ArrayList<>();
chainedCommandPart.generateTabComplete(tabCompletes, new TestCommandSender(), new String[]{""}, 0);
assertThat(tabCompletes.size(), is(2));
assertThat(tabCompletes.get(0), is("hello"));
assertThat(tabCompletes.get(1), is("world"));
}
@Test
public void testChainedCommandTabCompleteOther() {
List<String> tabCompletes = new ArrayList<>();
chainedCommandPart.generateTabComplete(tabCompletes, new TestCommandSender(), new String[]{"hello", ""}, 0);
assertThat(tabCompletes.size(), is(0));
}
@Test
public void testVarArgsCommandTabComplete() {
List<String> tabCompletes = new ArrayList<>();
varArgCommandPart.generateTabComplete(tabCompletes, new TestCommandSender(), new String[]{"hello"}, 0);
assertThat(tabCompletes.size(), is(2));
assertThat(tabCompletes.get(0), is("hello"));
assertThat(tabCompletes.get(1), is("world"));
}
@Test
public void testVarArgsCommandTabCompleteDeeper() {
List<String> tabCompletes = new ArrayList<>();
varArgCommandPart.generateTabComplete(tabCompletes, new TestCommandSender(), new String[]{"hello", "world", "hello", "world"}, 0);
System.out.println(tabCompletes);
assertThat(tabCompletes.size(), is(2));
assertThat(tabCompletes.get(0), is("hello"));
assertThat(tabCompletes.get(1), is("world"));
}
@Test
public void testVarArgsCommandArgumentParsing() {
List<Object> argumentArray = new ArrayList<>();
varArgCommandPart.generateArgumentArray(argumentArray, new TestCommandSender(), new String[]{"hello"}, 0);
assertThat(argumentArray.size(), is(1));
assertThat(argumentArray.get(0), instanceOf(String[].class));
assertThat((String[]) argumentArray.get(0), arrayWithSize(1));
assertThat((String[]) argumentArray.get(0), is(new String[]{"hello"}));
}
@Test
public void testVarArgsCommandArgumentParsingDeeper() {
List<Object> argumentArray = new ArrayList<>();
varArgCommandPart.generateArgumentArray(argumentArray, new TestCommandSender(), new String[]{"hello", "world", "hello", "world"}, 0);
assertThat(argumentArray.size(), is(1));
assertThat(argumentArray.get(0), instanceOf(String[].class));
assertThat((String[]) argumentArray.get(0), arrayWithSize(4));
assertThat((String[]) argumentArray.get(0), is(new String[]{"hello", "world", "hello", "world"}));
}
@Test
public void testGuardCommandExecute() {
List<Object> argumentArray = new ArrayList<>();
simpleGuardPart.generateArgumentArray(argumentArray, new TestCommandSender(), new String[]{"hello"}, 0);
assertThat(argumentArray.size(), is(1));
}
@Test(expected = CommandNoHelpException.class)
public void testGuardGuardCheck() {
simpleGuardPart.guardCheck(new TestCommandSender(), new String[]{"hello"}, 0);
}
@Test
public void testGuardCommandExecuteValid() {
List<Object> argumentArray = new ArrayList<>();
simpleGuardPart.generateArgumentArray(argumentArray, new TestCommandSender(), new String[]{"world"}, 0);
assertThat(argumentArray.size(), is(1));
}
@Test
public void testGuardGuardCheckValid() {
boolean guardResult = simpleGuardPart.guardCheck(new TestCommandSender(), new String[]{"world"}, 0);
assertThat(guardResult, is(true));
}
@Test
public void testOptionalCommandPartTabComplete() {
List<String> tabCompletes = new ArrayList<>();
optionalCommandPart.generateTabComplete(tabCompletes, new TestCommandSender(), new String[]{""}, 0);
assertThat(tabCompletes.size(), is(4));
assertThat(tabCompletes.get(0), is("hello"));
assertThat(tabCompletes.get(1), is("world"));
assertThat(tabCompletes.get(2), is("hello2"));
assertThat(tabCompletes.get(3), is("world2"));
}
@Test
public void testOptionalCommandPartTabCompleteSecond() {
List<String> tabCompletes = new ArrayList<>();
optionalCommandPart.generateTabComplete(tabCompletes, new TestCommandSender(), new String[]{"hello", ""}, 0);
assertThat(tabCompletes.size(), is(2));
assertThat(tabCompletes.get(0), is("hello2"));
assertThat(tabCompletes.get(1), is("world2"));
}
@Test(expected = CommandParseException.class)
public void testOptionalCommandPartExecution() {
optionalCommandPart.generateArgumentArray(new ArrayList<>(), new TestCommandSender(), new String[]{""}, 0);
}
@Test
public void testOptionalCommandPartExecutionValid() {
List<Object> argumentArray = new ArrayList<>();
optionalCommandPart.generateArgumentArray(argumentArray, new TestCommandSender(), new String[]{"hello2"}, 0);
assertThat(argumentArray.size(), is(2));
assertThat(argumentArray.get(0), is("hello"));
assertThat(argumentArray.get(1), is("hello2"));
}
@Test(expected = CommandParseException.class)
public void testOptionalCommandPartExecutionInvalid() {
optionalCommandPart.generateArgumentArray(new ArrayList<>(), new TestCommandSender(), new String[]{"hello"}, 0);
}
@Test
public void testOptionalCommandPartExecutionFullyValid() {
List<Object> argumentArray = new ArrayList<>();
optionalCommandPart.generateArgumentArray(argumentArray, new TestCommandSender(), new String[]{"world", "hello2"}, 0);
assertThat(argumentArray.size(), is(2));
assertThat(argumentArray.get(0), is("world"));
assertThat(argumentArray.get(1), is("hello2"));
}
}

Datei anzeigen

@ -0,0 +1,61 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2020 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
import de.steamwar.TestCommandSender;
import org.junit.Before;
import org.junit.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
public class SimpleCommandTest {
private SimpleCommand simpleCommand;
@Before
public void setUp() throws Exception {
simpleCommand = new SimpleCommand();
}
@Test
public void testCommandParsing() {
try {
simpleCommand.execute(new TestCommandSender(), "", new String[]{});
} catch (SecurityException securityException) {
if (securityException.getCause().getCause() instanceof ExecutionIdentifier) {
ExecutionIdentifier executionIdentifier = (ExecutionIdentifier) securityException.getCause().getCause();
assertThat(executionIdentifier.getMessage(), is("Simple execute without any parameters"));
return;
}
}
assert false;
}
@Test
public void testUnknownCommandParsing() {
try {
simpleCommand.execute(new TestCommandSender(), "", new String[]{"unknown"});
} catch (SecurityException securityException) {
securityException.printStackTrace();
assert false;
}
}
}

Datei anzeigen

@ -3,6 +3,7 @@ build:
- "cp ~/gradle.properties ."
- "chmod u+x build.gradle"
- "./gradlew buildProject"
- "./gradlew test"
artifacts:
"/binarys/spigotcore.jar": "build/libs/spigotcore.jar"