Started moving towards passing around one big reader, instead of lots of strings

This commit is contained in:
Nathan Adams 2017-07-25 15:07:58 +02:00
parent a7674e984d
commit 9e481e3f24
13 changed files with 560 additions and 366 deletions

View file

@ -0,0 +1,175 @@
package com.mojang.brigadier;
import com.mojang.brigadier.exceptions.CommandException;
import com.mojang.brigadier.exceptions.ParameterizedCommandExceptionType;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
public class StringReader {
private static final char SYNTAX_ESCAPE = '\\';
private static final char SYNTAX_QUOTE = '"';
public static final SimpleCommandExceptionType ERROR_EXPECTED_START_OF_QUOTE = new SimpleCommandExceptionType("parsing.quote.expected.start", "Expected quote to start a string");
public static final SimpleCommandExceptionType ERROR_EXPECTED_END_OF_QUOTE = new SimpleCommandExceptionType("parsing.quote.expected.end", "Unclosed quoted string");
public static final ParameterizedCommandExceptionType ERROR_INVALID_ESCAPE = new ParameterizedCommandExceptionType("parsing.quote.escape", "Invalid escape sequence '\\${character}' in quoted string)", "character");
public static final ParameterizedCommandExceptionType ERROR_INVALID_BOOL = new ParameterizedCommandExceptionType("parsing.bool.invalid", "Invalid bool, expected true or false but found '${value}'", "value");
public static final ParameterizedCommandExceptionType ERROR_INVALID_INT = new ParameterizedCommandExceptionType("parsing.int.invalid", "Invalid integer '${value}'", "value");
public static final SimpleCommandExceptionType ERROR_EXPECTED_INT = new SimpleCommandExceptionType("parsing.int.expected", "Expected integer");
public static final ParameterizedCommandExceptionType ERROR_INVALID_DOUBLE = new ParameterizedCommandExceptionType("parsing.double.invalid", "Invalid double '${value}'", "value");
public static final SimpleCommandExceptionType ERROR_EXPECTED_DOUBLE = new SimpleCommandExceptionType("parsing.double.expected", "Expected double");
private final String string;
private int cursor;
public StringReader(String string) {
this.string = string;
}
public String getString() {
return string;
}
public void setCursor(int cursor) {
this.cursor = cursor;
}
public int getRemainingLength() {
return string.length() - cursor;
}
public int getTotalLength() {
return string.length();
}
public int getCursor() {
return cursor;
}
public String getRead() {
return string.substring(0, cursor);
}
public String getRemaining() {
return string.substring(cursor);
}
public boolean canRead(final int length) {
return cursor + length <= string.length();
}
public boolean canRead() {
return canRead(1);
}
public char peek() {
return string.charAt(cursor);
}
public char read() {
return string.charAt(cursor++);
}
public void skip() {
cursor++;
}
private static boolean isAllowedNumber(final char c) {
return c >= '0' && c <= '9' || c == '.' || c == '-';
}
public int readInt() throws CommandException {
final int start = cursor;
while (canRead() && isAllowedNumber(peek())) {
skip();
}
final String number = string.substring(start, cursor);
if (number.isEmpty()) {
throw ERROR_EXPECTED_INT.create();
}
try {
return Integer.parseInt(number);
} catch (final NumberFormatException ex) {
throw ERROR_INVALID_INT.create(number);
}
}
public double readDouble() throws CommandException {
final int start = cursor;
while (canRead() && isAllowedNumber(peek())) {
skip();
}
final String number = string.substring(start, cursor);
if (number.isEmpty()) {
throw ERROR_EXPECTED_DOUBLE.create();
}
try {
return Double.parseDouble(number);
} catch (final NumberFormatException ex) {
throw ERROR_INVALID_DOUBLE.create(number);
}
}
private static boolean isAllowedInUnquotedString(final char c) {
return c >= '0' && c <= '9'
|| c >= 'A' && c <= 'Z'
|| c >= 'a' && c <= 'z'
|| c == '_' || c == '-'
|| c == '.' || c == '+';
}
public String readUnquotedString() throws CommandException {
final int start = cursor;
while (canRead() && isAllowedInUnquotedString(peek())) {
skip();
}
return string.substring(start, cursor);
}
public String readQuotedString() throws CommandException {
if (!canRead()) {
return "";
} else if (peek() != SYNTAX_QUOTE) {
throw ERROR_EXPECTED_START_OF_QUOTE.create();
}
skip();
final StringBuilder result = new StringBuilder();
boolean escaped = false;
while (canRead()) {
final char c = read();
if (escaped) {
if (c == SYNTAX_QUOTE || c == SYNTAX_ESCAPE) {
result.append(c);
escaped = false;
} else {
throw ERROR_INVALID_ESCAPE.create(String.valueOf(c));
}
} else if (c == SYNTAX_ESCAPE) {
escaped = true;
} else if (c == SYNTAX_QUOTE) {
return result.toString();
} else {
result.append(c);
}
}
throw ERROR_EXPECTED_END_OF_QUOTE.create();
}
public String readString() throws CommandException {
if (canRead() && peek() == SYNTAX_QUOTE) {
return readQuotedString();
} else {
return readUnquotedString();
}
}
public boolean readBoolean() throws CommandException {
String value = readString();
if (value.equals("true")) {
return true;
} else if (value.equals("false")) {
return false;
} else {
throw ERROR_INVALID_BOOL.create(value);
}
}
}

View file

@ -1,5 +1,6 @@
package com.mojang.brigadier.arguments;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.context.CommandContextBuilder;
import com.mojang.brigadier.context.ParsedArgument;
import com.mojang.brigadier.exceptions.CommandException;
@ -7,7 +8,13 @@ import com.mojang.brigadier.exceptions.CommandException;
import java.util.Set;
public interface ArgumentType<T> {
<S> ParsedArgument<S, T> parse(String command, CommandContextBuilder<S> contextBuilder) throws CommandException;
default <S> ParsedArgument<S, T> parse(String command, CommandContextBuilder<S> contextBuilder) throws CommandException {
StringReader reader = new StringReader(command);
T result = parse(reader, contextBuilder);
return new ParsedArgument<>(reader.getRead(), result);
}
<S> T parse(StringReader reader, CommandContextBuilder<S> contextBuilder) throws CommandException;
default <S> void listSuggestions(String command, Set<String> output, CommandContextBuilder<S> contextBuilder) {}

View file

@ -1,6 +1,7 @@
package com.mojang.brigadier.arguments;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.context.CommandContextBuilder;
import com.mojang.brigadier.context.ParsedArgument;
@ -22,20 +23,8 @@ public class BoolArgumentType implements ArgumentType<Boolean> {
}
@Override
public <S> ParsedArgument<S, Boolean> parse(String command, CommandContextBuilder<S> contextBuilder) throws CommandException {
int end = command.indexOf(CommandDispatcher.ARGUMENT_SEPARATOR);
String raw = command;
if (end > -1) {
raw = command.substring(0, end);
}
if (raw.equals("true")) {
return new ParsedArgument<>(raw, true);
} else if (raw.equals("false")) {
return new ParsedArgument<>(raw, false);
} else {
throw ERROR_INVALID.create();
}
public <S> Boolean parse(StringReader reader, CommandContextBuilder<S> contextBuilder) throws CommandException {
return reader.readBoolean();
}
@Override

View file

@ -1,29 +0,0 @@
package com.mojang.brigadier.arguments;
import com.mojang.brigadier.ParseResults;
import com.mojang.brigadier.context.CommandContextBuilder;
import com.mojang.brigadier.context.ParsedArgument;
import com.mojang.brigadier.exceptions.CommandException;
import java.util.Arrays;
import java.util.Set;
public class CommandArgumentType<T> implements ArgumentType<ParseResults<T>> {
public static <S> CommandArgumentType<S> command() {
return new CommandArgumentType<S>();
}
@Override
public <S> ParsedArgument<S, ParseResults<T>> parse(String command, CommandContextBuilder<S> contextBuilder) throws CommandException {
final ParseResults<S> parse = contextBuilder.getDispatcher().parse(command, contextBuilder.getSource());
//noinspection unchecked
return new ParsedArgument<>(command, (ParseResults<T>) parse);
}
@Override
public <S> void listSuggestions(String command, Set<String> output, CommandContextBuilder<S> contextBuilder) {
final String[] suggestions = contextBuilder.getDispatcher().getCompletionSuggestions(command, contextBuilder.getSource());
output.addAll(Arrays.asList(suggestions));
}
}

View file

@ -1,6 +1,7 @@
package com.mojang.brigadier.arguments;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.context.CommandContextBuilder;
import com.mojang.brigadier.context.ParsedArgument;
@ -10,7 +11,6 @@ import com.mojang.brigadier.exceptions.ParameterizedCommandExceptionType;
import java.util.Objects;
public class IntegerArgumentType implements ArgumentType<Integer> {
public static final ParameterizedCommandExceptionType ERROR_NOT_A_NUMBER = new ParameterizedCommandExceptionType("argument.integer.invalid", "Expected an integer, found '${found}'", "found");
public static final ParameterizedCommandExceptionType ERROR_WRONG_SUFFIX = new ParameterizedCommandExceptionType("argument.integer.wrongsuffix", "Expected suffix '${suffix}'", "suffix");
public static final ParameterizedCommandExceptionType ERROR_TOO_SMALL = new ParameterizedCommandExceptionType("argument.integer.low", "Integer must not be less than ${minimum}, found ${found}", "found", "minimum");
public static final ParameterizedCommandExceptionType ERROR_TOO_BIG = new ParameterizedCommandExceptionType("argument.integer.big", "Integer must not be more than ${maximum}, found ${found}", "found", "maximum");
@ -46,38 +46,22 @@ public class IntegerArgumentType implements ArgumentType<Integer> {
}
@Override
public <S> ParsedArgument<S, Integer> parse(String command, CommandContextBuilder<S> contextBuilder) throws CommandException {
int end = command.indexOf(CommandDispatcher.ARGUMENT_SEPARATOR);
String raw = command;
if (end > -1) {
raw = command.substring(0, end);
}
if (raw.length() < suffix.length()) {
throw ERROR_WRONG_SUFFIX.create(this.suffix);
}
String number = raw.substring(0, raw.length() - suffix.length());
String suffix = raw.substring(number.length());
if (!suffix.equals(this.suffix)) {
throw ERROR_WRONG_SUFFIX.create(this.suffix);
}
try {
int value = Integer.parseInt(number);
if (value < minimum) {
throw ERROR_TOO_SMALL.create(value, minimum);
public <S> Integer parse(StringReader reader, CommandContextBuilder<S> contextBuilder) throws CommandException {
int result = reader.readInt();
for (int i = 0; i < suffix.length(); i++) {
if (reader.canRead() && reader.peek() == suffix.charAt(i)) {
reader.skip();
} else {
throw ERROR_WRONG_SUFFIX.create(suffix);
}
if (value > maximum) {
throw ERROR_TOO_BIG.create(value, maximum);
}
return new ParsedArgument<>(raw, value);
} catch (NumberFormatException ignored) {
throw ERROR_NOT_A_NUMBER.create(number);
}
if (result < minimum) {
throw ERROR_TOO_SMALL.create(result, minimum);
}
if (result > maximum) {
throw ERROR_TOO_BIG.create(result, maximum);
}
return result;
}
@Override

View file

@ -1,6 +1,7 @@
package com.mojang.brigadier.arguments;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.context.CommandContextBuilder;
import com.mojang.brigadier.context.ParsedArgument;
@ -9,11 +10,6 @@ import com.mojang.brigadier.exceptions.ParameterizedCommandExceptionType;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
public class StringArgumentType implements ArgumentType<String> {
public static final ParameterizedCommandExceptionType ERROR_INVALID_ESCAPE = new ParameterizedCommandExceptionType("argument.string.escape.invalid", "Unknown or invalid escape sequence: ${input}", "input");
public static final SimpleCommandExceptionType ERROR_UNEXPECTED_ESCAPE = new SimpleCommandExceptionType("argument.string.escape.unexpected", "Unexpected escape sequence, please quote the whole argument");
public static final SimpleCommandExceptionType ERROR_UNEXPECTED_START_OF_QUOTE = new SimpleCommandExceptionType("argument.string.quote.unexpected_start", "Unexpected start-of-quote character (\"), please quote the whole argument");
public static final SimpleCommandExceptionType ERROR_UNEXPECTED_END_OF_QUOTE = new SimpleCommandExceptionType("argument.string.quote.unexpected_end", "Unexpected end-of-quote character (\"), it must be at the end or followed by a space (' ') for the next argument");
public static final SimpleCommandExceptionType ERROR_EXPECTED_END_OF_QUOTE = new SimpleCommandExceptionType("argument.string.quote.expected_end", "Expected end-of-quote character (\") but found no more input");
private final StringType type;
private StringArgumentType(StringType type) {
@ -37,59 +33,15 @@ public class StringArgumentType implements ArgumentType<String> {
}
@Override
public <S> ParsedArgument<S, String> parse(String command, CommandContextBuilder<S> contextBuilder) throws CommandException {
public <S> String parse(StringReader reader, CommandContextBuilder<S> contextBuilder) throws CommandException {
if (type == StringType.GREEDY_PHRASE) {
return new ParsedArgument<>(command, command);
String text = reader.getRemaining();
reader.setCursor(reader.getTotalLength());
return text;
} else if (type == StringType.SINGLE_WORD) {
int index = command.indexOf(CommandDispatcher.ARGUMENT_SEPARATOR);
if (index > 0) {
final String word = command.substring(0, index);
return new ParsedArgument<>(word, word);
} else {
return new ParsedArgument<>(command, command);
}
return reader.readUnquotedString();
} else {
StringBuilder result = new StringBuilder();
int i = 0;
boolean escaped = false;
boolean quoted = false;
while (i < command.length()) {
char c = command.charAt(i);
if (escaped) {
if (c == '"' || c == '\\') {
result.append(c);
} else {
throw ERROR_INVALID_ESCAPE.create("\\" + c);
}
escaped = false;
} else if (c == '\\') {
if (quoted) {
escaped = true;
} else {
throw ERROR_UNEXPECTED_ESCAPE.create();
}
} else if (c == '"') {
if (i == 0) {
quoted = true;
} else if (!quoted) {
throw ERROR_UNEXPECTED_START_OF_QUOTE.create();
} else if (i == command.length() - 1 || command.charAt(i + 1) == CommandDispatcher.ARGUMENT_SEPARATOR_CHAR) {
i++;
break;
} else {
throw ERROR_UNEXPECTED_END_OF_QUOTE.create();
}
} else if (!quoted && c == CommandDispatcher.ARGUMENT_SEPARATOR_CHAR) {
break;
} else if (quoted && i == command.length() - 1) {
throw ERROR_EXPECTED_END_OF_QUOTE.create();
} else {
result.append(c);
}
i++;
}
return new ParsedArgument<>(command.substring(0, i), result.toString());
return reader.readString();
}
}

View file

@ -168,8 +168,8 @@ public class CommandDispatcherTest {
subject.execute("foo bar", source);
fail();
} catch (CommandException ex) {
assertThat(ex.getType(), is(IntegerArgumentType.ERROR_NOT_A_NUMBER));
assertThat(ex.getData(), is(ImmutableMap.<String, Object>of("found", "bar")));
assertThat(ex.getType(), is(StringReader.ERROR_EXPECTED_INT));
assertThat(ex.getData(), is(Collections.emptyMap()));
}
}
}

View file

@ -0,0 +1,325 @@
package com.mojang.brigadier;
import com.google.common.collect.ImmutableMap;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.exceptions.CommandException;
import org.hamcrest.CoreMatchers;
import org.junit.Test;
import java.util.Collections;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
public class StringReaderTest {
@Test
public void canRead() throws Exception {
StringReader reader = new StringReader("abc");
assertThat(reader.canRead(), is(true));
reader.skip(); // 'a'
assertThat(reader.canRead(), is(true));
reader.skip(); // 'b'
assertThat(reader.canRead(), is(true));
reader.skip(); // 'c'
assertThat(reader.canRead(), is(false));
}
@Test
public void getRemainingLength() throws Exception {
StringReader reader = new StringReader("abc");
assertThat(reader.getRemainingLength(), is(3));
reader.setCursor(1);
assertThat(reader.getRemainingLength(), is(2));
reader.setCursor(2);
assertThat(reader.getRemainingLength(), is(1));
reader.setCursor(3);
assertThat(reader.getRemainingLength(), is(0));
}
@Test
public void canRead_length() throws Exception {
StringReader reader = new StringReader("abc");
assertThat(reader.canRead(1), is(true));
assertThat(reader.canRead(2), is(true));
assertThat(reader.canRead(3), is(true));
assertThat(reader.canRead(4), is(false));
assertThat(reader.canRead(5), is(false));
}
@Test
public void peek() throws Exception {
StringReader reader = new StringReader("abc");
assertThat(reader.peek(), is('a'));
assertThat(reader.getCursor(), is(0));
reader.setCursor(2);
assertThat(reader.peek(), is('c'));
assertThat(reader.getCursor(), is(2));
}
@Test
public void read() throws Exception {
StringReader reader = new StringReader("abc");
assertThat(reader.read(), is('a'));
assertThat(reader.read(), is('b'));
assertThat(reader.read(), is('c'));
assertThat(reader.getCursor(), is(3));
}
@Test
public void skip() throws Exception {
StringReader reader = new StringReader("abc");
reader.skip();
assertThat(reader.getCursor(), is(1));
}
@Test
public void getRemaining() throws Exception {
StringReader reader = new StringReader("Hello!");
assertThat(reader.getRemaining(), equalTo("Hello!"));
reader.setCursor(3);
assertThat(reader.getRemaining(), equalTo("lo!"));
reader.setCursor(6);
assertThat(reader.getRemaining(), equalTo(""));
}
@Test
public void getRead() throws Exception {
StringReader reader = new StringReader("Hello!");
assertThat(reader.getRead(), equalTo(""));
reader.setCursor(3);
assertThat(reader.getRead(), equalTo("Hel"));
reader.setCursor(6);
assertThat(reader.getRead(), equalTo("Hello!"));
}
@Test
public void readUnquotedString() throws Exception {
final StringReader reader = new StringReader("hello world");
assertThat(reader.readUnquotedString(), equalTo("hello"));
assertThat(reader.getRead(), equalTo("hello"));
assertThat(reader.getRemaining(), equalTo(" world"));
}
@Test
public void readUnquotedString_empty() throws Exception {
final StringReader reader = new StringReader("");
assertThat(reader.readUnquotedString(), equalTo(""));
assertThat(reader.getRead(), equalTo(""));
assertThat(reader.getRemaining(), equalTo(""));
}
@Test
public void readUnquotedString_empty_withRemaining() throws Exception {
final StringReader reader = new StringReader(" hello world");
assertThat(reader.readUnquotedString(), equalTo(""));
assertThat(reader.getRead(), equalTo(""));
assertThat(reader.getRemaining(), equalTo(" hello world"));
}
@Test
public void readQuotedString() throws Exception {
final StringReader reader = new StringReader("\"hello world\"");
assertThat(reader.readQuotedString(), equalTo("hello world"));
assertThat(reader.getRead(), equalTo("\"hello world\""));
assertThat(reader.getRemaining(), equalTo(""));
}
@Test
public void readQuotedString_empty() throws Exception {
final StringReader reader = new StringReader("");
assertThat(reader.readQuotedString(), equalTo(""));
assertThat(reader.getRead(), equalTo(""));
assertThat(reader.getRemaining(), equalTo(""));
}
@Test
public void readQuotedString_emptyQuoted() throws Exception {
final StringReader reader = new StringReader("\"\"");
assertThat(reader.readQuotedString(), equalTo(""));
assertThat(reader.getRead(), equalTo("\"\""));
assertThat(reader.getRemaining(), equalTo(""));
}
@Test
public void readQuotedString_emptyQuoted_withRemaining() throws Exception {
final StringReader reader = new StringReader("\"\" hello world");
assertThat(reader.readQuotedString(), equalTo(""));
assertThat(reader.getRead(), equalTo("\"\""));
assertThat(reader.getRemaining(), equalTo(" hello world"));
}
@Test
public void readQuotedString_withEscapedQuote() throws Exception {
final StringReader reader = new StringReader("\"hello \\\"world\\\"\"");
assertThat(reader.readQuotedString(), equalTo("hello \"world\""));
assertThat(reader.getRead(), equalTo("\"hello \\\"world\\\"\""));
assertThat(reader.getRemaining(), equalTo(""));
}
@Test
public void readQuotedString_withEscapedEscapes() throws Exception {
final StringReader reader = new StringReader("\"\\\\o/\"");
assertThat(reader.readQuotedString(), equalTo("\\o/"));
assertThat(reader.getRead(), equalTo("\"\\\\o/\""));
assertThat(reader.getRemaining(), equalTo(""));
}
@Test
public void readQuotedString_withRemaining() throws Exception {
final StringReader reader = new StringReader("\"hello world\" foo bar");
assertThat(reader.readQuotedString(), equalTo("hello world"));
assertThat(reader.getRead(), equalTo("\"hello world\""));
assertThat(reader.getRemaining(), equalTo(" foo bar"));
}
@Test
public void readQuotedString_withImmediateRemaining() throws Exception {
final StringReader reader = new StringReader("\"hello world\"foo bar");
assertThat(reader.readQuotedString(), equalTo("hello world"));
assertThat(reader.getRead(), equalTo("\"hello world\""));
assertThat(reader.getRemaining(), equalTo("foo bar"));
}
@Test
public void readQuotedString_noOpen() throws Exception {
try {
new StringReader("hello world\"").readQuotedString();
} catch (final CommandException ex) {
assertThat(ex.getType(), is(StringReader.ERROR_EXPECTED_START_OF_QUOTE));
assertThat(ex.getData(), equalTo(Collections.emptyMap()));
}
}
@Test
public void readQuotedString_noClose() throws Exception {
try {
new StringReader("\"hello world").readQuotedString();
} catch (final CommandException ex) {
assertThat(ex.getType(), is(StringReader.ERROR_EXPECTED_END_OF_QUOTE));
assertThat(ex.getData(), equalTo(Collections.emptyMap()));
}
}
@Test
public void readQuotedString_invalidEscape() throws Exception {
try {
new StringReader("\"hello\\nworld\"").readQuotedString();
} catch (final CommandException ex) {
assertThat(ex.getType(), is(StringReader.ERROR_INVALID_ESCAPE));
assertThat(ex.getData(), equalTo(ImmutableMap.of("character", "n")));
}
}
@Test
public void readInt() throws Exception {
final StringReader reader = new StringReader("1234567890");
assertThat(reader.readInt(), is(1234567890));
assertThat(reader.getRead(), equalTo("1234567890"));
assertThat(reader.getRemaining(), equalTo(""));
}
@Test
public void readInt_negative() throws Exception {
final StringReader reader = new StringReader("-1234567890");
assertThat(reader.readInt(), is(-1234567890));
assertThat(reader.getRead(), equalTo("-1234567890"));
assertThat(reader.getRemaining(), equalTo(""));
}
@Test
public void readInt_invalid() throws Exception {
try {
new StringReader("12.34").readInt();
} catch (final CommandException ex) {
assertThat(ex.getType(), is(StringReader.ERROR_INVALID_INT));
assertThat(ex.getData(), equalTo(ImmutableMap.of("value", "12.34")));
}
}
@Test
public void readInt_none() throws Exception {
try {
new StringReader("").readInt();
} catch (final CommandException ex) {
assertThat(ex.getType(), is(StringReader.ERROR_EXPECTED_INT));
assertThat(ex.getData(), equalTo(Collections.emptyMap()));
}
}
@Test
public void readInt_withRemaining() throws Exception {
final StringReader reader = new StringReader("1234567890 foo bar");
assertThat(reader.readInt(), is(1234567890));
assertThat(reader.getRead(), equalTo("1234567890"));
assertThat(reader.getRemaining(), equalTo(" foo bar"));
}
@Test
public void readInt_withRemainingImmediate() throws Exception {
final StringReader reader = new StringReader("1234567890foo bar");
assertThat(reader.readInt(), is(1234567890));
assertThat(reader.getRead(), equalTo("1234567890"));
assertThat(reader.getRemaining(), equalTo("foo bar"));
}
@Test
public void readDouble() throws Exception {
final StringReader reader = new StringReader("123");
assertThat(reader.readDouble(), is(123.0));
assertThat(reader.getRead(), equalTo("123"));
assertThat(reader.getRemaining(), equalTo(""));
}
@Test
public void readDouble_withDecimal() throws Exception {
final StringReader reader = new StringReader("12.34");
assertThat(reader.readDouble(), is(12.34));
assertThat(reader.getRead(), equalTo("12.34"));
assertThat(reader.getRemaining(), equalTo(""));
}
@Test
public void readDouble_negative() throws Exception {
final StringReader reader = new StringReader("-123");
assertThat(reader.readDouble(), is(-123.0));
assertThat(reader.getRead(), equalTo("-123"));
assertThat(reader.getRemaining(), equalTo(""));
}
@Test
public void readDouble_invalid() throws Exception {
try {
new StringReader("12.34.56").readDouble();
} catch (final CommandException ex) {
assertThat(ex.getType(), is(StringReader.ERROR_INVALID_DOUBLE));
assertThat(ex.getData(), equalTo(ImmutableMap.of("value", "12.34.56")));
}
}
@Test
public void readDouble_none() throws Exception {
try {
new StringReader("").readDouble();
} catch (final CommandException ex) {
assertThat(ex.getType(), is(StringReader.ERROR_EXPECTED_DOUBLE));
assertThat(ex.getData(), equalTo(Collections.emptyMap()));
}
}
@Test
public void readDouble_withRemaining() throws Exception {
final StringReader reader = new StringReader("12.34 foo bar");
assertThat(reader.readDouble(), is(12.34));
assertThat(reader.getRead(), equalTo("12.34"));
assertThat(reader.getRemaining(), equalTo(" foo bar"));
}
@Test
public void readDouble_withRemainingImmediate() throws Exception {
final StringReader reader = new StringReader("12.34foo bar");
assertThat(reader.readDouble(), is(12.34));
assertThat(reader.getRead(), equalTo("12.34"));
assertThat(reader.getRemaining(), equalTo("foo bar"));
}
}

View file

@ -1,5 +1,6 @@
package com.mojang.brigadier.arguments;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.context.CommandContextBuilder;
import com.mojang.brigadier.context.ParsedArgument;
import com.mojang.brigadier.exceptions.CommandException;
@ -7,6 +8,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import java.util.Collections;
@ -16,13 +18,14 @@ import static com.mojang.brigadier.arguments.BoolArgumentType.bool;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class BoolArgumentTypeTest {
private BoolArgumentType type;
@Mock
private Object source;
@Mock
private CommandContextBuilder<Object> context;
@Before
@ -31,54 +34,11 @@ public class BoolArgumentTypeTest {
}
@Test
public void parse_true() throws Exception {
ParsedArgument<Object, Boolean> parse = type.parse("true", context);
assertThat(parse.getResult(), is(true));
assertThat(parse.getRaw(), equalTo("true"));
}
@Test
public void parse_false() throws Exception {
ParsedArgument<Object, Boolean> parse = type.parse("false", context);
assertThat(parse.getResult(), is(false));
assertThat(parse.getRaw(), equalTo("false"));
}
@Test
public void parse_trailing() throws Exception {
ParsedArgument<Object, Boolean> parse = type.parse("false hello world", context);
assertThat(parse.getResult(), is(false));
assertThat(parse.getRaw(), equalTo("false"));
}
@Test
public void parse_invalid() throws Exception {
try {
type.parse("tuesday", context);
} catch (CommandException ex) {
assertThat(ex.getType(), is(ERROR_INVALID));
assertThat(ex.getData(), equalTo(Collections.emptyMap()));
}
}
@Test
public void parse_empty() throws Exception {
try {
type.parse("", context);
} catch (CommandException ex) {
assertThat(ex.getType(), is(ERROR_INVALID));
assertThat(ex.getData(), equalTo(Collections.emptyMap()));
}
}
@Test
public void parse_empty_remaining() throws Exception {
try {
type.parse(" true", context);
} catch (CommandException ex) {
assertThat(ex.getType(), is(ERROR_INVALID));
assertThat(ex.getData(), equalTo(Collections.emptyMap()));
}
public void parse() throws Exception {
StringReader reader = mock(StringReader.class);
when(reader.readBoolean()).thenReturn(true);
assertThat(type.parse(reader, context), is(true));
verify(reader).readBoolean();
}
@Test

View file

@ -1,64 +0,0 @@
package com.mojang.brigadier.arguments;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.ParseResults;
import com.mojang.brigadier.context.CommandContextBuilder;
import com.mojang.brigadier.context.ParsedArgument;
import com.mojang.brigadier.exceptions.CommandException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import java.util.Set;
import static com.mojang.brigadier.arguments.CommandArgumentType.command;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class CommandArgumentTypeTest {
@Mock
private Object source;
@Mock
private CommandDispatcher<Object> dispatcher;
@SuppressWarnings("unchecked")
@Test
public void testParse() throws Exception {
final ParseResults<Object> command = mock(ParseResults.class);
when(dispatcher.parse("hello world", source)).thenReturn(command);
final ParsedArgument<Object, ParseResults<Object>> argument = command().parse("hello world", new CommandContextBuilder<>(dispatcher, source));
assertThat(argument.getRaw(), equalTo("hello world"));
assertThat(argument.getResult(), is(command));
}
@SuppressWarnings("unchecked")
@Test
public void testParse_fail() throws Exception {
final CommandException thrown = mock(CommandException.class);
when(dispatcher.parse("hello world", source)).thenThrow(thrown);
try {
command().parse("hello world", new CommandContextBuilder<>(dispatcher, source));
fail();
} catch (CommandException exception) {
assertThat(exception, is(thrown));
}
}
@Test
public void listSuggestions() throws Exception {
Set<String> output = Sets.newHashSet();
when(dispatcher.getCompletionSuggestions("foo bar baz", source)).thenReturn(new String[] {"a", "b"});
command().listSuggestions("foo bar baz", output, new CommandContextBuilder<>(dispatcher, source));
verify(dispatcher).getCompletionSuggestions("foo bar baz", source);
assertThat(output, equalTo(ImmutableSet.of("a", "b")));
}
}

View file

@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import com.google.common.testing.EqualsTester;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.context.CommandContextBuilder;
import com.mojang.brigadier.context.ParsedArgument;
@ -15,6 +16,7 @@ import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import java.util.Collections;
import java.util.Set;
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
@ -40,6 +42,7 @@ public class IntegerArgumentTypeTest {
@Test
public void testParse() throws Exception {
ParsedArgument<Object, Integer> result = type.parse("50", new CommandContextBuilder<>(dispatcher, source));
assertThat(result.getRaw(), is("50"));
@ -78,13 +81,8 @@ public class IntegerArgumentTypeTest {
@Test
public void testParse_unexpectedSuffix() throws Exception {
try {
type.parse("50L", new CommandContextBuilder<>(dispatcher, source));
fail();
} catch (CommandException ex) {
assertThat(ex.getType(), is(IntegerArgumentType.ERROR_NOT_A_NUMBER));
assertThat(ex.getData(), is(ImmutableMap.<String, Object>of("found", "50L")));
}
type.parse("50L", new CommandContextBuilder<>(dispatcher, source));
// This has to pass, it's the responsibility of a node to decide "this isn't right, it's followed by text!"
}
@Test
@ -93,8 +91,8 @@ public class IntegerArgumentTypeTest {
type.parse("fifty", new CommandContextBuilder<>(dispatcher, source));
fail();
} catch (CommandException ex) {
assertThat(ex.getType(), is(IntegerArgumentType.ERROR_NOT_A_NUMBER));
assertThat(ex.getData(), is(ImmutableMap.<String, Object>of("found", "fifty")));
assertThat(ex.getType(), is(StringReader.ERROR_EXPECTED_INT));
assertThat(ex.getData(), is(Collections.emptyMap()));
}
}
@ -104,8 +102,8 @@ public class IntegerArgumentTypeTest {
type.parse("", new CommandContextBuilder<>(dispatcher, source));
fail();
} catch (CommandException ex) {
assertThat(ex.getType(), is(IntegerArgumentType.ERROR_NOT_A_NUMBER));
assertThat(ex.getData(), is(ImmutableMap.<String, Object>of("found", "")));
assertThat(ex.getType(), is(StringReader.ERROR_EXPECTED_INT));
assertThat(ex.getData(), is(Collections.emptyMap()));
}
}
@ -115,8 +113,8 @@ public class IntegerArgumentTypeTest {
integer(0, 100, "L").parse("", new CommandContextBuilder<>(dispatcher, source));
fail();
} catch (CommandException ex) {
assertThat(ex.getType(), is(IntegerArgumentType.ERROR_WRONG_SUFFIX));
assertThat(ex.getData(), is(ImmutableMap.<String, Object>of("suffix", "L")));
assertThat(ex.getType(), is(StringReader.ERROR_EXPECTED_INT));
assertThat(ex.getData(), is(Collections.emptyMap()));
}
}
@ -126,8 +124,8 @@ public class IntegerArgumentTypeTest {
integer(0, 100, "L").parse("L", new CommandContextBuilder<>(dispatcher, source));
fail();
} catch (CommandException ex) {
assertThat(ex.getType(), is(IntegerArgumentType.ERROR_NOT_A_NUMBER));
assertThat(ex.getData(), is(ImmutableMap.<String, Object>of("found", "")));
assertThat(ex.getType(), is(StringReader.ERROR_EXPECTED_INT));
assertThat(ex.getData(), is(Collections.emptyMap()));
}
}

View file

@ -4,21 +4,14 @@ import com.google.common.collect.Sets;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.context.CommandContextBuilder;
import com.mojang.brigadier.context.ParsedArgument;
import com.mojang.brigadier.exceptions.CommandException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import java.util.Collections;
import java.util.Set;
import static com.mojang.brigadier.arguments.StringArgumentType.ERROR_EXPECTED_END_OF_QUOTE;
import static com.mojang.brigadier.arguments.StringArgumentType.ERROR_INVALID_ESCAPE;
import static com.mojang.brigadier.arguments.StringArgumentType.ERROR_UNEXPECTED_END_OF_QUOTE;
import static com.mojang.brigadier.arguments.StringArgumentType.ERROR_UNEXPECTED_ESCAPE;
import static com.mojang.brigadier.arguments.StringArgumentType.ERROR_UNEXPECTED_START_OF_QUOTE;
import static com.mojang.brigadier.arguments.StringArgumentType.escapeIfRequired;
import static com.mojang.brigadier.arguments.StringArgumentType.greedyString;
import static com.mojang.brigadier.arguments.StringArgumentType.string;
@ -28,7 +21,6 @@ import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasToString;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
@RunWith(MockitoJUnitRunner.class)
public class StringArgumentTypeTest {
@ -97,8 +89,8 @@ public class StringArgumentTypeTest {
type = word();
ParsedArgument<Object, String> result = type.parse("\"hello \\\" world\"", new CommandContextBuilder<>(dispatcher, source));
assertThat(result.getRaw(), is("\"hello"));
assertThat(result.getResult(), is("\"hello"));
assertThat(result.getRaw(), is(""));
assertThat(result.getResult(), is(""));
}
@Test
@ -128,18 +120,6 @@ public class StringArgumentTypeTest {
assertThat(result.getResult(), is("hello"));
}
@Test
public void testParseInvalidQuote_earlyUnquote() throws Exception {
try {
type = string();
type.parse("\"hello \"world", new CommandContextBuilder<>(dispatcher, source));
fail();
} catch (CommandException e) {
assertThat(e.getType(), is(ERROR_UNEXPECTED_END_OF_QUOTE));
assertThat(e.getData(), is(equalTo(Collections.emptyMap())));
}
}
@Test
public void testParseQuote_earlyUnquoteWithRemaining() throws Exception {
type = string();
@ -149,18 +129,6 @@ public class StringArgumentTypeTest {
assertThat(result.getResult(), is("hello"));
}
@Test
public void testParseInvalidQuote_lateQuote() throws Exception {
try {
type = string();
type.parse("hello\" world\"", new CommandContextBuilder<>(dispatcher, source));
fail();
} catch (CommandException e) {
assertThat(e.getType(), is(ERROR_UNEXPECTED_START_OF_QUOTE));
assertThat(e.getData(), is(equalTo(Collections.emptyMap())));
}
}
@Test
public void testParseQuote_lateQuoteWithRemaining() throws Exception {
type = string();
@ -170,30 +138,6 @@ public class StringArgumentTypeTest {
assertThat(result.getResult(), is("hello"));
}
@Test
public void testParseInvalidQuote_middleQuote() throws Exception {
try {
type = string();
type.parse("hel\"lo", new CommandContextBuilder<>(dispatcher, source));
fail();
} catch (CommandException e) {
assertThat(e.getType(), is(ERROR_UNEXPECTED_START_OF_QUOTE));
assertThat(e.getData(), is(equalTo(Collections.emptyMap())));
}
}
@Test
public void testParseInvalidQuote_noUnquote() throws Exception {
try {
type = string();
type.parse("\"hello world", new CommandContextBuilder<>(dispatcher, source));
fail();
} catch (CommandException e) {
assertThat(e.getType(), is(ERROR_EXPECTED_END_OF_QUOTE));
assertThat(e.getData(), is(equalTo(Collections.emptyMap())));
}
}
@Test
public void testParseEmpty() throws Exception {
type = string();
@ -203,42 +147,6 @@ public class StringArgumentTypeTest {
assertThat(result.getResult(), is(""));
}
@Test
public void testParseInvalidEscape_onlyEscape() throws Exception {
try {
type = string();
type.parse("\\", new CommandContextBuilder<>(dispatcher, source));
fail();
} catch (CommandException e) {
assertThat(e.getType(), is(ERROR_UNEXPECTED_ESCAPE));
assertThat(e.getData(), is(equalTo(Collections.emptyMap())));
}
}
@Test
public void testParseInvalidEscape_unknownSequence() throws Exception {
try {
type = string();
type.parse("\"\\n\"", new CommandContextBuilder<>(dispatcher, source));
fail();
} catch (CommandException e) {
assertThat(e.getType(), is(ERROR_INVALID_ESCAPE));
assertThat(e.getData(), is(equalTo(Collections.singletonMap("input", "\\n"))));
}
}
@Test
public void testParseInvalidEscape_notQuoted() throws Exception {
try {
type = string();
type.parse("hel\\\\o", new CommandContextBuilder<>(dispatcher, source));
fail();
} catch (CommandException e) {
assertThat(e.getType(), is(ERROR_UNEXPECTED_ESCAPE));
assertThat(e.getData(), is(equalTo(Collections.emptyMap())));
}
}
@Test
public void testSuggestions() throws Exception {
type = string();

View file

@ -57,17 +57,6 @@ public class ArgumentCommandNodeTest extends AbstractCommandNodeTest {
assertThat(contextBuilder.getArguments().get("foo").getResult(), is(123));
}
@Test
public void testParseInvalid() throws Exception {
try {
node.parse("foo", contextBuilder);
fail();
} catch (CommandException ex) {
assertThat(ex.getType(), is(IntegerArgumentType.ERROR_NOT_A_NUMBER));
assertThat(ex.getData(), is(ImmutableMap.<String, Object>of("found", "foo")));
}
}
@Test
public void testUsage() throws Exception {
assertThat(node.getUsageText(), is("<foo: int>"));