use std::convert::Infallible;
use crate ::{
error, integer, key_ref, string_ref, token_ref,
visitor::{
DictionaryVisitor, EntryVisitor, Ignored, InnerListVisitor, ItemVisitor, ListVisitor,
ParameterVisitor,
},
BareItemFromInput, Decimal, Error, KeyRef, Num, Parser, RefBareItem,
};
#[ cfg(feature =
"parsed-types" )]
use crate ::{BareItem, Date, Dictionary, InnerList, Item, List, Parameters, Version};
#[ test]
#[ cfg(feature =
"parsed-types" )]
fn parse() -> Result<(), Error> {
let input = r
#" "some_value" "#;
let parsed_item = Item::new(string_ref(
"some_value" ));
let expected = parsed_item;
assert_eq!(expected, Parser::new(input).parse::<Item>()?);
let input =
"12.35;a " ;
let params = Parameters::from_iter(vec![(key_ref(
"a" ).to_owned(), BareItem::Boolean(
true ))]);
let expected = Item::with_params(Decimal::try_from(
12 .
35 )?, params);
assert_eq!(expected, Parser::new(input).parse::<Item>()?);
Ok(())
}
#[ test]
fn parse_errors() {
let input = r
#" "some_value¢" "#;
assert_eq!(
Err(error::Repr::InvalidStringCharacter(
11 ).into()),
Parser::new(input).parse_item_with_visitor(Ignored)
);
let input = r
#" "some_value" trailing_text
"" #;
assert_eq!(
Err(error::Repr::TrailingCharactersAfterParsedValue(
13 ).into()),
Parser::new(input).parse_item_with_visitor(Ignored)
);
assert_eq!(
Err(error::Repr::ExpectedStartOfBareItem(
0 ).into()),
Parser::new(
"" ).parse_item_with_visitor(Ignored)
);
}
#[ test]
#[ cfg(feature =
"parsed-types" )]
fn parse_list_of_numbers() -> Result<(), Error> {
let input =
"1,42" ;
let item1 = Item::new(
1 );
let item2 = Item::new(
42 );
let expected_list: List = vec![item1.into(), item2.into()];
assert_eq!(expected_list, Parser::new(input).parse::<List>()?);
Ok(())
}
#[ test]
#[ cfg(feature =
"parsed-types" )]
fn parse_list_with_multiple_spaces() -> Result<(), Error> {
let input =
"1 , 42" ;
let item1 = Item::new(
1 );
let item2 = Item::new(
42 );
let expected_list: List = vec![item1.into(), item2.into()];
assert_eq!(expected_list, Parser::new(input).parse::<List>()?);
Ok(())
}
#[ test]
#[ cfg(feature =
"parsed-types" )]
fn parse_list_of_lists() -> Result<(), Error> {
let input =
"(1 2), (42 43)" ;
let item1 = Item::new(
1 );
let item2 = Item::new(
2 );
let item3 = Item::new(
42 );
let item4 = Item::new(
43 );
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, Parser::new(input).parse::<List>()?);
Ok(())
}
#[ test]
#[ cfg(feature =
"parsed-types" )]
fn parse_list_empty_inner_list() -> Result<(), Error> {
let input =
"()" ;
let inner_list = InnerList::new(vec![]);
let expected_list: List = vec![inner_list.into()];
assert_eq!(expected_list, Parser::new(input).parse::<List>()?);
Ok(())
}
#[ test]
#[ cfg(feature =
"parsed-types" )]
fn parse_list_empty() -> Result<(), Error> {
let input =
"" ;
let expected_list: List = vec![];
assert_eq!(expected_list, Parser::new(input).parse::<List>()?);
Ok(())
}
#[ test]
#[ cfg(feature =
"parsed-types" )]
fn parse_list_of_lists_with_param_and_spaces() -> Result<(), Error> {
let input =
"( 1 42 ); k=*" ;
let item1 = Item::new(
1 );
let item2 = Item::new(
42 );
let inner_list_param = Parameters::from_iter(vec![(
key_ref(
"k" ).to_owned(),
BareItem::Token(token_ref(
"*" ).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, Parser::new(input).parse::<List>()?);
Ok(())
}
#[ test]
#[ cfg(feature =
"parsed-types" )]
fn parse_list_of_items_and_lists_with_param() -> Result<(), Error> {
let input = r
#" 12 ,
14 , (a b); param=
"param_value_1" , ()
"#;
let item1 = Item::new(
12 );
let item2 = Item::new(
14 );
let item3 = Item::new(token_ref(
"a" ));
let item4 = Item::new(token_ref(
"b" ));
let inner_list_param = Parameters::from_iter(vec![(
key_ref(
"param" ).to_owned(),
BareItem::String(string_ref(
"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, Parser::new(input).parse::<List>()?);
Ok(())
}
#[ test]
fn parse_list_errors() {
let input =
"," ;
assert_eq!(
Err(error::Repr::ExpectedStartOfBareItem(
0 ).into()),
Parser::new(input).parse_list_with_visitor(&
mut Ignored)
);
let input =
"a, b c" ;
assert_eq!(
Err(error::Repr::TrailingCharactersAfterMember(
5 ).into()),
Parser::new(input).parse_list_with_visitor(&
mut Ignored)
);
let input =
"a," ;
assert_eq!(
Err(error::Repr::TrailingComma(
1 ).into()),
Parser::new(input).parse_list_with_visitor(&
mut Ignored)
);
let input =
"a , " ;
assert_eq!(
Err(error::Repr::TrailingComma(
6 ).into()),
Parser::new(input).parse_list_with_visitor(&
mut Ignored)
);
let input =
"a\t \t ,\t " ;
assert_eq!(
Err(error::Repr::TrailingComma(
5 ).into()),
Parser::new(input).parse_list_with_visitor(&
mut Ignored)
);
let input =
"a\t\t,\t\t\t" ;
assert_eq!(
Err(error::Repr::TrailingComma(
3 ).into()),
Parser::new(input).parse_list_with_visitor(&
mut Ignored)
);
let input =
"(a b)," ;
assert_eq!(
Err(error::Repr::TrailingComma(
5 ).into()),
Parser::new(input).parse_list_with_visitor(&
mut Ignored)
);
let input =
"(1, 2, (a b)" ;
assert_eq!(
Err(error::Repr::ExpectedInnerListDelimiter(
2 ).into()),
Parser::new(input).parse_list_with_visitor(&
mut Ignored)
);
}
#[ test]
fn parse_inner_list_errors() {
let input =
"c b); a=1" ;
assert_eq!(
Err(error::Repr::ExpectedStartOfInnerList(
0 )),
Parser::new(input).parse_inner_list(Ignored)
);
let input =
"(" ;
assert_eq!(
Err(error::Repr::UnterminatedInnerList(
1 )),
Parser::new(input).parse_inner_list(Ignored)
);
}
#[ test]
#[ cfg(feature =
"parsed-types" )]
fn parse_inner_list_with_param_and_spaces() -> Result<(), Error> {
let input =
"(c b); a=1" ;
let inner_list_param = Parameters::from_iter(vec![(key_ref(
"a" ).to_owned(),
1 .into()
)]);
let item1 = Item::new(token_ref("c" ));
let item2 = Item::new(token_ref("b" ));
let expected = InnerList::with_params(vec![item1, item2], inner_list_param);
let mut inner_list = InnerList::default();
Parser::new(input).parse_inner_list(&mut inner_list)?;
assert_eq!(expected, inner_list);
Ok(())
}
#[ test]
#[ cfg(feature = "parsed-types" )]
fn parse_item_int_with_space() -> Result<(), Error> {
let input = "12 " ;
assert_eq!(Item::new(12 ), Parser::new(input).parse::<Item>()?);
Ok(())
}
#[ test]
#[ cfg(feature = "parsed-types" )]
fn parse_item_decimal_with_bool_param_and_space() -> Result<(), Error> {
let input = "12.35;a " ;
let param = Parameters::from_iter(vec![(key_ref("a" ).to_owned(), BareItem::Boolean(true ))]);
assert_eq!(
Item::with_params(Decimal::try_from(12 .35 )?, param),
Parser::new(input).parse::<Item>()?
);
Ok(())
}
#[ test]
#[ cfg(feature = "parsed-types" )]
fn parse_item_number_with_param() -> Result<(), Error> {
let param = Parameters::from_iter(vec![(
key_ref("a1" ).to_owned(),
BareItem::Token(token_ref("*" ).to_owned()),
)]);
assert_eq!(
Item::with_params(string_ref("12.35" ), param),
Parser::new(r#" "12.35" ;a1=*"#).parse::<Item>()?
);
Ok(())
}
#[ test]
#[ cfg(feature = "parsed-types" )]
fn parse_dict_empty() -> Result<(), Error> {
assert_eq!(Dictionary::new(), Parser::new("" ).parse::<Dictionary>()?);
Ok(())
}
#[ test]
fn parse_dict_errors() {
let input = "abc=123;a=1;b=2 def" ;
assert_eq!(
Err(error::Repr::TrailingCharactersAfterMember(16 ).into()),
Parser::new(input).parse_dictionary_with_visitor(&mut Ignored)
);
let input = "abc=123;a=1," ;
assert_eq!(
Err(error::Repr::TrailingComma(11 ).into()),
Parser::new(input).parse_dictionary_with_visitor(&mut Ignored)
);
}
#[ test]
#[ cfg(feature = "parsed-types" )]
fn parse_dict_with_spaces_and_params() -> Result<(), Error> {
let input = r#" abc=123 ;a=1 ;b=2 , def=456 , ghi=789 ;q=9 ;r="+w" "#;
let item1_params = Parameters::from_iter(vec![
(key_ref("a" ).to_owned(), 1 .into()),
(key_ref("b" ).to_owned(), 2 .into()),
]);
let item3_params = Parameters::from_iter(vec![
(key_ref("q" ).to_owned(), 9 .into()),
(
key_ref("r" ).to_owned(),
BareItem::String(string_ref("+w" ).to_owned()),
),
]);
let item1 = Item::with_params(123 , item1_params);
let item2 = Item::new(456 );
let item3 = Item::with_params(789 , item3_params);
let expected_dict = Dictionary::from_iter(vec![
(key_ref("abc" ).to_owned(), item1.into()),
(key_ref("def" ).to_owned(), item2.into()),
(key_ref("ghi" ).to_owned(), item3.into()),
]);
assert_eq!(expected_dict, Parser::new(input).parse::<Dictionary>()?);
Ok(())
}
#[ test]
#[ cfg(feature = "parsed-types" )]
fn parse_dict_empty_value() -> Result<(), Error> {
let input = "a=()" ;
let inner_list = InnerList::new(vec![]);
let expected_dict = Dictionary::from_iter(vec![(key_ref("a" ).to_owned(), inner_list.into())]);
assert_eq!(expected_dict, Parser::new(input).parse::<Dictionary>()?);
Ok(())
}
#[ test]
#[ cfg(feature = "parsed-types" )]
fn parse_dict_with_token_param() -> Result<(), Error> {
let input = "a=1, b;foo=*, c=3" ;
let item2_params = Parameters::from_iter(vec![(
key_ref("foo" ).to_owned(),
BareItem::Token(token_ref("*" ).to_owned()),
)]);
let item1 = Item::new(1 );
let item2 = Item::with_params(true , item2_params);
let item3 = Item::new(3 );
let expected_dict = Dictionary::from_iter(vec![
(key_ref("a" ).to_owned(), item1.into()),
(key_ref("b" ).to_owned(), item2.into()),
(key_ref("c" ).to_owned(), item3.into()),
]);
assert_eq!(expected_dict, Parser::new(input).parse::<Dictionary>()?);
Ok(())
}
#[ test]
#[ cfg(feature = "parsed-types" )]
fn parse_dict_multiple_spaces() -> Result<(), Error> {
// input1, input2, input3 must be parsed into the same structure
let item1 = Item::new(1 );
let item2 = Item::new(2 );
let expected_dict = Dictionary::from_iter(vec![
(key_ref("a" ).to_owned(), item1.into()),
(key_ref("b" ).to_owned(), item2.into()),
]);
let input1 = "a=1 , b=2" ;
let input2 = "a=1\t,\tb=2" ;
let input3 = "a=1, b=2" ;
assert_eq!(expected_dict, Parser::new(input1).parse::<Dictionary>()?);
assert_eq!(expected_dict, Parser::new(input2).parse::<Dictionary>()?);
assert_eq!(expected_dict, Parser::new(input3).parse::<Dictionary>()?);
Ok(())
}
#[ test]
fn parse_bare_item() -> Result<(), Error> {
assert_eq!(
RefBareItem::Boolean(false ),
Parser::new("?0" ).parse_bare_item()?
);
assert_eq!(
RefBareItem::String(string_ref("test string" )),
Parser::new(r#" "test string" "#).parse_bare_item()?
);
assert_eq!(
RefBareItem::Token(token_ref("*token" )),
Parser::new("*token" ).parse_bare_item()?
);
assert_eq!(
RefBareItem::ByteSequence(b"base_64 encoding test" ),
Parser::new(":YmFzZV82NCBlbmNvZGluZyB0ZXN0:" ).parse_bare_item()?
);
assert_eq!(
RefBareItem::Decimal(Decimal::try_from(-3 .55 )?),
Parser::new("-3.55" ).parse_bare_item()?
);
Ok(())
}
#[ test]
fn parse_bare_item_errors() {
assert_eq!(
Err(error::Repr::ExpectedStartOfBareItem(0 )),
Parser::new("!?0" ).parse_bare_item()
);
assert_eq!(
Err(error::Repr::ExpectedStartOfBareItem(0 )),
Parser::new("_11abc" ).parse_bare_item()
);
assert_eq!(
Err(error::Repr::ExpectedStartOfBareItem(0 )),
Parser::new(" " ).parse_bare_item()
);
}
#[ test]
#[ allow(clippy::bool_assert_comparison)]
fn parse_bool() -> Result<(), Error> {
let mut parser = Parser::new("?0gk" );
assert_eq!(false , parser.parse_bool()?);
assert_eq!(parser.remaining(), b"gk" );
assert_eq!(false , Parser::new("?0" ).parse_bool()?);
assert_eq!(true , Parser::new("?1" ).parse_bool()?);
Ok(())
}
#[ test]
fn parse_bool_errors() {
assert_eq!(
Err(error::Repr::ExpectedStartOfBoolean(0 )),
Parser::new("" ).parse_bool()
);
assert_eq!(
Err(error::Repr::ExpectedBoolean(1 )),
Parser::new("?" ).parse_bool()
);
}
#[ test]
fn parse_string() -> Result<(), Error> {
let mut parser = Parser::new(r#" "some string" ;not string"#);
assert_eq!(string_ref("some string" ), parser.parse_string()?);
assert_eq!(parser.remaining(), " ;not string" .as_bytes());
assert_eq!(string_ref("test" ), Parser::new(r#" "test" "#).parse_string()?);
assert_eq!(
string_ref("te\\st" ),
Parser::new(r#" "te\\st" "#).parse_string()?
);
assert_eq!(string_ref("" ), Parser::new(r#" "" "#).parse_string()?);
assert_eq!(
string_ref("some string" ),
Parser::new(r#" "some string" "#).parse_string()?
);
Ok(())
}
#[ test]
fn parse_string_errors() {
assert_eq!(
Err(error::Repr::ExpectedStartOfString(0 )),
Parser::new("test" ).parse_string()
);
assert_eq!(
Err(error::Repr::UnterminatedEscapeSequence(2 )),
Parser::new(r#" "\" #) .parse_string()
);
assert_eq!(
Err(error::Repr::InvalidEscapeSequence(2 )),
Parser::new(r#" "\l" "#).parse_string()
);
assert_eq!(
Err(error::Repr::InvalidStringCharacter(1 )),
Parser::new("\" \u{1 f}\"" ).parse_string()
);
assert_eq!(
Err(error::Repr::UnterminatedString(5 )),
Parser::new(r#" "smth" #) .parse_string()
);
}
#[ test]
fn parse_token() -> Result<(), Error> {
let mut parser = Parser::new("*some:token}not token" );
assert_eq!(token_ref("*some:token" ), parser.parse_token()?);
assert_eq!(parser.remaining(), b"}not token" );
assert_eq!(token_ref("token" ), Parser::new("token" ).parse_token()?);
assert_eq!(
token_ref("a_b-c.d3:f%00/*"),
Parser::new("a_b-c.d3:f%00/*").parse_token()?
);
assert_eq!(
token_ref("TestToken" ),
Parser::new("TestToken" ).parse_token()?
);
assert_eq!(token_ref("some" ), Parser::new("some@token" ).parse_token()?);
assert_eq!(
token_ref("*TestToken*" ),
Parser::new("*TestToken*" ).parse_token()?
);
assert_eq!(token_ref("*" ), Parser::new("*[@:token" ).parse_token()?);
assert_eq!(token_ref("test" ), Parser::new("test token" ).parse_token()?);
Ok(())
}
#[ test]
fn parse_token_errors() {
let mut parser = Parser::new("765token" );
assert_eq!(
Err(error::Repr::ExpectedStartOfToken(0 )),
parser.parse_token()
);
assert_eq!(parser.remaining(), b"765token" );
assert_eq!(
Err(error::Repr::ExpectedStartOfToken(0 )),
Parser::new("7token" ).parse_token()
);
assert_eq!(
Err(error::Repr::ExpectedStartOfToken(0 )),
Parser::new("" ).parse_token()
);
}
#[ test]
fn parse_byte_sequence() -> Result<(), Error> {
let mut parser = Parser::new(":aGVsbG8:rest_of_str" );
assert_eq!("hello" .as_bytes(), parser.parse_byte_sequence()?);
assert_eq!(parser.remaining(), b"rest_of_str" );
assert_eq!(
"hello" .as_bytes(),
Parser::new(":aGVsbG8:" ).parse_byte_sequence()?
);
assert_eq!(
"test_encode" .as_bytes(),
Parser::new(":dGVzdF9lbmNvZGU:" ).parse_byte_sequence()?
);
assert_eq!(
"new:year tree" .as_bytes(),
Parser::new(":bmV3OnllYXIgdHJlZQ==:" ).parse_byte_sequence()?
);
assert_eq!("" .as_bytes(), Parser::new("::" ).parse_byte_sequence()?);
Ok(())
}
#[ test]
fn parse_byte_sequence_errors() {
assert_eq!(
Err(error::Repr::ExpectedStartOfByteSequence(0 )),
Parser::new("aGVsbG8" ).parse_byte_sequence()
);
assert_eq!(
Err(error::Repr::InvalidByteSequence(6 )),
Parser::new(":aGVsb G8=:" ).parse_byte_sequence()
);
assert_eq!(
Err(error::Repr::UnterminatedByteSequence(9 )),
Parser::new(":aGVsbG8=" ).parse_byte_sequence()
);
}
#[ test]
fn parse_number_int() -> Result<(), Error> {
let mut parser = Parser::new("-733333333332d.14" );
assert_eq!(
Num::Integer(integer(-733 _333 _333 _332 )),
parser.parse_number()?
);
assert_eq!(parser.remaining(), b"d.14" );
assert_eq!(Num::Integer(integer(42 )), Parser::new("42" ).parse_number()?);
assert_eq!(
Num::Integer(integer(-42 )),
Parser::new("-42" ).parse_number()?
);
assert_eq!(
Num::Integer(integer(-42 )),
Parser::new("-042" ).parse_number()?
);
assert_eq!(Num::Integer(integer(0 )), Parser::new("0" ).parse_number()?);
assert_eq!(Num::Integer(integer(0 )), Parser::new("00" ).parse_number()?);
assert_eq!(
Num::Integer(integer(123 _456 _789 _012 _345 )),
Parser::new("123456789012345" ).parse_number()?
);
assert_eq!(
Num::Integer(integer(-123 _456 _789 _012 _345 )),
Parser::new("-123456789012345" ).parse_number()?
);
assert_eq!(Num::Integer(integer(2 )), Parser::new("2,3" ).parse_number()?);
assert_eq!(Num::Integer(integer(4 )), Parser::new("4-2" ).parse_number()?);
assert_eq!(
Num::Integer(integer(-999 _999 _999 _999 _999 )),
Parser::new("-999999999999999" ).parse_number()?
);
assert_eq!(
Num::Integer(integer(999 _999 _999 _999 _999 )),
Parser::new("999999999999999" ).parse_number()?
);
Ok(())
}
#[ test]
fn parse_number_decimal() -> Result<(), Error> {
let mut parser = Parser::new("00.42 test string" );
assert_eq!(
Num::Decimal(Decimal::try_from(0 .42 )?),
parser.parse_number()?
);
assert_eq!(parser.remaining(), b" test string" );
assert_eq!(
Num::Decimal(Decimal::try_from(1 .5 )?),
Parser::new("1.5.4." ).parse_number()?
);
assert_eq!(
Num::Decimal(Decimal::try_from(1 .8 )?),
Parser::new("1.8." ).parse_number()?
);
assert_eq!(
Num::Decimal(Decimal::try_from(1 .7 )?),
Parser::new("1.7.0" ).parse_number()?
);
assert_eq!(
Num::Decimal(Decimal::try_from(2 .14 )?),
Parser::new("2.14" ).parse_number()?
);
assert_eq!(
Num::Decimal(Decimal::try_from(-2 .14 )?),
Parser::new("-2.14" ).parse_number()?
);
assert_eq!(
Num::Decimal(Decimal::try_from(123 _456 _789 _012 .1 )?),
Parser::new("123456789012.1" ).parse_number()?
);
assert_eq!(
Num::Decimal(Decimal::try_from(1 _234 _567 _890 .112 )?),
Parser::new("1234567890.112" ).parse_number()?
);
Ok(())
}
#[ test]
fn parse_number_errors() {
let mut parser = Parser::new(":aGVsbG8:rest" );
assert_eq!(Err(error::Repr::ExpectedDigit(0 )), parser.parse_number());
assert_eq!(parser.remaining(), b":aGVsbG8:rest" );
let mut parser = Parser::new("-11.5555 test string" );
assert_eq!(
Err(error::Repr::TooManyDigitsAfterDecimalPoint(7 )),
parser.parse_number()
);
assert_eq!(parser.remaining(), b"5 test string" );
assert_eq!(
Err(error::Repr::ExpectedDigit(1 )),
Parser::new("--0" ).parse_number()
);
assert_eq!(
Err(error::Repr::TooManyDigitsBeforeDecimalPoint(13 )),
Parser::new("1999999999999.1" ).parse_number()
);
assert_eq!(
Err(error::Repr::TrailingDecimalPoint(11 )),
Parser::new("19888899999." ).parse_number()
);
assert_eq!(
Err(error::Repr::TooManyDigits(15 )),
Parser::new("1999999999999999" ).parse_number()
);
assert_eq!(
Err(error::Repr::TooManyDigitsAfterDecimalPoint(15 )),
Parser::new("19999999999.99991" ).parse_number()
);
assert_eq!(
Err(error::Repr::ExpectedDigit(1 )),
Parser::new("- 42" ).parse_number()
);
assert_eq!(
Err(error::Repr::TrailingDecimalPoint(1 )),
Parser::new("1..4" ).parse_number()
);
assert_eq!(
Err(error::Repr::ExpectedDigit(1 )),
Parser::new("-" ).parse_number()
);
assert_eq!(
Err(error::Repr::TrailingDecimalPoint(2 )),
Parser::new("-5. 14" ).parse_number()
);
assert_eq!(
Err(error::Repr::TrailingDecimalPoint(1 )),
Parser::new("7. 1" ).parse_number()
);
assert_eq!(
Err(error::Repr::TooManyDigitsAfterDecimalPoint(6 )),
Parser::new("-7.3333333333" ).parse_number()
);
assert_eq!(
Err(error::Repr::TooManyDigitsBeforeDecimalPoint(14 )),
Parser::new("-7333333333323.12" ).parse_number()
);
}
#[ test]
#[ cfg(feature = "parsed-types" )]
fn parse_params_string() -> Result<(), Error> {
let input = r#" ;b="param_val" "#;
let expected = Parameters::from_iter(vec![(
key_ref("b" ).to_owned(),
BareItem::String(string_ref("param_val" ).to_owned()),
)]);
let mut params = Parameters::new();
Parser::new(input).parse_parameters(&mut params)?;
assert_eq!(expected, params);
Ok(())
}
#[ test]
#[ cfg(feature = "parsed-types" )]
fn parse_params_bool() -> Result<(), Error> {
let input = ";b;a" ;
let expected = Parameters::from_iter(vec![
(key_ref("b" ).to_owned(), BareItem::Boolean(true )),
(key_ref("a" ).to_owned(), BareItem::Boolean(true )),
]);
let mut params = Parameters::new();
Parser::new(input).parse_parameters(&mut params)?;
assert_eq!(expected, params);
Ok(())
}
#[ test]
#[ cfg(feature = "parsed-types" )]
fn parse_params_mixed_types() -> Result<(), Error> {
let input = ";key1=?0;key2=746.15" ;
let expected = Parameters::from_iter(vec![
(key_ref("key1" ).to_owned(), BareItem::Boolean(false )),
(
key_ref("key2" ).to_owned(),
Decimal::try_from(746 .15 )?.into(),
),
]);
let mut params = Parameters::new();
Parser::new(input).parse_parameters(&mut params)?;
assert_eq!(expected, params);
Ok(())
}
#[ test]
#[ cfg(feature = "parsed-types" )]
fn parse_params_with_spaces() -> Result<(), Error> {
let input = "; key1=?0; key2=11111" ;
let expected = Parameters::from_iter(vec![
(key_ref("key1" ).to_owned(), BareItem::Boolean(false )),
(key_ref("key2" ).to_owned(), 11111 .into()),
]);
let mut params = Parameters::new();
Parser::new(input).parse_parameters(&mut params)?;
assert_eq!(expected, params);
Ok(())
}
#[ test]
#[ cfg(feature = "parsed-types" )]
fn parse_params_empty() -> Result<(), Error> {
let mut params = Parameters::new();
Parser::new(" key1=?0; key2=11111" ).parse_parameters(&mut params)?;
assert_eq!(Parameters::new(), params);
Parser::new("" ).parse_parameters(&mut params)?;
assert_eq!(Parameters::new(), params);
Parser::new("[;a=1" ).parse_parameters(&mut params)?;
assert_eq!(Parameters::new(), params);
Parser::new("" ).parse_parameters(&mut params)?;
assert_eq!(Parameters::new(), params);
Ok(())
}
#[ test]
fn parse_key() -> Result<(), Error> {
assert_eq!(key_ref("a" ), Parser::new("a=1" ).parse_key()?);
assert_eq!(key_ref("a1" ), Parser::new("a1=10" ).parse_key()?);
assert_eq!(key_ref("*1" ), Parser::new("*1=10" ).parse_key()?);
assert_eq!(key_ref("f" ), Parser::new("f[f=10" ).parse_key()?);
Ok(())
}
#[ test]
fn parse_key_errors() {
assert_eq!(
Err(error::Repr::ExpectedStartOfKey(0 )),
Parser::new("[*f=10" ).parse_key()
);
}
#[ test]
#[ cfg(feature = "parsed-types" )]
fn parse_more_list() -> Result<(), Error> {
let item1 = Item::new(1 );
let item2 = Item::new(2 );
let item3 = Item::new(42 );
let inner_list_1 = InnerList::new(vec![item1, item2]);
let expected_list: List = vec![inner_list_1.into(), item3.into()];
let mut parsed_header: List = Parser::new("(1 2)" ).parse()?;
Parser::new("42" ).parse_list_with_visitor(&mut parsed_header)?;
assert_eq!(expected_list, parsed_header);
Ok(())
}
#[ test]
#[ cfg(feature = "parsed-types" )]
fn parse_more_dict() -> Result<(), Error> {
let item2_params = Parameters::from_iter(vec![(
key_ref("foo" ).to_owned(),
BareItem::Token(token_ref("*" ).to_owned()),
)]);
let item1 = Item::new(1 );
let item2 = Item::with_params(true , item2_params);
let item3 = Item::new(3 );
let expected_dict = Dictionary::from_iter(vec![
(key_ref("a" ).to_owned(), item1.into()),
(key_ref("b" ).to_owned(), item2.into()),
(key_ref("c" ).to_owned(), item3.into()),
]);
let mut parsed_header: Dictionary = Parser::new("a=1, b;foo=*\t\t" ).parse()?;
Parser::new(" c=3" ).parse_dictionary_with_visitor(&mut parsed_header)?;
assert_eq!(expected_dict, parsed_header);
Ok(())
}
#[ test]
#[ cfg(feature = "parsed-types" )]
fn parse_more_errors() -> Result<(), Error> {
let mut parsed_dict_header: Dictionary = Parser::new("a=1, b;foo=*" ).parse()?;
assert!(Parser::new(",a" )
.parse_dictionary_with_visitor(&mut parsed_dict_header)
.is_err());
let mut parsed_list_header: List = Parser::new("a, b;foo=*" ).parse()?;
assert!(Parser::new("(a, 2)" )
.parse_list_with_visitor(&mut parsed_list_header)
.is_err());
Ok(())
}
#[ test]
#[ cfg(feature = "parsed-types" )]
fn parse_date() -> Result<(), Error> {
let input = "@0" ;
assert!(Parser::new(input)
.with_version(Version::Rfc8941)
.parse::<Item>()
.is_err());
assert_eq!(
Parser::new(input).parse::<Item>()?,
Item::new(Date::UNIX_EPOCH)
);
Ok(())
}
#[ test]
#[ cfg(feature = "parsed-types" )]
fn parse_display_string() -> Result<(), Error> {
let input = r#" %"This is intended for display to %c3%bcsers." "#;
assert!(Parser::new(input)
.with_version(Version::Rfc8941)
.parse::<Item>()
.is_err());
assert_eq!(
Parser::new(input).parse::<Item>()?,
Item::new(BareItem::DisplayString(
"This is intended for display to üsers." .to_owned()
))
);
Ok(())
}
#[ test]
#[ cfg(feature = "parsed-types" )]
fn parse_display_string_errors() {
assert_eq!(
Parser::new(" %" ).parse::<Item>(),
Err(error::Repr::ExpectedQuote(2 ).into())
);
assert_eq!(
Parser::new(r#" %"" #) .parse::<Item>(),
Err(error::Repr::UnterminatedDisplayString(3 ).into())
);
assert_eq!(
Parser::new(r#" %"%" #) .parse::<Item>(),
Err(error::Repr::UnterminatedEscapeSequence(4 ).into())
);
assert_eq!(
Parser::new(r#" %"%a" #) .parse::<Item>(),
Err(error::Repr::UnterminatedEscapeSequence(5 ).into())
);
assert_eq!(
Parser::new(r#" %"%A" #) .parse::<Item>(),
Err(error::Repr::InvalidEscapeSequence(4 ).into())
);
assert_eq!(
Parser::new(r#" %"%aA" #) .parse::<Item>(),
Err(error::Repr::InvalidEscapeSequence(5 ).into())
);
assert_eq!(
Parser::new(r#" %"x%aa" "#).parse::<Item>(),
Err(error::Repr::InvalidUtf8InDisplayString(4 ).into())
);
}
/// A simple struct used for the complex tests.
#[ derive(Default, Debug, PartialEq)]
struct Point {
x: i64,
y: i64,
}
impl Point {
fn new(x: i64, y: i64) -> Self {
Self { x, y }
}
}
struct PointVisitor<'a> {
point: &'a mut Point,
}
/// For when a `Point` is a parameter somewhere.
impl <'de> ParameterVisitor<' de> for PointVisitor<'_> {
type Error = Infallible;
fn parameter(
&mut self ,
key: &'de KeyRef,
value: BareItemFromInput<'de>,
) -> Result<(), Self ::Error> {
let Some(v) = value.as_integer() else {
return Ok(());
};
let ptr = match key.as_str() {
"x" => &mut self .point.x,
"y" => &mut self .point.y,
_ => return Ok(()),
};
*ptr = i64::from(v);
Ok(())
}
}
impl <'de> DictionaryVisitor<' de> for PointVisitor<'_> {
type Error = Infallible;
fn entry(&mut self , key: &'de KeyRef) -> Result<impl EntryVisitor<' de>, Self ::Error> {
let coord = match key.as_str() {
"x" => &mut self .point.x,
"y" => &mut self .point.y,
_ => return Ok(None),
};
Ok(Some(CoordVisitor { coord }))
}
}
struct CoordVisitor<'a> {
coord: &'a mut i64,
}
impl <'de> ItemVisitor<' de> for CoordVisitor<'_> {
type Error = Infallible;
fn bare_item(
self ,
bare_item: BareItemFromInput<'de>,
) -> Result<impl ParameterVisitor<'de>, Self::Error> {
if let Some(v) = bare_item.as_integer() {
*self .coord = i64::from(v);
}
Ok(None::<Ignored>)
}
}
impl <'de> EntryVisitor<' de> for CoordVisitor<'_> {
fn inner_list(self ) -> Result<impl InnerListVisitor<'de>, Self::Error> {
Ok(Ignored)
}
}
#[ test]
fn complex_dict_visitor() {
let mut point = Point::default();
let parser = Parser::new("x=10, y=3" );
let mut visit = PointVisitor { point: &mut point };
parser
.parse_dictionary_with_visitor(&mut visit)
.expect("successful parse" );
assert_eq!(point, Point::new(10 , 3 ));
}
/// An item with parameters.
#[ derive(Default, Debug, PartialEq)]
struct Holder {
v: i64,
point: Point,
}
/// A visitor for an item that is an integer, with optional `x` and `y` parameters.
struct HolderVisitor<'a> {
holder: &'a mut Holder,
}
impl <'de> ItemVisitor<' de> for HolderVisitor<'_> {
type Error = Infallible;
fn bare_item(
self ,
bare_item: BareItemFromInput<'de>,
) -> Result<impl ParameterVisitor<'de>, Self::Error> {
Ok(if let Some(v) = bare_item.as_integer() {
self .holder.v = i64::from(v);
Some(PointVisitor {
point: &mut self .holder.point,
})
} else {
None
})
}
}
#[ test]
fn complex_item_visitor() {
let mut holder = Holder::default();
let parser = Parser::new("12;x=7;y=-5" );
let visit = HolderVisitor {
holder: &mut holder,
};
parser
.parse_item_with_visitor(visit)
.expect("successful parse" );
assert_eq!(holder.point, Point::new(7 , -5 ));
}
#[ test]
fn complex_list_visitor() {
#[ derive(Default, Debug, PartialEq)]
struct ListHolder {
list: Vec<Holder>,
point: Point,
}
struct OuterListVisitor<'a> {
list: &'a mut Vec<ListHolder>,
}
impl <'de> ListVisitor<' de> for OuterListVisitor<'_> {
type Error = Infallible;
fn entry(&mut self ) -> Result<impl EntryVisitor<'de>, Self::Error> {
self .list.push(ListHolder::default());
let list = self .list.last_mut().unwrap(); // cannot fail
Ok(HolderListVisitor { list })
}
}
struct HolderListVisitor<'a> {
list: &'a mut ListHolder,
}
impl <'de> ItemVisitor<' de> for HolderListVisitor<'_> {
type Error = Infallible;
fn bare_item(
self ,
_bare_item: BareItemFromInput<'de>,
) -> Result<impl ParameterVisitor<'de>, Self::Error> {
Ok(None::<Ignored>)
}
}
impl <'de> EntryVisitor<' de> for HolderListVisitor<'_> {
fn inner_list(self ) -> Result<impl InnerListVisitor<'de>, Self::Error> {
Ok(self )
}
}
impl <'de> InnerListVisitor<' de> for HolderListVisitor<'_> {
type Error = Infallible;
fn item(&mut self ) -> Result<impl ItemVisitor<'de>, Self::Error> {
self .list.list.push(Holder::default());
let holder = self .list.list.last_mut().unwrap(); // cannot fail
Ok(HolderVisitor { holder })
}
fn finish(self ) -> Result<impl ParameterVisitor<'de>, Self::Error> {
let point = &mut self .list.point;
Ok(Some(PointVisitor { point }))
}
}
let mut list = Vec::default();
let parser = Parser::new("(1;x=4 2;y=5 3);x=1;y=2,(4;x=12;y=33), ()" );
let mut visit = OuterListVisitor { list: &mut list };
parser
.parse_list_with_visitor(&mut visit)
.expect("successful parse" );
let expected = vec![
ListHolder {
list: vec![
Holder {
v: 1 ,
point: Point::new(4 , 0 ),
},
Holder {
v: 2 ,
point: Point::new(0 , 5 ),
},
Holder {
v: 3 ,
point: Point::default(),
},
],
point: Point::new(1 , 2 ),
},
ListHolder {
list: vec![Holder {
v: 4 ,
point: Point::new(12 , 33 ),
}],
point: Point::default(),
},
ListHolder {
list: Vec::new(),
point: Point::default(),
},
];
assert_eq!(list, expected);
}
// Regression test for https://github.com/undef1nd/sfv/issues/194.
// This test does not compile without the associated fix.
#[ test]
fn parse_dictionary_lifetime() -> Result<(), Error> {
struct Visitor<'de>(Option<&' de KeyRef>);
impl <'de> DictionaryVisitor<' de> for Visitor<'de> {
type Error = Infallible;
fn entry(&mut self , key: &'de KeyRef) -> Result<impl EntryVisitor<' de>, Self ::Error> {
self .0 = Some(key);
Ok(Ignored)
}
}
let mut visitor = Visitor(None);
Parser::new("a=1" ).parse_dictionary_with_visitor(&mut visitor)?;
assert_eq!(visitor.0 , Some(key_ref("a" )));
Ok(())
}
Messung V0.5 in Prozent C=90 H=98 G=94
¤ Dauer der Verarbeitung: 0.11 Sekunden
¤
*© Formatika GbR, Deutschland