Commits vergleichen

...

2 Commits

Autor SHA1 Nachricht Datum
yoyosource
7ecff22b6d Merge branch 'master' into RemoveCommandFramework
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
2024-03-23 11:11:02 +01:00
yoyosource
8b9e957982 Remove CommandFramework
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
2024-03-22 18:48:34 +01:00
42 geänderte Dateien mit 0 neuen und 3732 gelöschten Zeilen

Datei anzeigen

@ -1,711 +0,0 @@
/*
* 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 java.lang.annotation.*;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public abstract class AbstractSWCommand<T> {
private static final Map<Class<AbstractSWCommand<?>>, List<AbstractSWCommand<?>>> dependencyMap = new HashMap<>();
private Class<?> clazz; // This is used in createMappings()
private boolean initialized = false;
protected final List<SubCommand<T>> commandList = new ArrayList<>();
protected final List<SubCommand<T>> helpCommandList = new ArrayList<>();
private final Map<String, AbstractTypeMapper<T, ?>> localTypeMapper = new HashMap<>();
private final Map<String, AbstractValidator<T, ?>> localValidators = new HashMap<>();
protected AbstractSWCommand(Class<T> clazz, String command) {
this(clazz, command, new String[0]);
}
protected AbstractSWCommand(Class<T> clazz, String command, String... aliases) {
this.clazz = clazz;
PartOf partOf = this.getClass().getAnnotation(PartOf.class);
if (partOf != null) {
dependencyMap.computeIfAbsent((Class<AbstractSWCommand<?>>) partOf.value(), k -> new ArrayList<>()).add(this);
return;
}
createAndSafeCommand(command, aliases);
unregister();
register();
}
protected abstract void createAndSafeCommand(String command, String[] aliases);
public abstract void unregister();
public abstract void register();
protected void commandSystemError(T sender, CommandFrameworkException e) {
e.printStackTrace();
}
protected void commandSystemWarning(Supplier<String> message) {
System.out.println(message.get());
}
protected void sendMessage(T sender, String message, Object[] args) {
}
protected void initialisePartOf(AbstractSWCommand parent) {
}
protected final void execute(T sender, String alias, String[] args) {
initialize();
List<Runnable> errors = new ArrayList<>();
try {
if (commandList.stream().noneMatch(s -> s.invoke(errors::add, sender, alias, args))) {
errors.forEach(Runnable::run);
} else return;
if (errors.isEmpty() && helpCommandList.stream().noneMatch(s -> s.invoke(errors::add, sender, alias, args))) {
errors.forEach(Runnable::run);
}
} catch (CommandFrameworkException e) {
commandSystemError(sender, e);
throw e;
}
}
protected final List<String> tabComplete(T sender, String alias, String[] args) throws IllegalArgumentException {
initialize();
String string = args[args.length - 1].toLowerCase();
return Stream.concat(commandList.stream(), helpCommandList.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) || string.startsWith(s.toLowerCase()))
.distinct()
.collect(Collectors.toList());
}
private synchronized void initialize() {
if (initialized) return;
List<Method> methods = methods().stream()
.filter(this::validateMethod)
.collect(Collectors.toList());
for (Method method : methods) {
Cached cached = method.getAnnotation(Cached.class);
this.<Mapper, AbstractTypeMapper<?, ?>>add(Mapper.class, method, (anno, typeMapper) -> {
TabCompletionCache.add(typeMapper, cached);
(anno.local() ? ((Map) localTypeMapper) : SWCommandUtils.getMAPPER_FUNCTIONS()).put(anno.value(), typeMapper);
});
this.<ClassMapper, AbstractTypeMapper<?, ?>>add(ClassMapper.class, method, (anno, typeMapper) -> {
TabCompletionCache.add(typeMapper, cached);
(anno.local() ? ((Map) localTypeMapper) : SWCommandUtils.getMAPPER_FUNCTIONS()).put(anno.value().getName(), typeMapper);
});
this.<Validator, AbstractValidator<?, ?>>add(Validator.class, method, (anno, validator) -> {
(anno.local() ? ((Map) localValidators) : SWCommandUtils.getVALIDATOR_FUNCTIONS()).put(anno.value(), validator);
});
this.<ClassValidator, AbstractValidator<?, ?>>add(ClassValidator.class, method, (anno, validator) -> {
(anno.local() ? ((Map) localValidators) : SWCommandUtils.getVALIDATOR_FUNCTIONS()).put(anno.value().getName(), validator);
});
}
for (Method method : methods) {
add(Register.class, method, true, (anno, parameters) -> {
for (int i = 1; i < parameters.length; i++) {
Parameter parameter = parameters[i];
Class<?> clazz = parameter.getType();
if (parameter.isVarArgs()) clazz = clazz.getComponentType();
Mapper mapper = parameter.getAnnotation(Mapper.class);
if (clazz.isEnum() && mapper == null && !SWCommandUtils.getMAPPER_FUNCTIONS().containsKey(clazz.getTypeName())) {
continue;
}
String name = mapper != null ? mapper.value() : clazz.getTypeName();
if (!SWCommandUtils.getMAPPER_FUNCTIONS().containsKey(name) && !localTypeMapper.containsKey(name)) {
commandSystemWarning(() -> "The parameter '" + parameter.toString() + "' is using an unsupported Mapper of type '" + name + "'");
return;
}
}
commandList.add(new SubCommand<>(this, method, anno.value(), localTypeMapper, localValidators, anno.description(), anno.noTabComplete()));
});
}
if (dependencyMap.containsKey(this.getClass())) {
dependencyMap.get(this.getClass()).forEach(abstractSWCommand -> {
abstractSWCommand.localTypeMapper.putAll((Map) localTypeMapper);
abstractSWCommand.localValidators.putAll((Map) localValidators);
abstractSWCommand.initialisePartOf(this);
abstractSWCommand.initialize();
commandList.addAll((Collection) abstractSWCommand.commandList);
});
}
Collections.sort(commandList);
commandList.removeIf(subCommand -> {
if (subCommand.isHelp) {
helpCommandList.add(subCommand);
return true;
} else {
return false;
}
});
initialized = true;
}
private boolean validateMethod(Method method) {
if (!checkType(method.getAnnotations(), method.getReturnType(), false, annotation -> {
CommandMetaData.Method methodMetaData = annotation.annotationType().getAnnotation(CommandMetaData.Method.class);
if (methodMetaData == null) return (aClass, varArg) -> true;
if (method.getParameterCount() > methodMetaData.maxParameterCount() || method.getParameterCount() < methodMetaData.minParameterCount())
return (aClass, varArg) -> false;
return (aClass, varArg) -> {
Class<?>[] types = methodMetaData.value();
if (types == null) return true;
for (Class<?> type : types) {
if (type.isAssignableFrom(aClass)) return true;
}
return false;
};
}, "The method '" + method + "'")) return false;
boolean valid = true;
for (Parameter parameter : method.getParameters()) {
if (!checkType(parameter.getAnnotations(), parameter.getType(), parameter.isVarArgs(), annotation -> {
CommandMetaData.Parameter parameterMetaData = annotation.annotationType().getAnnotation(CommandMetaData.Parameter.class);
if (parameterMetaData == null) return (aClass, varArg) -> true;
Class<?> handler = parameterMetaData.handler();
if (BiPredicate.class.isAssignableFrom(handler)) {
try {
return (BiPredicate<Class<?>, Boolean>) handler.getConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
NoSuchMethodException e) {
}
}
return (aClass, varArg) -> {
if (varArg) aClass = aClass.getComponentType();
Class<?>[] types = parameterMetaData.value();
if (types == null) return true;
for (Class<?> current : types) {
if (current.isAssignableFrom(aClass)) return true;
}
return false;
};
}, "The parameter '" + parameter + "'")) valid = false;
}
return valid;
}
private boolean checkType(Annotation[] annotations, Class<?> clazz, boolean varArg, Function<Annotation, BiPredicate<Class<?>, Boolean>> toApplicableTypes, String warning) {
boolean valid = true;
for (Annotation annotation : annotations) {
BiPredicate<Class<?>, Boolean> predicate = toApplicableTypes.apply(annotation);
if (!predicate.test(clazz, varArg)) {
commandSystemWarning(() -> warning + " is using an unsupported annotation of type '" + annotation.annotationType().getName() + "'");
valid = false;
}
}
return valid;
}
private <T extends Annotation> void add(Class<T> annotation, Method method, boolean firstParameter, BiConsumer<T, Parameter[]> consumer) {
T[] anno = SWCommandUtils.getAnnotation(method, annotation);
if (anno == null || anno.length == 0) return;
Parameter[] parameters = method.getParameters();
if (firstParameter && !clazz.isAssignableFrom(parameters[0].getType())) {
commandSystemWarning(() -> "The method '" + method.toString() + "' is lacking the first parameter of type '" + clazz.getTypeName() + "'");
return;
}
Arrays.stream(anno).forEach(t -> consumer.accept(t, parameters));
}
private <T extends Annotation, K> void add(Class<T> annotation, Method method, BiConsumer<T, K> consumer) {
add(annotation, method, false, (anno, parameters) -> {
try {
method.setAccessible(true);
consumer.accept(anno, (K) method.invoke(this));
} catch (Exception e) {
throw new SecurityException(e.getMessage(), e);
}
});
}
// TODO: Implement this when Message System is ready
/*
public void addDefaultHelpMessage(String message) {
defaultHelpMessages.add(message);
}
*/
private List<Method> methods() {
List<Method> methods = new ArrayList<>();
Class<?> current = getClass();
while (current != AbstractSWCommand.class) {
methods.addAll(Arrays.asList(current.getDeclaredMethods()));
current = current.getSuperclass();
}
return methods;
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface PartOf {
Class<?> value();
}
// --- Annotation for the command ---
/**
* Annotation for registering a method as a command
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Repeatable(Register.Registeres.class)
@CommandMetaData.Method(value = void.class, minParameterCount = 1)
protected @interface Register {
/**
* Identifier of subcommand
*/
String[] value() default {};
@Deprecated
boolean help() default false;
String[] description() default {};
boolean noTabComplete() default false;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@CommandMetaData.Method(value = void.class, minParameterCount = 1)
@interface Registeres {
Register[] value();
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER, ElementType.METHOD})
@CommandMetaData.Method(value = AbstractTypeMapper.class, maxParameterCount = 0)
@CommandMetaData.ImplicitTypeMapper(handler = Mapper.Handler.class)
protected @interface Mapper {
String value();
boolean local() default false;
class Handler<T> implements AbstractTypeMapper<T, Object> {
private AbstractTypeMapper<T, Object> inner;
public Handler(AbstractSWCommand.Mapper mapper, Map<String, AbstractTypeMapper<T, ?>> localTypeMapper) {
inner = (AbstractTypeMapper<T, Object>) SWCommandUtils.getTypeMapper(mapper.value(), localTypeMapper);
}
@Override
public Object map(T sender, PreviousArguments previousArguments, String s) {
return inner.map(sender, previousArguments, s);
}
@Override
public boolean validate(T sender, Object value, MessageSender messageSender) {
return inner.validate(sender, value, messageSender);
}
@Override
public Collection<String> tabCompletes(T sender, PreviousArguments previousArguments, String s) {
return inner.tabCompletes(sender, previousArguments, s);
}
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@CommandMetaData.Method(value = AbstractTypeMapper.class, maxParameterCount = 0)
protected @interface ClassMapper {
Class<?> value();
boolean local() default false;
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@CommandMetaData.Method(value = AbstractTypeMapper.class, maxParameterCount = 0)
protected @interface Cached {
long cacheDuration() default 5;
TimeUnit timeUnit() default TimeUnit.SECONDS;
boolean global() default false;
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER, ElementType.METHOD})
@CommandMetaData.Method(value = AbstractValidator.class, maxParameterCount = 0)
@CommandMetaData.ImplicitValidator(handler = Validator.Handler.class, order = 0)
protected @interface Validator {
String value() default "";
boolean local() default false;
boolean invert() default false;
class Handler<T> implements AbstractValidator<T, Object> {
private AbstractValidator<T, Object> inner;
private boolean invert;
public Handler(AbstractSWCommand.Validator validator, Class<?> clazz, Map<String, AbstractValidator<T, ?>> localValidator) {
inner = (AbstractValidator<T, Object>) SWCommandUtils.getValidator(validator, clazz, localValidator);
invert = validator.invert();
}
@Override
public boolean validate(T sender, Object value, MessageSender messageSender) {
return inner.validate(sender, value, messageSender) ^ invert;
}
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@CommandMetaData.Method(value = AbstractValidator.class, maxParameterCount = 0)
protected @interface ClassValidator {
Class<?> value();
boolean local() default false;
}
// --- Implicit TypeMapper ---
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@CommandMetaData.Parameter({String.class, int.class, Integer.class, long.class, Long.class, boolean.class, Boolean.class})
@CommandMetaData.ImplicitTypeMapper(handler = StaticValue.Handler.class)
protected @interface StaticValue {
String[] value();
/**
* This is the short form for 'allowImplicitSwitchExpressions'
* and can be set to true if you want to allow int as well as boolean as annotated parameter types.
* The value array needs to be at least 2 long for this flag to be considered.
* While using an int, the value will represent the index into the value array.
* While using a boolean, the {@link #falseValues()} defines which indices are
* considered {@code false} or {@code true}.
*/
boolean allowISE() default false;
int[] falseValues() default {0};
class Handler<T> implements AbstractTypeMapper<T, Object> {
private AbstractTypeMapper inner;
public Handler(StaticValue staticValue, Class<?> clazz) {
if (clazz == String.class) {
inner = SWCommandUtils.createMapper(staticValue.value());
return;
}
if (!staticValue.allowISE()) {
throw new IllegalArgumentException("The parameter type '" + clazz.getTypeName() + "' is not supported by the StaticValue annotation");
}
if (clazz == boolean.class || clazz == Boolean.class) {
List<String> tabCompletes = new ArrayList<>(Arrays.asList(staticValue.value()));
Set<Integer> falseValues = new HashSet<>();
for (int i : staticValue.falseValues()) falseValues.add(i);
inner = SWCommandUtils.createMapper(s -> {
int index = tabCompletes.indexOf(s);
return index == -1 ? null : !falseValues.contains(index);
}, (commandSender, s) -> tabCompletes);
} else if (clazz == int.class || clazz == Integer.class || clazz == long.class || clazz == Long.class) {
List<String> tabCompletes = new ArrayList<>(Arrays.asList(staticValue.value()));
inner = SWCommandUtils.createMapper(s -> {
Number index = tabCompletes.indexOf(s);
return index.longValue() == -1 ? null : index;
}, (commandSender, s) -> tabCompletes);
} else {
throw new IllegalArgumentException("The parameter type '" + clazz.getTypeName() + "' is not supported by the StaticValue annotation");
}
}
@Override
public Object map(T sender, PreviousArguments previousArguments, String s) {
return inner.map(sender, previousArguments, s);
}
@Override
public Collection<String> tabCompletes(T sender, PreviousArguments previousArguments, String s) {
return inner.tabCompletes(sender, previousArguments, s);
}
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
protected @interface OptionalValue {
/**
* Will pe parsed against the TypeMapper specified by the parameter or annotation.
*/
String value();
/**
* The method name stands for 'onlyUseIfNoneIsGiven'.
*/
boolean onlyUINIG() default false;
}
// --- Implicit Validator ---
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@CommandMetaData.ImplicitValidator(handler = ErrorMessage.Handler.class, order = Integer.MAX_VALUE)
protected @interface ErrorMessage {
/**
* Error message to be displayed when the parameter is invalid.
*/
String value();
/**
* This is the short form for 'allowEmptyArrays'.
*/
boolean allowEAs() default true;
class Handler<T> implements AbstractValidator<T, Object> {
private AbstractSWCommand.ErrorMessage errorMessage;
public Handler(AbstractSWCommand.ErrorMessage errorMessage) {
this.errorMessage = errorMessage;
}
@Override
public boolean validate(T sender, Object value, MessageSender messageSender) {
if (value == null) messageSender.send(errorMessage.value());
if (!errorMessage.allowEAs() && value != null && value.getClass().isArray() && Array.getLength(value) == 0) {
messageSender.send(errorMessage.value());
return false;
}
return value != null;
}
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
protected @interface AllowNull {
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@CommandMetaData.Parameter({int.class, Integer.class, long.class, Long.class, float.class, Float.class, double.class, Double.class})
@CommandMetaData.ImplicitValidator(handler = Min.Handler.class, order = 2)
protected @interface Min {
int intValue() default Integer.MIN_VALUE;
long longValue() default Long.MIN_VALUE;
float floatValue() default Float.MIN_VALUE;
double doubleValue() default Double.MIN_VALUE;
boolean inclusive() default true;
class Handler<T> implements AbstractValidator<T, Number> {
private int value;
private Function<Number, Number> comparator;
public Handler(AbstractSWCommand.Min min, Class<?> clazz) {
this.value = min.inclusive() ? 0 : 1;
this.comparator = createComparator("Min", clazz, min.intValue(), min.longValue(), min.floatValue(), min.doubleValue());
}
@Override
public boolean validate(T sender, Number value, MessageSender messageSender) {
if (value == null) return true;
return (comparator.apply(value).intValue()) >= this.value;
}
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@CommandMetaData.Parameter({int.class, Integer.class, long.class, Long.class, float.class, Float.class, double.class, Double.class})
@CommandMetaData.ImplicitValidator(handler = Max.Handler.class, order = 2)
protected @interface Max {
int intValue() default Integer.MAX_VALUE;
long longValue() default Long.MAX_VALUE;
float floatValue() default Float.MAX_VALUE;
double doubleValue() default Double.MAX_VALUE;
boolean inclusive() default true;
class Handler<T> implements AbstractValidator<T, Number> {
private int value;
private Function<Number, Number> comparator;
public Handler(AbstractSWCommand.Max max, Class<?> clazz) {
this.value = max.inclusive() ? 0 : -1;
this.comparator = createComparator("Max", clazz, max.intValue(), max.longValue(), max.floatValue(), max.doubleValue());
}
@Override
public boolean validate(T sender, Number value, MessageSender messageSender) {
if (value == null) return true;
return (comparator.apply(value).intValue()) <= this.value;
}
}
}
private static Function<Number, Number> createComparator(String type, Class<?> clazz, int iValue, long lValue, float fValue, double dValue) {
if (clazz == int.class || clazz == Integer.class) {
return number -> Integer.compare(number.intValue(), iValue);
} else if (clazz == long.class || clazz == Long.class) {
return number -> Long.compare(number.longValue(), lValue);
} else if (clazz == float.class || clazz == Float.class) {
return number -> Float.compare(number.floatValue(), fValue);
} else if (clazz == double.class || clazz == Double.class) {
return number -> Double.compare(number.doubleValue(), dValue);
} else {
throw new IllegalArgumentException(type + " annotation is not supported for " + clazz);
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@CommandMetaData.ImplicitTypeMapper(handler = Length.Handler.class)
protected @interface Length {
int min() default 0;
int max() default Integer.MAX_VALUE;
class Handler<T> implements AbstractTypeMapper<T, Object> {
private int min;
private int max;
private AbstractTypeMapper<T, Object> inner;
public Handler(Length length, AbstractTypeMapper<T, Object> inner) {
this.min = length.min();
this.max = length.max();
this.inner = inner;
}
@Override
public Object map(T sender, PreviousArguments previousArguments, String s) {
if (s.length() < min || s.length() > max) return null;
return inner.map(sender, previousArguments, s);
}
@Override
public Collection<String> tabCompletes(T sender, PreviousArguments previousArguments, String s) {
List<String> tabCompletes = inner.tabCompletes(sender, previousArguments, s)
.stream()
.filter(str -> str.length() >= min)
.map(str -> str.substring(0, Math.min(str.length(), max)))
.collect(Collectors.toList());
if (s.length() < min) {
tabCompletes.add(0, s);
}
return tabCompletes;
}
@Override
public String normalize(T sender, String s) {
return inner.normalize(sender, s);
}
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@CommandMetaData.Parameter(handler = ArrayLength.Type.class)
@CommandMetaData.ImplicitTypeMapper(handler = ArrayLength.HandlerTypeMapper.class)
@CommandMetaData.ImplicitValidator(handler = ArrayLength.HandlerValidator.class, order = 1)
protected @interface ArrayLength {
int min() default 0;
int max() default Integer.MAX_VALUE;
class Type implements BiPredicate<Class<?>, Boolean> {
@Override
public boolean test(Class<?> clazz, Boolean isVarArgs) {
return clazz.isArray();
}
}
class HandlerTypeMapper<T> implements AbstractTypeMapper<T, Object> {
private int max;
private AbstractTypeMapper<T, Object> inner;
public HandlerTypeMapper(ArrayLength arrayLength, AbstractTypeMapper<T, Object> inner) {
this.max = arrayLength.max();
this.inner = inner;
}
@Override
public Object map(T sender, PreviousArguments previousArguments, String s) {
return inner.map(sender, previousArguments, s);
}
@Override
public Collection<String> tabCompletes(T sender, PreviousArguments previousArguments, String s) {
Object[] mapped = previousArguments.getMappedArg(0);
if (mapped.length >= max) return Collections.emptyList();
return inner.tabCompletes(sender, previousArguments, s);
}
@Override
public String normalize(T sender, String s) {
return inner.normalize(sender, s);
}
}
class HandlerValidator<T> implements AbstractValidator<T, Object> {
private int min;
private int max;
public HandlerValidator(ArrayLength arrayLength) {
this.min = arrayLength.min();
this.max = arrayLength.max();
}
@Override
public boolean validate(T sender, Object value, MessageSender messageSender) {
if (value == null) return true;
int length = Array.getLength(value);
return length >= min && length <= max;
}
}
}
}

Datei anzeigen

@ -1,62 +0,0 @@
/*
* 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 java.util.Collection;
public interface AbstractTypeMapper<K, T> extends AbstractValidator<K, T> {
/**
* The CommandSender can be null!
*/
@Deprecated
default T map(K sender, String[] previousArguments, String s) {
throw new IllegalArgumentException("This method is deprecated and should not be used anymore!");
}
/**
* The CommandSender can be null!
*/
default T map(K sender, PreviousArguments previousArguments, String s) {
return map(sender, previousArguments.userArgs, s);
}
@Override
default boolean validate(K sender, T value, MessageSender messageSender) {
return true;
}
@Deprecated
default Collection<String> tabCompletes(K sender, String[] previousArguments, String s) {
throw new IllegalArgumentException("This method is deprecated and should not be used anymore!");
}
default Collection<String> tabCompletes(K sender, PreviousArguments previousArguments, String s) {
return tabCompletes(sender, previousArguments.userArgs, s);
}
/**
* Normalize the cache key by sender and user provided argument. <br>
* Note: The CommandSender can be null! <br>
* Returning null and the empty string are equivalent.
*/
default String normalize(K sender, String s) {
return null;
}
}

Datei anzeigen

@ -1,96 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 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.RequiredArgsConstructor;
import java.util.function.BooleanSupplier;
import java.util.function.Function;
import java.util.function.Predicate;
@FunctionalInterface
public interface AbstractValidator<K, T> {
/**
* Validates the given value.
*
* @param sender The sender of the command.
* @param value The value to validate or null if mapping returned null.
* @param messageSender The message sender to send messages to the player. Never send messages directly to the player.
* @return The result of the validation.
*/
boolean validate(K sender, T value, MessageSender messageSender);
@Deprecated
default <C> Validator<C> validate(C value, MessageSender messageSender) {
return new Validator<>(value, messageSender);
}
@Deprecated
@RequiredArgsConstructor
class Validator<C> {
private final C value;
private final MessageSender messageSender;
private boolean valid = true;
public <M> Validator<M> map(Function<C, M> mapper) {
return new Validator<>(mapper.apply(value), messageSender).set(valid);
}
public Validator<C> set(boolean value) {
this.valid = value;
return this;
}
public Validator<C> and(Predicate<C> predicate) {
valid &= predicate.test(value);
return this;
}
public Validator<C> or(Predicate<C> predicate) {
valid |= predicate.test(value);
return this;
}
public Validator<C> errorMessage(String s, Object... args) {
if (!valid) messageSender.send(s, args);
return this;
}
public boolean result() {
return valid;
}
}
@FunctionalInterface
interface MessageSender {
void send(String s, Object... args);
default boolean send(boolean condition, String s, Object... args) {
if (condition) send(s, args);
return condition;
}
default boolean send(BooleanSupplier condition, String s, Object... args) {
return send(condition.getAsBoolean(), s, args);
}
}
}

Datei anzeigen

@ -1,110 +0,0 @@
/*
* 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 java.io.PrintStream;
import java.io.PrintWriter;
import java.lang.reflect.Executable;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.function.Function;
import java.util.stream.Stream;
public class CommandFrameworkException extends RuntimeException {
private Function causeMessage;
private Throwable cause;
private Function stackTraceExtractor;
private String extraStackTraces;
private String message;
static CommandFrameworkException commandPartExceptions(String type, Throwable cause, String current, Class<?> clazzType, Executable executable, int index) {
return new CommandFrameworkException(e -> {
return CommandFrameworkException.class.getTypeName() + ": Error while " + type + " (" + current + ") to type " + clazzType.getTypeName() + " with parameter index " + index;
}, cause, exception -> {
StackTraceElement[] stackTraceElements = exception.getStackTrace();
int last = 0;
for (int i = 0; i < stackTraceElements.length; i++) {
if (stackTraceElements[i].getClassName().equals(CommandPart.class.getTypeName())) {
last = i;
break;
}
}
return Arrays.stream(stackTraceElements).limit(last - 1);
}, executable.getDeclaringClass().getTypeName() + "." + executable.getName() + "(Unknown Source)");
}
CommandFrameworkException(InvocationTargetException invocationTargetException, String alias, String[] args) {
this(e -> {
StringBuilder st = new StringBuilder();
st.append(e.getCause().getClass().getTypeName());
if (e.getCause().getMessage() != null) {
st.append(": ").append(e.getCause().getMessage());
}
if (alias != null && !alias.isEmpty()) {
st.append("\n").append("Performed command: " + alias + " " + String.join(" ", args));
}
return st.toString();
}, invocationTargetException, e -> {
StackTraceElement[] stackTraceElements = e.getCause().getStackTrace();
return Arrays.stream(stackTraceElements).limit(stackTraceElements.length - e.getStackTrace().length);
}, null);
}
private <T extends Throwable> CommandFrameworkException(Function<T, String> causeMessage, T cause, Function<T, Stream<StackTraceElement>> stackTraceExtractor, String extraStackTraces) {
super(causeMessage.apply(cause), cause);
this.causeMessage = causeMessage;
this.cause = cause;
this.stackTraceExtractor = stackTraceExtractor;
this.extraStackTraces = extraStackTraces;
}
public synchronized String getBuildStackTrace() {
if (message != null) {
return message;
}
StringBuilder st = new StringBuilder();
st.append(causeMessage.apply(cause)).append("\n");
((Stream<StackTraceElement>) stackTraceExtractor.apply(cause)).forEach(stackTraceElement -> {
st.append("\tat ").append(stackTraceElement.toString()).append("\n");
});
if (extraStackTraces != null) {
st.append("\tat ").append(extraStackTraces).append("\n");
}
message = st.toString();
return message;
}
@Override
public void printStackTrace() {
printStackTrace(System.err);
}
@Override
public void printStackTrace(PrintStream s) {
s.print(getBuildStackTrace());
}
@Override
public void printStackTrace(PrintWriter s) {
s.print(getBuildStackTrace());
}
}

Datei anzeigen

@ -1,92 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 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 java.lang.annotation.*;
public @interface CommandMetaData {
/**
* This annotation is only for internal use.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
@interface Method {
Class<?>[] value();
int minParameterCount() default 0;
int maxParameterCount() default Integer.MAX_VALUE;
}
/**
* This annotation denotes what types are allowed as parameter types the annotation annotated with can use.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
@interface Parameter {
Class<?>[] value() default {};
Class<?> handler() default void.class;
}
/**
* This annotation can be used in conjunction with a class that implements {@link AbstractTypeMapper} to
* create a custom type mapper for a parameter. The class must have one of two constructors with the following
* types:
* <ul>
* <li>Annotation this annotation annotates</li>
* <li>{@link Class}</li>
* <li>{@link AbstractTypeMapper}, optional, if not present only one per parameter</li>
* <li>{@link java.util.Map} with types {@link String} and {@link AbstractValidator}</li>
* </ul>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
@interface ImplicitTypeMapper {
/**
* The validator class that should be used.
*/
Class<?> handler();
}
/**
* This annotation can be used in conjunction with a class that implements {@link AbstractValidator} to
* create a custom validator short hands for commands. The validator class must have one constructor with
* one of the following types:
* <ul>
* <li>Annotation this annotation annotates</li>
* <li>{@link Class}</li>
* <li>{@link java.util.Map} with types {@link String} and {@link AbstractValidator}</li>
* </ul>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
@interface ImplicitValidator {
/**
* The validator class that should be used.
*/
Class<?> handler();
/**
* Defines when this validator should be processed. Negative numbers denote that this will be
* processed before {@link AbstractSWCommand.Validator} and positive numbers
* denote that this will be processed after {@link AbstractSWCommand.Validator}.
*/
int order();
}
}

Datei anzeigen

@ -1,26 +0,0 @@
/*
* 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 CommandParseException extends RuntimeException {
public CommandParseException() {
}
}

Datei anzeigen

@ -1,226 +0,0 @@
/*
* 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 java.lang.reflect.Array;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
class CommandPart<T> {
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
@AllArgsConstructor
private static class CheckArgumentResult {
private final boolean success;
private final Object value;
}
private AbstractSWCommand<T> command;
private AbstractTypeMapper<T, ?> typeMapper;
private List<AbstractValidator<T, Object>> validators = new ArrayList<>();
private Class<?> varArgType;
private String optional;
private CommandPart<T> next = null;
@Setter
private boolean ignoreAsArgument = false;
@Setter
private boolean onlyUseIfNoneIsGiven = false;
private Parameter parameter;
private int parameterIndex;
public CommandPart(AbstractSWCommand<T> command, AbstractTypeMapper<T, ?> typeMapper, Class<?> varArgType, String optional, Parameter parameter, int parameterIndex) {
this.command = command;
this.typeMapper = typeMapper;
this.varArgType = varArgType;
this.optional = optional;
this.parameter = parameter;
this.parameterIndex = parameterIndex;
if (optional != null && varArgType != null) {
throw new IllegalArgumentException("A vararg part can't have an optional part! In method " + parameter.getDeclaringExecutable() + " with parameter " + parameterIndex);
}
}
void addValidator(AbstractValidator<T, Object> validator) {
if (validator == null) return;
validators.add(validator);
}
public void setNext(CommandPart<T> next) {
if (varArgType != null) {
throw new IllegalArgumentException("There can't be a next part if this is a vararg part! In method " + parameter.getDeclaringExecutable() + " with parameter " + parameterIndex);
}
this.next = next;
}
public boolean isHelp() {
if (next == null) {
if (varArgType == null) {
return false;
}
if (varArgType != String.class) {
return false;
}
return typeMapper == SWCommandUtils.STRING_MAPPER;
} else {
return next.isHelp();
}
}
public void generateArgumentArray(Consumer<Runnable> errors, List<Object> current, T sender, String[] args, int startIndex) {
if (varArgType != null) {
Object array = Array.newInstance(varArgType, args.length - startIndex);
for (int i = startIndex; i < args.length; i++) {
CheckArgumentResult validArgument = checkArgument(null, sender, args, current, i);
if (!validArgument.success) throw new CommandParseException();
Array.set(array, i - startIndex, validArgument.value);
}
for (AbstractValidator<T, Object> validator : validators) {
if (!validator.validate(sender, array, (s, objects) -> {
errors.accept(() -> command.sendMessage(sender, s, objects));
})) throw new CommandParseException();
}
current.add(array);
return;
}
CheckArgumentResult validArgument = checkArgument(errors, sender, args, current, startIndex);
if (!validArgument.success && optional == null) {
throw new CommandParseException();
}
if (!validArgument.success) {
if (!ignoreAsArgument) {
if (!onlyUseIfNoneIsGiven) {
current.add(typeMapper.map(sender, new PreviousArguments(EMPTY_STRING_ARRAY, EMPTY_OBJECT_ARRAY), optional));
} else if (startIndex >= args.length) {
current.add(typeMapper.map(sender, new PreviousArguments(EMPTY_STRING_ARRAY, EMPTY_OBJECT_ARRAY), optional));
} else {
throw new CommandParseException();
}
}
if (next != null) {
next.generateArgumentArray(errors, current, sender, args, startIndex);
}
return;
}
if (!ignoreAsArgument) {
current.add(validArgument.value);
}
if (next != null) {
next.generateArgumentArray(errors, current, sender, args, startIndex + 1);
} else if (startIndex + 1 < args.length) {
throw new CommandParseException();
}
}
public void generateTabComplete(List<String> current, T sender, String[] args, List<Object> mappedArgs, int startIndex) {
if (varArgType != null) {
List<Object> currentArgs = new ArrayList<>(mappedArgs);
List<Object> varArgs = new ArrayList<>();
for (int i = startIndex; i < args.length - 1; i++) {
CheckArgumentResult validArgument = checkArgument((ignore) -> {}, sender, args, mappedArgs, i);
if (!validArgument.success) return;
varArgs.add(validArgument.value);
}
currentArgs.add(varArgs.toArray());
Collection<String> strings = tabCompletes(sender, args, currentArgs, args.length - 1);
if (strings != null) {
current.addAll(strings);
}
return;
}
if (args.length - 1 > startIndex) {
CheckArgumentResult checkArgumentResult = checkArgument((ignore) -> {}, sender, args, mappedArgs, startIndex);
if (checkArgumentResult.success && next != null) {
if (!ignoreAsArgument) {
mappedArgs.add(checkArgumentResult.value);
}
next.generateTabComplete(current, sender, args, mappedArgs, startIndex + 1);
return;
}
if (optional != null && next != null) {
next.generateTabComplete(current, sender, args, mappedArgs, startIndex);
}
return;
}
Collection<String> strings = tabCompletes(sender, args, mappedArgs, startIndex);
if (strings != null) {
current.addAll(strings);
}
if (optional != null && next != null) {
next.generateTabComplete(current, sender, args, mappedArgs, startIndex);
}
}
private Collection<String> tabCompletes(T sender, String[] args, List<Object> mappedArgs, int startIndex) {
return TabCompletionCache.tabComplete(sender, args[startIndex], (AbstractTypeMapper<Object, ?>) typeMapper, () -> {
try {
return typeMapper.tabCompletes(sender, new PreviousArguments(Arrays.copyOf(args, startIndex), mappedArgs.toArray()), args[startIndex]);
} catch (Throwable e) {
throw CommandFrameworkException.commandPartExceptions("tabcompleting", e, args[startIndex], (varArgType != null ? varArgType : parameter.getType()), parameter.getDeclaringExecutable(), parameterIndex);
}
});
}
private CheckArgumentResult checkArgument(Consumer<Runnable> errors, T sender, String[] args, List<Object> mappedArgs, int index) {
Object value;
try {
value = typeMapper.map(sender, new PreviousArguments(Arrays.copyOf(args, index), mappedArgs.toArray()), args[index]);
} catch (Exception e) {
return new CheckArgumentResult(false, null);
}
boolean success = true;
for (AbstractValidator<T, Object> validator : validators) {
try {
if (!validator.validate(sender, value, (s, objects) -> {
errors.accept(() -> {
command.sendMessage(sender, s, objects);
});
})) {
success = false;
value = null;
}
} catch (Throwable e) {
throw CommandFrameworkException.commandPartExceptions("validating", e, args[index], (varArgType != null ? varArgType : parameter.getType()), parameter.getDeclaringExecutable(), parameterIndex);
}
}
return new CheckArgumentResult(success, value);
}
public Class<?> getType() {
return varArgType != null ? varArgType : parameter.getType();
}
}

Datei anzeigen

@ -1,62 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 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 java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class PreviousArguments {
public final String[] userArgs;
public final Object[] mappedArgs;
public PreviousArguments(String[] userArgs, Object[] mappedArgs) {
this.userArgs = userArgs;
this.mappedArgs = mappedArgs;
}
public String getUserArg(int index) {
return userArgs[userArgs.length - index - 1];
}
public <T> T getMappedArg(int index) {
return (T) mappedArgs[mappedArgs.length - index - 1];
}
public <T> Optional<T> getFirst(Class<T> clazz) {
for (Object o : mappedArgs) {
if (clazz.isInstance(o)) {
return Optional.of((T) o);
}
}
return Optional.empty();
}
public <T> List<T> getAll(Class<T> clazz) {
List<T> list = new ArrayList<>();
for (Object o : mappedArgs) {
if (clazz.isInstance(o)) {
list.add((T) o);
}
}
return list;
}
}

Datei anzeigen

@ -1,185 +0,0 @@
/*
* 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.Getter;
import lombok.experimental.UtilityClass;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
@UtilityClass
public class SWCommandUtils {
@Getter
private final Map<String, AbstractTypeMapper<?, ?>> MAPPER_FUNCTIONS = new HashMap<>();
@Getter
private final Map<String, AbstractValidator<?, ?>> VALIDATOR_FUNCTIONS = new HashMap<>();
private SWTypeMapperCreator swTypeMapperCreator = (mapper, tabCompleter) -> new AbstractTypeMapper<Object, Object>() {
@Override
public Object map(Object sender, PreviousArguments previousArguments, String s) {
return mapper.apply(s);
}
@Override
public Collection<String> tabCompletes(Object sender, PreviousArguments previousArguments, String s) {
return ((BiFunction<Object, Object, Collection<String>>) tabCompleter).apply(sender, s);
}
};
static final AbstractTypeMapper<Object, String> STRING_MAPPER = createMapper(s -> s, Collections::singletonList);
static {
addMapper(boolean.class, Boolean.class, createMapper(s -> {
if (s.equalsIgnoreCase("true")) return true;
if (s.equalsIgnoreCase("false")) return false;
return null;
}, s -> Arrays.asList("true", "false")));
addMapper(float.class, Float.class, createMapper(numberMapper(Float::parseFloat), numberCompleter(Float::parseFloat, true)));
addMapper(double.class, Double.class, createMapper(numberMapper(Double::parseDouble), numberCompleter(Double::parseDouble, true)));
addMapper(int.class, Integer.class, createMapper(numberMapper(Integer::parseInt), numberCompleter(Integer::parseInt, false)));
addMapper(long.class, Long.class, createMapper(numberMapper(Long::parseLong), numberCompleter(Long::parseLong, false)));
MAPPER_FUNCTIONS.put(String.class.getTypeName(), STRING_MAPPER);
}
public static <T extends AbstractTypeMapper<K, V>, K, V> void init(SWTypeMapperCreator<T, K, V> swTypeMapperCreator) {
SWCommandUtils.swTypeMapperCreator = swTypeMapperCreator;
}
private static void addMapper(Class<?> clazz, Class<?> alternativeClazz, AbstractTypeMapper<?, ?> mapper) {
MAPPER_FUNCTIONS.put(clazz.getTypeName(), mapper);
MAPPER_FUNCTIONS.put(alternativeClazz.getTypeName(), mapper);
}
public static <T> AbstractTypeMapper<T, ?> getTypeMapper(String name, Map<String, AbstractTypeMapper<T, ?>> localTypeMapper) {
AbstractTypeMapper<T, ?> typeMapper = localTypeMapper.getOrDefault(name, (AbstractTypeMapper<T, ?>) MAPPER_FUNCTIONS.getOrDefault(name, null));
if (typeMapper == null) {
throw new IllegalArgumentException("No mapper found for " + name);
}
return typeMapper;
}
public static <T> AbstractTypeMapper<T, ?> getTypeMapper(Parameter parameter, Map<String, AbstractTypeMapper<T, ?>> localTypeMapper) {
Class<?> clazz = parameter.getType();
if (parameter.isVarArgs()) {
clazz = clazz.getComponentType();
}
if (clazz.isEnum() && !MAPPER_FUNCTIONS.containsKey(clazz.getTypeName()) && !localTypeMapper.containsKey(clazz.getTypeName())) {
return createEnumMapper((Class<Enum<?>>) clazz);
}
return getTypeMapper(clazz.getTypeName(), localTypeMapper);
}
public static <T> AbstractValidator<T, ?> getValidator(AbstractSWCommand.Validator validator, Class<?> type, Map<String, AbstractValidator<T, ?>> localValidator) {
String s = validator.value() != null && !validator.value().isEmpty() ? validator.value() : type.getTypeName();
AbstractValidator<T, ?> concreteValidator = localValidator.getOrDefault(s, (AbstractValidator<T, ?>) VALIDATOR_FUNCTIONS.getOrDefault(s, null));
if (concreteValidator == null) {
throw new IllegalArgumentException("No validator found for " + s);
}
return concreteValidator;
}
public static <K, T> void addMapper(Class<T> clazz, AbstractTypeMapper<K, T> mapper) {
addMapper(clazz.getTypeName(), mapper);
}
public static <T> void addMapper(String name, AbstractTypeMapper<T, ?> mapper) {
MAPPER_FUNCTIONS.putIfAbsent(name, mapper);
}
public static <T> void addValidator(Class<T> clazz, AbstractValidator<T, ?> validator) {
addValidator(clazz.getTypeName(), validator);
}
public static <T> void addValidator(String name, AbstractValidator<T, ?> validator) {
VALIDATOR_FUNCTIONS.putIfAbsent(name, validator);
}
public static <T extends AbstractTypeMapper<K, String>, K> T createMapper(String... values) {
List<String> strings = Arrays.stream(values).map(String::toLowerCase).collect(Collectors.toList());
List<String> tabCompletes = Arrays.asList(values);
return createMapper(s -> strings.contains(s.toLowerCase()) ? s : null, s -> tabCompletes);
}
public static <T extends AbstractTypeMapper<K, V>, K, V> T createMapper(Function<String, V> mapper, Function<String, Collection<String>> tabCompleter) {
return createMapper(mapper, (commandSender, s) -> tabCompleter.apply(s));
}
public static <T extends AbstractTypeMapper<K, V>, K, V> T createMapper(Function<String, V> mapper, BiFunction<K, String, Collection<String>> tabCompleter) {
return (T) swTypeMapperCreator.createTypeMapper(mapper, tabCompleter);
}
public static <T extends AbstractTypeMapper<K, Enum<?>>, K> T createEnumMapper(Class<Enum<?>> enumClass) {
Map<String, Enum<?>> enumMap = new HashMap<>();
for (Enum<?> e : enumClass.getEnumConstants()) {
enumMap.put(e.name().toLowerCase(), e);
}
return createMapper(s -> enumMap.get(s.toLowerCase()), (k, s) -> enumMap.keySet());
}
private static <T> Function<String, T> numberMapper(Function<String, T> mapper) {
return s -> {
if (s.equalsIgnoreCase("nan")) return null;
try {
return mapper.apply(s);
} catch (NumberFormatException e) {
// Ignored
}
try {
return mapper.apply(s.replace(',', '.'));
} catch (NumberFormatException e) {
return null;
}
};
}
private static Function<String, Collection<String>> numberCompleter(Function<String, ?> mapper, boolean comma) {
return s -> {
if (numberMapper(mapper).apply(s) == null) {
return Collections.emptyList();
}
List<String> strings = new ArrayList<>();
if (s.length() == 0) {
strings.add("-");
} else {
strings.add(s);
}
for (int i = 0; i < 10; i++) {
strings.add(s + i);
}
if (comma && (!s.contains(".") || !s.contains(","))) {
strings.add(s + ".");
}
return strings;
};
}
static <T extends Annotation> T[] getAnnotation(Method method, Class<T> annotation) {
if (method.getAnnotations().length == 0) return null;
return method.getDeclaredAnnotationsByType(annotation);
}
}

Datei anzeigen

@ -1,28 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 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 java.util.Collection;
import java.util.function.BiFunction;
import java.util.function.Function;
public interface SWTypeMapperCreator<T extends AbstractTypeMapper<K, V>, K, V> {
T createTypeMapper(Function<String, V> mapper, BiFunction<K, String, Collection<String>> tabCompleter);
}

Datei anzeigen

@ -1,292 +0,0 @@
/*
* 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 java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
public class SubCommand<T> implements Comparable<SubCommand<T>> {
private AbstractSWCommand<T> abstractSWCommand;
Method method;
String[] description;
String[] subCommand;
private Predicate<T> senderPredicate;
private Function<T, ?> senderFunction;
AbstractValidator<T, T> validator;
boolean noTabComplete;
private Parameter[] parameters;
private CommandPart<T> commandPart;
boolean isHelp = false;
SubCommand(AbstractSWCommand<T> abstractSWCommand, Method method, String[] subCommand, Map<String, AbstractTypeMapper<T, ?>> localTypeMapper, Map<String, AbstractValidator<T, ?>> localValidator, String[] description, boolean noTabComplete) {
this.abstractSWCommand = abstractSWCommand;
this.method = method;
try {
this.method.setAccessible(true);
} catch (SecurityException e) {
throw new SecurityException(e.getMessage(), e);
}
this.subCommand = subCommand;
this.description = description;
this.noTabComplete = noTabComplete;
parameters = method.getParameters();
AbstractSWCommand.Validator validator = parameters[0].getAnnotation(AbstractSWCommand.Validator.class);
if (validator != null) {
this.validator = (AbstractValidator<T, T>) SWCommandUtils.getValidator(validator, parameters[0].getType(), localValidator);
if (validator.invert()) {
AbstractValidator<T, T> current = this.validator;
this.validator = (sender, value, messageSender) -> !current.validate(sender, value, messageSender);
}
}
commandPart = generateCommandPart(abstractSWCommand, subCommand, parameters, localTypeMapper, localValidator);
if (commandPart != null) isHelp = commandPart.isHelp();
senderPredicate = t -> parameters[0].getType().isAssignableFrom(t.getClass());
senderFunction = t -> parameters[0].getType().cast(t);
}
@Override
public int compareTo(SubCommand<T> o) {
int tLength = parameters.length + subCommand.length;
int oLength = o.parameters.length + o.subCommand.length;
boolean tVarArgs = parameters[parameters.length - 1].isVarArgs();
boolean oVarArgs = o.parameters[o.parameters.length - 1].isVarArgs();
if (tVarArgs) tLength *= -1;
if (oVarArgs) oLength *= -1;
if (tVarArgs && oVarArgs) return Integer.compare(tLength, oLength);
return -Integer.compare(tLength, oLength);
}
boolean invoke(Consumer<Runnable> errors, T sender, String alias, String[] args) {
try {
if (!senderPredicate.test(sender)) {
return false;
}
if (commandPart == null) {
if (args.length != 0) {
return false;
}
if (validator != null) {
if (!validator.validate(sender, sender, (s, objectArgs) -> {
abstractSWCommand.sendMessage(sender, s, objectArgs);
})) {
return false;
}
}
method.invoke(abstractSWCommand, senderFunction.apply(sender));
} else {
List<Object> objects = new ArrayList<>();
commandPart.generateArgumentArray(errors, objects, sender, args, 0);
if (validator != null) {
if (!validator.validate(sender, sender, (s, objectArgs) -> {
abstractSWCommand.sendMessage(sender, s, objectArgs);
})) {
return false;
}
}
objects.add(0, senderFunction.apply(sender));
method.invoke(abstractSWCommand, objects.toArray());
}
} catch (CommandFrameworkException e) {
throw e;
} catch (CommandParseException e) {
return false;
} catch (InvocationTargetException e) {
throw new CommandFrameworkException(e, alias, args);
} catch (IllegalAccessException | RuntimeException e) {
throw new SecurityException(e.getMessage(), e);
}
return true;
}
List<String> tabComplete(T sender, String[] args) {
if (validator != null && !validator.validate(sender, sender, (s, objects) -> {})) {
return null;
}
if (commandPart == null) {
return null;
}
List<String> list = new ArrayList<>();
commandPart.generateTabComplete(list, sender, args, new ArrayList<>(), 0);
return list;
}
private static <T> CommandPart<T> generateCommandPart(AbstractSWCommand<T> command, String[] subCommand, Parameter[] parameters, Map<String, AbstractTypeMapper<T, ?>> localTypeMapper, Map<String, AbstractValidator<T, ?>> localValidator) {
CommandPart<T> first = null;
CommandPart<T> current = null;
for (String s : subCommand) {
CommandPart commandPart = new CommandPart(command, SWCommandUtils.createMapper(s), null, null, null, -1);
commandPart.addValidator(NULL_FILTER);
commandPart.setIgnoreAsArgument(true);
if (current != null) {
current.setNext(commandPart);
}
current = commandPart;
if (first == null) {
first = current;
}
}
for (int i = 1; i < parameters.length; i++) {
Parameter parameter = parameters[i];
AbstractTypeMapper<T, ?> typeMapper = handleImplicitTypeMapper(parameter, localTypeMapper);
Class<?> varArgType = parameter.isVarArgs() ? parameter.getType().getComponentType() : null;
AbstractSWCommand.OptionalValue optionalValue = parameter.getAnnotation(AbstractSWCommand.OptionalValue.class);
CommandPart<T> commandPart = new CommandPart<>(command, typeMapper, varArgType, optionalValue != null ? optionalValue.value() : null, parameter, i);
commandPart.setOnlyUseIfNoneIsGiven(optionalValue != null && optionalValue.onlyUINIG());
handleImplicitTypeValidator(parameter, commandPart, localValidator);
if (parameter.getAnnotation(AbstractSWCommand.AllowNull.class) == null) {
commandPart.addValidator((AbstractValidator<T, Object>) NULL_FILTER);
}
if (current != null) {
current.setNext(commandPart);
}
current = commandPart;
if (first == null) {
first = current;
}
}
return first;
}
private static <T> AbstractTypeMapper<T, Object> handleImplicitTypeMapper(Parameter parameter, Map<String, AbstractTypeMapper<T, ?>> localTypeMapper) {
Class<?> type = parameter.getType();
if (parameter.isVarArgs()) {
type = type.getComponentType();
}
Annotation[] annotations = parameter.getAnnotations();
Constructor<?> sourceConstructor = null;
Annotation sourceAnnotation = null;
List<Constructor<?>> parentConstructors = new ArrayList<>();
List<Annotation> parentAnnotations = new ArrayList<>();
for (Annotation annotation : annotations) {
CommandMetaData.ImplicitTypeMapper implicitTypeMapper = annotation.annotationType().getAnnotation(CommandMetaData.ImplicitTypeMapper.class);
if (implicitTypeMapper == null) continue;
Class<?> clazz = implicitTypeMapper.handler();
if (!AbstractTypeMapper.class.isAssignableFrom(clazz)) continue;
Constructor<?>[] constructors = clazz.getConstructors();
if (constructors.length != 1) continue;
Constructor<?> constructor = constructors[0];
if (needsTypeMapper(constructor)) {
parentConstructors.add(constructor);
parentAnnotations.add(annotation);
} else {
if (sourceAnnotation != null) {
throw new IllegalArgumentException("Multiple source type mappers found for parameter " + parameter);
}
sourceConstructor = constructor;
sourceAnnotation = annotation;
}
}
AbstractTypeMapper<T, Object> current;
if (sourceAnnotation != null) {
current = createInstance(sourceConstructor, sourceAnnotation, type, localTypeMapper);
} else {
current = (AbstractTypeMapper<T, Object>) SWCommandUtils.getTypeMapper(parameter, localTypeMapper);
}
for (int i = 0; i < parentConstructors.size(); i++) {
Constructor<?> constructor = parentConstructors.get(i);
Annotation annotation = parentAnnotations.get(i);
current = createInstance(constructor, annotation, type, localTypeMapper, current);
}
return current;
}
private static boolean needsTypeMapper(Constructor<?> constructor) {
Class<?>[] parameterTypes = constructor.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
if (AbstractTypeMapper.class.isAssignableFrom(parameterType)) {
return true;
}
}
return false;
}
private static <T> void handleImplicitTypeValidator(Parameter parameter, CommandPart<T> commandPart, Map<String, AbstractValidator<T, ?>> localValidator) {
Annotation[] annotations = parameter.getAnnotations();
Map<Integer, List<AbstractValidator<T, Object>>> validators = new HashMap<>();
for (Annotation annotation : annotations) {
CommandMetaData.ImplicitValidator implicitValidator = annotation.annotationType().getAnnotation(CommandMetaData.ImplicitValidator.class);
if (implicitValidator == null) continue;
Class<?> clazz = implicitValidator.handler();
if (!AbstractValidator.class.isAssignableFrom(clazz)) continue;
Constructor<?>[] constructors = clazz.getConstructors();
if (constructors.length != 1) continue;
AbstractValidator<T, Object> validator = createInstance(constructors[0], annotation, commandPart.getType(), localValidator);
validators.computeIfAbsent(implicitValidator.order(), integer -> new ArrayList<>()).add(validator);
}
List<Integer> keys = new ArrayList<>(validators.keySet());
keys.sort(Integer::compareTo);
for (Integer key : keys) {
List<AbstractValidator<T, Object>> list = validators.get(key);
for (AbstractValidator<T, Object> validator : list) {
commandPart.addValidator(validator);
}
}
}
private static <T> T createInstance(Constructor<?> constructor, Object... parameter) {
Class<?>[] types = constructor.getParameterTypes();
List<Object> objects = new ArrayList<>();
for (Class<?> clazz : types) {
boolean found = false;
for (Object o : parameter) {
if (clazz.isAssignableFrom(o.getClass())) {
objects.add(o);
found = true;
break;
}
}
if (!found) {
throw new RuntimeException("Could not find type " + clazz + " for constructor " + constructor);
}
}
try {
return (T) constructor.newInstance(objects.toArray());
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
private static final AbstractValidator<?, Object> NULL_FILTER = (sender, value, messageSender) -> value != null;
}

Datei anzeigen

@ -1,93 +0,0 @@
/*
* 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.EqualsAndHashCode;
import lombok.experimental.UtilityClass;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
@UtilityClass
public class TabCompletionCache {
private Map<Key, TabCompletions> tabCompletionCache = new HashMap<>();
Set<AbstractTypeMapper<?, ?>> cached = new HashSet<>();
Set<AbstractTypeMapper<?, ?>> global = new HashSet<>();
Map<AbstractTypeMapper<?, ?>, Long> cacheDuration = new HashMap<>();
void add(AbstractTypeMapper<?, ?> typeMapper, AbstractSWCommand.Cached cached) {
if (cached != null) {
add(typeMapper, cached.global(), cached.cacheDuration(), cached.timeUnit());
}
}
public void add(AbstractTypeMapper<?, ?> typeMapper, boolean global, long cacheDuration, TimeUnit timeUnit) {
TabCompletionCache.cached.add(typeMapper);
if (global) TabCompletionCache.global.add(typeMapper);
TabCompletionCache.cacheDuration.put(typeMapper, timeUnit.toMillis(cacheDuration));
}
@EqualsAndHashCode
@AllArgsConstructor
private static class Key {
private Object sender;
private String arg;
private AbstractTypeMapper<?, ?> typeMapper;
}
@AllArgsConstructor
private static class TabCompletions {
private long timestamp;
private Collection<String> tabCompletions;
}
Collection<String> tabComplete(Object sender, String arg, AbstractTypeMapper<Object, ?> typeMapper, Supplier<Collection<String>> tabCompleteSupplier) {
if (!cached.contains(typeMapper)) return tabCompleteSupplier.get();
String normalizedArg = typeMapper.normalize(sender, arg);
if (normalizedArg == null) normalizedArg = "";
Key key = new Key(global.contains(typeMapper) ? null : sender, normalizedArg, typeMapper);
TabCompletions tabCompletions = tabCompletionCache.computeIfAbsent(key, ignore -> {
return new TabCompletions(System.currentTimeMillis(), tabCompleteSupplier.get());
});
if (System.currentTimeMillis() - tabCompletions.timestamp > cacheDuration.get(typeMapper)) {
tabCompletions.tabCompletions = tabCompleteSupplier.get();
}
tabCompletions.timestamp = System.currentTimeMillis();
return tabCompletions.tabCompletions;
}
public void invalidateOldEntries() {
Set<Key> toRemove = new HashSet<>();
for (Map.Entry<Key, TabCompletions> tabCompletionsEntry : tabCompletionCache.entrySet()) {
if (System.currentTimeMillis() - tabCompletionsEntry.getValue().timestamp > cacheDuration.get(tabCompletionsEntry.getKey().typeMapper)) {
toRemove.add(tabCompletionsEntry.getKey());
}
}
for (Key key : toRemove) {
tabCompletionCache.remove(key);
}
}
}

Datei anzeigen

@ -1,45 +0,0 @@
/*
* 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 de.steamwar.command.CommandFrameworkException;
import lombok.experimental.UtilityClass;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
@UtilityClass
public class AssertionUtils {
public static void assertCMDFramework(Exception e, Class<?> clazz, String message) {
assertThat(e, is(instanceOf(CommandFrameworkException.class)));
assertThat(e.getCause().getCause(), is(instanceOf(clazz)));
assertThat(e.getCause().getCause().getMessage(), is(message));
}
public static <T> void assertTabCompletes(List<T> list, T... elements) {
assertThat(list.size(), is(elements.length));
if (elements.length > 0) {
assertThat(list, containsInAnyOrder(elements));
}
}
}

Datei anzeigen

@ -1,74 +0,0 @@
/*
* 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.command.dto.ExecutionIdentifier;
import de.steamwar.command.dto.TestSWCommand;
public class ArgumentCommand extends TestSWCommand {
public ArgumentCommand() {
super("argument");
}
@Register
public void argument(String sender, boolean b, boolean b2) {
throw new ExecutionIdentifier("RunArgument with Boolean");
}
@Register
public void argument(String sender, float f, float f2, float f3) {
throw new ExecutionIdentifier("RunArgument with Float");
}
@Register
public void argument(String sender, double d, double d2, double d3, double d4) {
throw new ExecutionIdentifier("RunArgument with Double");
}
@Register
public void argument(String sender, int i) {
throw new ExecutionIdentifier("RunArgument with Integer");
}
@Register
public void argument(String sender, long l, long l2) {
throw new ExecutionIdentifier("RunArgument with Long");
}
@Register
public void argument(String sender, String arg) {
throw new ExecutionIdentifier("RunArgument with String");
}
@Register
public void minLengthArgument(String sender, @Length(min = 3) @StaticValue({"he", "hello"}) String arg) {
throw new ExecutionIdentifier("RunLengthArgument with String");
}
@Register
public void minAndMaxLengthArgument(String sender, @Length(min = 3, max = 3) @StaticValue({"wo", "world"}) String arg) {
throw new ExecutionIdentifier("RunLengthArgument with String");
}
public void arrayLengthArgument(String sender, @ArrayLength(max = 3) @StaticValue({"one", "two", "three"}) String... args) {
throw new ExecutionIdentifier("RunArrayLengthArgument with String");
}
}

Datei anzeigen

@ -1,128 +0,0 @@
/*
* 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.command.dto.ExecutionIdentifier;
import org.junit.Test;
import java.util.List;
import static de.steamwar.AssertionUtils.assertCMDFramework;
import static de.steamwar.AssertionUtils.assertTabCompletes;
public class ArgumentCommandTest {
@Test
public void testNoArgs() {
ArgumentCommand cmd = new ArgumentCommand();
try {
cmd.execute("test", "", new String[0]);
} catch (Exception e) {
throw new AssertionError("No exception expected");
}
}
@Test
public void testBoolean() {
ArgumentCommand cmd = new ArgumentCommand();
try {
cmd.execute("test", "", new String[]{"true", "false"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunArgument with Boolean");
}
}
@Test
public void testFloat() {
ArgumentCommand cmd = new ArgumentCommand();
try {
cmd.execute("test", "", new String[]{"0.0", "0.0", "0.0"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunArgument with Float");
}
}
@Test
public void testDouble() {
ArgumentCommand cmd = new ArgumentCommand();
try {
cmd.execute("test", "", new String[]{"0.0", "0.0", "0.0", "0.0"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunArgument with Double");
}
}
@Test
public void testInt() {
ArgumentCommand cmd = new ArgumentCommand();
try {
cmd.execute("test", "", new String[]{"0"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunArgument with Integer");
}
}
@Test
public void testLong() {
ArgumentCommand cmd = new ArgumentCommand();
try {
cmd.execute("test", "", new String[]{"0", "0"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunArgument with Long");
}
}
@Test
public void testTabComplete() {
ArgumentCommand cmd = new ArgumentCommand();
List<String> strings = cmd.tabComplete("test", "", new String[]{""});
assertTabCompletes(strings, "true", "false", "hello", "wor");
}
@Test
public void testPartialTabComplete() {
ArgumentCommand cmd = new ArgumentCommand();
List<String> strings = cmd.tabComplete("test", "", new String[]{"t"});
assertTabCompletes(strings, "true", "t");
strings = cmd.tabComplete("test", "", new String[]{"h"});
assertTabCompletes(strings, "h", "hello");
strings = cmd.tabComplete("test", "", new String[]{"hel"});
assertTabCompletes(strings, "hel", "hello");
strings = cmd.tabComplete("test", "", new String[]{"w"});
assertTabCompletes(strings, "w", "wor");
strings = cmd.tabComplete("test", "", new String[]{"wor"});
assertTabCompletes(strings, "wor");
strings = cmd.tabComplete("test", "", new String[]{"worl"});
assertTabCompletes(strings, "wor", "worl");
strings = cmd.tabComplete("test", "", new String[]{"one", "two", "three", "one"});
assertTabCompletes(strings);
}
}

Datei anzeigen

@ -1,58 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 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.command.dto.TestSWCommand;
import de.steamwar.command.dto.TestTypeMapper;
import java.util.Collection;
public class BetterExceptionCommand extends TestSWCommand {
public BetterExceptionCommand() {
super("betterexception");
}
@Register
public void exceptionOnTabComplete(String s, @Mapper("exception") @Validator("exception") String s1) {
}
@Mapper("exception")
@Validator("exception")
public TestTypeMapper<String> tabCompleteException() {
return new TestTypeMapper<String>() {
@Override
public String map(String sender, PreviousArguments previousArguments, String s) {
return null;
}
@Override
public boolean validate(String sender, String value, MessageSender messageSender) {
System.out.println("Validate: " + value);
throw new SecurityException();
}
@Override
public Collection<String> tabCompletes(String sender, PreviousArguments previousArguments, String s) {
throw new SecurityException();
}
};
}
}

Datei anzeigen

@ -1,53 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 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.junit.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
public class BetterExceptionCommandTest {
@Test
public void testTabCompleteException() {
BetterExceptionCommand cmd = new BetterExceptionCommand();
try {
cmd.tabComplete("test", "", new String[]{""});
assert false;
} catch (Exception e) {
assertThat(e, is(instanceOf(CommandFrameworkException.class)));
assertThat(e.getMessage(), is("de.steamwar.command.CommandFrameworkException: Error while tabcompleting () to type java.lang.String with parameter index 1"));
}
}
@Test
public void testValidationException() {
BetterExceptionCommand cmd = new BetterExceptionCommand();
try {
cmd.execute("test", "", new String[]{""});
assert false;
} catch (Exception e) {
assertThat(e, is(instanceOf(CommandFrameworkException.class)));
assertThat(e.getMessage(), is("de.steamwar.command.CommandFrameworkException: Error while validating () to type java.lang.String with parameter index 1"));
}
}
}

Datei anzeigen

@ -1,56 +0,0 @@
/*
* 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.command.dto.TestSWCommand;
import de.steamwar.command.dto.TestTypeMapper;
import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.atomic.AtomicInteger;
public class CacheCommand extends TestSWCommand {
public CacheCommand() {
super("typemapper");
}
@Register
public void test(String sender, int tabCompleteTest) {
}
private AtomicInteger count = new AtomicInteger();
@Cached
@Mapper(value = "int", local = true)
public AbstractTypeMapper<String, Integer> typeMapper() {
return new TestTypeMapper<Integer>() {
@Override
public Integer map(String sender, PreviousArguments previousArguments, String s) {
return Integer.parseInt(s);
}
@Override
public Collection<String> tabCompletes(String sender, PreviousArguments previousArguments, String s) {
return Arrays.asList(count.getAndIncrement() + "");
}
};
}
}

Datei anzeigen

@ -1,54 +0,0 @@
/*
* 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.junit.Test;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
public class CacheCommandTest {
@Test
public void testCaching() {
CacheCommand cmd = new CacheCommand();
List<String> tabCompletions1 = cmd.tabComplete("test", "", new String[]{""});
List<String> tabCompletions2 = cmd.tabComplete("test", "", new String[]{""});
assertThat(tabCompletions1, is(equalTo(tabCompletions2)));
}
@Test
public void testCachingWithDifferentMessages() {
CacheCommand cmd = new CacheCommand();
List<String> tabCompletions1 = cmd.tabComplete("test", "", new String[]{""});
List<String> tabCompletions2 = cmd.tabComplete("test", "", new String[]{"0"});
assertThat(tabCompletions1, is(equalTo(tabCompletions2)));
}
@Test
public void testCachingWithDifferentSenders() {
CacheCommand cmd = new CacheCommand();
List<String> tabCompletions1 = cmd.tabComplete("test", "", new String[]{""});
List<String> tabCompletions2 = cmd.tabComplete("test2", "", new String[]{""});
assertThat(tabCompletions1, is(not(equalTo(tabCompletions2))));
}
}

Datei anzeigen

@ -1,59 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 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.command.dto.ExecutionIdentifier;
import de.steamwar.command.dto.TestSWCommand;
import de.steamwar.command.dto.TestTypeMapper;
import java.util.Collection;
public class NullMapperCommand extends TestSWCommand {
public NullMapperCommand() {
super("nullmapper");
}
@Register
public void test(String sender, @AllowNull String arg) {
if (arg == null) {
throw new ExecutionIdentifier("null");
}
throw new ExecutionIdentifier("notnull");
}
@ClassMapper(value = String.class, local = true)
public TestTypeMapper<String> typeMapper() {
return new TestTypeMapper<String>() {
@Override
public String map(String sender, PreviousArguments previousArguments, String s) {
if (s.equals("Hello World")) {
return null;
}
return s;
}
@Override
public Collection<String> tabCompletes(String sender, PreviousArguments previousArguments, String s) {
return null;
}
};
}
}

Datei anzeigen

@ -1,52 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 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.command.dto.ExecutionIdentifier;
import org.junit.Test;
import static de.steamwar.AssertionUtils.assertCMDFramework;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
public class NullMapperCommandTest {
@Test
public void testNull() {
NullMapperCommand command = new NullMapperCommand();
try {
command.execute("test", "", new String[] {"Hello World"});
assertThat(true, is(false));
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "null");
}
}
@Test
public void testNonNull() {
NullMapperCommand command = new NullMapperCommand();
try {
command.execute("test", "", new String[] {"Hello"});
assertThat(true, is(false));
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "notnull");
}
}
}

Datei anzeigen

@ -1,35 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 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.command.dto.ExecutionIdentifier;
import de.steamwar.command.dto.TestSWCommand;
public class NumberValidatorCommand extends TestSWCommand {
public NumberValidatorCommand() {
super("numberValidator");
}
@Register
public void test(String sender, @Min(intValue = 0) @Max(intValue = 10) int i) {
throw new ExecutionIdentifier("RunNumberValidator with int");
}
}

Datei anzeigen

@ -1,51 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 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.command.dto.ExecutionIdentifier;
import org.junit.Test;
import static de.steamwar.AssertionUtils.assertCMDFramework;
public class NumberValidatorCommandTest {
@Test
public void testMinValue() {
NumberValidatorCommand command = new NumberValidatorCommand();
command.execute("sender", "", new String[]{"-1"});
}
@Test
public void testMaxValue() {
NumberValidatorCommand command = new NumberValidatorCommand();
command.execute("sender", "", new String[]{"11"});
}
@Test
public void testValidValue() {
try {
NumberValidatorCommand command = new NumberValidatorCommand();
command.execute("sender", "", new String[]{"2"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunNumberValidator with int");
}
}
}

Datei anzeigen

@ -1,70 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 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.command.dto.ExecutionIdentifier;
import de.steamwar.command.dto.TestSWCommand;
import de.steamwar.command.dto.TestTypeMapper;
import java.util.Arrays;
import java.util.Collection;
public class PartOfCommand {
public static class ParentCommand extends TestSWCommand {
public ParentCommand() {
super("parent");
}
@Register
public void execute(String s, String... args) {
throw new ExecutionIdentifier("ParentCommand with String...");
}
@Mapper("test")
public TestTypeMapper<Integer> typeMapper() {
return new TestTypeMapper<Integer>() {
@Override
public Integer map(String sender, PreviousArguments previousArguments, String s) {
return -1;
}
@Override
public Collection<String> tabCompletes(String sender, PreviousArguments previousArguments, String s) {
return Arrays.asList(s);
}
};
}
}
@AbstractSWCommand.PartOf(ParentCommand.class)
public static class SubCommand extends TestSWCommand {
public SubCommand() {
super(null);
}
@Register
public void execute(String s, @Mapper("test") int i) {
throw new ExecutionIdentifier("SubCommand with int " + i);
}
}
}

Datei anzeigen

@ -1,42 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 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.command.dto.ExecutionIdentifier;
import org.junit.Test;
import static de.steamwar.AssertionUtils.assertCMDFramework;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
public class PartOfCommandTest {
@Test
public void testMerging() {
PartOfCommand.ParentCommand command = new PartOfCommand.ParentCommand();
new PartOfCommand.SubCommand();
try {
command.execute("test", "", new String[]{"0"});
assertThat(true, is(false));
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "SubCommand with int -1");
}
}
}

Datei anzeigen

@ -1,54 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 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.command.dto.ExecutionIdentifier;
import de.steamwar.command.dto.TestSWCommand;
import de.steamwar.command.dto.TestTypeMapper;
import java.util.Arrays;
import java.util.Collection;
public class PreviousArgumentCommand extends TestSWCommand {
public PreviousArgumentCommand() {
super("previous");
}
@Register
public void genericCommand(String s, int i, String l) {
throw new ExecutionIdentifier(l);
}
@ClassMapper(value = String.class, local = true)
public TestTypeMapper<String> typeMapper() {
return new TestTypeMapper<String>() {
@Override
public String map(String sender, PreviousArguments previousArguments, String s) {
return "RunTypeMapper_" + previousArguments.getMappedArg(0) + "_" + previousArguments.getMappedArg(0).getClass().getSimpleName();
}
@Override
public Collection<String> tabCompletes(String sender, PreviousArguments previousArguments, String s) {
return Arrays.asList(previousArguments.getMappedArg(0) + "");
}
};
}
}

Datei anzeigen

@ -1,56 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 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.command.dto.ExecutionIdentifier;
import org.junit.Test;
import java.util.List;
import static de.steamwar.AssertionUtils.assertCMDFramework;
import static de.steamwar.AssertionUtils.assertTabCompletes;
public class PreviousArgumentCommandTest {
@Test
public void testPrevArg1() {
PreviousArgumentCommand command = new PreviousArgumentCommand();
List<String> strings = command.tabComplete("", "", new String[]{"1", ""});
assertTabCompletes(strings, "1");
}
@Test
public void testPrevArg2() {
PreviousArgumentCommand command = new PreviousArgumentCommand();
List<String> strings = command.tabComplete("", "", new String[]{"2", ""});
assertTabCompletes(strings, "2");
}
@Test
public void testPrevArgExecute() {
PreviousArgumentCommand command = new PreviousArgumentCommand();
try {
command.execute("", "", new String[]{"2", "2"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunTypeMapper_2_Integer");
}
}
}

Datei anzeigen

@ -1,40 +0,0 @@
/*
* 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.command.dto.ExecutionIdentifier;
import de.steamwar.command.dto.TestSWCommand;
public class SimpleCommand extends TestSWCommand {
public SimpleCommand() {
super("simple");
}
@Register(value = "a", noTabComplete = true)
public void test(String s, String... varargs) {
throw new ExecutionIdentifier("RunSimple with Varargs");
}
@Register
public void simple(String s) {
throw new ExecutionIdentifier("RunSimple with noArgs");
}
}

Datei anzeigen

@ -1,68 +0,0 @@
/*
* 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.command.dto.ExecutionIdentifier;
import org.junit.Test;
import java.util.List;
import static de.steamwar.AssertionUtils.assertCMDFramework;
import static de.steamwar.AssertionUtils.assertTabCompletes;
public class SimpleCommandTest {
@Test
public void testSimpleParsing() {
SimpleCommand cmd = new SimpleCommand();
try {
cmd.execute("test", "", new String[0]);
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunSimple with noArgs");
}
}
@Test
public void testVarArgs() {
SimpleCommand cmd = new SimpleCommand();
try {
cmd.execute("test", "", new String[] {"a", "b", "c"});
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunSimple with Varargs");
}
}
@Test
public void testSimpleParsingNoResult() {
SimpleCommand cmd = new SimpleCommand();
try {
cmd.execute("test", "", new String[]{"Hello"});
} catch (CommandFrameworkException e) {
throw new AssertionError("No exception expected");
}
}
@Test
public void testSimpleTabComplete() {
SimpleCommand cmd = new SimpleCommand();
List<String> strings = cmd.tabComplete("test", "", new String[]{""});
assertTabCompletes(strings);
}
}

Datei anzeigen

@ -1,55 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 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.command.dto.ExecutionIdentifier;
import de.steamwar.command.dto.TestSWCommand;
public class StaticValueCommand extends TestSWCommand {
public StaticValueCommand() {
super("staticvalue");
}
@Register
public void defaultStaticValue(String s, @StaticValue({"hello", "world"}) String staticValue) {
throw new ExecutionIdentifier("RunStaticValue with " + staticValue);
}
@Register
public void booleanStaticValue(String s, @StaticValue(value = {"-a", "-b", "-c"}, allowISE = true) boolean staticValue) {
throw new ExecutionIdentifier("RunStaticValue with " + staticValue);
}
@Register
public void booleanStaticValueOtherFalseValue(String s, @StaticValue(value = {"-d", "-e", "-f"}, allowISE = true, falseValues = { 1 }) boolean staticValue) {
throw new ExecutionIdentifier("RunStaticValue with " + staticValue);
}
@Register
public void intStaticValue(String s, @StaticValue(value = {"-g", "-h", "-i"}, allowISE = true) int staticValue) {
throw new ExecutionIdentifier("RunStaticValue with int " + staticValue);
}
@Register
public void longStaticValue(String s, @StaticValue(value = {"-j", "-k", "-l"}, allowISE = true) long staticValue) {
throw new ExecutionIdentifier("RunStaticValue with long " + staticValue);
}
}

Datei anzeigen

@ -1,147 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 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.command.dto.ExecutionIdentifier;
import org.junit.Test;
import java.util.List;
import static de.steamwar.AssertionUtils.assertCMDFramework;
import static de.steamwar.AssertionUtils.assertTabCompletes;
public class StaticValueCommandTest {
@Test
public void tabCompletionTest() {
StaticValueCommand cmd = new StaticValueCommand();
List<String> strings = cmd.tabComplete("", "", new String[]{""});
assertTabCompletes(strings, "hello", "world", "-a", "-b", "-c", "-d", "-e", "-f", "-g", "-h", "-i", "-j", "-k", "-l");
}
@Test
public void defaultTest() {
StaticValueCommand cmd = new StaticValueCommand();
try {
cmd.execute("", "", new String[] {"hello"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with hello");
}
try {
cmd.execute("", "", new String[] {"world"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with world");
}
}
@Test
public void booleanTest() {
StaticValueCommand cmd = new StaticValueCommand();
try {
cmd.execute("", "", new String[] {"-a"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with false");
}
try {
cmd.execute("", "", new String[] {"-b"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with true");
}
try {
cmd.execute("", "", new String[] {"-c"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with true");
}
}
@Test
public void booleanOtherFalseTest() {
StaticValueCommand cmd = new StaticValueCommand();
try {
cmd.execute("", "", new String[] {"-d"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with true");
}
try {
cmd.execute("", "", new String[] {"-e"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with false");
}
try {
cmd.execute("", "", new String[] {"-f"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with true");
}
}
@Test
public void intTest() {
StaticValueCommand cmd = new StaticValueCommand();
try {
cmd.execute("", "", new String[] {"-g"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with int 0");
}
try {
cmd.execute("", "", new String[] {"-h"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with int 1");
}
try {
cmd.execute("", "", new String[] {"-i"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with int 2");
}
}
@Test
public void longTest() {
StaticValueCommand cmd = new StaticValueCommand();
try {
cmd.execute("", "", new String[] {"-j"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with long 0");
}
try {
cmd.execute("", "", new String[] {"-k"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with long 1");
}
try {
cmd.execute("", "", new String[] {"-l"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunStaticValue with long 2");
}
}
}

Datei anzeigen

@ -1,58 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 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.command.dto.ExecutionIdentifier;
import de.steamwar.command.dto.TestSWCommand;
import de.steamwar.command.dto.TestTypeMapper;
import java.util.Collections;
public class SubCMDSortingCommand extends TestSWCommand {
public SubCMDSortingCommand() {
super("subcmdsorting");
}
@Register
public void test(String s) {
throw new ExecutionIdentifier("Command with 0 parameters");
}
@Register
public void test(String s, String args) {
throw new ExecutionIdentifier("Command with 1 parameter");
}
@Register
public void test(String s, String i1, String i2, String i3, String... args) {
throw new ExecutionIdentifier("Command with 3+n parameters");
}
@Register
public void test(String s, String... args) {
throw new ExecutionIdentifier("Command with n parameters");
}
@ClassMapper(value = String.class, local = true)
public AbstractTypeMapper<String, String> stringMapper() {
return SWCommandUtils.createMapper(s -> s, Collections::singletonList);
}
}

Datei anzeigen

@ -1,83 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 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.command.dto.ExecutionIdentifier;
import org.junit.Test;
import static de.steamwar.AssertionUtils.assertCMDFramework;
public class SubCMDSortingCommandTest {
@Test
public void testNoArgs() {
SubCMDSortingCommand cmd = new SubCMDSortingCommand();
try {
cmd.execute("", "", new String[]{});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "Command with 0 parameters");
}
}
@Test
public void testOneArgs() {
SubCMDSortingCommand cmd = new SubCMDSortingCommand();
try {
cmd.execute("", "", new String[]{"Hello"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "Command with 1 parameter");
}
}
@Test
public void testOneArgsVarArg() {
SubCMDSortingCommand cmd = new SubCMDSortingCommand();
try {
cmd.execute("", "", new String[]{"Hello", "World"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "Command with n parameters");
}
}
@Test
public void testThreeArgsVarArg() {
SubCMDSortingCommand cmd = new SubCMDSortingCommand();
try {
cmd.execute("", "", new String[]{"Hello", "World", "YoyoNow", "Hugo"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "Command with 3+n parameters");
}
}
@Test
public void testThreeArgsVarArg2() {
SubCMDSortingCommand cmd = new SubCMDSortingCommand();
try {
cmd.execute("", "", new String[]{"Hello", "World", "YoyoNow"});
assert false;
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "Command with 3+n parameters");
}
}
}

Datei anzeigen

@ -1,40 +0,0 @@
/*
* 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.command.dto.ExecutionIdentifier;
import de.steamwar.command.dto.TestSWCommand;
public class TypeMapperCommand extends TestSWCommand {
public TypeMapperCommand() {
super("typemapper");
}
@Register
public void test(String sender, String s) {
throw new ExecutionIdentifier("RunTypeMapper with CustomMapper");
}
@ClassMapper(value = String.class, local = true)
public AbstractTypeMapper<String, String> getTypeMapper() {
return SWCommandUtils.createMapper("1", "2", "3", "4", "5");
}
}

Datei anzeigen

@ -1,36 +0,0 @@
/*
* 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.junit.Test;
import java.util.List;
import static de.steamwar.AssertionUtils.assertTabCompletes;
public class TypeMapperCommandTest {
@Test
public void testTabComplete() {
TypeMapperCommand cmd = new TypeMapperCommand();
List<String> strings = cmd.tabComplete("test", "", new String[]{""});
assertTabCompletes(strings, "1", "2", "3", "4", "5");
}
}

Datei anzeigen

@ -1,62 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 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.command.dto.ExecutionIdentifier;
import de.steamwar.command.dto.TestSWCommand;
import de.steamwar.command.dto.TestValidator;
public class ValidatorCommand extends TestSWCommand {
public ValidatorCommand() {
super("testvalidator");
}
@Register
public void test(@Validator String sender) {
throw new ExecutionIdentifier("RunTest");
}
@Override
protected void sendMessage(String sender, String message, Object[] args) {
if (message.equals("Hello World")) {
throw new ExecutionIdentifier("RunSendMessageWithHelloWorldParameter");
}
}
@Register
public void onError(String sender, @ErrorMessage("Hello World") int error) {
System.out.println("onError: " + sender + " " + error);
throw new ExecutionIdentifier("RunOnError");
}
@Register
public void onError(String sender, double error) {
System.out.println("onError: " + sender + " " + error);
throw new ExecutionIdentifier("RunOnErrorDouble");
}
@ClassValidator(value = String.class, local = true)
public TestValidator<String> validator() {
return (sender, value, messageSender) -> {
throw new ExecutionIdentifier("RunValidator");
};
}
}

Datei anzeigen

@ -1,85 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 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.command.dto.ExecutionIdentifier;
import org.junit.Test;
import static de.steamwar.AssertionUtils.assertCMDFramework;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
public class ValidatorCommandTest {
@Test
public void testValidator() {
ValidatorCommand cmd = new ValidatorCommand();
try {
cmd.execute("test", "", new String[0]);
assertThat(true, is(false));
} catch (Exception e) {
assertThat(e.getMessage(), is("RunValidator"));
}
}
@Test
public void testErrorMessage() {
ValidatorCommand cmd = new ValidatorCommand();
try {
cmd.execute("test", "", new String[]{"Hello"});
assertThat(true, is(false));
} catch (Exception e) {
assertThat(e.getMessage(), is("RunSendMessageWithHelloWorldParameter"));
}
}
@Test
public void testErrorNoMessage() {
ValidatorCommand cmd = new ValidatorCommand();
try {
cmd.execute("test", "", new String[]{"0.0"});
assertThat(true, is(false));
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunOnErrorDouble");
}
}
@Test
public void testInvert() {
ValidatorInvertCommand cmd = new ValidatorInvertCommand();
try {
cmd.execute("test", "", new String[]{"false", "true"});
assertThat(true, is(false));
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunTestInvert");
}
}
@Test
public void testInvertOther() {
ValidatorInvertCommand cmd = new ValidatorInvertCommand();
try {
cmd.execute("test", "", new String[]{"Hello", "0"});
assertThat(true, is(false));
} catch (Exception e) {
assertCMDFramework(e, ExecutionIdentifier.class, "RunTestInvert2");
}
}
}

Datei anzeigen

@ -1,51 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 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.command.dto.ExecutionIdentifier;
import de.steamwar.command.dto.TestSWCommand;
import de.steamwar.command.dto.TestValidator;
public class ValidatorInvertCommand extends TestSWCommand {
public ValidatorInvertCommand() {
super("testvalidator");
}
@Register
public void test(@Validator(value = "Text", invert = true) String sender, boolean b, boolean b2) {
System.out.println("test: " + sender + " " + b + " " + b2);
throw new ExecutionIdentifier("RunTestInvert");
}
@Register
public void test(String sender, @Validator(value = "Text", invert = true) String h, int i) {
System.out.println("test: " + sender + " " + h + " " + i);
throw new ExecutionIdentifier("RunTestInvert2");
}
@Validator(value = "Text", local = true)
public TestValidator<String> testValidator() {
return (sender, value, messageSender) -> {
System.out.println("testValidator: " + sender + " " + value + " " + messageSender);
return false;
};
}
}

Datei anzeigen

@ -1,26 +0,0 @@
/*
* 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.dto;
public class ExecutionIdentifier extends RuntimeException {
public ExecutionIdentifier(String message) {
super(message);
}
}

Datei anzeigen

@ -1,61 +0,0 @@
/*
* 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.dto;
import de.steamwar.command.AbstractSWCommand;
import de.steamwar.command.CommandFrameworkException;
import java.util.function.Supplier;
public class TestSWCommand extends AbstractSWCommand<String> {
protected TestSWCommand(String command) {
super(String.class, command);
}
protected TestSWCommand(String command, String[] aliases) {
super(String.class, command, aliases);
}
@Override
protected void createAndSafeCommand(String command, String[] aliases) {
}
@Override
public void unregister() {
}
@Override
public void register() {
}
@Override
protected void commandSystemError(String sender, CommandFrameworkException e) {
System.out.println("CommandSystemError: " + e.getMessage());
}
@Override
protected void commandSystemWarning(Supplier<String> message) {
System.out.println("CommandSystemWarning: " + message.get());
}
}

Datei anzeigen

@ -1,25 +0,0 @@
/*
* 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.dto;
import de.steamwar.command.AbstractTypeMapper;
public interface TestTypeMapper<T> extends AbstractTypeMapper<String, T> {
}

Datei anzeigen

@ -1,25 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 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.dto;
import de.steamwar.command.AbstractValidator;
public interface TestValidator<T> extends AbstractValidator<String, T> {
}