278 lines · 9.6 KB · Rust
RawDownload
#[test]fn section_mut_must_exist_as_section_is_not_created_automatically() {    let mut config = multi_value_section();    assert!(config.section_mut("foo", None).is_err());} #[test]fn section_mut_or_create_new_is_infallible() -> crate::Result {    let mut config = multi_value_section();    let section = config.section_mut_or_create_new("name", Some("subsection".into()))?;    assert_eq!(section.header().name(), "name");    assert_eq!(section.header().subsection_name().expect("set"), "subsection");    Ok(())} #[test]fn section_mut_or_create_new_filter_may_reject_existing_sections() -> crate::Result {    let mut config = multi_value_section();    let section = config.section_mut_or_create_new_filter("a", None, &mut |_| false)?;    assert_eq!(section.header().name(), "a");    assert_eq!(section.header().subsection_name(), None);    assert_eq!(section.to_bstring(), "[a]\n");    assert_eq!(        section.meta(),        &git_config::file::Metadata::api(),        "new sections are of source 'API'"    );    Ok(())} #[test]fn section_mut_by_id() {    let mut config = multi_value_section();    let id = config.sections_and_ids().next().expect("at least one").1;    let section = config.section_mut_by_id(id).expect("present");    assert_eq!(section.header().name(), "a");    assert_eq!(section.header().subsection_name(), None);} mod remove {    use super::multi_value_section;     #[test]    fn all() -> crate::Result {        let mut config = multi_value_section();        let mut section = config.section_mut("a", None)?;         assert_eq!(section.num_values(), 5);        assert_eq!(section.keys().count(), 5);         let prev_values = vec!["v", "", "", "", "a        b        c"];        let mut num_values = section.num_values();        for (key, expected_prev_value) in ('a'..='e').zip(prev_values) {            let prev_value = section.remove(key.to_string());            num_values -= 1;            assert_eq!(prev_value.expect("present").as_ref(), expected_prev_value);            assert_eq!(section.num_values(), num_values);        }         assert!(!section.is_void(), "everything is still there");        assert_eq!(config.to_string(), "\n        [a]\n");        Ok(())    }} mod pop {    use super::multi_value_section;     #[test]    fn all() -> crate::Result {        let mut config = multi_value_section();        let mut section = config.section_mut_by_key("a")?;         assert_eq!(section.num_values(), 5);        assert_eq!(section.keys().count(), 5);         for key in b'a'..=b'e' {            assert!(section.contains_key(std::str::from_utf8(&[key])?));        }        let mut num_values = section.num_values();        for _ in 0..section.num_values() {            section.pop();            num_values -= 1;            assert_eq!(section.num_values(), num_values);        }        assert!(!section.is_void(), "there still is some whitespace");        assert_eq!(config.to_string(), "\n        [a]\n");        Ok(())    }} mod set {    use std::convert::TryInto;     use super::multi_value_section;     #[test]    fn various_escapes_onto_various_kinds_of_values() -> crate::Result {        let mut config = multi_value_section();        let mut section = config.section_mut("a", None)?;        let values = vec!["", " a", "b\t", "; comment", "a\n\tc  d\\ \"x\""];        let prev_values = vec!["v", "", "", "", "a        b        c"];        assert_eq!(section.num_values(), values.len());         for (key, (new_value, expected_prev_value)) in (b'a'..=b'e').zip(values.into_iter().zip(prev_values)) {            let key = std::str::from_utf8(std::slice::from_ref(&key))?.to_owned();            let prev_value = section.set(key.try_into()?, new_value);            assert_eq!(prev_value.as_deref().expect("prev value set"), expected_prev_value);        }         assert_eq!(config.to_string(), "\n        [a]\n            a = \n            b = \" a\"\n            c=\"b\\t\"\n            d\"; comment\"\n            e =a\\n\\tc  d\\\\ \\\"x\\\"\n");        assert_eq!(            config                .section_mut("a", None)?                .set("new-one".to_owned().try_into()?, "value"),            None,            "new values don't replace an existing one"        );        Ok(())    }} mod push {    use std::convert::{TryFrom, TryInto};     use git_config::parse::section::Key;     use crate::file::cow_str;     #[test]    fn none_as_value_omits_the_key_value_separator() -> crate::Result {        let mut file = git_config::File::default();        let mut section = file.section_mut_or_create_new("a", Some("sub".into()))?;        section.push("key".try_into()?, None);        let expected = format!("[a \"sub\"]{nl}\tkey{nl}", nl = section.newline());        assert_eq!(section.value("key"), None, "single value counts as None");        assert_eq!(            section.values("key"),            &[cow_str("")],            "multi-value counts as empty value"        );        assert_eq!(file.to_bstring(), expected);        Ok(())    }     #[test]    fn whitespace_is_derived_from_whitespace_before_first_value() -> crate::Result {        for (input, expected_pre_key, expected_sep) in [            ("[a]\n\t\tb=c", Some("\t\t".into()), (None, None)),            ("[a]\nb= c", None, (None, Some(" "))),            ("[a]", Some("\t".into()), (Some(" "), Some(" "))),            ("[a] b", Some(" ".into()), (None, None)),            ("[a]\tb = ", Some("\t".into()), (Some(" "), Some(" "))),            ("[a]\t\tb =c", Some("\t\t".into()), (Some(" "), None)),            (                "[a]\n\t\t  \n    \t    b =  c",                Some("    \t    ".into()),                (Some(" "), Some("  ")),            ),        ] {            let mut config: git_config::File = input.parse()?;            let section = config.section_mut("a", None)?;            assert_eq!(                section.leading_whitespace(),                expected_pre_key,                "{:?} should find {:?} as leading whitespace",                input,                expected_pre_key            );             let (pre_sep, post_sep) = expected_sep;            assert_eq!(                section.separator_whitespace(),                (pre_sep.map(|s| s.into()), post_sep.map(|s| s.into())),                "{:?} should find {:?} as sep whitespace",                input,                expected_sep            );        }        Ok(())    }     #[test]    fn values_are_escaped() {        for (value, expected) in [            ("a b", "$head\tk = a b$nl"),            (" a b", "$head\tk = \" a b\"$nl"),            ("a b\t", "$head\tk = \"a b\\t\"$nl"),            (";c", "$head\tk = \";c\"$nl"),            ("#c", "$head\tk = \"#c\"$nl"),            ("a\nb\n\tc", "$head\tk = a\\nb\\n\\tc$nl"),        ] {            let mut config = git_config::File::default();            let mut section = config.new_section("a", None).unwrap();            section.set_implicit_newline(false);            section.push(Key::try_from("k").unwrap(), Some(value.into()));            let expected = expected                .replace("$head", &format!("[a]{nl}", nl = section.newline()))                .replace("$nl", &section.newline().to_string());            assert_eq!(config.to_bstring(), expected);        }    }} mod push_with_comment {    use git_config::parse::section::Key;     #[test]    fn various_comments_and_escaping() {        for (comment, expected) in [            ("", "$head\tk = v #$nl"),            ("this is v!", "$head\tk = v # this is v!$nl"),            (" no double space", "$head\tk = v # no double space$nl"),            ("\tno double whitespace", "$head\tk = v #\tno double whitespace$nl"),            (                "one\ntwo\nnewlines are replaced with space",                "$head\tk = v # one two newlines are replaced with space$nl",            ),            (                "a\rb\r\nlinefeeds aren't special",                "$head\tk = v # a\rb\r linefeeds aren't special$nl",            ),        ] {            let mut config = git_config::File::default();            let mut section = config.new_section("a", None).unwrap();            section.set_implicit_newline(false);            section.push_with_comment(Key::try_from("k").unwrap(), Some("v".into()), comment);            let expected = expected                .replace("$head", &format!("[a]{nl}", nl = section.newline()))                .replace("$nl", &section.newline().to_string());            assert_eq!(config.to_bstring(), expected);        }    }} mod set_leading_whitespace {    use std::{borrow::Cow, convert::TryFrom};     use bstr::BString;    use git_config::parse::section::Key;     use crate::file::cow_str;     #[test]    fn any_whitespace_is_ok() -> crate::Result {        let mut config = git_config::File::default();        let mut section = config.new_section("core", None)?;         let nl = section.newline().to_owned();        section.set_leading_whitespace(Some(Cow::Owned(BString::from(format!("{nl}\t")))));        section.push(Key::try_from("a")?, Some("v".into()));         assert_eq!(config.to_string(), format!("[core]{nl}{nl}\ta = v{nl}"));        Ok(())    }     #[test]    #[should_panic]    fn panics_if_non_whitespace_is_used() {        let mut config = git_config::File::default();        let mut section = config.new_section("core", None).unwrap();        section.set_leading_whitespace(cow_str("foo").into());    }} fn multi_value_section() -> git_config::File<'static> {    r#"        [a]            a = v            b =             c=            d            e =a \       b \       c"#    .parse()    .unwrap()}