use super::*; mod section_headers { use super::section_header; use crate::parse::tests::util::{fully_consumed, section_header as parsed_section_header}; #[test] fn no_subsection() { assert_eq!( section_header(b"[hello]").unwrap(), fully_consumed(parsed_section_header("hello", None)), ); } #[test] fn modern_subsection() { assert_eq!( section_header(br#"[hello "world"]"#).unwrap(), fully_consumed(parsed_section_header("hello", (" ", "world"))), ); } #[test] fn escaped_subsection() { assert_eq!( section_header(br#"[hello "foo\\bar\""]"#).unwrap(), fully_consumed(parsed_section_header("hello", (" ", r#"foo\bar""#))), ); } #[test] fn deprecated_subsection() { assert_eq!( section_header(br#"[hello.world]"#).unwrap(), fully_consumed(parsed_section_header("hello", (".", "world"))) ); assert_eq!( section_header(br#"[Hello.World]"#).unwrap(), fully_consumed(parsed_section_header("Hello", (".", "World"))) ); } #[test] fn empty_legacy_subsection_name() { assert_eq!( section_header(br#"[hello-world.]"#).unwrap(), fully_consumed(parsed_section_header("hello-world", (".", ""))) ); } #[test] fn empty_modern_subsection_name() { assert_eq!( section_header(br#"[hello ""]"#).unwrap(), fully_consumed(parsed_section_header("hello", (" ", ""))) ); } #[test] fn backslashes_in_subsections_do_not_escape_newlines_or_tabs() { assert_eq!( section_header(br#"[hello "single \ \\ \t \n \0"]"#).unwrap(), fully_consumed(parsed_section_header("hello", (" ", r#"single \ t n 0"#))) ); } #[test] fn newline_in_header() { assert!(section_header(b"[hello\n]").is_err()); } #[test] fn newline_in_sub_section() { assert!(section_header(b"[hello \"hello\n\"]").is_err()); } #[test] fn null_byt_in_sub_section() { assert!(section_header(b"[hello \"hello\0\"]").is_err()); } #[test] fn escaped_newline_in_sub_section() { assert!(section_header(b"[hello \"hello\\\n\"]").is_err()); } #[test] fn eof_after_escape_in_sub_section() { assert!(section_header(b"[hello \"hello\\").is_err()); } #[test] fn null_byte_in_header() { assert!(section_header(b"[hello\0]").is_err()); } #[test] fn invalid_characters_in_section() { assert!(section_header(b"[$]").is_err()); } #[test] fn invalid_characters_in_legacy_sub_section() { assert!(section_header(b"[hello.$]").is_err()); assert!(section_header(b"[hello. world]").is_err()); } #[test] fn right_brace_in_subsection_name() { assert_eq!( section_header(br#"[hello "]"]"#).unwrap(), fully_consumed(parsed_section_header("hello", (" ", "]"))) ); }} mod sub_section { use std::borrow::Cow; use super::sub_section; #[test] fn zero_copy_simple() { let actual = sub_section(b"name\"").unwrap().1; assert_eq!(actual.as_ref(), "name"); assert!(matches!(actual, Cow::Borrowed(_))); } #[test] fn escapes_need_allocation() { let actual = sub_section(br#"\x\t\n\0\\\"""#).unwrap().1; assert_eq!(actual.as_ref(), r#"xtn0\""#); assert!(matches!(actual, Cow::Owned(_))); }} mod config_name { use nom::combinator::all_consuming; use super::config_name; use crate::parse::tests::util::fully_consumed; #[test] fn just_name() { assert_eq!(config_name(b"name").unwrap(), fully_consumed("name".into())); } #[test] fn must_start_with_alphabetic() { assert!(config_name(b"4aaa").is_err()); assert!(config_name(b"-aaa").is_err()); } #[test] fn only_a_subset_of_characters_is_allowed() { assert!(all_consuming(config_name)(b"Name$_").is_err()); assert!(all_consuming(config_name)(b"other#").is_err()); } #[test] fn cannot_be_empty() { assert!(config_name(b"").is_err()); }} mod section { use crate::parse::{ error::ParseNode, section, tests::util::{ comment_event, fully_consumed, name_event, newline_custom_event, newline_event, section_header as parsed_section_header, value_done_event, value_event, value_not_done_event, whitespace_event, }, Event, Section, }; fn section<'a>(i: &'a [u8], node: &mut ParseNode) -> nom::IResult<&'a [u8], (Section<'a>, usize)> { let mut header = None; let mut events = section::Events::default(); super::section(i, node, &mut |e| match &header { None => { header = Some(e); } Some(_) => events.push(e), }) .map(|(i, o)| { ( i, ( Section { header: match header.expect("header set") { Event::SectionHeader(header) => header, _ => unreachable!("unexpected"), }, events, }, o, ), ) }) } #[test] fn empty_value_with_windows_newlines() { let mut node = ParseNode::SectionHeader; assert_eq!( section(b"[a] k = \r\n", &mut node).unwrap(), fully_consumed(( Section { header: parsed_section_header("a", None), events: vec![ whitespace_event(" "), name_event("k"), whitespace_event(" "), Event::KeyValueSeparator, whitespace_event(" "), value_event(""), newline_custom_event("\r\n") ] .into(), }, 1 )), ); } #[test] fn simple_value_with_windows_newlines() { let mut node = ParseNode::SectionHeader; assert_eq!( section(b"[a] k = v\r\n", &mut node).unwrap(), fully_consumed(( Section { header: parsed_section_header("a", None), events: vec![ whitespace_event(" "), name_event("k"), whitespace_event(" "), Event::KeyValueSeparator, whitespace_event(" "), value_event("v"), newline_custom_event("\r\n") ] .into(), }, 1 )), ); assert_eq!( section(b"[a] k = \r\n", &mut node).unwrap(), fully_consumed(( Section { header: parsed_section_header("a", None), events: vec![ whitespace_event(" "), name_event("k"), whitespace_event(" "), Event::KeyValueSeparator, whitespace_event(" "), value_event(""), newline_custom_event("\r\n") ] .into(), }, 1 )), ); } #[test] fn empty_section() { let mut node = ParseNode::SectionHeader; assert_eq!( section(b"[test]", &mut node).unwrap(), fully_consumed(( Section { header: parsed_section_header("test", None), events: Default::default() }, 0 )), ); } #[test] fn simple_section() { let mut node = ParseNode::SectionHeader; let section_data = br#"[hello] a = b c d = "lol""#; assert_eq!( section(section_data, &mut node).unwrap(), fully_consumed(( Section { header: parsed_section_header("hello", None), events: vec![ newline_event(), whitespace_event(" "), name_event("a"), whitespace_event(" "), Event::KeyValueSeparator, whitespace_event(" "), value_event("b"), newline_event(), whitespace_event(" "), name_event("c"), value_event(""), newline_event(), whitespace_event(" "), name_event("d"), whitespace_event(" "), Event::KeyValueSeparator, whitespace_event(" "), value_event("\"lol\"") ] .into() }, 3 )) ); } #[test] fn section_with_empty_value_simplified() { let mut node = ParseNode::SectionHeader; let section_data = b"[a] k="; assert_eq!( section(section_data, &mut node).unwrap(), fully_consumed(( Section { header: parsed_section_header("a", None), events: vec![ whitespace_event(" "), name_event("k"), Event::KeyValueSeparator, value_event(""), ] .into() }, 0 )) ); let section_data = b"[a] k=\n"; assert_eq!( section(section_data, &mut node).unwrap(), fully_consumed(( Section { header: parsed_section_header("a", None), events: vec![ whitespace_event(" "), name_event("k"), Event::KeyValueSeparator, value_event(""), newline_event(), ] .into() }, 1 )) ); } #[test] fn section_with_empty_value() { let mut node = ParseNode::SectionHeader; let section_data = br#"[hello] a = b c= d = "lol""#; assert_eq!( section(section_data, &mut node).unwrap(), fully_consumed(( Section { header: parsed_section_header("hello", None), events: vec![ newline_event(), whitespace_event(" "), name_event("a"), whitespace_event(" "), Event::KeyValueSeparator, whitespace_event(" "), value_event("b"), newline_event(), whitespace_event(" "), name_event("c"), Event::KeyValueSeparator, value_event(""), newline_event(), whitespace_event(" "), name_event("d"), whitespace_event(" "), Event::KeyValueSeparator, whitespace_event(" "), value_event("\"lol\"") ] .into() }, 3 )) ); } #[test] fn section_implicit_value() { let mut node = ParseNode::SectionHeader; assert_eq!( section(b"[hello] c", &mut node).unwrap(), fully_consumed(( Section { header: parsed_section_header("hello", None), events: vec![whitespace_event(" "), name_event("c"), value_event("")].into() }, 0 )) ); assert_eq!( section(b"[hello] c\nd", &mut node).unwrap(), fully_consumed(( Section { header: parsed_section_header("hello", None), events: vec![ whitespace_event(" "), name_event("c"), value_event(""), newline_event(), name_event("d"), value_event("") ] .into() }, 1 )) ); } #[test] fn section_very_commented() { let mut node = ParseNode::SectionHeader; let section_data = br#"[hello] ; commentA a = b # commentB ; commentC ; commentD c = d"#; assert_eq!( section(section_data, &mut node).unwrap(), fully_consumed(( Section { header: parsed_section_header("hello", None), events: vec![ whitespace_event(" "), comment_event(';', " commentA"), newline_event(), whitespace_event(" "), name_event("a"), whitespace_event(" "), Event::KeyValueSeparator, whitespace_event(" "), value_event("b"), whitespace_event(" "), comment_event('#', " commentB"), newline_event(), whitespace_event(" "), comment_event(';', " commentC"), newline_event(), whitespace_event(" "), comment_event(';', " commentD"), newline_event(), whitespace_event(" "), name_event("c"), whitespace_event(" "), Event::KeyValueSeparator, whitespace_event(" "), value_event("d"), ] .into() }, 4 )) ); } #[test] fn complex_continuation() { let mut node = ParseNode::SectionHeader; // This test is absolute hell. Good luck if this fails. assert_eq!( section(b"[section] a = 1 \"\\\"\\\na ; e \"\\\"\\\nd # \"b\t ; c", &mut node).unwrap(), fully_consumed(( Section { header: parsed_section_header("section", None), events: vec![ whitespace_event(" "), name_event("a"), whitespace_event(" "), Event::KeyValueSeparator, whitespace_event(" "), value_not_done_event(r#"1 "\""#),Lines 1–500 of 906. Load more
use super::*; mod section_headers { use super::section_header; use crate::parse::tests::util::{fully_consumed, section_header as parsed_section_header}; #[test] fn no_subsection() { assert_eq!( section_header(b"[hello]").unwrap(), fully_consumed(parsed_section_header("hello", None)), ); } #[test] fn modern_subsection() { assert_eq!( section_header(br#"[hello "world"]"#).unwrap(), fully_consumed(parsed_section_header("hello", (" ", "world"))), ); } #[test] fn escaped_subsection() { assert_eq!( section_header(br#"[hello "foo\\bar\""]"#).unwrap(), fully_consumed(parsed_section_header("hello", (" ", r#"foo\bar""#))), ); } #[test] fn deprecated_subsection() { assert_eq!( section_header(br#"[hello.world]"#).unwrap(), fully_consumed(parsed_section_header("hello", (".", "world"))) ); assert_eq!( section_header(br#"[Hello.World]"#).unwrap(), fully_consumed(parsed_section_header("Hello", (".", "World"))) ); } #[test] fn empty_legacy_subsection_name() { assert_eq!( section_header(br#"[hello-world.]"#).unwrap(), fully_consumed(parsed_section_header("hello-world", (".", ""))) ); } #[test] fn empty_modern_subsection_name() { assert_eq!( section_header(br#"[hello ""]"#).unwrap(), fully_consumed(parsed_section_header("hello", (" ", ""))) ); } #[test] fn backslashes_in_subsections_do_not_escape_newlines_or_tabs() { assert_eq!( section_header(br#"[hello "single \ \\ \t \n \0"]"#).unwrap(), fully_consumed(parsed_section_header("hello", (" ", r#"single \ t n 0"#))) ); } #[test] fn newline_in_header() { assert!(section_header(b"[hello\n]").is_err()); } #[test] fn newline_in_sub_section() { assert!(section_header(b"[hello \"hello\n\"]").is_err()); } #[test] fn null_byt_in_sub_section() { assert!(section_header(b"[hello \"hello\0\"]").is_err()); } #[test] fn escaped_newline_in_sub_section() { assert!(section_header(b"[hello \"hello\\\n\"]").is_err()); } #[test] fn eof_after_escape_in_sub_section() { assert!(section_header(b"[hello \"hello\\").is_err()); } #[test] fn null_byte_in_header() { assert!(section_header(b"[hello\0]").is_err()); } #[test] fn invalid_characters_in_section() { assert!(section_header(b"[$]").is_err()); } #[test] fn invalid_characters_in_legacy_sub_section() { assert!(section_header(b"[hello.$]").is_err()); assert!(section_header(b"[hello. world]").is_err()); } #[test] fn right_brace_in_subsection_name() { assert_eq!( section_header(br#"[hello "]"]"#).unwrap(), fully_consumed(parsed_section_header("hello", (" ", "]"))) ); } } mod sub_section { use std::borrow::Cow; use super::sub_section; #[test] fn zero_copy_simple() { let actual = sub_section(b"name\"").unwrap().1; assert_eq!(actual.as_ref(), "name"); assert!(matches!(actual, Cow::Borrowed(_))); } #[test] fn escapes_need_allocation() { let actual = sub_section(br#"\x\t\n\0\\\"""#).unwrap().1; assert_eq!(actual.as_ref(), r#"xtn0\""#); assert!(matches!(actual, Cow::Owned(_))); } } mod config_name { use nom::combinator::all_consuming; use super::config_name; use crate::parse::tests::util::fully_consumed; #[test] fn just_name() { assert_eq!(config_name(b"name").unwrap(), fully_consumed("name".into())); } #[test] fn must_start_with_alphabetic() { assert!(config_name(b"4aaa").is_err()); assert!(config_name(b"-aaa").is_err()); } #[test] fn only_a_subset_of_characters_is_allowed() { assert!(all_consuming(config_name)(b"Name$_").is_err()); assert!(all_consuming(config_name)(b"other#").is_err()); } #[test] fn cannot_be_empty() { assert!(config_name(b"").is_err()); } } mod section { use crate::parse::{ error::ParseNode, section, tests::util::{ comment_event, fully_consumed, name_event, newline_custom_event, newline_event, section_header as parsed_section_header, value_done_event, value_event, value_not_done_event, whitespace_event, }, Event, Section, }; fn section<'a>(i: &'a [u8], node: &mut ParseNode) -> nom::IResult<&'a [u8], (Section<'a>, usize)> { let mut header = None; let mut events = section::Events::default(); super::section(i, node, &mut |e| match &header { None => { header = Some(e); } Some(_) => events.push(e), }) .map(|(i, o)| { ( i, ( Section { header: match header.expect("header set") { Event::SectionHeader(header) => header, _ => unreachable!("unexpected"), }, events, }, o, ), ) }) } #[test] fn empty_value_with_windows_newlines() { let mut node = ParseNode::SectionHeader; assert_eq!( section(b"[a] k = \r\n", &mut node).unwrap(), fully_consumed(( Section { header: parsed_section_header("a", None), events: vec![ whitespace_event(" "), name_event("k"), whitespace_event(" "), Event::KeyValueSeparator, whitespace_event(" "), value_event(""), newline_custom_event("\r\n") ] .into(), }, 1 )), ); } #[test] fn simple_value_with_windows_newlines() { let mut node = ParseNode::SectionHeader; assert_eq!( section(b"[a] k = v\r\n", &mut node).unwrap(), fully_consumed(( Section { header: parsed_section_header("a", None), events: vec![ whitespace_event(" "), name_event("k"), whitespace_event(" "), Event::KeyValueSeparator, whitespace_event(" "), value_event("v"), newline_custom_event("\r\n") ] .into(), }, 1 )), ); assert_eq!( section(b"[a] k = \r\n", &mut node).unwrap(), fully_consumed(( Section { header: parsed_section_header("a", None), events: vec![ whitespace_event(" "), name_event("k"), whitespace_event(" "), Event::KeyValueSeparator, whitespace_event(" "), value_event(""), newline_custom_event("\r\n") ] .into(), }, 1 )), ); } #[test] fn empty_section() { let mut node = ParseNode::SectionHeader; assert_eq!( section(b"[test]", &mut node).unwrap(), fully_consumed(( Section { header: parsed_section_header("test", None), events: Default::default() }, 0 )), ); } #[test] fn simple_section() { let mut node = ParseNode::SectionHeader; let section_data = br#"[hello] a = b c d = "lol""#; assert_eq!( section(section_data, &mut node).unwrap(), fully_consumed(( Section { header: parsed_section_header("hello", None), events: vec![ newline_event(), whitespace_event(" "), name_event("a"), whitespace_event(" "), Event::KeyValueSeparator, whitespace_event(" "), value_event("b"), newline_event(), whitespace_event(" "), name_event("c"), value_event(""), newline_event(), whitespace_event(" "), name_event("d"), whitespace_event(" "), Event::KeyValueSeparator, whitespace_event(" "), value_event("\"lol\"") ] .into() }, 3 )) ); } #[test] fn section_with_empty_value_simplified() { let mut node = ParseNode::SectionHeader; let section_data = b"[a] k="; assert_eq!( section(section_data, &mut node).unwrap(), fully_consumed(( Section { header: parsed_section_header("a", None), events: vec![ whitespace_event(" "), name_event("k"), Event::KeyValueSeparator, value_event(""), ] .into() }, 0 )) ); let section_data = b"[a] k=\n"; assert_eq!( section(section_data, &mut node).unwrap(), fully_consumed(( Section { header: parsed_section_header("a", None), events: vec![ whitespace_event(" "), name_event("k"), Event::KeyValueSeparator, value_event(""), newline_event(), ] .into() }, 1 )) ); } #[test] fn section_with_empty_value() { let mut node = ParseNode::SectionHeader; let section_data = br#"[hello] a = b c= d = "lol""#; assert_eq!( section(section_data, &mut node).unwrap(), fully_consumed(( Section { header: parsed_section_header("hello", None), events: vec![ newline_event(), whitespace_event(" "), name_event("a"), whitespace_event(" "), Event::KeyValueSeparator, whitespace_event(" "), value_event("b"), newline_event(), whitespace_event(" "), name_event("c"), Event::KeyValueSeparator, value_event(""), newline_event(), whitespace_event(" "), name_event("d"), whitespace_event(" "), Event::KeyValueSeparator, whitespace_event(" "), value_event("\"lol\"") ] .into() }, 3 )) ); } #[test] fn section_implicit_value() { let mut node = ParseNode::SectionHeader; assert_eq!( section(b"[hello] c", &mut node).unwrap(), fully_consumed(( Section { header: parsed_section_header("hello", None), events: vec![whitespace_event(" "), name_event("c"), value_event("")].into() }, 0 )) ); assert_eq!( section(b"[hello] c\nd", &mut node).unwrap(), fully_consumed(( Section { header: parsed_section_header("hello", None), events: vec![ whitespace_event(" "), name_event("c"), value_event(""), newline_event(), name_event("d"), value_event("") ] .into() }, 1 )) ); } #[test] fn section_very_commented() { let mut node = ParseNode::SectionHeader; let section_data = br#"[hello] ; commentA a = b # commentB ; commentC ; commentD c = d"#; assert_eq!( section(section_data, &mut node).unwrap(), fully_consumed(( Section { header: parsed_section_header("hello", None), events: vec![ whitespace_event(" "), comment_event(';', " commentA"), newline_event(), whitespace_event(" "), name_event("a"), whitespace_event(" "), Event::KeyValueSeparator, whitespace_event(" "), value_event("b"), whitespace_event(" "), comment_event('#', " commentB"), newline_event(), whitespace_event(" "), comment_event(';', " commentC"), newline_event(), whitespace_event(" "), comment_event(';', " commentD"), newline_event(), whitespace_event(" "), name_event("c"), whitespace_event(" "), Event::KeyValueSeparator, whitespace_event(" "), value_event("d"), ] .into() }, 4 )) ); } #[test] fn complex_continuation() { let mut node = ParseNode::SectionHeader; // This test is absolute hell. Good luck if this fails. assert_eq!( section(b"[section] a = 1 \"\\\"\\\na ; e \"\\\"\\\nd # \"b\t ; c", &mut node).unwrap(), fully_consumed(( Section { header: parsed_section_header("section", None), events: vec![ whitespace_event(" "), name_event("a"), whitespace_event(" "), Event::KeyValueSeparator, whitespace_event(" "), value_not_done_event(r#"1 "\""#),