315 lines · 9.3 KB · Rust
RawDownload
use std::{borrow::Cow, convert::TryFrom}; use bstr::BStr;use git_config::{    color,    file::{init, Metadata},    integer, path, Boolean, Color, File, Integer,}; use crate::file::cow_str; /// Asserts we can cast into all variants of our type#[test]fn get_value_for_all_provided_values() -> crate::Result {    let config = r#"        [core]            other-quoted = "hello"        [core]            bool-explicit = false            bool-implicit            integer-no-prefix = 10            integer-prefix = 10g            color = brightgreen red \            bold            other = hello world            other-quoted = "hello world"            location = ~/tmp            location-quoted = "~/quoted"    "#;    for lossy in [false, true] {        let config = File::from_bytes_no_includes(            config.as_bytes(),            Metadata::api(),            init::Options {                lossy,                ..Default::default()            },        )?;         assert!(!config.value::<Boolean>("core", None, "bool-explicit")?.0);        assert!(!config.boolean("core", None, "bool-explicit").expect("exists")?);         assert!(            config.value::<Boolean>("core", None, "bool-implicit").is_err(),            "this cannot work like in git as the value isn't there for us"        );        assert!(            config.boolean("core", None, "bool-implicit").expect("present")?,            "this should work"        );         assert_eq!(config.string("doesnt", None, "exist"), None);         assert_eq!(            config.value::<Integer>("core", None, "integer-no-prefix")?,            Integer {                value: 10,                suffix: None            }        );         assert_eq!(            config.value::<Integer>("core", None, "integer-no-prefix")?,            Integer {                value: 10,                suffix: None            }        );         assert_eq!(            config.value::<Integer>("core", None, "integer-prefix")?,            Integer {                value: 10,                suffix: Some(integer::Suffix::Gibi),            }        );         assert_eq!(            config.value::<Color>("core", None, "color")?,            Color {                foreground: Some(color::Name::BrightGreen),                background: Some(color::Name::Red),                attributes: color::Attribute::BOLD            }        );         {            let string = config.value::<Cow<'_, BStr>>("core", None, "other")?;            assert_eq!(string, cow_str("hello world"));            assert!(                matches!(string, Cow::Borrowed(_)),                "no copy is made, we reference the `file` itself"            );        }         assert_eq!(            config.string("core", None, "other-quoted").unwrap(),            cow_str("hello world")        );         {            let strings = config.strings("core", None, "other-quoted").unwrap();            assert_eq!(strings, vec![cow_str("hello"), cow_str("hello world")]);            assert!(matches!(strings[0], Cow::Borrowed(_)));            assert!(matches!(strings[1], Cow::Borrowed(_)));        }         {            let cow = config.string("core", None, "other").expect("present");            assert_eq!(cow.as_ref(), "hello world");            assert!(matches!(cow, Cow::Borrowed(_)));        }        assert_eq!(            config.string("core", None, "other-quoted").expect("present").as_ref(),            "hello world"        );         {            let actual = config.value::<git_config::Path>("core", None, "location")?;            assert_eq!(&*actual, "~/tmp", "no interpolation occurs when querying a path");             let home = std::env::current_dir()?;            let expected = home.join("tmp");            assert!(matches!(actual.value, Cow::Borrowed(_)));            assert_eq!(                actual                    .interpolate(path::interpolate::Context {                        home_dir: home.as_path().into(),                        ..Default::default()                    })                    .unwrap(),                expected            );        }         let actual = config.path("core", None, "location").expect("present");        assert_eq!(&*actual, "~/tmp");         let actual = config.path("core", None, "location-quoted").expect("present");        assert_eq!(&*actual, "~/quoted");         let actual = config.value::<git_config::Path>("core", None, "location-quoted")?;        assert_eq!(&*actual, "~/quoted", "but the path is unquoted");    }     Ok(())} /// There was a regression where lookup would fail because we only checked the/// last section entry for any given section and subsection#[test]fn get_value_looks_up_all_sections_before_failing() -> crate::Result {    let config = r#"        [core]            bool-explicit = false            bool-implicit = false        [core]            bool-implicit    "#;     let file = File::try_from(config)?;     // Checks that we check the last entry first still    assert!(        !file.value::<Boolean>("core", None, "bool-implicit")?.0,        "this one can't do it, needs special handling"    );    assert!(        !file.boolean("core", None, "bool-implicit").expect("present")?,        "this should work, but doesn't yet"    );     assert!(!file.value::<Boolean>("core", None, "bool-explicit")?.0);     Ok(())} #[test]fn section_names_are_case_insensitive() -> crate::Result {    let config = "[core] a=true";    let file = File::try_from(config)?;    assert_eq!(        file.value::<Boolean>("core", None, "a").unwrap(),        file.value::<Boolean>("CORE", None, "a").unwrap()    );     Ok(())} #[test]fn value_names_are_case_insensitive() -> crate::Result {    let config = "[core]        a = true        A = false";    let file = File::try_from(config)?;    assert_eq!(file.values::<Boolean>("core", None, "a")?.len(), 2);    assert_eq!(        file.value::<Boolean>("core", None, "a").unwrap(),        file.value::<Boolean>("core", None, "A").unwrap()    );     Ok(())} #[test]fn single_section() {    let config = File::try_from("[core]\na=b\nc").unwrap();    let first_value = config.string("core", None, "a").unwrap();    assert_eq!(first_value, cow_str("b"));     assert!(        config.raw_value("core", None, "c").is_err(),        "value is considered false as it is without '=', so it's like not present"    );     assert!(        config.boolean("core", None, "c").expect("present").unwrap(),        "asking for a boolean is true true, as per git rules"    );} #[test]fn sections_by_name() {    let config = r#"    [core]        repositoryformatversion = 0        filemode = true        bare = false        logallrefupdates = true    [remote "origin"]        url = git@github.com:Byron/gitoxide.git        fetch = +refs/heads/*:refs/remotes/origin/*    "#;     let config = File::try_from(config).unwrap();    let value = config.string("remote", Some("origin"), "url").unwrap();    assert_eq!(value, cow_str("git@github.com:Byron/gitoxide.git"));} #[test]fn multi_line_value_plain() {    let config = r#"[alias]   save = !git status \        && git add -A \        && git commit -m \"$1\" \        && git push -f \        && git log -1 \        && :            # comment    "#;     let config = File::try_from(config).unwrap();     let expected = r#"!git status         && git add -A         && git commit -m "$1"         && git push -f         && git log -1         && :"#;    assert_eq!(config.raw_value("alias", None, "save").unwrap().as_ref(), expected);    assert_eq!(config.string("alias", None, "save").unwrap().as_ref(), expected);} #[test]fn complex_quoted_values() {    let config = r#"    [core]            escape-sequence = "hi\nho\n\tthere\bi\\\" \"""#;    let config = File::try_from(config).unwrap();    let expected = "hi\nho\n\ttheri\\\" \"";    assert_eq!(        config.raw_value("core", None, "escape-sequence").unwrap().as_ref(),        expected,        "raw_value is normalized…"    );    assert_eq!(        config.string("core", None, "escape-sequence").unwrap().as_ref(),        expected,        "…and so is the comfort API"    );} #[test]fn multi_line_value_outer_quotes_unescaped_inner_quotes() {    let config = r#"[alias]   save = "!f() { \           git status; \           git add -A; \           git commit -m "$1"; \           git push -f; \           git log -1;  \        }; \        f;  \        unset f""#;    let config = File::try_from(config).unwrap();    let expected = r#"!f() {            git status;            git add -A;            git commit -m $1;            git push -f;            git log -1;          };         f;          unset f"#;    assert_eq!(config.raw_value("alias", None, "save").unwrap().as_ref(), expected);} #[test]fn multi_line_value_outer_quotes_escaped_inner_quotes() {    let config = r#"[alias]   save = "!f() { \           git status; \           git add -A; \           git commit -m \"$1\"; \           git push -f; \           git log -1;  \        }; \        f;  \        unset f""#;    let config = File::try_from(config).unwrap();    let expected = r#"!f() {            git status;            git add -A;            git commit -m "$1";            git push -f;            git log -1;          };         f;          unset f"#;    assert_eq!(config.raw_value("alias", None, "save").unwrap().as_ref(), expected);}