Add parameter registry

This commit is contained in:
Alexander Söderberg 2020-09-13 13:50:47 +02:00
parent e01fd6af37
commit 53e5720f52
No known key found for this signature in database
GPG key ID: C0207FF7EA146678
11 changed files with 708 additions and 4 deletions

View file

@ -26,6 +26,8 @@ package com.intellectualsites.commands;
import com.google.common.reflect.TypeToken;
import com.intellectualsites.commands.components.CommandSyntaxFormatter;
import com.intellectualsites.commands.components.StandardCommandSyntaxFormatter;
import com.intellectualsites.commands.components.parser.ParserRegistry;
import com.intellectualsites.commands.components.parser.StandardParserRegistry;
import com.intellectualsites.commands.context.CommandContext;
import com.intellectualsites.commands.context.CommandContextFactory;
import com.intellectualsites.commands.context.StandardCommandContextFactory;
@ -61,6 +63,7 @@ public abstract class CommandManager<C extends CommandSender, M extends CommandM
private final CommandContextFactory<C> commandContextFactory = new StandardCommandContextFactory<>();
private final ServicePipeline servicePipeline = ServicePipeline.builder().build();
private final ParserRegistry<C> parserRegistry = new StandardParserRegistry<>();
private final CommandExecutionCoordinator<C, M> commandExecutionCoordinator;
private final CommandRegistrationHandler<M> commandRegistrationHandler;
@ -274,4 +277,14 @@ public abstract class CommandManager<C extends CommandSender, M extends CommandM
this.commandSuggestionProcessor = commandSuggestionProcessor;
}
/**
* Get the parser registry instance
*
* @return Parser registry instance
*/
@Nonnull
public ParserRegistry<C> getParserRegistry() {
return this.parserRegistry;
}
}

View file

@ -0,0 +1,53 @@
//
// MIT License
//
// Copyright (c) 2020 Alexander Söderberg
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package com.intellectualsites.commands.annotations.specifier;
import javax.annotation.Nonnull;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Used to specify min and max values of numerical {@link com.intellectualsites.commands.components.parser.ComponentParser parsers}
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Range {
/**
* Minimum value accepted by the parser
*
* @return String serialized number
*/
@Nonnull String min() default "";
/**
* Maximum value accepted by the parser
*
* @return String serialized number
*/
@Nonnull String max() default "";
}

View file

@ -0,0 +1,88 @@
//
// MIT License
//
// Copyright (c) 2020 Alexander Söderberg
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package com.intellectualsites.commands.components.parser;
import com.google.common.reflect.TypeToken;
import javax.annotation.Nonnull;
import java.util.Objects;
/**
* Parser parameter used when retrieving parsers from the {@link ParserRegistry}
*
* @param <T> Type required by the parameter
*/
public class ParserParameter<T> {
private final String key;
private final TypeToken<T> expectedType;
/**
* Create a new parser parameter
*
* @param key Parameter key
* @param expectedType Type that is expected to be mapped to this parameter
*/
public ParserParameter(@Nonnull final String key, @Nonnull final TypeToken<T> expectedType) {
this.key = key;
this.expectedType = expectedType;
}
/**
* Get the parameter key
*
* @return Parameter key
*/
@Nonnull public String getKey() {
return this.key;
}
/**
* Ge the type that is expected to be mapped to this parameter
*
* @return Expected type
*/
@Nonnull public TypeToken<T> getExpectedType() {
return this.expectedType;
}
@Override
public final boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final ParserParameter<?> that = (ParserParameter<?>) o;
return Objects.equals(key, that.key) &&
Objects.equals(expectedType, that.expectedType);
}
@Override
public final int hashCode() {
return Objects.hash(key, expectedType);
}
}

View file

@ -0,0 +1,108 @@
//
// MIT License
//
// Copyright (c) 2020 Alexander Söderberg
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package com.intellectualsites.commands.components.parser;
import com.google.common.collect.Maps;
import javax.annotation.Nonnull;
import java.util.Collections;
import java.util.Map;
/**
* Collection of {@link ParserParameter parameter}-{@link Object object} pairs
*/
public final class ParserParameters {
private final Map<ParserParameter<?>, Object> internalMap = Maps.newHashMap();
public ParserParameters() {
}
/**
* Get an empty {@link ParserParameters} instance
*
* @return Empty instance
*/
@Nonnull
public static ParserParameters empty() {
return new ParserParameters();
}
/**
* Check if this instance contains a parameter-object pair for a given parameter
*
* @param parameter Parameter
* @param <T> Parameter type
* @return {@code true} if such a pair is stored, else {@code false}
*/
public <T> boolean has(@Nonnull final ParserParameter<T> parameter) {
return this.internalMap.containsKey(parameter);
}
/**
* Store a parameter-object pair
*
* @param parameter Parameter
* @param value Object
* @param <T> Parameter type
*/
public <T> void store(@Nonnull final ParserParameter<T> parameter, @Nonnull final T value) {
this.internalMap.put(parameter, value);
}
/**
* Get a value from the parameter map, if it is stored, else return a default value
*
* @param parameter Parameter to retrieve
* @param defaultValue Default value
* @param <T> Parameter type
* @return Parameter value
*/
@Nonnull
@SuppressWarnings("unchecked")
public <T> T get(@Nonnull final ParserParameter<T> parameter, @Nonnull final T defaultValue) {
return (T) this.internalMap.getOrDefault(parameter, defaultValue);
}
/**
* Attempt to merge two {@link ParserParameters} instances. If the instances contain conflicting
* values, the values of the "other" instance will be preferred
*
* @param other Other instance
*/
public void merge(@Nonnull final ParserParameters other) {
this.internalMap.putAll(other.internalMap);
}
/**
* Get an immutable view of the internal map
*
* @return Immutable map
*/
@Nonnull
public Map<ParserParameter<?>, Object> getAll() {
return Collections.unmodifiableMap(this.internalMap);
}
}

View file

@ -0,0 +1,92 @@
//
// MIT License
//
// Copyright (c) 2020 Alexander Söderberg
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package com.intellectualsites.commands.components.parser;
import com.google.common.reflect.TypeToken;
import com.intellectualsites.commands.sender.CommandSender;
import javax.annotation.Nonnull;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Function;
/**
* Registry of {@link ComponentParser} that allows these components to be
* referenced by a {@link Class} (or really, a {@link com.google.common.reflect.TypeToken})
* or a {@link String} key
*
* @param <C> Command sender type
*/
public interface ParserRegistry<C extends CommandSender> {
/**
* Register a parser supplier
*
* @param type The type that is parsed by the parser
* @param supplier The function that generates the parser. The map supplied my contain parameters used
* to configure the parser, many of which are documented in {@link StandardParameters}
* @param <T> Generic type specifying what is produced by the parser
*/
<T> void registerParserSupplier(@Nonnull final TypeToken<T> type,
@Nonnull final Function<ParserParameters, ComponentParser<C, ?>> supplier);
/**
* Register a mapper that maps annotation instances to a map of parameter-object pairs
*
* @param annotation Annotation class
* @param mapper Mapper that maps the pair (annotation, type to be parsed) to a map of
* {@link ParserParameter parameter}-{@link Object object} pairs
* @param <A> Annotation type
* @param <T> Type of the object that the parser is retrieved for
*/
<A extends Annotation, T> void registerAnnotationMapper(@Nonnull final Class<A> annotation,
@Nonnull final BiFunction<A, TypeToken<?>,
ParserParameters> mapper);
/**
* Parse annotations into {@link ParserParameters}
*
* @param parsingType The type that is produced by the parser that is requesting the parsing parameters
* @param annotations The annotations to be parsed
* @return Parsed parameters
*/
@Nonnull
ParserParameters parseAnnotations(@Nonnull final TypeToken<?> parsingType, @Nonnull final Collection<? extends Annotation> annotations);
/**
* Attempt to create a {@link ComponentParser} for a specified type, using
* an instance of {@link ParserParameter} to configure the parser settings
*
* @param type Type that should be produced by the parser
* @param parserParameters Parser parameters
* @param <T> Generic type
* @return Parser, if one can be created
*/
@Nonnull
<T> Optional<ComponentParser<C, T>> createParser(@Nonnull final TypeToken<T> type,
@Nonnull final ParserParameters parserParameters);
}

View file

@ -0,0 +1,52 @@
//
// MIT License
//
// Copyright (c) 2020 Alexander Söderberg
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package com.intellectualsites.commands.components.parser;
import com.google.common.reflect.TypeToken;
import javax.annotation.Nonnull;
/**
* Common parser parameters used when resolving types in the {@link ParserRegistry}
*/
public final class StandardParameters {
private StandardParameters() {
}
/**
* Minimum value accepted by a numerical parser
*/
public static final ParserParameter<Number> RANGE_MIN = create("min", TypeToken.of(Number.class));
/**
* Maximum value accepted by a numerical parser
*/
public static final ParserParameter<Number> RANGE_MAX = create("max", TypeToken.of(Number.class));
private static <T> ParserParameter<T> create(@Nonnull final String key, @Nonnull final TypeToken<T> expectedType) {
return new ParserParameter<>(key, expectedType);
}
}

View file

@ -0,0 +1,194 @@
//
// MIT License
//
// Copyright (c) 2020 Alexander Söderberg
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package com.intellectualsites.commands.components.parser;
import com.google.common.collect.ImmutableMap;
import com.google.common.reflect.TypeToken;
import com.intellectualsites.commands.annotations.specifier.Range;
import com.intellectualsites.commands.components.standard.IntegerComponent;
import com.intellectualsites.commands.sender.CommandSender;
import javax.annotation.Nonnull;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Function;
/**
* Standard implementation of {@link ParserRegistry}
*
* @param <C> Command sender type
*/
public class StandardParserRegistry<C extends CommandSender> implements ParserRegistry<C> {
private static final Map<Class<?>, Class<?>> primitiveMappings = ImmutableMap.<Class<?>, Class<?>>builder()
.put(char.class, Character.class)
.put(int.class, Integer.class)
.put(short.class, Short.class)
.put(byte.class, Byte.class)
.put(float.class, Float.class)
.put(double.class, Double.class)
.put(long.class, Long.class)
.put(boolean.class, Boolean.class)
.build();
private final Map<TypeToken<?>, Function<ParserParameters, ComponentParser<C, ?>>> parserSuppliers = new HashMap<>();
private final Map<Class<? extends Annotation>, BiFunction<? extends Annotation, TypeToken<?>, ParserParameters>>
annotationMappers = new HashMap<>();
public StandardParserRegistry() {
/* Register standard mappers */
this.<Range, Number>registerAnnotationMapper(Range.class, new RangeMapper<>());
/* Register standard types */
this.registerParserSupplier(TypeToken.of(Integer.class), options ->
new IntegerComponent.IntegerParser<C>((int) options.get(StandardParameters.RANGE_MIN, Integer.MIN_VALUE),
(int) options.get(StandardParameters.RANGE_MAX, Integer.MAX_VALUE)));
}
@Override
public <T> void registerParserSupplier(@Nonnull final TypeToken<T> type,
@Nonnull final Function<ParserParameters, ComponentParser<C, ?>> supplier) {
this.parserSuppliers.put(type, supplier);
}
@Override
public <A extends Annotation, T> void registerAnnotationMapper(@Nonnull final Class<A> annotation,
@Nonnull final BiFunction<A, TypeToken<?>,
ParserParameters> mapper) {
this.annotationMappers.put(annotation, mapper);
}
@Nonnull
@Override
public ParserParameters parseAnnotations(@Nonnull final TypeToken<?> parsingType,
@Nonnull final Collection<? extends Annotation> annotations) {
final ParserParameters parserParameters = new ParserParameters();
annotations.forEach(annotation -> {
// noinspection all
final BiFunction mapper = this.annotationMappers.get(annotation.annotationType());
if (mapper == null) {
return;
}
@SuppressWarnings("unchecked")
final ParserParameters parserParametersCasted = (ParserParameters) mapper.apply(annotation, parsingType);
parserParameters.merge(parserParametersCasted);
});
return parserParameters;
}
@Nonnull
@Override
public <T> Optional<ComponentParser<C, T>> createParser(@Nonnull final TypeToken<T> type,
@Nonnull final ParserParameters parserParameters) {
final TypeToken<?> actualType;
if (type.isPrimitive()) {
actualType = TypeToken.of(primitiveMappings.get(type.getRawType()));
} else {
actualType = type;
}
final Function<ParserParameters, ComponentParser<C, ?>> producer = this.parserSuppliers.get(actualType);
if (producer == null) {
return Optional.empty();
}
@SuppressWarnings("unchecked")
final ComponentParser<C, T> parser = (ComponentParser<C, T>) producer.apply(parserParameters);
return Optional.of(parser);
}
private static final class RangeMapper<T> implements BiFunction<Range, TypeToken<?>, ParserParameters> {
@Override
public ParserParameters apply(final Range range, final TypeToken<?> type) {
final Class<?> clazz;
if (type.isPrimitive()) {
clazz = primitiveMappings.get(type.getRawType());
} else {
clazz = type.getRawType();
}
if (!Number.class.isAssignableFrom(clazz)) {
return ParserParameters.empty();
}
Number min = null;
Number max = null;
if (clazz.equals(Byte.class)) {
if (!range.min().isEmpty()) {
min = Byte.parseByte(range.min());
}
if (!range.max().isEmpty()) {
max = Byte.parseByte(range.max());
}
} else if (clazz.equals(Short.class)) {
if (!range.min().isEmpty()) {
min = Short.parseShort(range.min());
}
if (!range.max().isEmpty()) {
max = Short.parseShort(range.max());
}
} else if (clazz.equals(Integer.class)) {
if (!range.min().isEmpty()) {
min = Integer.parseInt(range.min());
}
if (!range.max().isEmpty()) {
max = Integer.parseInt(range.max());
}
} else if (clazz.equals(Long.class)) {
if (!range.min().isEmpty()) {
min = Long.parseLong(range.min());
}
if (!range.max().isEmpty()) {
max = Long.parseLong(range.max());
}
} else if (clazz.equals(Float.class)) {
if (!range.min().isEmpty()) {
min = Float.parseFloat(range.min());
}
if (!range.max().isEmpty()) {
max = Float.parseFloat(range.max());
}
} else if (clazz.equals(Double.class)) {
if (!range.min().isEmpty()) {
min = Double.parseDouble(range.min());
}
if (!range.max().isEmpty()) {
max = Double.parseDouble(range.max());
}
}
final ParserParameters parserParameters = new ParserParameters();
if (min != null) {
parserParameters.store(StandardParameters.RANGE_MIN, min);
}
if (max != null) {
parserParameters.store(StandardParameters.RANGE_MAX, max);
}
return parserParameters;
}
}
}

View file

@ -138,7 +138,7 @@ public final class BooleanComponent<C extends CommandSender> extends CommandComp
}
private static final class BooleanParser<C extends CommandSender> implements ComponentParser<C, Boolean> {
public static final class BooleanParser<C extends CommandSender> implements ComponentParser<C, Boolean> {
private static final List<String> LIBERAL = Arrays.asList("TRUE", "YES", "ON", "FALSE", "NO", "OFF");
private static final List<String> LIBERAL_TRUE = Arrays.asList("TRUE", "YES", "ON");

View file

@ -162,7 +162,7 @@ public final class ByteComponent<C extends CommandSender> extends CommandCompone
}
private static final class ByteParser<C extends CommandSender> implements ComponentParser<C, Byte> {
public static final class ByteParser<C extends CommandSender> implements ComponentParser<C, Byte> {
private final byte min;
private final byte max;

View file

@ -166,12 +166,12 @@ public final class IntegerComponent<C extends CommandSender> extends CommandComp
}
private static final class IntegerParser<C extends CommandSender> implements ComponentParser<C, Integer> {
public static final class IntegerParser<C extends CommandSender> implements ComponentParser<C, Integer> {
private final int min;
private final int max;
private IntegerParser(final int min, final int max) {
public IntegerParser(final int min, final int max) {
this.min = min;
this.max = max;
}
@ -197,6 +197,24 @@ public final class IntegerComponent<C extends CommandSender> extends CommandComp
}
}
/**
* Get the minimum value accepted by this parser
*
* @return Min value
*/
public int getMin() {
return this.min;
}
/**
* Get the maximum value accepted by this parser
*
* @return Max value
*/
public int getMax() {
return this.max;
}
}

View file

@ -0,0 +1,86 @@
//
// MIT License
//
// Copyright (c) 2020 Alexander Söderberg
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package com.intellectualsites.commands;
import com.google.common.reflect.TypeToken;
import com.intellectualsites.commands.annotations.specifier.Range;
import com.intellectualsites.commands.components.parser.ComponentParser;
import com.intellectualsites.commands.components.parser.ParserParameters;
import com.intellectualsites.commands.components.parser.ParserRegistry;
import com.intellectualsites.commands.components.parser.StandardParameters;
import com.intellectualsites.commands.components.parser.StandardParserRegistry;
import com.intellectualsites.commands.components.standard.IntegerComponent;
import com.intellectualsites.commands.sender.CommandSender;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import javax.annotation.Nonnull;
import java.lang.annotation.Annotation;
import java.util.Collections;
public class ParserRegistryTest {
public static final int RANGE_MIN = 10;
public static final int RANGE_MAX = 100;
@Test
void testParserRegistry() {
final ParserRegistry<CommandSender> parserRegistry = new StandardParserRegistry<>();
final Range range = new Range() {
@Override
public Class<? extends Annotation> annotationType() {
return Range.class;
}
@Nonnull
@Override
public String min() {
return Integer.toString(RANGE_MIN);
}
@Nonnull
@Override
public String max() {
return Integer.toString(RANGE_MAX);
}
};
final TypeToken<?> parsedType = TypeToken.of(int.class);
final ParserParameters parserParameters = parserRegistry.parseAnnotations(parsedType, Collections.singleton(range));
Assertions.assertTrue(parserParameters.has(StandardParameters.RANGE_MIN));
Assertions.assertTrue(parserParameters.has(StandardParameters.RANGE_MAX));
final ComponentParser<CommandSender, ?> parser = parserRegistry.createParser(parsedType,
parserParameters)
.orElseThrow(
() -> new NullPointerException("No parser found"));
Assertions.assertTrue(parser instanceof IntegerComponent.IntegerParser);
@SuppressWarnings("unchecked")
final IntegerComponent.IntegerParser<CommandSender> integerParser = (IntegerComponent.IntegerParser<CommandSender>) parser;
Assertions.assertEquals(RANGE_MIN, integerParser.getMin());
Assertions.assertEquals(RANGE_MAX, integerParser.getMax());
}
}