Made all exceptions throw with context

This commit is contained in:
Nathan Adams 2017-07-27 09:58:14 +02:00
parent 9276feddd4
commit 5181559f46
16 changed files with 275 additions and 61 deletions

View file

@ -22,7 +22,7 @@ import java.util.stream.Collectors;
public class CommandDispatcher<S> { public class CommandDispatcher<S> {
public static final SimpleCommandExceptionType ERROR_UNKNOWN_COMMAND = new SimpleCommandExceptionType("command.unknown.command", "Unknown command"); public static final SimpleCommandExceptionType ERROR_UNKNOWN_COMMAND = new SimpleCommandExceptionType("command.unknown.command", "Unknown command");
public static final ParameterizedCommandExceptionType ERROR_UNKNOWN_ARGUMENT = new ParameterizedCommandExceptionType("command.unknown.argument", "Incorrect argument for command, couldn't parse: ${argument}", "argument"); public static final SimpleCommandExceptionType ERROR_UNKNOWN_ARGUMENT = new SimpleCommandExceptionType("command.unknown.argument", "Incorrect argument for command");
public static final SimpleCommandExceptionType ERROR_EXPECTED_ARGUMENT_SEPARATOR = new SimpleCommandExceptionType("command.expected.separator", "Expected whitespace to end one argument, but found trailing data"); public static final SimpleCommandExceptionType ERROR_EXPECTED_ARGUMENT_SEPARATOR = new SimpleCommandExceptionType("command.expected.separator", "Expected whitespace to end one argument, but found trailing data");
public static final String ARGUMENT_SEPARATOR = " "; public static final String ARGUMENT_SEPARATOR = " ";
@ -52,19 +52,19 @@ public class CommandDispatcher<S> {
} }
public int execute(final ParseResults<S> parse) throws CommandException { public int execute(final ParseResults<S> parse) throws CommandException {
if (parse.getRemaining().length() > 0) { if (parse.getReader().canRead()) {
if (parse.getExceptions().size() == 1) { if (parse.getExceptions().size() == 1) {
throw parse.getExceptions().values().iterator().next(); throw parse.getExceptions().values().iterator().next();
} else if (parse.getContext().getInput().isEmpty()) { } else if (parse.getContext().getInput().isEmpty()) {
throw ERROR_UNKNOWN_COMMAND.create(); throw ERROR_UNKNOWN_COMMAND.createWithContext(parse.getReader());
} else { } else {
throw ERROR_UNKNOWN_ARGUMENT.create(parse.getRemaining()); throw ERROR_UNKNOWN_ARGUMENT.createWithContext(parse.getReader());
} }
} }
final CommandContext<S> context = parse.getContext().build(); final CommandContext<S> context = parse.getContext().build();
final Command<S> command = context.getCommand(); final Command<S> command = context.getCommand();
if (command == null) { if (command == null) {
throw ERROR_UNKNOWN_COMMAND.create(); throw ERROR_UNKNOWN_COMMAND.createWithContext(parse.getReader());
} }
return command.run(context); return command.run(context);
} }
@ -95,7 +95,7 @@ public class CommandDispatcher<S> {
context.withCommand(child.getCommand()); context.withCommand(child.getCommand());
if (reader.canRead()) { if (reader.canRead()) {
if (reader.peek() != ARGUMENT_SEPARATOR_CHAR) { if (reader.peek() != ARGUMENT_SEPARATOR_CHAR) {
throw ERROR_EXPECTED_ARGUMENT_SEPARATOR.create(); throw ERROR_EXPECTED_ARGUMENT_SEPARATOR.createWithContext(reader);
} }
reader.skip(); reader.skip();
return parseNodes(child, reader, context); return parseNodes(child, reader, context);
@ -104,7 +104,7 @@ public class CommandDispatcher<S> {
} }
} }
return new ParseResults<>(contextBuilder, reader.getRemaining(), errors); return new ParseResults<>(contextBuilder, reader, errors);
} }
public String[] getAllUsage(final CommandNode<S> node, final S source) { public String[] getAllUsage(final CommandNode<S> node, final S source) {

View file

@ -0,0 +1,23 @@
package com.mojang.brigadier;
public interface ImmutableStringReader {
String getString();
int getRemainingLength();
int getTotalLength();
int getCursor();
String getRead();
String getRemaining();
boolean canRead(int length);
boolean canRead();
char peek();
char peek(int offset);
}

View file

@ -9,25 +9,25 @@ import java.util.Map;
public class ParseResults<S> { public class ParseResults<S> {
private final CommandContextBuilder<S> context; private final CommandContextBuilder<S> context;
private final String remaining;
private final Map<CommandNode<S>, CommandException> exceptions; private final Map<CommandNode<S>, CommandException> exceptions;
private final ImmutableStringReader reader;
public ParseResults(final CommandContextBuilder<S> context, final String remaining, final Map<CommandNode<S>, CommandException> exceptions) { public ParseResults(final CommandContextBuilder<S> context, final ImmutableStringReader reader, final Map<CommandNode<S>, CommandException> exceptions) {
this.context = context; this.context = context;
this.remaining = remaining; this.reader = reader;
this.exceptions = exceptions; this.exceptions = exceptions;
} }
public ParseResults(final CommandContextBuilder<S> context) { public ParseResults(final CommandContextBuilder<S> context) {
this(context, "", Collections.emptyMap()); this(context, new StringReader(""), Collections.emptyMap());
} }
public CommandContextBuilder<S> getContext() { public CommandContextBuilder<S> getContext() {
return context; return context;
} }
public String getRemaining() { public ImmutableStringReader getReader() {
return remaining; return reader;
} }
public Map<CommandNode<S>, CommandException> getExceptions() { public Map<CommandNode<S>, CommandException> getExceptions() {

View file

@ -4,7 +4,7 @@ import com.mojang.brigadier.exceptions.CommandException;
import com.mojang.brigadier.exceptions.ParameterizedCommandExceptionType; import com.mojang.brigadier.exceptions.ParameterizedCommandExceptionType;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
public class StringReader { public class StringReader implements ImmutableStringReader {
private static final char SYNTAX_ESCAPE = '\\'; private static final char SYNTAX_ESCAPE = '\\';
private static final char SYNTAX_QUOTE = '"'; private static final char SYNTAX_QUOTE = '"';
@ -16,6 +16,7 @@ public class StringReader {
public static final SimpleCommandExceptionType ERROR_EXPECTED_INT = new SimpleCommandExceptionType("parsing.int.expected", "Expected integer"); 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 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"); public static final SimpleCommandExceptionType ERROR_EXPECTED_DOUBLE = new SimpleCommandExceptionType("parsing.double.expected", "Expected double");
public static final SimpleCommandExceptionType ERROR_EXPECTED_BOOL = new SimpleCommandExceptionType("parsing.bool.expected", "Expected bool");
public static final ParameterizedCommandExceptionType ERROR_EXPECTED_SYMBOL = new ParameterizedCommandExceptionType("parsing.expected", "Expected '${symbol}'", "symbol"); public static final ParameterizedCommandExceptionType ERROR_EXPECTED_SYMBOL = new ParameterizedCommandExceptionType("parsing.expected", "Expected '${symbol}'", "symbol");
private final String string; private final String string;
@ -25,6 +26,7 @@ public class StringReader {
this.string = string; this.string = string;
} }
@Override
public String getString() { public String getString() {
return string; return string;
} }
@ -33,38 +35,47 @@ public class StringReader {
this.cursor = cursor; this.cursor = cursor;
} }
@Override
public int getRemainingLength() { public int getRemainingLength() {
return string.length() - cursor; return string.length() - cursor;
} }
@Override
public int getTotalLength() { public int getTotalLength() {
return string.length(); return string.length();
} }
@Override
public int getCursor() { public int getCursor() {
return cursor; return cursor;
} }
@Override
public String getRead() { public String getRead() {
return string.substring(0, cursor); return string.substring(0, cursor);
} }
@Override
public String getRemaining() { public String getRemaining() {
return string.substring(cursor); return string.substring(cursor);
} }
@Override
public boolean canRead(final int length) { public boolean canRead(final int length) {
return cursor + length <= string.length(); return cursor + length <= string.length();
} }
@Override
public boolean canRead() { public boolean canRead() {
return canRead(1); return canRead(1);
} }
@Override
public char peek() { public char peek() {
return string.charAt(cursor); return string.charAt(cursor);
} }
@Override
public char peek(final int offset) { public char peek(final int offset) {
return string.charAt(cursor + offset); return string.charAt(cursor + offset);
} }
@ -94,12 +105,13 @@ public class StringReader {
} }
final String number = string.substring(start, cursor); final String number = string.substring(start, cursor);
if (number.isEmpty()) { if (number.isEmpty()) {
throw ERROR_EXPECTED_INT.create(); throw ERROR_EXPECTED_INT.createWithContext(this);
} }
try { try {
return Integer.parseInt(number); return Integer.parseInt(number);
} catch (final NumberFormatException ex) { } catch (final NumberFormatException ex) {
throw ERROR_INVALID_INT.create(number); cursor = start;
throw ERROR_INVALID_INT.createWithContext(this, number);
} }
} }
@ -110,12 +122,13 @@ public class StringReader {
} }
final String number = string.substring(start, cursor); final String number = string.substring(start, cursor);
if (number.isEmpty()) { if (number.isEmpty()) {
throw ERROR_EXPECTED_DOUBLE.create(); throw ERROR_EXPECTED_DOUBLE.createWithContext(this);
} }
try { try {
return Double.parseDouble(number); return Double.parseDouble(number);
} catch (final NumberFormatException ex) { } catch (final NumberFormatException ex) {
throw ERROR_INVALID_DOUBLE.create(number); cursor = start;
throw ERROR_INVALID_DOUBLE.createWithContext(this, number);
} }
} }
@ -139,7 +152,7 @@ public class StringReader {
if (!canRead()) { if (!canRead()) {
return ""; return "";
} else if (peek() != SYNTAX_QUOTE) { } else if (peek() != SYNTAX_QUOTE) {
throw ERROR_EXPECTED_START_OF_QUOTE.create(); throw ERROR_EXPECTED_START_OF_QUOTE.createWithContext(this);
} }
skip(); skip();
final StringBuilder result = new StringBuilder(); final StringBuilder result = new StringBuilder();
@ -151,7 +164,8 @@ public class StringReader {
result.append(c); result.append(c);
escaped = false; escaped = false;
} else { } else {
throw ERROR_INVALID_ESCAPE.create(String.valueOf(c)); setCursor(getCursor() - 1);
throw ERROR_INVALID_ESCAPE.createWithContext(this, String.valueOf(c));
} }
} else if (c == SYNTAX_ESCAPE) { } else if (c == SYNTAX_ESCAPE) {
escaped = true; escaped = true;
@ -162,7 +176,7 @@ public class StringReader {
} }
} }
throw ERROR_EXPECTED_END_OF_QUOTE.create(); throw ERROR_EXPECTED_END_OF_QUOTE.createWithContext(this);
} }
public String readString() throws CommandException { public String readString() throws CommandException {
@ -174,19 +188,25 @@ public class StringReader {
} }
public boolean readBoolean() throws CommandException { public boolean readBoolean() throws CommandException {
final int start = cursor;
final String value = readString(); final String value = readString();
if (value.isEmpty()) {
throw ERROR_EXPECTED_BOOL.createWithContext(this);
}
if (value.equals("true")) { if (value.equals("true")) {
return true; return true;
} else if (value.equals("false")) { } else if (value.equals("false")) {
return false; return false;
} else { } else {
throw ERROR_INVALID_BOOL.create(value); cursor = start;
throw ERROR_INVALID_BOOL.createWithContext(this, value);
} }
} }
public void expect(final char c) throws CommandException { public void expect(final char c) throws CommandException {
if (!canRead() || peek() != c) { if (!canRead() || peek() != c) {
throw ERROR_EXPECTED_SYMBOL.create(String.valueOf(c)); throw ERROR_EXPECTED_SYMBOL.createWithContext(this, String.valueOf(c));
} }
skip(); skip();
} }

View file

@ -45,19 +45,23 @@ public class IntegerArgumentType implements ArgumentType<Integer> {
@Override @Override
public <S> Integer parse(final StringReader reader, final CommandContextBuilder<S> contextBuilder) throws CommandException { public <S> Integer parse(final StringReader reader, final CommandContextBuilder<S> contextBuilder) throws CommandException {
final int start = reader.getCursor();
final int result = reader.readInt(); final int result = reader.readInt();
for (int i = 0; i < suffix.length(); i++) { for (int i = 0; i < suffix.length(); i++) {
if (reader.canRead() && reader.peek() == suffix.charAt(i)) { if (reader.canRead() && reader.peek() == suffix.charAt(i)) {
reader.skip(); reader.skip();
} else { } else {
throw ERROR_WRONG_SUFFIX.create(suffix); reader.setCursor(start);
throw ERROR_WRONG_SUFFIX.createWithContext(reader, suffix);
} }
} }
if (result < minimum) { if (result < minimum) {
throw ERROR_TOO_SMALL.create(result, minimum); reader.setCursor(start);
throw ERROR_TOO_SMALL.createWithContext(reader, result, minimum);
} }
if (result > maximum) { if (result > maximum) {
throw ERROR_TOO_BIG.create(result, maximum); reader.setCursor(start);
throw ERROR_TOO_BIG.createWithContext(reader, result, maximum);
} }
return result; return result;
} }

View file

@ -3,27 +3,70 @@ package com.mojang.brigadier.exceptions;
import java.util.Map; import java.util.Map;
public class CommandException extends Exception { public class CommandException extends Exception {
public static final int CONTEXT_AMOUNT = 10;
public static boolean ENABLE_COMMAND_STACK_TRACES = true; public static boolean ENABLE_COMMAND_STACK_TRACES = true;
private final CommandExceptionType type; private final CommandExceptionType type;
private final Map<String, Object> data; private final Map<String, String> data;
private final String input;
private final int cursor;
public CommandException(final CommandExceptionType type, final Map<String, Object> data) { public CommandException(final CommandExceptionType type, final Map<String, String> data) {
super(type.getTypeName(), null, ENABLE_COMMAND_STACK_TRACES, ENABLE_COMMAND_STACK_TRACES); super(type.getTypeName(), null, ENABLE_COMMAND_STACK_TRACES, ENABLE_COMMAND_STACK_TRACES);
this.type = type; this.type = type;
this.data = data; this.data = data;
this.input = null;
this.cursor = -1;
}
public CommandException(final CommandExceptionType type, final Map<String, String> data, final String input, final int cursor) {
super(type.getTypeName(), null, ENABLE_COMMAND_STACK_TRACES, ENABLE_COMMAND_STACK_TRACES);
this.type = type;
this.data = data;
this.input = input;
this.cursor = cursor;
} }
@Override @Override
public String getMessage() { public String getMessage() {
return type.getErrorMessage(this); String message = type.getErrorMessage(data);
final String context = getContext();
if (context != null) {
message += " at position " + cursor + ": " + context;
}
return message;
}
public String getContext() {
if (input == null || cursor < 0) {
return null;
}
final StringBuilder builder = new StringBuilder();
final int cursor = Math.min(input.length(), this.cursor);
if (cursor > CONTEXT_AMOUNT) {
builder.append("...");
}
builder.append(input.substring(Math.max(0, cursor - CONTEXT_AMOUNT), cursor));
builder.append("<--[HERE]");
return builder.toString();
} }
public CommandExceptionType getType() { public CommandExceptionType getType() {
return type; return type;
} }
public Map<String, Object> getData() { public Map<String, String> getData() {
return data; return data;
} }
public String getInput() {
return input;
}
public int getCursor() {
return cursor;
}
} }

View file

@ -1,7 +1,9 @@
package com.mojang.brigadier.exceptions; package com.mojang.brigadier.exceptions;
import java.util.Map;
public interface CommandExceptionType { public interface CommandExceptionType {
String getTypeName(); String getTypeName();
String getErrorMessage(CommandException exception); String getErrorMessage(Map<String, String> data);
} }

View file

@ -2,7 +2,10 @@ package com.mojang.brigadier.exceptions;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.mojang.brigadier.ImmutableStringReader;
import com.mojang.brigadier.StringReader;
import java.util.Map;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -26,28 +29,31 @@ public class ParameterizedCommandExceptionType implements CommandExceptionType {
} }
@Override @Override
public String getErrorMessage(final CommandException exception) { public String getErrorMessage(final Map<String, String> data) {
final Matcher matcher = PATTERN.matcher(message); final Matcher matcher = PATTERN.matcher(message);
final StringBuffer result = new StringBuffer(); final StringBuffer result = new StringBuffer();
while (matcher.find()) { while (matcher.find()) {
matcher.appendReplacement(result, Matcher.quoteReplacement(exception.getData().get(matcher.group(1)).toString())); matcher.appendReplacement(result, Matcher.quoteReplacement(data.get(matcher.group(1))));
} }
matcher.appendTail(result); matcher.appendTail(result);
return result.toString(); return result.toString();
} }
public CommandException create(final Object... values) { public CommandException createWithContext(final ImmutableStringReader reader, final Object... values) {
return new CommandException(this, createMap(values), reader.getString(), reader.getCursor());
}
public Map<String, String> createMap(final Object... values) {
if (values.length != keys.length) { if (values.length != keys.length) {
throw new IllegalArgumentException("Invalid values! (Expected: " + JOINER.join(keys) + ")"); throw new IllegalArgumentException("Invalid values! (Expected: " + JOINER.join(keys) + ")");
} }
ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder(); ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
for (int i = 0; i < keys.length; i++) { for (int i = 0; i < keys.length; i++) {
builder = builder.put(keys[i], values[i]); builder = builder.put(keys[i], String.valueOf(values[i]));
} }
return builder.build();
return new CommandException(this, builder.build());
} }
@Override @Override

View file

@ -1,6 +1,10 @@
package com.mojang.brigadier.exceptions; package com.mojang.brigadier.exceptions;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.mojang.brigadier.ImmutableStringReader;
import com.mojang.brigadier.StringReader;
import java.util.Map;
public class SimpleCommandExceptionType implements CommandExceptionType { public class SimpleCommandExceptionType implements CommandExceptionType {
private final String name; private final String name;
@ -17,12 +21,12 @@ public class SimpleCommandExceptionType implements CommandExceptionType {
} }
@Override @Override
public String getErrorMessage(final CommandException exception) { public String getErrorMessage(final Map<String, String> data) {
return message; return message;
} }
public CommandException create() { public CommandException createWithContext(final ImmutableStringReader reader) {
return new CommandException(this, ImmutableMap.of()); return new CommandException(this, ImmutableMap.of(), reader.getString(), reader.getCursor());
} }
@Override @Override

View file

@ -31,11 +31,13 @@ public class LiteralCommandNode<S> extends CommandNode<S> {
@Override @Override
public void parse(final StringReader reader, final CommandContextBuilder<S> contextBuilder) throws CommandException { public void parse(final StringReader reader, final CommandContextBuilder<S> contextBuilder) throws CommandException {
final int start = reader.getCursor();
for (int i = 0; i < literal.length(); i++) { for (int i = 0; i < literal.length(); i++) {
if (reader.canRead() && reader.peek() == literal.charAt(i)) { if (reader.canRead() && reader.peek() == literal.charAt(i)) {
reader.skip(); reader.skip();
} else { } else {
throw ERROR_INCORRECT_LITERAL.create(literal); reader.setCursor(start);
throw ERROR_INCORRECT_LITERAL.createWithContext(reader, literal);
} }
} }

View file

@ -68,6 +68,7 @@ public class CommandDispatcherTest {
} catch (final CommandException ex) { } catch (final CommandException ex) {
assertThat(ex.getType(), is(CommandDispatcher.ERROR_UNKNOWN_COMMAND)); assertThat(ex.getType(), is(CommandDispatcher.ERROR_UNKNOWN_COMMAND));
assertThat(ex.getData(), is(Collections.<String, Object>emptyMap())); assertThat(ex.getData(), is(Collections.<String, Object>emptyMap()));
assertThat(ex.getCursor(), is(0));
} }
} }
@ -81,6 +82,7 @@ public class CommandDispatcherTest {
} catch (final CommandException ex) { } catch (final CommandException ex) {
assertThat(ex.getType(), is(CommandDispatcher.ERROR_UNKNOWN_COMMAND)); assertThat(ex.getType(), is(CommandDispatcher.ERROR_UNKNOWN_COMMAND));
assertThat(ex.getData(), is(Collections.<String, Object>emptyMap())); assertThat(ex.getData(), is(Collections.<String, Object>emptyMap()));
assertThat(ex.getCursor(), is(0));
} }
} }
@ -94,6 +96,7 @@ public class CommandDispatcherTest {
} catch (final CommandException ex) { } catch (final CommandException ex) {
assertThat(ex.getType(), is(CommandDispatcher.ERROR_UNKNOWN_COMMAND)); assertThat(ex.getType(), is(CommandDispatcher.ERROR_UNKNOWN_COMMAND));
assertThat(ex.getData(), is(Collections.<String, Object>emptyMap())); assertThat(ex.getData(), is(Collections.<String, Object>emptyMap()));
assertThat(ex.getCursor(), is(0));
} }
} }
@ -106,7 +109,8 @@ public class CommandDispatcherTest {
fail(); fail();
} catch (final CommandException ex) { } catch (final CommandException ex) {
assertThat(ex.getType(), is(CommandDispatcher.ERROR_UNKNOWN_ARGUMENT)); assertThat(ex.getType(), is(CommandDispatcher.ERROR_UNKNOWN_ARGUMENT));
assertThat(ex.getData(), is(Collections.singletonMap("argument", "bar"))); assertThat(ex.getData(), is(Collections.emptyMap()));
assertThat(ex.getCursor(), is(4));
} }
} }
@ -120,6 +124,7 @@ public class CommandDispatcherTest {
} catch (final CommandException ex) { } catch (final CommandException ex) {
assertThat(ex.getType(), is(LiteralCommandNode.ERROR_INCORRECT_LITERAL)); assertThat(ex.getType(), is(LiteralCommandNode.ERROR_INCORRECT_LITERAL));
assertThat(ex.getData(), is(Collections.singletonMap("expected", "bar"))); assertThat(ex.getData(), is(Collections.singletonMap("expected", "bar")));
assertThat(ex.getCursor(), is(4));
} }
} }
@ -136,7 +141,8 @@ public class CommandDispatcherTest {
fail(); fail();
} catch (final CommandException ex) { } catch (final CommandException ex) {
assertThat(ex.getType(), is(CommandDispatcher.ERROR_UNKNOWN_ARGUMENT)); assertThat(ex.getType(), is(CommandDispatcher.ERROR_UNKNOWN_ARGUMENT));
assertThat(ex.getData(), is(Collections.singletonMap("argument", "unknown"))); assertThat(ex.getData(), is(Collections.emptyMap()));
assertThat(ex.getCursor(), is(4));
} }
} }
@ -158,6 +164,36 @@ public class CommandDispatcherTest {
verify(subCommand).run(any(CommandContext.class)); verify(subCommand).run(any(CommandContext.class));
} }
@Test
public void testExecuteOrphanedSubcommand() throws Exception {
subject.register(literal("foo").then(
argument("bar", integer())
).executes(command));
try {
subject.execute("foo 5", source);
fail();
} catch (final CommandException ex) {
assertThat(ex.getType(), is(CommandDispatcher.ERROR_UNKNOWN_COMMAND));
assertThat(ex.getData(), is(Collections.emptyMap()));
assertThat(ex.getCursor(), is(0));
}
}
@Test
public void parse_noSpaceSeparator() throws Exception {
subject.register(literal("foo").then(argument("bar", integer()).executes(command)));
try {
subject.execute("foo5", source);
fail();
} catch (final CommandException ex) {
assertThat(ex.getType(), is(CommandDispatcher.ERROR_EXPECTED_ARGUMENT_SEPARATOR));
assertThat(ex.getData(), is(Collections.emptyMap()));
assertThat(ex.getCursor(), is(3));
}
}
@Test @Test
public void testExecuteInvalidSubcommand() throws Exception { public void testExecuteInvalidSubcommand() throws Exception {
subject.register(literal("foo").then( subject.register(literal("foo").then(
@ -170,6 +206,7 @@ public class CommandDispatcherTest {
} catch (final CommandException ex) { } catch (final CommandException ex) {
assertThat(ex.getType(), is(StringReader.ERROR_EXPECTED_INT)); assertThat(ex.getType(), is(StringReader.ERROR_EXPECTED_INT));
assertThat(ex.getData(), is(Collections.emptyMap())); assertThat(ex.getData(), is(Collections.emptyMap()));
assertThat(ex.getCursor(), is(4));
} }
} }
} }

View file

@ -219,6 +219,7 @@ public class StringReaderTest {
} catch (final CommandException ex) { } catch (final CommandException ex) {
assertThat(ex.getType(), is(StringReader.ERROR_EXPECTED_START_OF_QUOTE)); assertThat(ex.getType(), is(StringReader.ERROR_EXPECTED_START_OF_QUOTE));
assertThat(ex.getData(), equalTo(Collections.emptyMap())); assertThat(ex.getData(), equalTo(Collections.emptyMap()));
assertThat(ex.getCursor(), is(0));
} }
} }
@ -229,6 +230,7 @@ public class StringReaderTest {
} catch (final CommandException ex) { } catch (final CommandException ex) {
assertThat(ex.getType(), is(StringReader.ERROR_EXPECTED_END_OF_QUOTE)); assertThat(ex.getType(), is(StringReader.ERROR_EXPECTED_END_OF_QUOTE));
assertThat(ex.getData(), equalTo(Collections.emptyMap())); assertThat(ex.getData(), equalTo(Collections.emptyMap()));
assertThat(ex.getCursor(), is(12));
} }
} }
@ -239,6 +241,7 @@ public class StringReaderTest {
} catch (final CommandException ex) { } catch (final CommandException ex) {
assertThat(ex.getType(), is(StringReader.ERROR_INVALID_ESCAPE)); assertThat(ex.getType(), is(StringReader.ERROR_INVALID_ESCAPE));
assertThat(ex.getData(), equalTo(ImmutableMap.of("character", "n"))); assertThat(ex.getData(), equalTo(ImmutableMap.of("character", "n")));
assertThat(ex.getCursor(), is(7));
} }
} }
@ -265,6 +268,7 @@ public class StringReaderTest {
} catch (final CommandException ex) { } catch (final CommandException ex) {
assertThat(ex.getType(), is(StringReader.ERROR_INVALID_INT)); assertThat(ex.getType(), is(StringReader.ERROR_INVALID_INT));
assertThat(ex.getData(), equalTo(ImmutableMap.of("value", "12.34"))); assertThat(ex.getData(), equalTo(ImmutableMap.of("value", "12.34")));
assertThat(ex.getCursor(), is(0));
} }
} }
@ -275,6 +279,7 @@ public class StringReaderTest {
} catch (final CommandException ex) { } catch (final CommandException ex) {
assertThat(ex.getType(), is(StringReader.ERROR_EXPECTED_INT)); assertThat(ex.getType(), is(StringReader.ERROR_EXPECTED_INT));
assertThat(ex.getData(), equalTo(Collections.emptyMap())); assertThat(ex.getData(), equalTo(Collections.emptyMap()));
assertThat(ex.getCursor(), is(0));
} }
} }
@ -325,6 +330,7 @@ public class StringReaderTest {
} catch (final CommandException ex) { } catch (final CommandException ex) {
assertThat(ex.getType(), is(StringReader.ERROR_INVALID_DOUBLE)); assertThat(ex.getType(), is(StringReader.ERROR_INVALID_DOUBLE));
assertThat(ex.getData(), equalTo(ImmutableMap.of("value", "12.34.56"))); assertThat(ex.getData(), equalTo(ImmutableMap.of("value", "12.34.56")));
assertThat(ex.getCursor(), is(0));
} }
} }
@ -335,6 +341,7 @@ public class StringReaderTest {
} catch (final CommandException ex) { } catch (final CommandException ex) {
assertThat(ex.getType(), is(StringReader.ERROR_EXPECTED_DOUBLE)); assertThat(ex.getType(), is(StringReader.ERROR_EXPECTED_DOUBLE));
assertThat(ex.getData(), equalTo(Collections.emptyMap())); assertThat(ex.getData(), equalTo(Collections.emptyMap()));
assertThat(ex.getCursor(), is(0));
} }
} }
@ -370,6 +377,7 @@ public class StringReaderTest {
} catch (final CommandException ex) { } catch (final CommandException ex) {
assertThat(ex.getType(), is(StringReader.ERROR_EXPECTED_SYMBOL)); assertThat(ex.getType(), is(StringReader.ERROR_EXPECTED_SYMBOL));
assertThat(ex.getData(), equalTo(ImmutableMap.of("symbol", "a"))); assertThat(ex.getData(), equalTo(ImmutableMap.of("symbol", "a")));
assertThat(ex.getCursor(), is(0));
} }
} }
@ -382,6 +390,40 @@ public class StringReaderTest {
} catch (final CommandException ex) { } catch (final CommandException ex) {
assertThat(ex.getType(), is(StringReader.ERROR_EXPECTED_SYMBOL)); assertThat(ex.getType(), is(StringReader.ERROR_EXPECTED_SYMBOL));
assertThat(ex.getData(), equalTo(ImmutableMap.of("symbol", "a"))); assertThat(ex.getData(), equalTo(ImmutableMap.of("symbol", "a")));
assertThat(ex.getCursor(), is(0));
}
}
@Test
public void readBoolean_correct() throws Exception {
final StringReader reader = new StringReader("true");
assertThat(reader.readBoolean(), is(true));
assertThat(reader.getRead(), equalTo("true"));
}
@Test
public void readBoolean_incorrect() throws Exception {
final StringReader reader = new StringReader("tuesday");
try {
reader.readBoolean();
fail();
} catch (final CommandException ex) {
assertThat(ex.getType(), is(StringReader.ERROR_INVALID_BOOL));
assertThat(ex.getData(), equalTo(ImmutableMap.of("value", "tuesday")));
assertThat(ex.getCursor(), is(0));
}
}
@Test
public void readBoolean_none() throws Exception {
final StringReader reader = new StringReader("");
try {
reader.readBoolean();
fail();
} catch (final CommandException ex) {
assertThat(ex.getType(), is(StringReader.ERROR_EXPECTED_BOOL));
assertThat(ex.getData(), equalTo(Collections.emptyMap()));
assertThat(ex.getCursor(), is(0));
} }
} }
} }

View file

@ -57,6 +57,7 @@ public class IntegerArgumentTypeTest {
} catch (final CommandException ex) { } catch (final CommandException ex) {
assertThat(ex.getType(), is(IntegerArgumentType.ERROR_WRONG_SUFFIX)); assertThat(ex.getType(), is(IntegerArgumentType.ERROR_WRONG_SUFFIX));
assertThat(ex.getData(), equalTo(ImmutableMap.<String, Object>of("suffix", "L"))); assertThat(ex.getData(), equalTo(ImmutableMap.<String, Object>of("suffix", "L")));
assertThat(ex.getCursor(), is(0));
} }
} }
@ -69,6 +70,7 @@ public class IntegerArgumentTypeTest {
} catch (final CommandException ex) { } catch (final CommandException ex) {
assertThat(ex.getType(), is(IntegerArgumentType.ERROR_WRONG_SUFFIX)); assertThat(ex.getType(), is(IntegerArgumentType.ERROR_WRONG_SUFFIX));
assertThat(ex.getData(), equalTo(ImmutableMap.<String, Object>of("suffix", "L"))); assertThat(ex.getData(), equalTo(ImmutableMap.<String, Object>of("suffix", "L")));
assertThat(ex.getCursor(), is(0));
} }
} }
@ -80,7 +82,8 @@ public class IntegerArgumentTypeTest {
fail(); fail();
} catch (final CommandException ex) { } catch (final CommandException ex) {
assertThat(ex.getType(), is(IntegerArgumentType.ERROR_TOO_SMALL)); assertThat(ex.getType(), is(IntegerArgumentType.ERROR_TOO_SMALL));
assertThat(ex.getData(), equalTo(ImmutableMap.<String, Object>of("found", -5, "minimum", 0))); assertThat(ex.getData(), equalTo(ImmutableMap.<String, Object>of("found", "-5", "minimum", "0")));
assertThat(ex.getCursor(), is(0));
} }
} }
@ -92,7 +95,8 @@ public class IntegerArgumentTypeTest {
fail(); fail();
} catch (final CommandException ex) { } catch (final CommandException ex) {
assertThat(ex.getType(), is(IntegerArgumentType.ERROR_TOO_BIG)); assertThat(ex.getType(), is(IntegerArgumentType.ERROR_TOO_BIG));
assertThat(ex.getData(), equalTo(ImmutableMap.<String, Object>of("found", 5, "maximum", 0))); assertThat(ex.getData(), equalTo(ImmutableMap.<String, Object>of("found", "5", "maximum", "0")));
assertThat(ex.getCursor(), is(0));
} }
} }

View file

@ -2,10 +2,12 @@ package com.mojang.brigadier.exceptions;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.testing.EqualsTester; import com.google.common.testing.EqualsTester;
import com.mojang.brigadier.StringReader;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
@SuppressWarnings("ThrowableResultOfMethodCallIgnored") @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
@ -18,21 +20,19 @@ public class ParameterizedCommandExceptionTypeTest {
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void testCreateTooFewArguments() throws Exception { public void createMap_TooManyArguments() throws Exception {
type.create(); type.createMap("World", "Universe");
}
@Test(expected = IllegalArgumentException.class)
public void testCreateTooManyArguments() throws Exception {
type.create("World", "Universe");
} }
@Test @Test
public void testCreate() throws Exception { public void createWithContext() throws Exception {
final CommandException exception = type.create("World"); final StringReader reader = new StringReader("Foo bar");
reader.setCursor(5);
final CommandException exception = type.createWithContext(reader, "World");
assertThat(exception.getType(), is(type)); assertThat(exception.getType(), is(type));
assertThat(exception.getData(), is(ImmutableMap.<String, Object>of("name", "World"))); assertThat(exception.getData(), is(ImmutableMap.<String, Object>of("name", "World")));
assertThat(exception.getMessage(), is("Hello, World!")); assertThat(exception.getInput(), is("Foo bar"));
assertThat(exception.getCursor(), is(5));
} }
@Test @Test

View file

@ -1,21 +1,29 @@
package com.mojang.brigadier.exceptions; package com.mojang.brigadier.exceptions;
import com.google.common.testing.EqualsTester; import com.google.common.testing.EqualsTester;
import com.mojang.brigadier.StringReader;
import org.junit.Test; import org.junit.Test;
import static org.hamcrest.Matchers.empty; import java.util.Collections;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
@SuppressWarnings("ThrowableResultOfMethodCallIgnored") @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
public class SimpleCommandExceptionTypeTest { public class SimpleCommandExceptionTypeTest {
@Test @Test
public void testCreate() throws Exception { public void createWithContext() throws Exception {
final SimpleCommandExceptionType type = new SimpleCommandExceptionType("foo", "bar"); final SimpleCommandExceptionType type = new SimpleCommandExceptionType("foo", "bar");
final CommandException exception = type.create(); final StringReader reader = new StringReader("Foo bar");
reader.setCursor(5);
final CommandException exception = type.createWithContext(reader);
assertThat(exception.getType(), is(type)); assertThat(exception.getType(), is(type));
assertThat(exception.getMessage(), is("bar")); assertThat(exception.getData(), is(Collections.emptyMap()));
assertThat(exception.getData().values(), empty()); assertThat(exception.getInput(), is("Foo bar"));
assertThat(exception.getCursor(), is(5));
} }
@Test @Test
@ -25,4 +33,22 @@ public class SimpleCommandExceptionTypeTest {
.addEqualityGroup(new SimpleCommandExceptionType("bar", "Hello, world!"), new SimpleCommandExceptionType("bar", "Hello, universe!")) .addEqualityGroup(new SimpleCommandExceptionType("bar", "Hello, world!"), new SimpleCommandExceptionType("bar", "Hello, universe!"))
.testEquals(); .testEquals();
} }
@Test
public void getContext_none() throws Exception {
final CommandException exception = new CommandException(mock(CommandExceptionType.class), Collections.emptyMap());
assertThat(exception.getContext(), is(nullValue()));
}
@Test
public void getContext_short() throws Exception {
final CommandException exception = new CommandException(mock(CommandExceptionType.class), Collections.emptyMap(), "Hello world!", 5);
assertThat(exception.getContext(), equalTo("Hello<--[HERE]"));
}
@Test
public void getContext_long() throws Exception {
final CommandException exception = new CommandException(mock(CommandExceptionType.class), Collections.emptyMap(), "Hello world! This has an error in it. Oh dear!", 20);
assertThat(exception.getContext(), equalTo("...d! This ha<--[HERE]"));
}
} }

View file

@ -69,6 +69,7 @@ public class LiteralCommandNodeTest extends AbstractCommandNodeTest {
} catch (final CommandException ex) { } catch (final CommandException ex) {
assertThat(ex.getType(), is(LiteralCommandNode.ERROR_INCORRECT_LITERAL)); assertThat(ex.getType(), is(LiteralCommandNode.ERROR_INCORRECT_LITERAL));
assertThat(ex.getData(), is(ImmutableMap.<String, Object>of("expected", "foo"))); assertThat(ex.getData(), is(ImmutableMap.<String, Object>of("expected", "foo")));
assertThat(ex.getCursor(), is(0));
} }
} }