1976 lines · 59.6 KB · Rust
RawDownload
use gix_diff::{    Rewrites,    rewrites::{Copies, CopySource},    tree::{recorder::Location, visit::Relation},    tree_with_rewrites::{Change, Options},};use gix_object::{TreeRefIter, bstr::BStr}; #[test]fn empty_to_new_tree_without_rename_tracking() -> crate::Result {    let (changes, _out) = collect_changes(None, "c1 - initial").expect("full path tracking is the default");    insta::assert_snapshot!(crate::normalize_debug_snapshot(&changes).0, @r#"    [        Addition {            location: "a",            relation: None,            entry_mode: EntryMode(0o100644),            id: Oid(1),        },        Addition {            location: "b",            relation: None,            entry_mode: EntryMode(0o100644),            id: Oid(1),        },        Addition {            location: "d",            relation: None,            entry_mode: EntryMode(0o100644),            id: Oid(1),        },        Addition {            location: "dir",            relation: Some(                Parent(                    1,                ),            ),            entry_mode: EntryMode(0o40000),            id: Oid(2),        },        Addition {            location: "dir/c",            relation: Some(                ChildOfParent(                    1,                ),            ),            entry_mode: EntryMode(0o100644),            id: Oid(1),        },    ]    "#);     let (changes, _out) = collect_changes_opts(        None,        "c1 - initial",        Options {            location: Some(Location::FileName),            ..Default::default()        },    )    .expect("the path-options are respected - we only see the filename here");    insta::assert_snapshot!(crate::normalize_debug_snapshot(&changes).0, @r#"    [        Addition {            location: "a",            relation: None,            entry_mode: EntryMode(0o100644),            id: Oid(1),        },        Addition {            location: "b",            relation: None,            entry_mode: EntryMode(0o100644),            id: Oid(1),        },        Addition {            location: "d",            relation: None,            entry_mode: EntryMode(0o100644),            id: Oid(1),        },        Addition {            location: "dir",            relation: Some(                Parent(                    1,                ),            ),            entry_mode: EntryMode(0o40000),            id: Oid(2),        },        Addition {            location: "c",            relation: Some(                ChildOfParent(                    1,                ),            ),            entry_mode: EntryMode(0o100644),            id: Oid(1),        },    ]    "#);     {        let (lhs, rhs, mut cache, odb) = repo_with_trees(None, "c1 - initial")?;        let err = gix_diff::tree_with_rewrites(            TreeRefIter::from_bytes(&lhs, gix_testtools::object_hash()),            TreeRefIter::from_bytes(&rhs, gix_testtools::object_hash()),            &mut cache,            &mut Default::default(),            &odb,            |_change| Err(std::io::Error::other("custom error")),            Options::default(),        )        .unwrap_err();        assert_eq!(            err.to_string(),            "The user-provided callback failed",            "custom errors made visible and not squelched"        );    }    Ok(())} #[test]fn changes_against_modified_tree_with_filename_tracking() -> crate::Result {    let (changes, _out) = collect_changes("c2", "c3-modification")?;     insta::assert_snapshot!(crate::normalize_debug_snapshot(&changes).0, @r#"    [        Modification {            location: "a",            previous_entry_mode: EntryMode(0o100644),            previous_id: Oid(1),            entry_mode: EntryMode(0o100644),            id: Oid(2),        },        Modification {            location: "dir",            previous_entry_mode: EntryMode(0o40000),            previous_id: Oid(3),            entry_mode: EntryMode(0o40000),            id: Oid(4),        },        Modification {            location: "dir/c",            previous_entry_mode: EntryMode(0o100644),            previous_id: Oid(5),            entry_mode: EntryMode(0o100644),            id: Oid(6),        },    ]    "#);    let (changes, _out) = collect_changes_opts(        "c2",        "c3-modification",        Options {            location: Some(Location::FileName),            ..Default::default()        },    )?;    insta::assert_snapshot!(crate::normalize_debug_snapshot(&changes).0, @r#"    [        Modification {            location: "a",            previous_entry_mode: EntryMode(0o100644),            previous_id: Oid(1),            entry_mode: EntryMode(0o100644),            id: Oid(2),        },        Modification {            location: "dir",            previous_entry_mode: EntryMode(0o40000),            previous_id: Oid(3),            entry_mode: EntryMode(0o40000),            id: Oid(4),        },        Modification {            location: "c",            previous_entry_mode: EntryMode(0o100644),            previous_id: Oid(5),            entry_mode: EntryMode(0o100644),            id: Oid(6),        },    ]    "#);    Ok(())} #[test]fn renames_by_identity() -> crate::Result {    for (from, to, expected, assert_msg, track_empty) in [        (            "c3-modification",            "r1-identity",            vec![BStr::new("a"), "dir/a-moved".into()],            "one rename and nothing else",            false,        ),        (            "c4 - add identical files",            "r2-ambiguous",            vec![                "s1".into(),                "b1".into(),                "s2".into(),                "b2".into(),                "s3".into(),                "z".into(),            ],            "multiple possible sources decide by ordering everything lexicographically",            true,        ),        (            "c4 - add identical files",            "r2-ambiguous",            vec![],            "nothing is tracked with `track_empty = false`",            false,        ),        (            "c5 - add links",            "r4-symlinks",            vec!["link-1".into(), "renamed-link-1".into()],            "symlinks are only tracked by identity",            false,        ),        (            "r1-identity",            "c4 - add identical files",            vec![],            "not having any renames is OK as well",            false,        ),        (            "tc1-identity",            "tc1-identity",            vec![],            "copy tracking is off by default",            false,        ),    ] {        for percentage in [None, Some(0.5)] {            let (changes, out) = collect_changes_opts(                from,                to,                Options {                    location: Some(Location::Path),                    rewrites: Some(Rewrites {                        percentage,                        track_empty,                        ..Default::default()                    }),                },            )?;            let actual: Vec<_> = changes                .into_iter()                .filter(|c| !c.entry_mode().is_tree())                .flat_map(|c| match c {                    Change::Rewrite {                        source_location,                        location,                        copy,                        ..                    } => {                        assert!(!copy);                        vec![source_location, location]                    }                    _ => vec![],                })                .collect();             assert_eq!(actual, expected, "{assert_msg}");            #[cfg(not(windows))]            assert_eq!(                out.expect("present as rewrites are configured").num_similarity_checks,                0,                "there are no fuzzy checks in if everything was resolved by identity only"            );        }    }    Ok(())} #[test]fn rename_by_similarity() -> crate::Result {    insta::allow_duplicates! {    for percentage in [        None,        Some(0.76), /*cutoff point where git stops seeing it as equal */    ] {        let (changes, out) = collect_changes_opts(            "r2-ambiguous",            "r3-simple",            Options {                location: Some(Location::Path),                rewrites: Some(Rewrites {                    percentage,                    ..Default::default()                }),            },        ).expect("errors can only happen with IO or ODB access fails");        insta::assert_snapshot!(crate::normalize_debug_snapshot(&(            changes)).0,            @r#"        [            Modification {                location: "b",                previous_entry_mode: EntryMode(0o100644),                previous_id: Oid(1),                entry_mode: EntryMode(0o100644),                id: Oid(2),            },            Modification {                location: "dir",                previous_entry_mode: EntryMode(0o40000),                previous_id: Oid(3),                entry_mode: EntryMode(0o40000),                id: Oid(4),            },            Deletion {                location: "dir/c",                relation: None,                entry_mode: EntryMode(0o100644),                id: Oid(5),            },            Addition {                location: "dir/c-moved",                relation: None,                entry_mode: EntryMode(0o100644),                id: Oid(6),            },        ]        "#            );            let out = out.expect("tracking enabled");            assert_eq!(out.num_similarity_checks, if percentage.is_some() { 1 } else { 0 });            assert_eq!(out.num_similarity_checks_skipped_for_rename_tracking_due_to_limit, 0);            assert_eq!(out.num_similarity_checks_skipped_for_copy_tracking_due_to_limit, 0);        }    }     let (changes, out) = collect_changes_opts(        "r2-ambiguous",        "r3-simple",        Options {            location: Some(Location::Path),            rewrites: Some(Rewrites {                percentage: Some(0.6),                limit: 1, // has no effect as it's just one item here.                ..Default::default()            }),        },    )    .expect("it found all items at the cut-off point, similar to git");     insta::assert_snapshot!(crate::normalize_debug_snapshot(&changes).0, @r#"    [        Modification {            location: "b",            previous_entry_mode: EntryMode(0o100644),            previous_id: Oid(1),            entry_mode: EntryMode(0o100644),            id: Oid(2),        },        Modification {            location: "dir",            previous_entry_mode: EntryMode(0o40000),            previous_id: Oid(3),            entry_mode: EntryMode(0o40000),            id: Oid(4),        },        Rewrite {            source_location: "dir/c",            source_entry_mode: EntryMode(0o100644),            source_relation: None,            source_id: Oid(5),            diff: Some(                DiffLineStats {                    removals: 0,                    insertions: 1,                    before: 2,                    after: 3,                    similarity: 0.65,                },            ),            entry_mode: EntryMode(0o100644),            id: Oid(6),            location: "dir/c-moved",            relation: None,            copy: false,        },    ]    "#);     let out = out.expect("tracking enabled");    assert_eq!(out.num_similarity_checks, 1);    assert_eq!(out.num_similarity_checks_skipped_for_rename_tracking_due_to_limit, 0);    assert_eq!(out.num_similarity_checks_skipped_for_copy_tracking_due_to_limit, 0);    Ok(())} #[test]fn renames_by_similarity_with_limit() -> crate::Result {    let (changes, out) = collect_changes_opts(        "c6",        "r5",        Options {            location: Some(Location::Path),            rewrites: Some(Rewrites {                limit: 1, // prevent fuzzy tracking from happening                ..Default::default()            }),        },    )?;    assert_eq!(        changes.iter().filter(|c| matches!(c, Change::Rewrite { .. })).count(),        0,        "fuzzy tracking is effectively disabled due to limit"    );    let actual: Vec<_> = changes.iter().map(Change::location).collect();    assert_eq!(actual, ["f1", "f1-renamed", "f2", "f2-renamed"]);     let out = out.expect("tracking enabled");    assert_eq!(out.num_similarity_checks, 0);    assert_eq!(out.num_similarity_checks_skipped_for_rename_tracking_due_to_limit, 4);    assert_eq!(out.num_similarity_checks_skipped_for_copy_tracking_due_to_limit, 0);     Ok(())} #[test]fn copies_by_identity() -> crate::Result {    let (changes, out) = collect_changes_opts(        "c7",        "tc1-identity",        Options {            location: Some(Location::Path),            rewrites: Some(Rewrites {                copies: Some(Copies {                    source: CopySource::FromSetOfModifiedFiles,                    percentage: None,                }),                limit: 1, // the limit isn't actually used for identity based checks                ..Default::default()            }),        },    )?;    insta::assert_snapshot!(crate::normalize_debug_snapshot(&changes).0, @r#"    [        Modification {            location: "dir",            previous_entry_mode: EntryMode(0o40000),            previous_id: Oid(1),            entry_mode: EntryMode(0o40000),            id: Oid(2),        },        Rewrite {            source_location: "base",            source_entry_mode: EntryMode(0o100644),            source_relation: None,            source_id: Oid(3),            diff: None,            entry_mode: EntryMode(0o100644),            id: Oid(3),            location: "c1",            relation: None,            copy: true,        },        Rewrite {            source_location: "base",            source_entry_mode: EntryMode(0o100644),            source_relation: None,            source_id: Oid(3),            diff: None,            entry_mode: EntryMode(0o100644),            id: Oid(3),            location: "c2",            relation: None,            copy: true,        },        Rewrite {            source_location: "base",            source_entry_mode: EntryMode(0o100644),            source_relation: None,            source_id: Oid(3),            diff: None,            entry_mode: EntryMode(0o100644),            id: Oid(3),            location: "dir/c3",            relation: None,            copy: true,        },    ]    "#);    let out = out.expect("tracking enabled");    assert_eq!(out.num_similarity_checks, 0);

Lines 1–500 of 1976.