summaryrefslogtreecommitdiffstats
path: root/third_party/rust/sfv/src/test_parser.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
commit0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch)
treea31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /third_party/rust/sfv/src/test_parser.rs
parentInitial commit. (diff)
downloadfirefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz
firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/sfv/src/test_parser.rs')
-rw-r--r--third_party/rust/sfv/src/test_parser.rs850
1 files changed, 850 insertions, 0 deletions
diff --git a/third_party/rust/sfv/src/test_parser.rs b/third_party/rust/sfv/src/test_parser.rs
new file mode 100644
index 0000000000..97404eb951
--- /dev/null
+++ b/third_party/rust/sfv/src/test_parser.rs
@@ -0,0 +1,850 @@
+use crate::FromStr;
+use crate::{BareItem, Decimal, Dictionary, InnerList, Item, List, Num, Parameters};
+use crate::{ParseMore, ParseValue, Parser};
+use std::error::Error;
+use std::iter::FromIterator;
+
+#[test]
+fn parse() -> Result<(), Box<dyn Error>> {
+ let input = "\"some_value\"".as_bytes();
+ let parsed_item = Item::new(BareItem::String("some_value".to_owned()));
+ let expected = parsed_item;
+ assert_eq!(expected, Parser::parse_item(input)?);
+
+ let input = "12.35;a ".as_bytes();
+ let params = Parameters::from_iter(vec![("a".to_owned(), BareItem::Boolean(true))]);
+ let expected = Item::with_params(Decimal::from_str("12.35")?.into(), params);
+
+ assert_eq!(expected, Parser::parse_item(input)?);
+ Ok(())
+}
+
+#[test]
+fn parse_errors() -> Result<(), Box<dyn Error>> {
+ let input = "\"some_value¢\"".as_bytes();
+ assert_eq!(
+ Err("parse: non-ascii characters in input"),
+ Parser::parse_item(input)
+ );
+ let input = "\"some_value\" trailing_text".as_bytes();
+ assert_eq!(
+ Err("parse: trailing characters after parsed value"),
+ Parser::parse_item(input)
+ );
+ assert_eq!(
+ Err("parse_bare_item: empty item"),
+ Parser::parse_item("".as_bytes())
+ );
+ Ok(())
+}
+
+#[test]
+fn parse_list_of_numbers() -> Result<(), Box<dyn Error>> {
+ let mut input = "1,42".chars().peekable();
+ let item1 = Item::new(1.into());
+ let item2 = Item::new(42.into());
+ let expected_list: List = vec![item1.into(), item2.into()];
+ assert_eq!(expected_list, List::parse(&mut input)?);
+ Ok(())
+}
+
+#[test]
+fn parse_list_with_multiple_spaces() -> Result<(), Box<dyn Error>> {
+ let mut input = "1 , 42".chars().peekable();
+ let item1 = Item::new(1.into());
+ let item2 = Item::new(42.into());
+ let expected_list: List = vec![item1.into(), item2.into()];
+ assert_eq!(expected_list, List::parse(&mut input)?);
+ Ok(())
+}
+
+#[test]
+fn parse_list_of_lists() -> Result<(), Box<dyn Error>> {
+ let mut input = "(1 2), (42 43)".chars().peekable();
+ let item1 = Item::new(1.into());
+ let item2 = Item::new(2.into());
+ let item3 = Item::new(42.into());
+ let item4 = Item::new(43.into());
+ let inner_list_1 = InnerList::new(vec![item1, item2]);
+ let inner_list_2 = InnerList::new(vec![item3, item4]);
+ let expected_list: List = vec![inner_list_1.into(), inner_list_2.into()];
+ assert_eq!(expected_list, List::parse(&mut input)?);
+ Ok(())
+}
+
+#[test]
+fn parse_list_empty_inner_list() -> Result<(), Box<dyn Error>> {
+ let mut input = "()".chars().peekable();
+ let inner_list = InnerList::new(vec![]);
+ let expected_list: List = vec![inner_list.into()];
+ assert_eq!(expected_list, List::parse(&mut input)?);
+ Ok(())
+}
+
+#[test]
+fn parse_list_empty() -> Result<(), Box<dyn Error>> {
+ let mut input = "".chars().peekable();
+ let expected_list: List = vec![];
+ assert_eq!(expected_list, List::parse(&mut input)?);
+ Ok(())
+}
+
+#[test]
+fn parse_list_of_lists_with_param_and_spaces() -> Result<(), Box<dyn Error>> {
+ let mut input = "( 1 42 ); k=*".chars().peekable();
+ let item1 = Item::new(1.into());
+ let item2 = Item::new(42.into());
+ let inner_list_param =
+ Parameters::from_iter(vec![("k".to_owned(), BareItem::Token("*".to_owned()))]);
+ let inner_list = InnerList::with_params(vec![item1, item2], inner_list_param);
+ let expected_list: List = vec![inner_list.into()];
+ assert_eq!(expected_list, List::parse(&mut input)?);
+ Ok(())
+}
+
+#[test]
+fn parse_list_of_items_and_lists_with_param() -> Result<(), Box<dyn Error>> {
+ let mut input = "12, 14, (a b); param=\"param_value_1\", ()"
+ .chars()
+ .peekable();
+ let item1 = Item::new(12.into());
+ let item2 = Item::new(14.into());
+ let item3 = Item::new(BareItem::Token("a".to_owned()));
+ let item4 = Item::new(BareItem::Token("b".to_owned()));
+ let inner_list_param = Parameters::from_iter(vec![(
+ "param".to_owned(),
+ BareItem::String("param_value_1".to_owned()),
+ )]);
+ let inner_list = InnerList::with_params(vec![item3, item4], inner_list_param);
+ let empty_inner_list = InnerList::new(vec![]);
+ let expected_list: List = vec![
+ item1.into(),
+ item2.into(),
+ inner_list.into(),
+ empty_inner_list.into(),
+ ];
+ assert_eq!(expected_list, List::parse(&mut input)?);
+ Ok(())
+}
+
+#[test]
+fn parse_list_errors() -> Result<(), Box<dyn Error>> {
+ let mut input = ",".chars().peekable();
+ assert_eq!(
+ Err("parse_bare_item: item type can't be identified"),
+ List::parse(&mut input)
+ );
+
+ let mut input = "a, b c".chars().peekable();
+ assert_eq!(
+ Err("parse_list: trailing characters after list member"),
+ List::parse(&mut input)
+ );
+
+ let mut input = "a,".chars().peekable();
+ assert_eq!(Err("parse_list: trailing comma"), List::parse(&mut input));
+
+ let mut input = "a , ".chars().peekable();
+ assert_eq!(Err("parse_list: trailing comma"), List::parse(&mut input));
+
+ let mut input = "a\t \t ,\t ".chars().peekable();
+ assert_eq!(Err("parse_list: trailing comma"), List::parse(&mut input));
+
+ let mut input = "a\t\t,\t\t\t".chars().peekable();
+ assert_eq!(Err("parse_list: trailing comma"), List::parse(&mut input));
+
+ let mut input = "(a b),".chars().peekable();
+ assert_eq!(Err("parse_list: trailing comma"), List::parse(&mut input));
+
+ let mut input = "(1, 2, (a b)".chars().peekable();
+ assert_eq!(
+ Err("parse_inner_list: bad delimitation"),
+ List::parse(&mut input)
+ );
+
+ Ok(())
+}
+
+#[test]
+fn parse_inner_list_errors() -> Result<(), Box<dyn Error>> {
+ let mut input = "c b); a=1".chars().peekable();
+ assert_eq!(
+ Err("parse_inner_list: input does not start with '('"),
+ Parser::parse_inner_list(&mut input)
+ );
+ Ok(())
+}
+
+#[test]
+fn parse_inner_list_with_param_and_spaces() -> Result<(), Box<dyn Error>> {
+ let mut input = "(c b); a=1".chars().peekable();
+ let inner_list_param = Parameters::from_iter(vec![("a".to_owned(), 1.into())]);
+
+ let item1 = Item::new(BareItem::Token("c".to_owned()));
+ let item2 = Item::new(BareItem::Token("b".to_owned()));
+ let expected = InnerList::with_params(vec![item1, item2], inner_list_param);
+ assert_eq!(expected, Parser::parse_inner_list(&mut input)?);
+ Ok(())
+}
+
+#[test]
+fn parse_item_int_with_space() -> Result<(), Box<dyn Error>> {
+ let mut input = "12 ".chars().peekable();
+ assert_eq!(Item::new(12.into()), Item::parse(&mut input)?);
+ Ok(())
+}
+
+#[test]
+fn parse_item_decimal_with_bool_param_and_space() -> Result<(), Box<dyn Error>> {
+ let mut input = "12.35;a ".chars().peekable();
+ let param = Parameters::from_iter(vec![("a".to_owned(), BareItem::Boolean(true))]);
+ assert_eq!(
+ Item::with_params(Decimal::from_str("12.35")?.into(), param),
+ Item::parse(&mut input)?
+ );
+ Ok(())
+}
+
+#[test]
+fn parse_item_number_with_param() -> Result<(), Box<dyn Error>> {
+ let param = Parameters::from_iter(vec![("a1".to_owned(), BareItem::Token("*".to_owned()))]);
+ assert_eq!(
+ Item::with_params(BareItem::String("12.35".to_owned()), param),
+ Item::parse(&mut "\"12.35\";a1=*".chars().peekable())?
+ );
+ Ok(())
+}
+
+#[test]
+fn parse_item_errors() -> Result<(), Box<dyn Error>> {
+ assert_eq!(
+ Err("parse_bare_item: empty item"),
+ Item::parse(&mut "".chars().peekable())
+ );
+ Ok(())
+}
+
+#[test]
+fn parse_dict_empty() -> Result<(), Box<dyn Error>> {
+ assert_eq!(
+ Dictionary::new(),
+ Dictionary::parse(&mut "".chars().peekable())?
+ );
+ Ok(())
+}
+
+#[test]
+fn parse_dict_errors() -> Result<(), Box<dyn Error>> {
+ let mut input = "abc=123;a=1;b=2 def".chars().peekable();
+ assert_eq!(
+ Err("parse_dict: trailing characters after dictionary member"),
+ Dictionary::parse(&mut input)
+ );
+ let mut input = "abc=123;a=1,".chars().peekable();
+ assert_eq!(
+ Err("parse_dict: trailing comma"),
+ Dictionary::parse(&mut input)
+ );
+ Ok(())
+}
+
+#[test]
+fn parse_dict_with_spaces_and_params() -> Result<(), Box<dyn Error>> {
+ let mut input = "abc=123;a=1;b=2, def=456, ghi=789;q=9;r=\"+w\""
+ .chars()
+ .peekable();
+ let item1_params =
+ Parameters::from_iter(vec![("a".to_owned(), 1.into()), ("b".to_owned(), 2.into())]);
+ let item3_params = Parameters::from_iter(vec![
+ ("q".to_owned(), 9.into()),
+ ("r".to_owned(), BareItem::String("+w".to_owned())),
+ ]);
+
+ let item1 = Item::with_params(123.into(), item1_params);
+ let item2 = Item::new(456.into());
+ let item3 = Item::with_params(789.into(), item3_params);
+
+ let expected_dict = Dictionary::from_iter(vec![
+ ("abc".to_owned(), item1.into()),
+ ("def".to_owned(), item2.into()),
+ ("ghi".to_owned(), item3.into()),
+ ]);
+ assert_eq!(expected_dict, Dictionary::parse(&mut input)?);
+
+ Ok(())
+}
+
+#[test]
+fn parse_dict_empty_value() -> Result<(), Box<dyn Error>> {
+ let mut input = "a=()".chars().peekable();
+ let inner_list = InnerList::new(vec![]);
+ let expected_dict = Dictionary::from_iter(vec![("a".to_owned(), inner_list.into())]);
+ assert_eq!(expected_dict, Dictionary::parse(&mut input)?);
+ Ok(())
+}
+
+#[test]
+fn parse_dict_with_token_param() -> Result<(), Box<dyn Error>> {
+ let mut input = "a=1, b;foo=*, c=3".chars().peekable();
+ let item2_params =
+ Parameters::from_iter(vec![("foo".to_owned(), BareItem::Token("*".to_owned()))]);
+ let item1 = Item::new(1.into());
+ let item2 = Item::with_params(BareItem::Boolean(true), item2_params);
+ let item3 = Item::new(3.into());
+ let expected_dict = Dictionary::from_iter(vec![
+ ("a".to_owned(), item1.into()),
+ ("b".to_owned(), item2.into()),
+ ("c".to_owned(), item3.into()),
+ ]);
+ assert_eq!(expected_dict, Dictionary::parse(&mut input)?);
+ Ok(())
+}
+
+#[test]
+fn parse_dict_multiple_spaces() -> Result<(), Box<dyn Error>> {
+ // input1, input2, input3 must be parsed into the same structure
+ let item1 = Item::new(1.into());
+ let item2 = Item::new(2.into());
+ let expected_dict = Dictionary::from_iter(vec![
+ ("a".to_owned(), item1.into()),
+ ("b".to_owned(), item2.into()),
+ ]);
+
+ let mut input1 = "a=1 , b=2".chars().peekable();
+ let mut input2 = "a=1\t,\tb=2".chars().peekable();
+ let mut input3 = "a=1, b=2".chars().peekable();
+ assert_eq!(expected_dict, Dictionary::parse(&mut input1)?);
+ assert_eq!(expected_dict, Dictionary::parse(&mut input2)?);
+ assert_eq!(expected_dict, Dictionary::parse(&mut input3)?);
+
+ Ok(())
+}
+
+#[test]
+fn parse_bare_item() -> Result<(), Box<dyn Error>> {
+ assert_eq!(
+ BareItem::Boolean(false),
+ Parser::parse_bare_item(&mut "?0".chars().peekable())?
+ );
+ assert_eq!(
+ BareItem::String("test string".to_owned()),
+ Parser::parse_bare_item(&mut "\"test string\"".chars().peekable())?
+ );
+ assert_eq!(
+ BareItem::Token("*token".to_owned()),
+ Parser::parse_bare_item(&mut "*token".chars().peekable())?
+ );
+ assert_eq!(
+ BareItem::ByteSeq("base_64 encoding test".to_owned().into_bytes()),
+ Parser::parse_bare_item(&mut ":YmFzZV82NCBlbmNvZGluZyB0ZXN0:".chars().peekable())?
+ );
+ assert_eq!(
+ BareItem::Decimal(Decimal::from_str("-3.55")?),
+ Parser::parse_bare_item(&mut "-3.55".chars().peekable())?
+ );
+ Ok(())
+}
+
+#[test]
+fn parse_bare_item_errors() -> Result<(), Box<dyn Error>> {
+ assert_eq!(
+ Err("parse_bare_item: item type can't be identified"),
+ Parser::parse_bare_item(&mut "!?0".chars().peekable())
+ );
+ assert_eq!(
+ Err("parse_bare_item: item type can't be identified"),
+ Parser::parse_bare_item(&mut "_11abc".chars().peekable())
+ );
+ assert_eq!(
+ Err("parse_bare_item: item type can't be identified"),
+ Parser::parse_bare_item(&mut " ".chars().peekable())
+ );
+ Ok(())
+}
+
+#[test]
+fn parse_bool() -> Result<(), Box<dyn Error>> {
+ let mut input = "?0gk".chars().peekable();
+ assert_eq!(false, Parser::parse_bool(&mut input)?);
+ assert_eq!(input.collect::<String>(), "gk");
+
+ assert_eq!(false, Parser::parse_bool(&mut "?0".chars().peekable())?);
+ assert_eq!(true, Parser::parse_bool(&mut "?1".chars().peekable())?);
+ Ok(())
+}
+
+#[test]
+fn parse_bool_errors() -> Result<(), Box<dyn Error>> {
+ assert_eq!(
+ Err("parse_bool: first character is not '?'"),
+ Parser::parse_bool(&mut "".chars().peekable())
+ );
+ assert_eq!(
+ Err("parse_bool: invalid variant"),
+ Parser::parse_bool(&mut "?".chars().peekable())
+ );
+ Ok(())
+}
+
+#[test]
+fn parse_string() -> Result<(), Box<dyn Error>> {
+ let mut input = "\"some string\" ;not string".chars().peekable();
+ assert_eq!("some string".to_owned(), Parser::parse_string(&mut input)?);
+ assert_eq!(input.collect::<String>(), " ;not string");
+
+ assert_eq!(
+ "test".to_owned(),
+ Parser::parse_string(&mut "\"test\"".chars().peekable())?
+ );
+ assert_eq!(
+ r#"te\st"#.to_owned(),
+ Parser::parse_string(&mut "\"te\\\\st\"".chars().peekable())?
+ );
+ assert_eq!(
+ "".to_owned(),
+ Parser::parse_string(&mut "\"\"".chars().peekable())?
+ );
+ assert_eq!(
+ "some string".to_owned(),
+ Parser::parse_string(&mut "\"some string\"".chars().peekable())?
+ );
+ Ok(())
+}
+
+#[test]
+fn parse_string_errors() -> Result<(), Box<dyn Error>> {
+ assert_eq!(
+ Err("parse_string: first character is not '\"'"),
+ Parser::parse_string(&mut "test".chars().peekable())
+ );
+ assert_eq!(
+ Err("parse_string: last input character is '\\'"),
+ Parser::parse_string(&mut "\"\\".chars().peekable())
+ );
+ assert_eq!(
+ Err("parse_string: disallowed character after '\\'"),
+ Parser::parse_string(&mut "\"\\l\"".chars().peekable())
+ );
+ assert_eq!(
+ Err("parse_string: not a visible character"),
+ Parser::parse_string(&mut "\"\u{1f}\"".chars().peekable())
+ );
+ assert_eq!(
+ Err("parse_string: no closing '\"'"),
+ Parser::parse_string(&mut "\"smth".chars().peekable())
+ );
+ Ok(())
+}
+
+#[test]
+fn parse_token() -> Result<(), Box<dyn Error>> {
+ let mut input = "*some:token}not token".chars().peekable();
+ assert_eq!("*some:token".to_owned(), Parser::parse_token(&mut input)?);
+ assert_eq!(input.collect::<String>(), "}not token");
+
+ assert_eq!(
+ "token".to_owned(),
+ Parser::parse_token(&mut "token".chars().peekable())?
+ );
+ assert_eq!(
+ "a_b-c.d3:f%00/*".to_owned(),
+ Parser::parse_token(&mut "a_b-c.d3:f%00/*".chars().peekable())?
+ );
+ assert_eq!(
+ "TestToken".to_owned(),
+ Parser::parse_token(&mut "TestToken".chars().peekable())?
+ );
+ assert_eq!(
+ "some".to_owned(),
+ Parser::parse_token(&mut "some@token".chars().peekable())?
+ );
+ assert_eq!(
+ "*TestToken*".to_owned(),
+ Parser::parse_token(&mut "*TestToken*".chars().peekable())?
+ );
+ assert_eq!(
+ "*".to_owned(),
+ Parser::parse_token(&mut "*[@:token".chars().peekable())?
+ );
+ assert_eq!(
+ "test".to_owned(),
+ Parser::parse_token(&mut "test token".chars().peekable())?
+ );
+
+ Ok(())
+}
+
+#[test]
+fn parse_token_errors() -> Result<(), Box<dyn Error>> {
+ let mut input = "765token".chars().peekable();
+ assert_eq!(
+ Err("parse_token: first character is not ALPHA or '*'"),
+ Parser::parse_token(&mut input)
+ );
+ assert_eq!(input.collect::<String>(), "765token");
+
+ assert_eq!(
+ Err("parse_token: first character is not ALPHA or '*'"),
+ Parser::parse_token(&mut "7token".chars().peekable())
+ );
+ assert_eq!(
+ Err("parse_token: empty input string"),
+ Parser::parse_token(&mut "".chars().peekable())
+ );
+ Ok(())
+}
+
+#[test]
+fn parse_byte_sequence() -> Result<(), Box<dyn Error>> {
+ let mut input = ":aGVsbG8:rest_of_str".chars().peekable();
+ assert_eq!(
+ "hello".to_owned().into_bytes(),
+ Parser::parse_byte_sequence(&mut input)?
+ );
+ assert_eq!("rest_of_str", input.collect::<String>());
+
+ assert_eq!(
+ "hello".to_owned().into_bytes(),
+ Parser::parse_byte_sequence(&mut ":aGVsbG8:".chars().peekable())?
+ );
+ assert_eq!(
+ "test_encode".to_owned().into_bytes(),
+ Parser::parse_byte_sequence(&mut ":dGVzdF9lbmNvZGU:".chars().peekable())?
+ );
+ assert_eq!(
+ "new:year tree".to_owned().into_bytes(),
+ Parser::parse_byte_sequence(&mut ":bmV3OnllYXIgdHJlZQ==:".chars().peekable())?
+ );
+ assert_eq!(
+ "".to_owned().into_bytes(),
+ Parser::parse_byte_sequence(&mut "::".chars().peekable())?
+ );
+ Ok(())
+}
+
+#[test]
+fn parse_byte_sequence_errors() -> Result<(), Box<dyn Error>> {
+ assert_eq!(
+ Err("parse_byte_seq: first char is not ':'"),
+ Parser::parse_byte_sequence(&mut "aGVsbG8".chars().peekable())
+ );
+ assert_eq!(
+ Err("parse_byte_seq: invalid char in byte sequence"),
+ Parser::parse_byte_sequence(&mut ":aGVsb G8=:".chars().peekable())
+ );
+ assert_eq!(
+ Err("parse_byte_seq: no closing ':'"),
+ Parser::parse_byte_sequence(&mut ":aGVsbG8=".chars().peekable())
+ );
+ Ok(())
+}
+
+#[test]
+fn parse_number_int() -> Result<(), Box<dyn Error>> {
+ let mut input = "-733333333332d.14".chars().peekable();
+ assert_eq!(
+ Num::Integer(-733333333332),
+ Parser::parse_number(&mut input)?
+ );
+ assert_eq!("d.14", input.collect::<String>());
+
+ assert_eq!(
+ Num::Integer(42),
+ Parser::parse_number(&mut "42".chars().peekable())?
+ );
+ assert_eq!(
+ Num::Integer(-42),
+ Parser::parse_number(&mut "-42".chars().peekable())?
+ );
+ assert_eq!(
+ Num::Integer(-42),
+ Parser::parse_number(&mut "-042".chars().peekable())?
+ );
+ assert_eq!(
+ Num::Integer(0),
+ Parser::parse_number(&mut "0".chars().peekable())?
+ );
+ assert_eq!(
+ Num::Integer(0),
+ Parser::parse_number(&mut "00".chars().peekable())?
+ );
+ assert_eq!(
+ Num::Integer(123456789012345),
+ Parser::parse_number(&mut "123456789012345".chars().peekable())?
+ );
+ assert_eq!(
+ Num::Integer(-123456789012345),
+ Parser::parse_number(&mut "-123456789012345".chars().peekable())?
+ );
+ assert_eq!(
+ Num::Integer(2),
+ Parser::parse_number(&mut "2,3".chars().peekable())?
+ );
+ assert_eq!(
+ Num::Integer(4),
+ Parser::parse_number(&mut "4-2".chars().peekable())?
+ );
+ assert_eq!(
+ Num::Integer(-999999999999999),
+ Parser::parse_number(&mut "-999999999999999".chars().peekable())?
+ );
+ assert_eq!(
+ Num::Integer(999999999999999),
+ Parser::parse_number(&mut "999999999999999".chars().peekable())?
+ );
+
+ Ok(())
+}
+
+#[test]
+fn parse_number_decimal() -> Result<(), Box<dyn Error>> {
+ let mut input = "00.42 test string".chars().peekable();
+ assert_eq!(
+ Num::Decimal(Decimal::from_str("0.42")?),
+ Parser::parse_number(&mut input)?
+ );
+ assert_eq!(" test string", input.collect::<String>());
+
+ assert_eq!(
+ Num::Decimal(Decimal::from_str("1.5")?),
+ Parser::parse_number(&mut "1.5.4.".chars().peekable())?
+ );
+ assert_eq!(
+ Num::Decimal(Decimal::from_str("1.8")?),
+ Parser::parse_number(&mut "1.8.".chars().peekable())?
+ );
+ assert_eq!(
+ Num::Decimal(Decimal::from_str("1.7")?),
+ Parser::parse_number(&mut "1.7.0".chars().peekable())?
+ );
+ assert_eq!(
+ Num::Decimal(Decimal::from_str("3.14")?),
+ Parser::parse_number(&mut "3.14".chars().peekable())?
+ );
+ assert_eq!(
+ Num::Decimal(Decimal::from_str("-3.14")?),
+ Parser::parse_number(&mut "-3.14".chars().peekable())?
+ );
+ assert_eq!(
+ Num::Decimal(Decimal::from_str("123456789012.1")?),
+ Parser::parse_number(&mut "123456789012.1".chars().peekable())?
+ );
+ assert_eq!(
+ Num::Decimal(Decimal::from_str("1234567890.112")?),
+ Parser::parse_number(&mut "1234567890.112".chars().peekable())?
+ );
+
+ Ok(())
+}
+
+#[test]
+fn parse_number_errors() -> Result<(), Box<dyn Error>> {
+ let mut input = ":aGVsbG8:rest".chars().peekable();
+ assert_eq!(
+ Err("parse_number: input number does not start with a digit"),
+ Parser::parse_number(&mut input)
+ );
+ assert_eq!(":aGVsbG8:rest", input.collect::<String>());
+
+ let mut input = "-11.5555 test string".chars().peekable();
+ assert_eq!(
+ Err("parse_number: invalid decimal fraction length"),
+ Parser::parse_number(&mut input)
+ );
+ assert_eq!(" test string", input.collect::<String>());
+
+ assert_eq!(
+ Err("parse_number: input number does not start with a digit"),
+ Parser::parse_number(&mut "--0".chars().peekable())
+ );
+ assert_eq!(
+ Err("parse_number: decimal too long, illegal position for decimal point"),
+ Parser::parse_number(&mut "1999999999999.1".chars().peekable())
+ );
+ assert_eq!(
+ Err("parse_number: decimal ends with '.'"),
+ Parser::parse_number(&mut "19888899999.".chars().peekable())
+ );
+ assert_eq!(
+ Err("parse_number: integer too long, length > 15"),
+ Parser::parse_number(&mut "1999999999999999".chars().peekable())
+ );
+ assert_eq!(
+ Err("parse_number: decimal too long, length > 16"),
+ Parser::parse_number(&mut "19999999999.99991".chars().peekable())
+ );
+ assert_eq!(
+ Err("parse_number: input number does not start with a digit"),
+ Parser::parse_number(&mut "- 42".chars().peekable())
+ );
+ assert_eq!(
+ Err("parse_number: input number does not start with a digit"),
+ Parser::parse_number(&mut "- 42".chars().peekable())
+ );
+ assert_eq!(
+ Err("parse_number: decimal ends with '.'"),
+ Parser::parse_number(&mut "1..4".chars().peekable())
+ );
+ assert_eq!(
+ Err("parse_number: input number lacks a digit"),
+ Parser::parse_number(&mut "-".chars().peekable())
+ );
+ assert_eq!(
+ Err("parse_number: decimal ends with '.'"),
+ Parser::parse_number(&mut "-5. 14".chars().peekable())
+ );
+ assert_eq!(
+ Err("parse_number: decimal ends with '.'"),
+ Parser::parse_number(&mut "7. 1".chars().peekable())
+ );
+ assert_eq!(
+ Err("parse_number: invalid decimal fraction length"),
+ Parser::parse_number(&mut "-7.3333333333".chars().peekable())
+ );
+ assert_eq!(
+ Err("parse_number: decimal too long, illegal position for decimal point"),
+ Parser::parse_number(&mut "-7333333333323.12".chars().peekable())
+ );
+
+ Ok(())
+}
+
+#[test]
+fn parse_params_string() -> Result<(), Box<dyn Error>> {
+ let mut input = ";b=\"param_val\"".chars().peekable();
+ let expected = Parameters::from_iter(vec![(
+ "b".to_owned(),
+ BareItem::String("param_val".to_owned()),
+ )]);
+ assert_eq!(expected, Parser::parse_parameters(&mut input)?);
+ Ok(())
+}
+
+#[test]
+fn parse_params_bool() -> Result<(), Box<dyn Error>> {
+ let mut input = ";b;a".chars().peekable();
+ let expected = Parameters::from_iter(vec![
+ ("b".to_owned(), BareItem::Boolean(true)),
+ ("a".to_owned(), BareItem::Boolean(true)),
+ ]);
+ assert_eq!(expected, Parser::parse_parameters(&mut input)?);
+ Ok(())
+}
+
+#[test]
+fn parse_params_mixed_types() -> Result<(), Box<dyn Error>> {
+ let mut input = ";key1=?0;key2=746.15".chars().peekable();
+ let expected = Parameters::from_iter(vec![
+ ("key1".to_owned(), BareItem::Boolean(false)),
+ ("key2".to_owned(), Decimal::from_str("746.15")?.into()),
+ ]);
+ assert_eq!(expected, Parser::parse_parameters(&mut input)?);
+ Ok(())
+}
+
+#[test]
+fn parse_params_with_spaces() -> Result<(), Box<dyn Error>> {
+ let mut input = "; key1=?0; key2=11111".chars().peekable();
+ let expected = Parameters::from_iter(vec![
+ ("key1".to_owned(), BareItem::Boolean(false)),
+ ("key2".to_owned(), 11111.into()),
+ ]);
+ assert_eq!(expected, Parser::parse_parameters(&mut input)?);
+ Ok(())
+}
+
+#[test]
+fn parse_params_empty() -> Result<(), Box<dyn Error>> {
+ assert_eq!(
+ Parameters::new(),
+ Parser::parse_parameters(&mut " key1=?0; key2=11111".chars().peekable())?
+ );
+ assert_eq!(
+ Parameters::new(),
+ Parser::parse_parameters(&mut "".chars().peekable())?
+ );
+ assert_eq!(
+ Parameters::new(),
+ Parser::parse_parameters(&mut "[;a=1".chars().peekable())?
+ );
+ assert_eq!(
+ Parameters::new(),
+ Parser::parse_parameters(&mut String::new().chars().peekable())?
+ );
+ Ok(())
+}
+
+#[test]
+fn parse_key() -> Result<(), Box<dyn Error>> {
+ assert_eq!(
+ "a".to_owned(),
+ Parser::parse_key(&mut "a=1".chars().peekable())?
+ );
+ assert_eq!(
+ "a1".to_owned(),
+ Parser::parse_key(&mut "a1=10".chars().peekable())?
+ );
+ assert_eq!(
+ "*1".to_owned(),
+ Parser::parse_key(&mut "*1=10".chars().peekable())?
+ );
+ assert_eq!(
+ "f".to_owned(),
+ Parser::parse_key(&mut "f[f=10".chars().peekable())?
+ );
+ Ok(())
+}
+
+#[test]
+fn parse_key_errors() -> Result<(), Box<dyn Error>> {
+ assert_eq!(
+ Err("parse_key: first character is not lcalpha or '*'"),
+ Parser::parse_key(&mut "[*f=10".chars().peekable())
+ );
+ Ok(())
+}
+
+#[test]
+fn parse_more_list() -> Result<(), Box<dyn Error>> {
+ let item1 = Item::new(1.into());
+ let item2 = Item::new(2.into());
+ let item3 = Item::new(42.into());
+ let inner_list_1 = InnerList::new(vec![item1, item2]);
+ let expected_list: List = vec![inner_list_1.into(), item3.into()];
+
+ let mut parsed_header = Parser::parse_list("(1 2)".as_bytes())?;
+ let _ = parsed_header.parse_more("42".as_bytes())?;
+ assert_eq!(expected_list, parsed_header);
+ Ok(())
+}
+
+#[test]
+fn parse_more_dict() -> Result<(), Box<dyn Error>> {
+ let item2_params =
+ Parameters::from_iter(vec![("foo".to_owned(), BareItem::Token("*".to_owned()))]);
+ let item1 = Item::new(1.into());
+ let item2 = Item::with_params(BareItem::Boolean(true), item2_params);
+ let item3 = Item::new(3.into());
+ let expected_dict = Dictionary::from_iter(vec![
+ ("a".to_owned(), item1.into()),
+ ("b".to_owned(), item2.into()),
+ ("c".to_owned(), item3.into()),
+ ]);
+
+ let mut parsed_header = Parser::parse_dictionary("a=1, b;foo=*\t\t".as_bytes())?;
+ let _ = parsed_header.parse_more(" c=3".as_bytes())?;
+ assert_eq!(expected_dict, parsed_header);
+ Ok(())
+}
+
+#[test]
+fn parse_more_errors() -> Result<(), Box<dyn Error>> {
+ let parsed_dict_header =
+ Parser::parse_dictionary("a=1, b;foo=*".as_bytes())?.parse_more(",a".as_bytes());
+ assert!(parsed_dict_header.is_err());
+
+ let parsed_list_header =
+ Parser::parse_list("a, b;foo=*".as_bytes())?.parse_more("(a, 2)".as_bytes());
+ assert!(parsed_list_header.is_err());
+ Ok(())
+}