| mod section { |
| use crate::parse::section::Header; |
| use crate::parse::{section, Comment, Event, Events, Section}; |
| use bstr::BStr; |
| use std::borrow::Cow; |
| |
| #[test] |
| fn size_of_events() { |
| assert_eq!( |
| std::mem::size_of::<Section<'_>>(), |
| 96, |
| "this value should only ever decrease" |
| ); |
| assert_eq!(std::mem::size_of::<Events<'_>>(), 616); |
| assert_eq!(std::mem::size_of::<Event<'_>>(), 72); |
| assert_eq!(std::mem::size_of::<Header<'_>>(), 72); |
| assert_eq!(std::mem::size_of::<Comment<'_>>(), 32); |
| assert_eq!(std::mem::size_of::<Option<Cow<'_, BStr>>>(), 24); |
| assert_eq!(std::mem::size_of::<section::Name<'_>>(), 24); |
| assert_eq!(std::mem::size_of::<section::Key<'_>>(), 24); |
| } |
| |
| mod header { |
| mod unvalidated { |
| use crate::parse::section::unvalidated::Key; |
| |
| #[test] |
| fn section_name_only() { |
| assert_eq!( |
| Key::parse("core").unwrap(), |
| Key { |
| section_name: "core", |
| subsection_name: None |
| } |
| ); |
| } |
| |
| #[test] |
| fn section_name_and_subsection() { |
| assert_eq!( |
| Key::parse("core.bare").unwrap(), |
| Key { |
| section_name: "core", |
| subsection_name: Some("bare".into()) |
| } |
| ); |
| } |
| |
| #[test] |
| fn section_name_and_subsection_with_separators() { |
| assert_eq!( |
| Key::parse("remote.https:///home/user.git").unwrap(), |
| Key { |
| section_name: "remote", |
| subsection_name: Some("https:///home/user.git".into()) |
| } |
| ); |
| } |
| } |
| |
| mod write_to { |
| use std::borrow::Cow; |
| |
| use crate::parse::section; |
| |
| fn header(name: &str, subsection: impl Into<Option<(&'static str, &'static str)>>) -> section::Header<'_> { |
| let name = section::Name(Cow::Borrowed(name.into())); |
| if let Some((separator, subsection_name)) = subsection.into() { |
| section::Header { |
| name, |
| separator: Some(Cow::Borrowed(separator.into())), |
| subsection_name: Some(Cow::Borrowed(subsection_name.into())), |
| } |
| } else { |
| section::Header { |
| name, |
| separator: None, |
| subsection_name: None, |
| } |
| } |
| } |
| |
| #[test] |
| fn legacy_subsection_format_does_not_use_escapes() { |
| let invalid = header("invalid", Some((".", "\\ \""))); |
| assert_eq!( |
| invalid.to_bstring(), |
| "[invalid.\\ \"]", |
| "no escaping happens for legacy subsections" |
| ); |
| assert!(invalid.is_legacy()); |
| } |
| |
| #[test] |
| fn subsections_escape_two_characters_only() { |
| let invalid = header("invalid", Some((" ", "\\ \"\npost newline"))); |
| assert_eq!( |
| invalid.to_bstring(), |
| "[invalid \"\\\\ \\\"\npost newline\"]", |
| "newlines are actually invalid in subsection, but they are possible due to unvalidated instance creation" |
| ); |
| assert!(!invalid.is_legacy()); |
| } |
| } |
| } |
| } |
| |
| pub(crate) mod util { |
| //! This module is only included for tests, and contains common unit test helper |
| //! functions. |
| |
| use std::borrow::Cow; |
| |
| use crate::parse::{section, Comment, Event}; |
| |
| pub fn section_header( |
| name: &str, |
| subsection: impl Into<Option<(&'static str, &'static str)>>, |
| ) -> section::Header<'_> { |
| let name = section::Name::try_from(name).unwrap(); |
| if let Some((separator, subsection_name)) = subsection.into() { |
| section::Header { |
| name, |
| separator: Some(Cow::Borrowed(separator.into())), |
| subsection_name: Some(Cow::Borrowed(subsection_name.into())), |
| } |
| } else { |
| section::Header { |
| name, |
| separator: None, |
| subsection_name: None, |
| } |
| } |
| } |
| |
| pub(crate) fn name_event(name: &'static str) -> Event<'static> { |
| Event::SectionKey(section::Key(Cow::Borrowed(name.into()))) |
| } |
| |
| pub(crate) fn value_event(value: &'static str) -> Event<'static> { |
| Event::Value(Cow::Borrowed(value.into())) |
| } |
| |
| pub(crate) fn value_not_done_event(value: &'static str) -> Event<'static> { |
| Event::ValueNotDone(Cow::Borrowed(value.into())) |
| } |
| |
| pub(crate) fn value_done_event(value: &'static str) -> Event<'static> { |
| Event::ValueDone(Cow::Borrowed(value.into())) |
| } |
| |
| pub(crate) fn newline_event() -> Event<'static> { |
| newline_custom_event("\n") |
| } |
| |
| pub(crate) fn newline_custom_event(value: &'static str) -> Event<'static> { |
| Event::Newline(Cow::Borrowed(value.into())) |
| } |
| |
| pub(crate) fn whitespace_event(value: &'static str) -> Event<'static> { |
| Event::Whitespace(Cow::Borrowed(value.into())) |
| } |
| |
| pub(crate) fn comment_event(tag: char, msg: &'static str) -> Event<'static> { |
| Event::Comment(comment(tag, msg)) |
| } |
| |
| pub(crate) fn comment(comment_tag: char, comment: &'static str) -> Comment<'static> { |
| Comment { |
| tag: comment_tag as u8, |
| text: Cow::Borrowed(comment.into()), |
| } |
| } |
| |
| pub(crate) const fn fully_consumed<T>(t: T) -> (&'static [u8], T) { |
| (&[], t) |
| } |
| } |