aboutsummaryrefslogtreecommitdiff
path: root/azalea-brigadier/tests
diff options
context:
space:
mode:
authormat <github@matdoes.dev>2022-04-24 17:37:57 -0500
committermat <github@matdoes.dev>2022-04-24 17:37:57 -0500
commit3e507f0db4020eaf406ba69aae3d4dc1301d29ac (patch)
treeca6c127c9db6dfd14511e98944fc031fe5f1e43a /azalea-brigadier/tests
parent9f576c5600ba9a244bc0d433bb7de174284066a2 (diff)
parentb7641ff308aab7840d2a2253ae50f8ee496b2a97 (diff)
downloadazalea-drasl-3e507f0db4020eaf406ba69aae3d4dc1301d29ac.tar.xz
Merge branch 'main' into auth
Diffstat (limited to 'azalea-brigadier/tests')
-rwxr-xr-xazalea-brigadier/tests/arguments/bool_argument_type_test.rs0
-rwxr-xr-xazalea-brigadier/tests/arguments/double_argument_type_test.rs0
-rwxr-xr-xazalea-brigadier/tests/arguments/float_argument_type_test.rs0
-rwxr-xr-xazalea-brigadier/tests/arguments/integer_argument_type_test.rs0
-rwxr-xr-xazalea-brigadier/tests/arguments/long_argument_type_test.rs0
-rwxr-xr-xazalea-brigadier/tests/arguments/string_argument_type_test.rs0
-rwxr-xr-xazalea-brigadier/tests/builder/argument_builder_test.rs75
-rwxr-xr-xazalea-brigadier/tests/builder/literal_argument_builder_test.rs0
-rwxr-xr-xazalea-brigadier/tests/builder/required_argument_builder_test.rs0
-rwxr-xr-xazalea-brigadier/tests/command_dispatcher_test.rs410
-rwxr-xr-xazalea-brigadier/tests/command_dispatcher_usages_test.rs1
-rwxr-xr-xazalea-brigadier/tests/command_suggestions_test.rs1
-rwxr-xr-xazalea-brigadier/tests/context/command_context_test.rs0
-rwxr-xr-xazalea-brigadier/tests/context/parsed_argument_test.rs0
-rwxr-xr-xazalea-brigadier/tests/exceptions/dynamic_command_syntax_exception_type_test.rs0
-rwxr-xr-xazalea-brigadier/tests/exceptions/simple_command_syntax_exception_type_test.rs0
-rwxr-xr-xazalea-brigadier/tests/string_reader_test.rs612
-rwxr-xr-xazalea-brigadier/tests/suggestion/suggestion_test.rs0
-rwxr-xr-xazalea-brigadier/tests/suggestion/suggestions_builder_test.rs0
-rwxr-xr-xazalea-brigadier/tests/suggestion/suggestions_test.rs0
-rwxr-xr-xazalea-brigadier/tests/tree/abstract_command_node_test.rs0
-rwxr-xr-xazalea-brigadier/tests/tree/argument_command_node_test.rs0
-rwxr-xr-xazalea-brigadier/tests/tree/literal_command_node_test.rs0
-rwxr-xr-xazalea-brigadier/tests/tree/root_command_node_test.rs0
24 files changed, 1099 insertions, 0 deletions
diff --git a/azalea-brigadier/tests/arguments/bool_argument_type_test.rs b/azalea-brigadier/tests/arguments/bool_argument_type_test.rs
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/azalea-brigadier/tests/arguments/bool_argument_type_test.rs
diff --git a/azalea-brigadier/tests/arguments/double_argument_type_test.rs b/azalea-brigadier/tests/arguments/double_argument_type_test.rs
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/azalea-brigadier/tests/arguments/double_argument_type_test.rs
diff --git a/azalea-brigadier/tests/arguments/float_argument_type_test.rs b/azalea-brigadier/tests/arguments/float_argument_type_test.rs
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/azalea-brigadier/tests/arguments/float_argument_type_test.rs
diff --git a/azalea-brigadier/tests/arguments/integer_argument_type_test.rs b/azalea-brigadier/tests/arguments/integer_argument_type_test.rs
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/azalea-brigadier/tests/arguments/integer_argument_type_test.rs
diff --git a/azalea-brigadier/tests/arguments/long_argument_type_test.rs b/azalea-brigadier/tests/arguments/long_argument_type_test.rs
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/azalea-brigadier/tests/arguments/long_argument_type_test.rs
diff --git a/azalea-brigadier/tests/arguments/string_argument_type_test.rs b/azalea-brigadier/tests/arguments/string_argument_type_test.rs
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/azalea-brigadier/tests/arguments/string_argument_type_test.rs
diff --git a/azalea-brigadier/tests/builder/argument_builder_test.rs b/azalea-brigadier/tests/builder/argument_builder_test.rs
new file mode 100755
index 00000000..e570c988
--- /dev/null
+++ b/azalea-brigadier/tests/builder/argument_builder_test.rs
@@ -0,0 +1,75 @@
+use std::rc::Rc;
+
+use crate::{
+ arguments::integer_argument_type::integer,
+ builder::{literal_argument_builder::literal, required_argument_builder::argument},
+};
+
+use super::ArgumentBuilder;
+
+// public class ArgumentBuilderTest {
+// private TestableArgumentBuilder<Object> builder;
+
+// @Before
+// public void setUp() throws Exception {
+// builder = new TestableArgumentBuilder<>();
+// }
+
+// @Test
+// public void testArguments() throws Exception {
+// final RequiredArgumentBuilder<Object, ?> argument = argument("bar", integer());
+
+// builder.then(argument);
+
+// assertThat(builder.getArguments(), hasSize(1));
+// assertThat(builder.getArguments(), hasItem((CommandNode<Object>) argument.build()));
+// }
+
+#[test]
+fn test_arguments() {
+ let mut builder: ArgumentBuilder<()> = literal("foo");
+
+ let argument: ArgumentBuilder<()> = argument("bar", integer());
+ builder.then(argument.clone());
+ assert_eq!(builder.arguments.children.len(), 1);
+ let built_argument = Rc::new(argument.build());
+ assert!(builder
+ .arguments
+ .children
+ .values()
+ .any(|e| *e.borrow() == *built_argument));
+}
+
+// @Test
+// public void testRedirect() throws Exception {
+// final CommandNode<Object> target = mock(CommandNode.class);
+// builder.redirect(target);
+// assertThat(builder.getRedirect(), is(target));
+// }
+
+// @Test(expected = IllegalStateException.class)
+// public void testRedirect_withChild() throws Exception {
+// final CommandNode<Object> target = mock(CommandNode.class);
+// builder.then(literal("foo"));
+// builder.redirect(target);
+// }
+
+// @Test(expected = IllegalStateException.class)
+// public void testThen_withRedirect() throws Exception {
+// final CommandNode<Object> target = mock(CommandNode.class);
+// builder.redirect(target);
+// builder.then(literal("foo"));
+// }
+
+// private static class TestableArgumentBuilder<S> extends ArgumentBuilder<S, TestableArgumentBuilder<S>> {
+// @Override
+// protected TestableArgumentBuilder<S> getThis() {
+// return this;
+// }
+
+// @Override
+// public CommandNode<S> build() {
+// return null;
+// }
+// }
+// }
diff --git a/azalea-brigadier/tests/builder/literal_argument_builder_test.rs b/azalea-brigadier/tests/builder/literal_argument_builder_test.rs
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/azalea-brigadier/tests/builder/literal_argument_builder_test.rs
diff --git a/azalea-brigadier/tests/builder/required_argument_builder_test.rs b/azalea-brigadier/tests/builder/required_argument_builder_test.rs
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/azalea-brigadier/tests/builder/required_argument_builder_test.rs
diff --git a/azalea-brigadier/tests/command_dispatcher_test.rs b/azalea-brigadier/tests/command_dispatcher_test.rs
new file mode 100755
index 00000000..cb33ac73
--- /dev/null
+++ b/azalea-brigadier/tests/command_dispatcher_test.rs
@@ -0,0 +1,410 @@
+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)
+}
diff --git a/azalea-brigadier/tests/command_dispatcher_usages_test.rs b/azalea-brigadier/tests/command_dispatcher_usages_test.rs
new file mode 100755
index 00000000..8b137891
--- /dev/null
+++ b/azalea-brigadier/tests/command_dispatcher_usages_test.rs
@@ -0,0 +1 @@
+
diff --git a/azalea-brigadier/tests/command_suggestions_test.rs b/azalea-brigadier/tests/command_suggestions_test.rs
new file mode 100755
index 00000000..8b137891
--- /dev/null
+++ b/azalea-brigadier/tests/command_suggestions_test.rs
@@ -0,0 +1 @@
+
diff --git a/azalea-brigadier/tests/context/command_context_test.rs b/azalea-brigadier/tests/context/command_context_test.rs
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/azalea-brigadier/tests/context/command_context_test.rs
diff --git a/azalea-brigadier/tests/context/parsed_argument_test.rs b/azalea-brigadier/tests/context/parsed_argument_test.rs
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/azalea-brigadier/tests/context/parsed_argument_test.rs
diff --git a/azalea-brigadier/tests/exceptions/dynamic_command_syntax_exception_type_test.rs b/azalea-brigadier/tests/exceptions/dynamic_command_syntax_exception_type_test.rs
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/azalea-brigadier/tests/exceptions/dynamic_command_syntax_exception_type_test.rs
diff --git a/azalea-brigadier/tests/exceptions/simple_command_syntax_exception_type_test.rs b/azalea-brigadier/tests/exceptions/simple_command_syntax_exception_type_test.rs
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/azalea-brigadier/tests/exceptions/simple_command_syntax_exception_type_test.rs
diff --git a/azalea-brigadier/tests/string_reader_test.rs b/azalea-brigadier/tests/string_reader_test.rs
new file mode 100755
index 00000000..5008eff8
--- /dev/null
+++ b/azalea-brigadier/tests/string_reader_test.rs
@@ -0,0 +1,612 @@
+use azalea_brigadier::{exceptions::BuiltInExceptions, string_reader::StringReader};
+
+#[test]
+fn can_read() {
+ let mut reader = StringReader::from("abc".to_string());
+ assert_eq!(reader.can_read(), true);
+ reader.skip(); // 'a'
+ assert_eq!(reader.can_read(), true);
+ reader.skip(); // 'b'
+ assert_eq!(reader.can_read(), true);
+ reader.skip(); // 'c'
+ assert_eq!(reader.can_read(), false);
+}
+
+#[test]
+fn get_remaining_length() {
+ let mut reader = StringReader::from("abc".to_string());
+ assert_eq!(reader.remaining_length(), 3);
+ reader.cursor = 1;
+ assert_eq!(reader.remaining_length(), 2);
+ reader.cursor = 2;
+ assert_eq!(reader.remaining_length(), 1);
+ reader.cursor = 3;
+ assert_eq!(reader.remaining_length(), 0);
+}
+
+#[test]
+fn can_read_length() {
+ let reader = StringReader::from("abc".to_string());
+ assert_eq!(reader.can_read_length(1), true);
+ assert_eq!(reader.can_read_length(2), true);
+ assert_eq!(reader.can_read_length(3), true);
+ assert_eq!(reader.can_read_length(4), false);
+ assert_eq!(reader.can_read_length(5), false);
+}
+
+#[test]
+fn peek() {
+ let mut reader = StringReader::from("abc".to_string());
+ assert_eq!(reader.peek(), 'a');
+ assert_eq!(reader.cursor(), 0);
+ reader.cursor = 2;
+ assert_eq!(reader.peek(), 'c');
+ assert_eq!(reader.cursor(), 2);
+}
+
+#[test]
+fn peek_length() {
+ let mut reader = StringReader::from("abc".to_string());
+ assert_eq!(reader.peek_offset(0), 'a');
+ assert_eq!(reader.peek_offset(2), 'c');
+ assert_eq!(reader.cursor(), 0);
+ reader.cursor = 1;
+ assert_eq!(reader.peek_offset(1), 'c');
+ assert_eq!(reader.cursor(), 1);
+}
+
+#[test]
+fn read() {
+ let mut reader = StringReader::from("abc".to_string());
+ assert_eq!(reader.read(), 'a');
+ assert_eq!(reader.read(), 'b');
+ assert_eq!(reader.read(), 'c');
+ assert_eq!(reader.cursor(), 3);
+}
+
+#[test]
+fn skip() {
+ let mut reader = StringReader::from("abc".to_string());
+ reader.skip();
+ assert_eq!(reader.cursor(), 1);
+}
+
+#[test]
+fn get_remaining() {
+ let mut reader = StringReader::from("Hello!".to_string());
+ assert_eq!(reader.remaining(), "Hello!");
+ reader.cursor = 3;
+ assert_eq!(reader.remaining(), "lo!");
+ reader.cursor = 6;
+ assert_eq!(reader.remaining(), "");
+}
+
+#[test]
+fn get_read() {
+ let mut reader = StringReader::from("Hello!".to_string());
+ assert_eq!(reader.get_read(), "");
+ reader.cursor = 3;
+ assert_eq!(reader.get_read(), "Hel");
+ reader.cursor = 6;
+ assert_eq!(reader.get_read(), "Hello!");
+}
+
+#[test]
+fn skip_whitespace_none() {
+ let mut reader = StringReader::from("Hello!".to_string());
+ reader.skip_whitespace();
+ assert_eq!(reader.cursor(), 0);
+}
+
+#[test]
+fn skip_whitespace_mixed() {
+ let mut reader = StringReader::from(" \t \t\nHello!".to_string());
+ reader.skip_whitespace();
+ assert_eq!(reader.cursor(), 5);
+}
+
+#[test]
+fn skip_whitespace_empty() {
+ let mut reader = StringReader::from("".to_string());
+ reader.skip_whitespace();
+ assert_eq!(reader.cursor(), 0);
+}
+
+#[test]
+fn read_unquoted_string() {
+ let mut reader = StringReader::from("hello world".to_string());
+ assert_eq!(reader.read_unquoted_string(), "hello");
+ assert_eq!(reader.get_read(), "hello");
+ assert_eq!(reader.remaining(), " world");
+}
+
+#[test]
+fn read_unquoted_string_empty() {
+ let mut reader = StringReader::from("".to_string());
+ assert_eq!(reader.read_unquoted_string(), "");
+ assert_eq!(reader.get_read(), "");
+ assert_eq!(reader.remaining(), "");
+}
+
+#[test]
+fn read_unquoted_string_empty_with_remaining() {
+ let mut reader = StringReader::from(" hello world".to_string());
+ assert_eq!(reader.read_unquoted_string(), "");
+ assert_eq!(reader.get_read(), "");
+ assert_eq!(reader.remaining(), " hello world");
+}
+
+#[test]
+fn read_quoted_string() {
+ let mut reader = StringReader::from("\"hello world\"".to_string());
+ assert_eq!(reader.read_quoted_string().unwrap(), "hello world");
+ assert_eq!(reader.get_read(), "\"hello world\"");
+ assert_eq!(reader.remaining(), "");
+}
+
+#[test]
+fn read_single_quoted_string() {
+ let mut reader = StringReader::from("'hello world'".to_string());
+ assert_eq!(reader.read_quoted_string().unwrap(), "hello world");
+ assert_eq!(reader.get_read(), "'hello world'");
+ assert_eq!(reader.remaining(), "");
+}
+
+#[test]
+fn read_mixed_quoted_string_double_inside_single() {
+ let mut reader = StringReader::from("'hello \"world\"'".to_string());
+ assert_eq!(reader.read_quoted_string().unwrap(), "hello \"world\"");
+ assert_eq!(reader.get_read(), "'hello \"world\"'");
+ assert_eq!(reader.remaining(), "");
+}
+
+#[test]
+fn read_mixed_quoted_string_single_inside_double() {
+ let mut reader = StringReader::from("\"hello 'world'\"".to_string());
+ assert_eq!(reader.read_quoted_string().unwrap(), "hello 'world'");
+ assert_eq!(reader.get_read(), "\"hello 'world'\"");
+ assert_eq!(reader.remaining(), "");
+}
+
+#[test]
+fn read_quoted_string_empty_quoted() {
+ let mut reader = StringReader::from("".to_string());
+ assert_eq!(reader.read_quoted_string().unwrap(), "");
+ assert_eq!(reader.get_read(), "");
+ assert_eq!(reader.remaining(), "");
+}
+
+#[test]
+fn read_quoted_string_empty_quoted_with_remaining() {
+ let mut reader = StringReader::from("\"\" hello world".to_string());
+ assert_eq!(reader.read_quoted_string().unwrap(), "");
+ assert_eq!(reader.get_read(), "\"\"");
+ assert_eq!(reader.remaining(), " hello world");
+}
+
+#[test]
+fn read_quoted_string_with_escaped_quote() {
+ let mut reader = StringReader::from("\"hello \\\"world\\\"\"".to_string());
+ assert_eq!(reader.read_quoted_string().unwrap(), "hello \"world\"");
+ assert_eq!(reader.get_read(), "\"hello \\\"world\\\"\"");
+ assert_eq!(reader.remaining(), "");
+}
+
+#[test]
+fn read_quoted_string_with_escaped_escapes() {
+ let mut reader = StringReader::from("\"\\\\o/\"".to_string());
+ assert_eq!(reader.read_quoted_string().unwrap(), "\\o/");
+ assert_eq!(reader.get_read(), "\"\\\\o/\"");
+ assert_eq!(reader.remaining(), "");
+}
+
+#[test]
+fn read_quoted_string_with_remaining() {
+ let mut reader = StringReader::from("\"hello world\" foo bar".to_string());
+ assert_eq!(reader.read_quoted_string().unwrap(), "hello world");
+ assert_eq!(reader.get_read(), "\"hello world\"");
+ assert_eq!(reader.remaining(), " foo bar");
+}
+
+#[test]
+fn read_quoted_string_with_immediate_remaining() {
+ let mut reader = StringReader::from("\"hello world\"foo bar".to_string());
+ assert_eq!(reader.read_quoted_string().unwrap(), "hello world");
+ assert_eq!(reader.get_read(), "\"hello world\"");
+ assert_eq!(reader.remaining(), "foo bar");
+}
+
+#[test]
+fn read_quoted_string_no_open() {
+ let mut reader = StringReader::from("hello world\"".to_string());
+ let result = reader.read_quoted_string();
+ assert!(result.is_err());
+ if let Err(e) = result {
+ assert_eq!(e.get_type(), &BuiltInExceptions::ReaderExpectedStartOfQuote);
+ assert_eq!(e.cursor(), Some(0));
+ }
+}
+
+#[test]
+fn read_quoted_string_no_close() {
+ let mut reader = StringReader::from("\"hello world".to_string());
+ let result = reader.read_quoted_string();
+ assert!(result.is_err());
+ if let Err(e) = result {
+ assert_eq!(e.get_type(), &BuiltInExceptions::ReaderExpectedEndOfQuote);
+ assert_eq!(e.cursor(), Some(12));
+ }
+}
+
+#[test]
+fn read_quoted_string_invalid_escape() {
+ let mut reader = StringReader::from("\"hello\\nworld\"".to_string());
+ let result = reader.read_quoted_string();
+ assert!(result.is_err());
+ if let Err(e) = result {
+ assert_eq!(
+ e.get_type(),
+ &BuiltInExceptions::ReaderInvalidEscape { character: 'n' }
+ );
+ assert_eq!(e.cursor(), Some(7));
+ }
+}
+
+#[test]
+fn read_quoted_string_invalid_quote_escape() {
+ let mut reader = StringReader::from("'hello\\\"\'world".to_string());
+ let result = reader.read_quoted_string();
+ assert!(result.is_err());
+ if let Err(e) = result {
+ assert_eq!(
+ e.get_type(),
+ &BuiltInExceptions::ReaderInvalidEscape { character: '"' }
+ );
+ assert_eq!(e.cursor(), Some(7));
+ }
+}
+
+#[test]
+fn read_string_no_quotes() {
+ let mut reader = StringReader::from("hello world".to_string());
+ assert_eq!(reader.read_string().unwrap(), "hello");
+ assert_eq!(reader.get_read(), "hello");
+ assert_eq!(reader.remaining(), " world");
+}
+
+#[test]
+fn read_string_single_quotes() {
+ let mut reader = StringReader::from("'hello world'".to_string());
+ assert_eq!(reader.read_string().unwrap(), "hello world");
+ assert_eq!(reader.get_read(), "'hello world'");
+ assert_eq!(reader.remaining(), "");
+}
+
+#[test]
+fn read_string_double_quotes() {
+ let mut reader = StringReader::from("\"hello world\"".to_string());
+ assert_eq!(reader.read_string().unwrap(), "hello world");
+ assert_eq!(reader.get_read(), "\"hello world\"");
+ assert_eq!(reader.remaining(), "");
+}
+
+#[test]
+fn read_int() {
+ let mut reader = StringReader::from("1234567890".to_string());
+ assert_eq!(reader.read_int().unwrap(), 1234567890);
+ assert_eq!(reader.get_read(), "1234567890");
+ assert_eq!(reader.remaining(), "");
+}
+
+#[test]
+fn read_int_negative() {
+ let mut reader = StringReader::from("-1234567890".to_string());
+ assert_eq!(reader.read_int().unwrap(), -1234567890);
+ assert_eq!(reader.get_read(), "-1234567890");
+ assert_eq!(reader.remaining(), "");
+}
+
+#[test]
+fn read_int_invalid() {
+ let mut reader = StringReader::from("12.34".to_string());
+ let result = reader.read_int();
+ assert!(result.is_err());
+ if let Err(e) = result {
+ assert_eq!(
+ e.get_type(),
+ &BuiltInExceptions::ReaderInvalidInt {
+ value: "12.34".to_string()
+ }
+ );
+ assert_eq!(e.cursor(), Some(0));
+ }
+}
+
+#[test]
+fn read_int_none() {
+ let mut reader = StringReader::from("".to_string());
+ let result = reader.read_int();
+ assert!(result.is_err());
+ if let Err(e) = result {
+ assert_eq!(e.get_type(), &BuiltInExceptions::ReaderExpectedInt);
+ assert_eq!(e.cursor(), Some(0));
+ }
+}
+
+#[test]
+fn read_int_with_remaining() {
+ let mut reader = StringReader::from("1234567890 foo bar".to_string());
+ assert_eq!(reader.read_int().unwrap(), 1234567890);
+ assert_eq!(reader.get_read(), "1234567890");
+ assert_eq!(reader.remaining(), " foo bar");
+}
+
+#[test]
+fn read_int_with_remaining_immediate() {
+ let mut reader = StringReader::from("1234567890foo bar".to_string());
+ assert_eq!(reader.read_int().unwrap(), 1234567890);
+ assert_eq!(reader.get_read(), "1234567890");
+ assert_eq!(reader.remaining(), "foo bar");
+}
+
+#[test]
+fn read_long() {
+ let mut reader = StringReader::from("1234567890".to_string());
+ assert_eq!(reader.read_long().unwrap(), 1234567890);
+ assert_eq!(reader.get_read(), "1234567890");
+ assert_eq!(reader.remaining(), "");
+}
+
+#[test]
+fn read_long_negative() {
+ let mut reader = StringReader::from("-1234567890".to_string());
+ assert_eq!(reader.read_long().unwrap(), -1234567890);
+ assert_eq!(reader.get_read(), "-1234567890");
+ assert_eq!(reader.remaining(), "");
+}
+
+#[test]
+fn read_long_invalid() {
+ let mut reader = StringReader::from("12.34".to_string());
+ let result = reader.read_long();
+ assert!(result.is_err());
+ if let Err(e) = result {
+ assert_eq!(
+ e.get_type(),
+ &BuiltInExceptions::ReaderInvalidLong {
+ value: "12.34".to_string()
+ }
+ );
+ assert_eq!(e.cursor(), Some(0));
+ }
+}
+
+#[test]
+fn read_long_none() {
+ let mut reader = StringReader::from("".to_string());
+ let result = reader.read_long();
+ assert!(result.is_err());
+ if let Err(e) = result {
+ assert_eq!(e.get_type(), &BuiltInExceptions::ReaderExpectedLong);
+ assert_eq!(e.cursor(), Some(0));
+ }
+}
+
+#[test]
+fn read_long_with_remaining() {
+ let mut reader = StringReader::from("1234567890 foo bar".to_string());
+ assert_eq!(reader.read_long().unwrap(), 1234567890);
+ assert_eq!(reader.get_read(), "1234567890");
+ assert_eq!(reader.remaining(), " foo bar");
+}
+
+#[test]
+fn read_long_with_remaining_immediate() {
+ let mut reader = StringReader::from("1234567890foo bar".to_string());
+ assert_eq!(reader.read_long().unwrap(), 1234567890);
+ assert_eq!(reader.get_read(), "1234567890");
+ assert_eq!(reader.remaining(), "foo bar");
+}
+
+#[test]
+fn read_double() {
+ let mut reader = StringReader::from("123".to_string());
+ assert_eq!(reader.read_double().unwrap(), 123.0);
+ assert_eq!(reader.get_read(), "123");
+ assert_eq!(reader.remaining(), "");
+}
+
+#[test]
+fn read_double_with_decimal() {
+ let mut reader = StringReader::from("12.34".to_string());
+ assert_eq!(reader.read_double().unwrap(), 12.34);
+ assert_eq!(reader.get_read(), "12.34");
+ assert_eq!(reader.remaining(), "");
+}
+
+#[test]
+fn read_double_negative() {
+ let mut reader = StringReader::from("-123".to_string());
+ assert_eq!(reader.read_double().unwrap(), -123.0);
+ assert_eq!(reader.get_read(), "-123");
+ assert_eq!(reader.remaining(), "");
+}
+
+#[test]
+fn read_double_invalid() {
+ let mut reader = StringReader::from("12.34.56".to_string());
+ let result = reader.read_double();
+ assert!(result.is_err());
+ if let Err(e) = result {
+ assert_eq!(
+ e.get_type(),
+ &BuiltInExceptions::ReaderInvalidDouble {
+ value: "12.34.56".to_string()
+ }
+ );
+ assert_eq!(e.cursor(), Some(0));
+ }
+}
+
+#[test]
+fn read_double_none() {
+ let mut reader = StringReader::from("".to_string());
+ let result = reader.read_double();
+ assert!(result.is_err());
+ if let Err(e) = result {
+ assert_eq!(e.get_type(), &BuiltInExceptions::ReaderExpectedDouble);
+ assert_eq!(e.cursor(), Some(0));
+ }
+}
+
+#[test]
+fn read_double_with_remaining() {
+ let mut reader = StringReader::from("12.34 foo bar".to_string());
+ assert_eq!(reader.read_double().unwrap(), 12.34);
+ assert_eq!(reader.get_read(), "12.34");
+ assert_eq!(reader.remaining(), " foo bar");
+}
+
+#[test]
+fn read_double_with_remaining_immediate() {
+ let mut reader = StringReader::from("12.34foo bar".to_string());
+ assert_eq!(reader.read_double().unwrap(), 12.34);
+ assert_eq!(reader.get_read(), "12.34");
+ assert_eq!(reader.remaining(), "foo bar");
+}
+
+#[test]
+fn read_float() {
+ let mut reader = StringReader::from("123".to_string());
+ assert_eq!(reader.read_float().unwrap(), 123.0f32);
+ assert_eq!(reader.get_read(), "123");
+ assert_eq!(reader.remaining(), "");
+}
+
+#[test]
+fn read_float_with_decimal() {
+ let mut reader = StringReader::from("12.34".to_string());
+ assert_eq!(reader.read_float().unwrap(), 12.34f32);
+ assert_eq!(reader.get_read(), "12.34");
+ assert_eq!(reader.remaining(), "");
+}
+
+#[test]
+fn read_float_negative() {
+ let mut reader = StringReader::from("-123".to_string());
+ assert_eq!(reader.read_float().unwrap(), -123.0f32);
+ assert_eq!(reader.get_read(), "-123");
+ assert_eq!(reader.remaining(), "");
+}
+
+#[test]
+fn read_float_invalid() {
+ let mut reader = StringReader::from("12.34.56".to_string());
+ let result = reader.read_float();
+ assert!(result.is_err());
+ if let Err(e) = result {
+ assert_eq!(
+ e.get_type(),
+ &BuiltInExceptions::ReaderInvalidFloat {
+ value: "12.34.56".to_string()
+ }
+ );
+ assert_eq!(e.cursor(), Some(0));
+ }
+}
+
+#[test]
+fn read_float_none() {
+ let mut reader = StringReader::from("".to_string());
+ let result = reader.read_float();
+ assert!(result.is_err());
+ if let Err(e) = result {
+ assert_eq!(e.get_type(), &BuiltInExceptions::ReaderExpectedFloat);
+ assert_eq!(e.cursor(), Some(0));
+ }
+}
+
+#[test]
+fn read_float_with_remaining() {
+ let mut reader = StringReader::from("12.34 foo bar".to_string());
+ assert_eq!(reader.read_float().unwrap(), 12.34f32);
+ assert_eq!(reader.get_read(), "12.34");
+ assert_eq!(reader.remaining(), " foo bar");
+}
+
+#[test]
+fn read_float_with_remaining_immediate() {
+ let mut reader = StringReader::from("12.34foo bar".to_string());
+ assert_eq!(reader.read_float().unwrap(), 12.34f32);
+ assert_eq!(reader.get_read(), "12.34");
+ assert_eq!(reader.remaining(), "foo bar");
+}
+
+#[test]
+fn expect_correct() {
+ let mut reader = StringReader::from("abc".to_string());
+ reader.expect('a').unwrap();
+ assert_eq!(reader.cursor(), 1);
+}
+
+#[test]
+fn expect_incorrect() {
+ let mut reader = StringReader::from("bcd".to_string());
+ let result = reader.expect('a');
+ assert!(result.is_err());
+ if let Err(e) = result {
+ assert_eq!(
+ e.get_type(),
+ &BuiltInExceptions::ReaderExpectedSymbol { symbol: 'a' }
+ );
+ assert_eq!(e.cursor(), Some(0));
+ }
+}
+
+#[test]
+fn expect_none() {
+ let mut reader = StringReader::from("".to_string());
+ let result = reader.expect('a');
+ assert!(result.is_err());
+ if let Err(e) = result {
+ assert_eq!(
+ e.get_type(),
+ &BuiltInExceptions::ReaderExpectedSymbol { symbol: 'a' }
+ );
+ assert_eq!(e.cursor(), Some(0));
+ }
+}
+
+#[test]
+fn read_boolean_correct() {
+ let mut reader = StringReader::from("true".to_string());
+ assert_eq!(reader.read_boolean().unwrap(), true);
+ assert_eq!(reader.get_read(), "true");
+}
+
+#[test]
+fn read_boolean_incorrect() {
+ let mut reader = StringReader::from("tuesday".to_string());
+ let result = reader.read_boolean();
+ assert!(result.is_err());
+ if let Err(e) = result {
+ assert_eq!(
+ e.get_type(),
+ &BuiltInExceptions::ReaderInvalidBool {
+ value: "tuesday".to_string()
+ }
+ );
+ assert_eq!(e.cursor(), Some(0));
+ }
+}
+
+#[test]
+fn read_boolean_none() {
+ let mut reader = StringReader::from("".to_string());
+ let result = reader.read_boolean();
+ assert!(result.is_err());
+ if let Err(e) = result {
+ assert_eq!(e.get_type(), &BuiltInExceptions::ReaderExpectedBool);
+ assert_eq!(e.cursor(), Some(0));
+ }
+}
diff --git a/azalea-brigadier/tests/suggestion/suggestion_test.rs b/azalea-brigadier/tests/suggestion/suggestion_test.rs
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/azalea-brigadier/tests/suggestion/suggestion_test.rs
diff --git a/azalea-brigadier/tests/suggestion/suggestions_builder_test.rs b/azalea-brigadier/tests/suggestion/suggestions_builder_test.rs
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/azalea-brigadier/tests/suggestion/suggestions_builder_test.rs
diff --git a/azalea-brigadier/tests/suggestion/suggestions_test.rs b/azalea-brigadier/tests/suggestion/suggestions_test.rs
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/azalea-brigadier/tests/suggestion/suggestions_test.rs
diff --git a/azalea-brigadier/tests/tree/abstract_command_node_test.rs b/azalea-brigadier/tests/tree/abstract_command_node_test.rs
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/azalea-brigadier/tests/tree/abstract_command_node_test.rs
diff --git a/azalea-brigadier/tests/tree/argument_command_node_test.rs b/azalea-brigadier/tests/tree/argument_command_node_test.rs
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/azalea-brigadier/tests/tree/argument_command_node_test.rs
diff --git a/azalea-brigadier/tests/tree/literal_command_node_test.rs b/azalea-brigadier/tests/tree/literal_command_node_test.rs
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/azalea-brigadier/tests/tree/literal_command_node_test.rs
diff --git a/azalea-brigadier/tests/tree/root_command_node_test.rs b/azalea-brigadier/tests/tree/root_command_node_test.rs
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/azalea-brigadier/tests/tree/root_command_node_test.rs