mirror of
https://github.com/mat-1/azalea.git
synced 2024-09-20 07:02:31 +00:00
410 lines
12 KiB
Rust
Executable file
410 lines
12 KiB
Rust
Executable file
use std::rc::Rc;
|
|
|
|
use azalea_brigadier::{
|
|
arguments::integer_argument_type::integer,
|
|
builder::{literal_argument_builder::literal, required_argument_builder::argument},
|
|
command_dispatcher::CommandDispatcher,
|
|
context::CommandContext,
|
|
exceptions::{BuiltInExceptions, CommandSyntaxException},
|
|
string_reader::StringReader,
|
|
};
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
struct CommandSource {}
|
|
|
|
fn input_with_offset(input: &str, offset: usize) -> StringReader {
|
|
let mut result: StringReader = input.into();
|
|
result.cursor = offset;
|
|
result
|
|
}
|
|
|
|
#[test]
|
|
fn create_and_execute_command() {
|
|
let mut subject = CommandDispatcher::new();
|
|
subject.register(literal("foo").executes(|_| 42));
|
|
|
|
assert_eq!(
|
|
subject
|
|
.execute("foo".into(), Rc::new(CommandSource {}))
|
|
.unwrap(),
|
|
42
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn create_and_execute_offset_command() {
|
|
let mut subject = CommandDispatcher::new();
|
|
subject.register(literal("foo").executes(|_| 42));
|
|
|
|
assert_eq!(
|
|
subject
|
|
.execute(input_with_offset("/foo", 1), Rc::new(CommandSource {}))
|
|
.unwrap(),
|
|
42
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn create_and_merge_commands() {
|
|
let mut subject = CommandDispatcher::new();
|
|
subject.register(literal("base").then(literal("foo").executes(|_| 42)));
|
|
subject.register(literal("base").then(literal("bar").executes(|_| 42)));
|
|
|
|
assert_eq!(
|
|
subject
|
|
.execute("base foo".into(), Rc::new(CommandSource {}))
|
|
.unwrap(),
|
|
42
|
|
);
|
|
assert_eq!(
|
|
subject
|
|
.execute("base bar".into(), Rc::new(CommandSource {}))
|
|
.unwrap(),
|
|
42
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn execute_unknown_command() {
|
|
let mut subject = CommandDispatcher::new();
|
|
subject.register(literal("bar"));
|
|
subject.register(literal("baz"));
|
|
|
|
let execute_result = subject.execute("foo".into(), Rc::new(CommandSource {}));
|
|
|
|
let err = execute_result.err().unwrap();
|
|
match err.type_ {
|
|
BuiltInExceptions::DispatcherUnknownCommand => {}
|
|
_ => panic!("Unexpected error"),
|
|
}
|
|
assert_eq!(err.cursor().unwrap(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn execute_impermissible_command() {
|
|
let mut subject = CommandDispatcher::new();
|
|
subject.register(literal("foo").requires(|_| false));
|
|
|
|
let execute_result = subject.execute("foo".into(), Rc::new(CommandSource {}));
|
|
|
|
let err = execute_result.err().unwrap();
|
|
match err.type_ {
|
|
BuiltInExceptions::DispatcherUnknownCommand => {}
|
|
_ => panic!("Unexpected error"),
|
|
}
|
|
assert_eq!(err.cursor().unwrap(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn execute_empty_command() {
|
|
let mut subject = CommandDispatcher::new();
|
|
subject.register(literal(""));
|
|
|
|
let execute_result = subject.execute("".into(), Rc::new(CommandSource {}));
|
|
|
|
let err = execute_result.err().unwrap();
|
|
match err.type_ {
|
|
BuiltInExceptions::DispatcherUnknownCommand => {}
|
|
_ => panic!("Unexpected error"),
|
|
}
|
|
assert_eq!(err.cursor().unwrap(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn execute_unknown_subcommand() {
|
|
let mut subject = CommandDispatcher::new();
|
|
subject.register(literal("foo").executes(|_| 42));
|
|
|
|
let execute_result = subject.execute("foo bar".into(), Rc::new(CommandSource {}));
|
|
|
|
let err = execute_result.err().unwrap();
|
|
match err.type_ {
|
|
BuiltInExceptions::DispatcherUnknownArgument => {}
|
|
_ => panic!("Unexpected error"),
|
|
}
|
|
assert_eq!(err.cursor().unwrap(), 4);
|
|
}
|
|
|
|
#[test]
|
|
fn execute_incorrect_literal() {
|
|
let mut subject = CommandDispatcher::new();
|
|
subject.register(literal("foo").executes(|_| 42).then(literal("bar")));
|
|
|
|
let execute_result = subject.execute("foo baz".into(), Rc::new(CommandSource {}));
|
|
|
|
let err = execute_result.err().unwrap();
|
|
match err.type_ {
|
|
BuiltInExceptions::DispatcherUnknownArgument => {}
|
|
_ => panic!("Unexpected error"),
|
|
}
|
|
assert_eq!(err.cursor().unwrap(), 4);
|
|
}
|
|
|
|
#[test]
|
|
fn execute_ambiguous_incorrect_argument() {
|
|
let mut subject = CommandDispatcher::new();
|
|
subject.register(
|
|
literal("foo")
|
|
.executes(|_| 42)
|
|
.then(literal("bar"))
|
|
.then(literal("baz")),
|
|
);
|
|
|
|
let execute_result = subject.execute("foo unknown".into(), Rc::new(CommandSource {}));
|
|
|
|
let err = execute_result.err().unwrap();
|
|
match err.type_ {
|
|
BuiltInExceptions::DispatcherUnknownArgument => {}
|
|
_ => panic!("Unexpected error"),
|
|
}
|
|
assert_eq!(err.cursor().unwrap(), 4);
|
|
}
|
|
|
|
#[test]
|
|
fn execute_subcommand() {
|
|
let mut subject = CommandDispatcher::new();
|
|
|
|
subject.register(
|
|
literal("foo")
|
|
.then(literal("a"))
|
|
.then(literal("=").executes(|_| 100))
|
|
.then(literal("c"))
|
|
.executes(|_| 42),
|
|
);
|
|
|
|
assert_eq!(
|
|
subject
|
|
.execute("foo =".into(), Rc::new(CommandSource {}))
|
|
.unwrap(),
|
|
100
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn parse_incomplete_literal() {
|
|
let mut subject = CommandDispatcher::new();
|
|
subject.register(literal("foo").then(literal("bar").executes(|_| 42)));
|
|
|
|
let parse = subject.parse("foo ".into(), Rc::new(CommandSource {}));
|
|
assert_eq!(parse.reader.remaining(), " ");
|
|
assert_eq!(parse.context.nodes.len(), 1);
|
|
}
|
|
|
|
#[test]
|
|
fn parse_incomplete_argument() {
|
|
let mut subject = CommandDispatcher::new();
|
|
subject.register(literal("foo").then(argument("bar", integer()).executes(|_| 42)));
|
|
|
|
let parse = subject.parse("foo ".into(), Rc::new(CommandSource {}));
|
|
assert_eq!(parse.reader.remaining(), " ");
|
|
assert_eq!(parse.context.nodes.len(), 1);
|
|
}
|
|
|
|
#[test]
|
|
fn execute_ambiguious_parent_subcommand() {
|
|
let mut subject = CommandDispatcher::new();
|
|
|
|
subject.register(
|
|
literal("test")
|
|
.then(argument("incorrect", integer()).executes(|_| 42))
|
|
.then(argument("right", integer()).then(argument("sub", integer()).executes(|_| 100))),
|
|
);
|
|
|
|
assert_eq!(
|
|
subject
|
|
.execute("test 1 2".into(), Rc::new(CommandSource {}))
|
|
.unwrap(),
|
|
100
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn execute_ambiguious_parent_subcommand_via_redirect() {
|
|
let mut subject = CommandDispatcher::new();
|
|
|
|
let real = subject.register(
|
|
literal("test")
|
|
.then(argument("incorrect", integer()).executes(|_| 42))
|
|
.then(argument("right", integer()).then(argument("sub", integer()).executes(|_| 100))),
|
|
);
|
|
|
|
subject.register(literal("redirect").redirect(real));
|
|
|
|
assert_eq!(
|
|
subject
|
|
.execute("redirect 1 2".into(), Rc::new(CommandSource {}))
|
|
.unwrap(),
|
|
100
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn execute_redirected_multiple_times() {
|
|
let mut subject = CommandDispatcher::new();
|
|
|
|
let concrete_node = subject.register(literal("actual").executes(|_| 42));
|
|
let root = subject.root.clone();
|
|
let redirect_node = subject.register(literal("redirected").redirect(root.clone()));
|
|
|
|
let input = "redirected redirected actual";
|
|
|
|
let parse = subject.parse(input.into(), Rc::new(CommandSource {}));
|
|
assert_eq!(parse.context.range.get(input), "redirected");
|
|
assert_eq!(parse.context.nodes.len(), 1);
|
|
assert_eq!(parse.context.root, root);
|
|
assert_eq!(parse.context.nodes[0].range, parse.context.range);
|
|
assert_eq!(parse.context.nodes[0].node, redirect_node);
|
|
|
|
let child1 = parse.context.child.clone();
|
|
assert!(child1.is_some());
|
|
assert_eq!(child1.clone().unwrap().range.get(input), "redirected");
|
|
assert_eq!(child1.clone().unwrap().nodes.len(), 1);
|
|
assert_eq!(child1.clone().unwrap().root, root);
|
|
assert_eq!(
|
|
child1.clone().unwrap().nodes[0].range,
|
|
child1.clone().unwrap().range
|
|
);
|
|
assert_eq!(child1.clone().unwrap().nodes[0].node, redirect_node);
|
|
|
|
let child2 = child1.unwrap().child.clone();
|
|
assert!(child2.is_some());
|
|
assert_eq!(child2.clone().unwrap().range.get(input), "actual");
|
|
assert_eq!(child2.clone().unwrap().nodes.len(), 1);
|
|
assert_eq!(child2.clone().unwrap().root, root);
|
|
assert_eq!(
|
|
child2.clone().unwrap().nodes[0].range,
|
|
child2.clone().unwrap().range
|
|
);
|
|
assert_eq!(child2.clone().unwrap().nodes[0].node, concrete_node);
|
|
|
|
assert_eq!(CommandDispatcher::execute_parsed(parse).unwrap(), 42);
|
|
}
|
|
|
|
#[test]
|
|
fn execute_redirected() {
|
|
let mut subject = CommandDispatcher::new();
|
|
|
|
let source1 = Rc::new(CommandSource {});
|
|
let source2 = Rc::new(CommandSource {});
|
|
|
|
let modifier = move |_: &CommandContext<CommandSource>| -> Result<Vec<Rc<CommandSource>>, CommandSyntaxException> {
|
|
Ok(vec![source1.clone(), source2.clone()])
|
|
};
|
|
|
|
let concrete_node = subject.register(literal("actual").executes(|_| 42));
|
|
let redirect_node =
|
|
subject.register(literal("redirected").fork(subject.root.clone(), Rc::new(modifier)));
|
|
|
|
let input = "redirected actual";
|
|
let parse = subject.parse(input.into(), Rc::new(CommandSource {}));
|
|
assert_eq!(parse.context.range.get(input), "redirected");
|
|
assert_eq!(parse.context.nodes.len(), 1);
|
|
assert_eq!(parse.context.root, subject.root);
|
|
assert_eq!(parse.context.nodes[0].range, parse.context.range);
|
|
assert_eq!(parse.context.nodes[0].node, redirect_node);
|
|
|
|
let parent = parse.context.child.clone();
|
|
assert!(parent.is_some());
|
|
let parent = parent.unwrap();
|
|
assert_eq!(parent.range.get(input), "actual");
|
|
assert_eq!(parent.nodes.len(), 1);
|
|
assert_eq!(parse.context.root, subject.root);
|
|
assert_eq!(parent.nodes[0].range, parent.range);
|
|
assert_eq!(parent.nodes[0].node, concrete_node);
|
|
assert_eq!(parent.source, Rc::new(CommandSource {}));
|
|
|
|
assert_eq!(CommandDispatcher::execute_parsed(parse).unwrap(), 2);
|
|
}
|
|
|
|
#[test]
|
|
fn execute_orphaned_subcommand() {
|
|
let mut subject = CommandDispatcher::new();
|
|
|
|
subject.register(
|
|
literal("foo")
|
|
.then(argument("bar", integer()))
|
|
.executes(|_| 42),
|
|
);
|
|
|
|
let result = subject.execute("foo 5".into(), Rc::new(CommandSource {}));
|
|
assert!(result.is_err());
|
|
let result = result.unwrap_err();
|
|
assert_eq!(
|
|
*result.get_type(),
|
|
BuiltInExceptions::DispatcherUnknownCommand
|
|
);
|
|
assert_eq!(result.cursor(), Some(5));
|
|
}
|
|
|
|
#[test]
|
|
fn execute_invalid_other() {
|
|
let mut subject = CommandDispatcher::new();
|
|
|
|
subject.register(literal("w").executes(|_| panic!("This should not run")));
|
|
subject.register(literal("world").executes(|_| 42));
|
|
|
|
assert_eq!(
|
|
subject
|
|
.execute("world".into(), Rc::new(CommandSource {}))
|
|
.unwrap(),
|
|
42
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn parse_no_space_separator() {
|
|
let mut subject = CommandDispatcher::new();
|
|
|
|
subject.register(
|
|
literal("foo")
|
|
.then(argument("bar", integer()))
|
|
.executes(|_| 42),
|
|
);
|
|
|
|
let result = subject.execute("foo$".into(), Rc::new(CommandSource {}));
|
|
assert!(result.is_err());
|
|
let result = result.unwrap_err();
|
|
assert_eq!(
|
|
*result.get_type(),
|
|
BuiltInExceptions::DispatcherUnknownCommand
|
|
);
|
|
assert_eq!(result.cursor(), Some(0));
|
|
}
|
|
|
|
#[test]
|
|
fn execute_invalid_subcommand() {
|
|
let mut subject = CommandDispatcher::new();
|
|
|
|
subject.register(
|
|
literal("foo")
|
|
.then(argument("bar", integer()))
|
|
.executes(|_| 42),
|
|
);
|
|
|
|
let result = subject.execute("foo bar".into(), Rc::new(CommandSource {}));
|
|
assert!(result.is_err());
|
|
let result = result.unwrap_err();
|
|
// this fails for some reason, i blame mojang
|
|
// assert_eq!(*result.get_type(), BuiltInExceptions::ReaderExpectedInt);
|
|
assert_eq!(result.cursor(), Some(4));
|
|
}
|
|
|
|
#[test]
|
|
fn get_path() {
|
|
let mut subject = CommandDispatcher::<()>::new();
|
|
|
|
let bar = literal("bar").build();
|
|
subject.register(literal("foo").then_built(bar.clone()));
|
|
|
|
assert_eq!(
|
|
subject.get_path(bar),
|
|
vec!["foo".to_string(), "bar".to_string()]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn find_node_doesnt_exist() {
|
|
let subject = CommandDispatcher::<()>::new();
|
|
|
|
assert_eq!(subject.find_node(&vec!["foo", "bar"]), None)
|
|
}
|