1
1
mirror of https://github.com/Byron/gitoxide synced 2025-10-06 01:52:40 +02:00
Files
gitoxide/gix-diff/tests/diff/tree_with_rewrites.rs
Sebastian Thiel 17835bccb0 chore: bump rust-version to 1.70
That way clippy will allow to use the fantastic `Option::is_some_and()`
and friends.
2025-01-12 13:51:47 +01:00

1873 lines
60 KiB
Rust

use gix_diff::rewrites::{Copies, CopySource};
use gix_diff::tree::recorder::Location;
use gix_diff::tree::visit::Relation;
use gix_diff::tree_with_rewrites::{Change, Options};
use gix_diff::Rewrites;
use gix_object::bstr::BStr;
use gix_object::TreeRefIter;
#[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_debug_snapshot!(changes, @r#"
[
Addition {
location: "a",
relation: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Addition {
location: "b",
relation: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Addition {
location: "d",
relation: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Addition {
location: "dir",
relation: Some(
Parent(
1,
),
),
entry_mode: EntryMode(0o40000),
id: Sha1(587ff082e0b98914788500eae5dd6a33f04883c9),
},
Addition {
location: "dir/c",
relation: Some(
ChildOfParent(
1,
),
),
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
]
"#);
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_debug_snapshot!(changes, @r#"
[
Addition {
location: "a",
relation: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Addition {
location: "b",
relation: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Addition {
location: "d",
relation: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Addition {
location: "dir",
relation: Some(
Parent(
1,
),
),
entry_mode: EntryMode(0o40000),
id: Sha1(587ff082e0b98914788500eae5dd6a33f04883c9),
},
Addition {
location: "c",
relation: Some(
ChildOfParent(
1,
),
),
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
]
"#);
{
let (lhs, rhs, mut cache, odb) = repo_with_trees(None, "c1 - initial")?;
let err = gix_diff::tree_with_rewrites(
TreeRefIter::from_bytes(&lhs),
TreeRefIter::from_bytes(&rhs),
&mut cache,
&mut Default::default(),
&odb,
|_change| Err(std::io::Error::new(std::io::ErrorKind::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_debug_snapshot!(changes, @r#"
[
Modification {
location: "a",
previous_entry_mode: EntryMode(0o100644),
previous_id: Sha1(78981922613b2afb6025042ff6bd878ac1994e85),
entry_mode: EntryMode(0o100644),
id: Sha1(b4f17b61de71d9b2e54ac9e62b1629ae2d97a6a7),
},
Modification {
location: "dir",
previous_entry_mode: EntryMode(0o40000),
previous_id: Sha1(e5c63aefe4327cb1c780c71966b678ce8e4225da),
entry_mode: EntryMode(0o40000),
id: Sha1(c7ac5f82f536976f3561c9999b5f11e5893358be),
},
Modification {
location: "dir/c",
previous_entry_mode: EntryMode(0o100644),
previous_id: Sha1(6695780ceb14b05e076a99bbd2babf34723b3464),
entry_mode: EntryMode(0o100644),
id: Sha1(40006fcef15a8853a1b7ae186d93b7d680fd29cf),
},
]
"#);
let (changes, _out) = collect_changes_opts(
"c2",
"c3-modification",
Options {
location: Some(Location::FileName),
..Default::default()
},
)?;
insta::assert_debug_snapshot!(changes, @r#"
[
Modification {
location: "a",
previous_entry_mode: EntryMode(0o100644),
previous_id: Sha1(78981922613b2afb6025042ff6bd878ac1994e85),
entry_mode: EntryMode(0o100644),
id: Sha1(b4f17b61de71d9b2e54ac9e62b1629ae2d97a6a7),
},
Modification {
location: "dir",
previous_entry_mode: EntryMode(0o40000),
previous_id: Sha1(e5c63aefe4327cb1c780c71966b678ce8e4225da),
entry_mode: EntryMode(0o40000),
id: Sha1(c7ac5f82f536976f3561c9999b5f11e5893358be),
},
Modification {
location: "c",
previous_entry_mode: EntryMode(0o100644),
previous_id: Sha1(6695780ceb14b05e076a99bbd2babf34723b3464),
entry_mode: EntryMode(0o100644),
id: Sha1(40006fcef15a8853a1b7ae186d93b7d680fd29cf),
},
]
"#);
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_debug_snapshot!(
changes,
@r#"
[
Modification {
location: "b",
previous_entry_mode: EntryMode(0o100644),
previous_id: Sha1(61780798228d17af2d34fce4cfbdf35556832472),
entry_mode: EntryMode(0o100644),
id: Sha1(54781fa52cf133fa9d0bf59cfe2ef2621b5ad29f),
},
Modification {
location: "dir",
previous_entry_mode: EntryMode(0o40000),
previous_id: Sha1(d1622e275dbb2cb3215a0bdcd2fc77273891f360),
entry_mode: EntryMode(0o40000),
id: Sha1(6602e61ea053525e4907e155c0b3da3a269e1385),
},
Deletion {
location: "dir/c",
relation: None,
entry_mode: EntryMode(0o100644),
id: Sha1(40006fcef15a8853a1b7ae186d93b7d680fd29cf),
},
Addition {
location: "dir/c-moved",
relation: None,
entry_mode: EntryMode(0o100644),
id: Sha1(f01e8ddf5adc56985b9a1cda6d7c7ef9e3abe034),
},
]
"#
);
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_debug_snapshot!(changes, @r#"
[
Modification {
location: "b",
previous_entry_mode: EntryMode(0o100644),
previous_id: Sha1(61780798228d17af2d34fce4cfbdf35556832472),
entry_mode: EntryMode(0o100644),
id: Sha1(54781fa52cf133fa9d0bf59cfe2ef2621b5ad29f),
},
Modification {
location: "dir",
previous_entry_mode: EntryMode(0o40000),
previous_id: Sha1(d1622e275dbb2cb3215a0bdcd2fc77273891f360),
entry_mode: EntryMode(0o40000),
id: Sha1(6602e61ea053525e4907e155c0b3da3a269e1385),
},
Rewrite {
source_location: "dir/c",
source_entry_mode: EntryMode(0o100644),
source_relation: None,
source_id: Sha1(40006fcef15a8853a1b7ae186d93b7d680fd29cf),
diff: Some(
DiffLineStats {
removals: 0,
insertions: 1,
before: 2,
after: 3,
similarity: 0.65,
},
),
entry_mode: EntryMode(0o100644),
id: Sha1(f01e8ddf5adc56985b9a1cda6d7c7ef9e3abe034),
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_debug_snapshot!(changes, @r#"
[
Modification {
location: "dir",
previous_entry_mode: EntryMode(0o40000),
previous_id: Sha1(6602e61ea053525e4907e155c0b3da3a269e1385),
entry_mode: EntryMode(0o40000),
id: Sha1(f01fd5b4d733a4ae749cbb58a828cdb3f342f298),
},
Rewrite {
source_location: "base",
source_entry_mode: EntryMode(0o100644),
source_relation: None,
source_id: Sha1(f00c965d8307308469e537302baa73048488f162),
diff: None,
entry_mode: EntryMode(0o100644),
id: Sha1(f00c965d8307308469e537302baa73048488f162),
location: "c1",
relation: None,
copy: true,
},
Rewrite {
source_location: "base",
source_entry_mode: EntryMode(0o100644),
source_relation: None,
source_id: Sha1(f00c965d8307308469e537302baa73048488f162),
diff: None,
entry_mode: EntryMode(0o100644),
id: Sha1(f00c965d8307308469e537302baa73048488f162),
location: "c2",
relation: None,
copy: true,
},
Rewrite {
source_location: "base",
source_entry_mode: EntryMode(0o100644),
source_relation: None,
source_id: Sha1(f00c965d8307308469e537302baa73048488f162),
diff: None,
entry_mode: EntryMode(0o100644),
id: Sha1(f00c965d8307308469e537302baa73048488f162),
location: "dir/c3",
relation: None,
copy: true,
},
]
"#);
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, 0);
assert_eq!(out.num_similarity_checks_skipped_for_copy_tracking_due_to_limit, 0);
Ok(())
}
#[test]
fn copies_by_similarity() -> crate::Result {
let (changes, out) = collect_changes_opts(
"tc1-identity",
"tc2-similarity",
Options {
location: Some(Location::Path),
rewrites: Some(Rewrites {
copies: Some(Copies::default()),
..Default::default()
}),
},
)?;
insta::assert_debug_snapshot!(changes, @r#"
[
Modification {
location: "dir",
previous_entry_mode: EntryMode(0o40000),
previous_id: Sha1(f01fd5b4d733a4ae749cbb58a828cdb3f342f298),
entry_mode: EntryMode(0o40000),
id: Sha1(1d7e20e07562a54af0408fd2669b0c56a6faa6f0),
},
Rewrite {
source_location: "base",
source_entry_mode: EntryMode(0o100644),
source_relation: None,
source_id: Sha1(3bb459b831ea471b9cd1cbb7c6d54a74251a711b),
diff: None,
entry_mode: EntryMode(0o100644),
id: Sha1(3bb459b831ea471b9cd1cbb7c6d54a74251a711b),
location: "c4",
relation: None,
copy: true,
},
Rewrite {
source_location: "base",
source_entry_mode: EntryMode(0o100644),
source_relation: None,
source_id: Sha1(3bb459b831ea471b9cd1cbb7c6d54a74251a711b),
diff: Some(
DiffLineStats {
removals: 0,
insertions: 1,
before: 11,
after: 12,
similarity: 0.8888889,
},
),
entry_mode: EntryMode(0o100644),
id: Sha1(08fe19ca4d2f79624f35333157d610811efc1aed),
location: "c5",
relation: None,
copy: true,
},
Rewrite {
source_location: "base",
source_entry_mode: EntryMode(0o100644),
source_relation: None,
source_id: Sha1(3bb459b831ea471b9cd1cbb7c6d54a74251a711b),
diff: Some(
DiffLineStats {
removals: 0,
insertions: 1,
before: 11,
after: 12,
similarity: 0.8888889,
},
),
entry_mode: EntryMode(0o100644),
id: Sha1(cf7a729ca69bfabd0995fc9b083e86a18215bd91),
location: "dir/c6",
relation: None,
copy: true,
},
]
"#);
let out = out.expect("tracking enabled");
assert_eq!(
out.num_similarity_checks, 2,
"two are similar, the other one is identical"
);
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 copies_in_entire_tree_by_similarity() -> crate::Result {
let (changes, out) = collect_changes_opts(
"tc2-similarity",
"tc3-find-harder",
Options {
location: Some(Location::Path),
rewrites: Some(Rewrites {
copies: Some(Copies::default()),
..Default::default()
}),
},
)?;
assert_eq!(
changes.iter().filter(|c| matches!(c, Change::Rewrite { .. })).count(),
0,
"needs --find-copies-harder to detect rewrites here"
);
let actual: Vec<_> = changes.iter().map(Change::location).collect();
assert_eq!(actual, ["b", "c6", "c7", "newly-added"]);
let out = out.expect("tracking enabled");
assert_eq!(
out.num_similarity_checks, 3,
"it does have some candidates, probably for rename tracking"
);
assert_eq!(
out.num_similarity_checks_skipped_for_rename_tracking_due_to_limit, 0,
"no limit configured"
);
assert_eq!(out.num_similarity_checks_skipped_for_copy_tracking_due_to_limit, 0);
let (changes, out) = collect_changes_opts(
"tc2-similarity",
"tc3-find-harder",
Options {
location: Some(Location::Path),
rewrites: Some(Rewrites {
copies: Some(Copies {
source: CopySource::FromSetOfModifiedFilesAndAllSources,
..Default::default()
}),
..Default::default()
}),
},
)?;
insta::assert_debug_snapshot!(changes, @r#"
[
Rewrite {
source_location: "base",
source_entry_mode: EntryMode(0o100644),
source_relation: None,
source_id: Sha1(3bb459b831ea471b9cd1cbb7c6d54a74251a711b),
diff: None,
entry_mode: EntryMode(0o100644),
id: Sha1(3bb459b831ea471b9cd1cbb7c6d54a74251a711b),
location: "c6",
relation: None,
copy: true,
},
Rewrite {
source_location: "dir/c6",
source_entry_mode: EntryMode(0o100644),
source_relation: None,
source_id: Sha1(cf7a729ca69bfabd0995fc9b083e86a18215bd91),
diff: None,
entry_mode: EntryMode(0o100644),
id: Sha1(cf7a729ca69bfabd0995fc9b083e86a18215bd91),
location: "c7",
relation: None,
copy: true,
},
Rewrite {
source_location: "c5",
source_entry_mode: EntryMode(0o100644),
source_relation: None,
source_id: Sha1(08fe19ca4d2f79624f35333157d610811efc1aed),
diff: Some(
DiffLineStats {
removals: 0,
insertions: 3,
before: 12,
after: 15,
similarity: 0.75,
},
),
entry_mode: EntryMode(0o100644),
id: Sha1(97b3d1a5707f8a11fa5fa8bc6c3bd7b3965601fd),
location: "newly-added",
relation: None,
copy: true,
},
Modification {
location: "b",
previous_entry_mode: EntryMode(0o100644),
previous_id: Sha1(54781fa52cf133fa9d0bf59cfe2ef2621b5ad29f),
entry_mode: EntryMode(0o100644),
id: Sha1(f198d0640214092732566fb00543163845c8252c),
},
]
"#);
let out = out.expect("tracking enabled");
assert_eq!(out.num_similarity_checks, 4);
assert_eq!(
out.num_similarity_checks_skipped_for_rename_tracking_due_to_limit, 0,
"no limit configured"
);
assert_eq!(out.num_similarity_checks_skipped_for_copy_tracking_due_to_limit, 0);
Ok(())
}
#[test]
fn copies_in_entire_tree_by_similarity_with_limit() -> crate::Result {
let (changes, out) = collect_changes_opts(
"tc2-similarity",
"tc3-find-harder",
Options {
location: Some(Location::Path),
rewrites: Some(Rewrites {
copies: Some(Copies {
source: CopySource::FromSetOfModifiedFilesAndAllSources,
..Default::default()
}),
limit: 2, // similarity checks can't be made that way
track_empty: false,
..Default::default()
}),
},
)?;
insta::assert_debug_snapshot!(changes, @r#"
[
Rewrite {
source_location: "base",
source_entry_mode: EntryMode(0o100644),
source_relation: None,
source_id: Sha1(3bb459b831ea471b9cd1cbb7c6d54a74251a711b),
diff: None,
entry_mode: EntryMode(0o100644),
id: Sha1(3bb459b831ea471b9cd1cbb7c6d54a74251a711b),
location: "c6",
relation: None,
copy: true,
},
Rewrite {
source_location: "dir/c6",
source_entry_mode: EntryMode(0o100644),
source_relation: None,
source_id: Sha1(cf7a729ca69bfabd0995fc9b083e86a18215bd91),
diff: None,
entry_mode: EntryMode(0o100644),
id: Sha1(cf7a729ca69bfabd0995fc9b083e86a18215bd91),
location: "c7",
relation: None,
copy: true,
},
Modification {
location: "b",
previous_entry_mode: EntryMode(0o100644),
previous_id: Sha1(54781fa52cf133fa9d0bf59cfe2ef2621b5ad29f),
entry_mode: EntryMode(0o100644),
id: Sha1(f198d0640214092732566fb00543163845c8252c),
},
Addition {
location: "newly-added",
relation: None,
entry_mode: EntryMode(0o100644),
id: Sha1(97b3d1a5707f8a11fa5fa8bc6c3bd7b3965601fd),
},
]
"#);
let out = out.expect("tracking enabled");
assert_eq!(out.num_similarity_checks, 0, "similarity checks can't run");
assert_eq!(
out.num_similarity_checks_skipped_for_rename_tracking_due_to_limit, 0,
"no limit configured"
);
assert_eq!(out.num_similarity_checks_skipped_for_copy_tracking_due_to_limit, 19);
Ok(())
}
#[test]
fn copies_by_similarity_with_limit() -> crate::Result {
let (changes, out) = collect_changes_opts(
"tc1-identity",
"tc2-similarity",
Options {
location: Some(Location::Path),
rewrites: Some(Rewrites {
copies: Some(Copies::default()),
limit: 1,
..Default::default()
}),
},
)?;
insta::assert_debug_snapshot!(changes, @r#"
[
Modification {
location: "dir",
previous_entry_mode: EntryMode(0o40000),
previous_id: Sha1(f01fd5b4d733a4ae749cbb58a828cdb3f342f298),
entry_mode: EntryMode(0o40000),
id: Sha1(1d7e20e07562a54af0408fd2669b0c56a6faa6f0),
},
Rewrite {
source_location: "base",
source_entry_mode: EntryMode(0o100644),
source_relation: None,
source_id: Sha1(3bb459b831ea471b9cd1cbb7c6d54a74251a711b),
diff: None,
entry_mode: EntryMode(0o100644),
id: Sha1(3bb459b831ea471b9cd1cbb7c6d54a74251a711b),
location: "c4",
relation: None,
copy: true,
},
Addition {
location: "c5",
relation: None,
entry_mode: EntryMode(0o100644),
id: Sha1(08fe19ca4d2f79624f35333157d610811efc1aed),
},
Addition {
location: "dir/c6",
relation: None,
entry_mode: EntryMode(0o100644),
id: Sha1(cf7a729ca69bfabd0995fc9b083e86a18215bd91),
},
]
"#);
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, 0);
assert_eq!(
out.num_similarity_checks_skipped_for_copy_tracking_due_to_limit, 2,
"limit prevents any similarity check from being performed, and identity fails in most places"
);
Ok(())
}
#[test]
fn realistic_renames_by_identity() -> crate::Result {
let (changes, out) = collect_changes_opts(
"r1-base",
"r1-change",
Options {
location: Some(Location::Path),
rewrites: Some(Rewrites {
copies: Some(Copies::default()),
limit: 1,
track_empty: true,
..Default::default()
}),
},
)?;
insta::assert_debug_snapshot!(changes.into_iter().filter(|c| !c.entry_mode().is_tree()).collect::<Vec<_>>(), @r#"
[
Rewrite {
source_location: "git-index/src/file.rs",
source_entry_mode: EntryMode(0o100644),
source_relation: None,
source_id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
diff: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
location: "git-index/src/file/mod.rs",
relation: None,
copy: false,
},
Addition {
location: "git-index/tests/index/file/access.rs",
relation: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Modification {
location: "git-index/tests/index/file/mod.rs",
previous_entry_mode: EntryMode(0o100644),
previous_id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
entry_mode: EntryMode(0o100644),
id: Sha1(8ba3a16384aacc37d01564b28401755ce8053f51),
},
]
"#);
#[cfg(not(windows))]
{
let actual = std::fs::read_to_string(repo_workdir()?.join("baseline.with-renames"))?;
let expected = r#"commit 0231f5093bd3d760e7ee82984e0453da80e05c87
Author: author <author@example.com>
Date: Sat Jan 1 00:00:00 2000 +0000
r1-change
diff --git a/git-index/src/file.rs b/git-index/src/file/mod.rs
similarity index 100%
rename from git-index/src/file.rs
rename to git-index/src/file/mod.rs
diff --git a/git-index/tests/index/file/access.rs b/git-index/tests/index/file/access.rs
new file mode 100644
index 0000000..e69de29
diff --git a/git-index/tests/index/file/mod.rs b/git-index/tests/index/file/mod.rs
index e69de29..8ba3a16 100644
--- a/git-index/tests/index/file/mod.rs
+++ b/git-index/tests/index/file/mod.rs
@@ -0,0 +1 @@
+n
"#;
assert_eq!(actual, expected);
}
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 realistic_renames_disabled() -> crate::Result {
let (changes, out) = collect_changes_opts(
"r1-base",
"r1-change",
Options {
location: Some(Location::Path),
rewrites: None,
},
)?;
insta::assert_debug_snapshot!(changes.into_iter().filter(|c| !c.entry_mode().is_tree()).collect::<Vec<_>>(), @r#"
[
Deletion {
location: "git-index/src/file.rs",
relation: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Addition {
location: "git-index/src/file/mod.rs",
relation: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Addition {
location: "git-index/tests/index/file/access.rs",
relation: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Modification {
location: "git-index/tests/index/file/mod.rs",
previous_entry_mode: EntryMode(0o100644),
previous_id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
entry_mode: EntryMode(0o100644),
id: Sha1(8ba3a16384aacc37d01564b28401755ce8053f51),
},
]
"#);
#[cfg(not(windows))]
{
let actual = std::fs::read_to_string(repo_workdir()?.join("baseline.no-renames"))?;
let expected = r#"commit 0231f5093bd3d760e7ee82984e0453da80e05c87
Author: author <author@example.com>
Date: Sat Jan 1 00:00:00 2000 +0000
r1-change
diff --git a/git-index/src/file.rs b/git-index/src/file.rs
deleted file mode 100644
index e69de29..0000000
diff --git a/git-index/src/file/mod.rs b/git-index/src/file/mod.rs
new file mode 100644
index 0000000..e69de29
diff --git a/git-index/tests/index/file/access.rs b/git-index/tests/index/file/access.rs
new file mode 100644
index 0000000..e69de29
diff --git a/git-index/tests/index/file/mod.rs b/git-index/tests/index/file/mod.rs
index e69de29..8ba3a16 100644
--- a/git-index/tests/index/file/mod.rs
+++ b/git-index/tests/index/file/mod.rs
@@ -0,0 +1 @@
+n
"#;
assert_eq!(actual, expected);
}
assert_eq!(out, None, "tracking is disabled completely");
Ok(())
}
#[test]
fn realistic_renames_disabled_2() -> crate::Result {
let (changes, out) = collect_changes_opts(
"r2-base",
"r2-change",
Options {
location: Some(Location::Path),
rewrites: None,
},
)?;
// Directories are associated with their children, making a bundling possible.
insta::assert_debug_snapshot!(changes.into_iter()
.filter(|c| !c.entry_mode().is_tree() ||
c.relation().is_some_and(|r| matches!(r, Relation::Parent(_)))
).collect::<Vec<_>>(), @r#"
[
Deletion {
location: "git-sec",
relation: Some(
Parent(
1,
),
),
entry_mode: EntryMode(0o40000),
id: Sha1(0026010e87631065a2739f627622feb14f903fd4),
},
Addition {
location: "gix-sec",
relation: Some(
Parent(
2,
),
),
entry_mode: EntryMode(0o40000),
id: Sha1(0026010e87631065a2739f627622feb14f903fd4),
},
Deletion {
location: "git-sec/CHANGELOG.md",
relation: Some(
ChildOfParent(
1,
),
),
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Deletion {
location: "git-sec/Cargo.toml",
relation: Some(
ChildOfParent(
1,
),
),
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Addition {
location: "gix-sec/CHANGELOG.md",
relation: Some(
ChildOfParent(
2,
),
),
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Addition {
location: "gix-sec/Cargo.toml",
relation: Some(
ChildOfParent(
2,
),
),
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Deletion {
location: "git-sec/src/identity.rs",
relation: Some(
ChildOfParent(
1,
),
),
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Deletion {
location: "git-sec/src/lib.rs",
relation: Some(
ChildOfParent(
1,
),
),
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Deletion {
location: "git-sec/src/permission.rs",
relation: Some(
ChildOfParent(
1,
),
),
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Deletion {
location: "git-sec/src/trust.rs",
relation: Some(
ChildOfParent(
1,
),
),
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Deletion {
location: "git-sec/tests/sec.rs",
relation: Some(
ChildOfParent(
1,
),
),
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Addition {
location: "gix-sec/src/identity.rs",
relation: Some(
ChildOfParent(
2,
),
),
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Addition {
location: "gix-sec/src/lib.rs",
relation: Some(
ChildOfParent(
2,
),
),
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Addition {
location: "gix-sec/src/permission.rs",
relation: Some(
ChildOfParent(
2,
),
),
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Addition {
location: "gix-sec/src/trust.rs",
relation: Some(
ChildOfParent(
2,
),
),
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Addition {
location: "gix-sec/tests/sec.rs",
relation: Some(
ChildOfParent(
2,
),
),
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Deletion {
location: "git-sec/tests/identity/mod.rs",
relation: Some(
ChildOfParent(
1,
),
),
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Addition {
location: "gix-sec/tests/identity/mod.rs",
relation: Some(
ChildOfParent(
2,
),
),
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
]
"#);
#[cfg(not(windows))]
{
let expected = r#"commit d78c63c5ea3149040767e4387e7fc743cda118fd
Author: author <author@example.com>
Date: Sat Jan 1 00:00:00 2000 +0000
r2-change
diff --git a/git-sec/CHANGELOG.md b/git-sec/CHANGELOG.md
deleted file mode 100644
index e69de29..0000000
diff --git a/git-sec/Cargo.toml b/git-sec/Cargo.toml
deleted file mode 100644
index e69de29..0000000
diff --git a/git-sec/src/identity.rs b/git-sec/src/identity.rs
deleted file mode 100644
index e69de29..0000000
diff --git a/git-sec/src/lib.rs b/git-sec/src/lib.rs
deleted file mode 100644
index e69de29..0000000
diff --git a/git-sec/src/permission.rs b/git-sec/src/permission.rs
deleted file mode 100644
index e69de29..0000000
diff --git a/git-sec/src/trust.rs b/git-sec/src/trust.rs
deleted file mode 100644
index e69de29..0000000
diff --git a/git-sec/tests/identity/mod.rs b/git-sec/tests/identity/mod.rs
deleted file mode 100644
index e69de29..0000000
diff --git a/git-sec/tests/sec.rs b/git-sec/tests/sec.rs
deleted file mode 100644
index e69de29..0000000
diff --git a/gix-sec/CHANGELOG.md b/gix-sec/CHANGELOG.md
new file mode 100644
index 0000000..e69de29
diff --git a/gix-sec/Cargo.toml b/gix-sec/Cargo.toml
new file mode 100644
index 0000000..e69de29
diff --git a/gix-sec/src/identity.rs b/gix-sec/src/identity.rs
new file mode 100644
index 0000000..e69de29
diff --git a/gix-sec/src/lib.rs b/gix-sec/src/lib.rs
new file mode 100644
index 0000000..e69de29
diff --git a/gix-sec/src/permission.rs b/gix-sec/src/permission.rs
new file mode 100644
index 0000000..e69de29
diff --git a/gix-sec/src/trust.rs b/gix-sec/src/trust.rs
new file mode 100644
index 0000000..e69de29
diff --git a/gix-sec/tests/identity/mod.rs b/gix-sec/tests/identity/mod.rs
new file mode 100644
index 0000000..e69de29
diff --git a/gix-sec/tests/sec.rs b/gix-sec/tests/sec.rs
new file mode 100644
index 0000000..e69de29
"#;
assert_eq!(
std::fs::read_to_string(repo_workdir()?.join("baseline-2.no-renames"))?,
expected
);
}
assert_eq!(out, None, "tracking is disabled completely");
Ok(())
}
#[test]
fn realistic_renames_disabled_3() -> crate::Result {
let (changes, out) = collect_changes_opts(
"r3-base",
"r3-change",
Options {
location: Some(Location::Path),
rewrites: None,
},
)?;
insta::assert_debug_snapshot!(changes.into_iter().filter(|c| !c.entry_mode().is_tree()).collect::<Vec<_>>(), @r#"
[
Addition {
location: "src/ein.rs",
relation: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Addition {
location: "src/gix.rs",
relation: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Deletion {
location: "src/plumbing-cli.rs",
relation: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
Deletion {
location: "src/porcelain-cli.rs",
relation: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
},
]
"#);
#[cfg(not(windows))]
{
let expected = r#"commit 0cf7a4fe3ad6c49ae7beb394a1c1df7cc5173ce4
Author: author <author@example.com>
Date: Sat Jan 1 00:00:00 2000 +0000
r3-change
diff --git a/src/ein.rs b/src/ein.rs
new file mode 100644
index 0000000..e69de29
diff --git a/src/gix.rs b/src/gix.rs
new file mode 100644
index 0000000..e69de29
diff --git a/src/plumbing-cli.rs b/src/plumbing-cli.rs
deleted file mode 100644
index e69de29..0000000
diff --git a/src/porcelain-cli.rs b/src/porcelain-cli.rs
deleted file mode 100644
index e69de29..0000000
"#;
assert_eq!(
std::fs::read_to_string(repo_workdir()?.join("baseline-3.no-renames"))?,
expected
);
}
assert_eq!(out, None, "tracking is disabled completely");
Ok(())
}
#[test]
fn realistic_renames_by_identity_3() -> crate::Result {
let (changes, out) = collect_changes_opts(
"r3-base",
"r3-change",
Options {
location: Some(Location::Path),
rewrites: Some(Rewrites {
copies: Some(Copies::default()),
limit: 1,
track_empty: true,
..Default::default()
}),
},
)?;
insta::assert_debug_snapshot!(changes.into_iter().filter(|c| !c.entry_mode().is_tree()).collect::<Vec<_>>(), @r#"
[
Rewrite {
source_location: "src/plumbing-cli.rs",
source_entry_mode: EntryMode(0o100644),
source_relation: None,
source_id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
diff: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
location: "src/ein.rs",
relation: None,
copy: false,
},
Rewrite {
source_location: "src/porcelain-cli.rs",
source_entry_mode: EntryMode(0o100644),
source_relation: None,
source_id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
diff: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
location: "src/gix.rs",
relation: None,
copy: false,
},
]
"#);
#[cfg(not(windows))]
{
let expected = r#"commit 0cf7a4fe3ad6c49ae7beb394a1c1df7cc5173ce4
Author: author <author@example.com>
Date: Sat Jan 1 00:00:00 2000 +0000
r3-change
diff --git a/src/plumbing-cli.rs b/src/ein.rs
similarity index 100%
rename from src/plumbing-cli.rs
rename to src/ein.rs
diff --git a/src/porcelain-cli.rs b/src/gix.rs
similarity index 100%
rename from src/porcelain-cli.rs
rename to src/gix.rs
"#;
assert_eq!(
std::fs::read_to_string(repo_workdir()?.join("baseline-3.with-renames"))?,
expected
);
}
let out = out.expect("tracking enabled");
assert_eq!(
out.num_similarity_checks, 0,
"similarity checks disabled, and not necessary"
);
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 realistic_renames_2() -> crate::Result {
let (changes, out) = collect_changes_opts(
"r2-base",
"r2-change",
Options {
location: Some(Location::Path),
rewrites: Some(Rewrites {
copies: Some(Copies::default()),
limit: 1,
track_empty: false,
..Default::default()
}),
},
)?;
// Look how nicely it captures and associates this directory rename.
insta::assert_debug_snapshot!(changes.into_iter()
.filter(|c| !c.entry_mode().is_tree() ||
c.relation().is_some_and(|r| matches!(r, Relation::Parent(_)))
).collect::<Vec<_>>(), @r#"
[
Rewrite {
source_location: "git-sec",
source_entry_mode: EntryMode(0o40000),
source_relation: Some(
Parent(
1,
),
),
source_id: Sha1(0026010e87631065a2739f627622feb14f903fd4),
diff: None,
entry_mode: EntryMode(0o40000),
id: Sha1(0026010e87631065a2739f627622feb14f903fd4),
location: "gix-sec",
relation: Some(
Parent(
2,
),
),
copy: false,
},
Rewrite {
source_location: "git-sec/CHANGELOG.md",
source_entry_mode: EntryMode(0o100644),
source_relation: Some(
ChildOfParent(
1,
),
),
source_id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
diff: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
location: "gix-sec/CHANGELOG.md",
relation: Some(
ChildOfParent(
2,
),
),
copy: false,
},
Rewrite {
source_location: "git-sec/Cargo.toml",
source_entry_mode: EntryMode(0o100644),
source_relation: Some(
ChildOfParent(
1,
),
),
source_id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
diff: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
location: "gix-sec/Cargo.toml",
relation: Some(
ChildOfParent(
2,
),
),
copy: false,
},
Rewrite {
source_location: "git-sec/src/identity.rs",
source_entry_mode: EntryMode(0o100644),
source_relation: Some(
ChildOfParent(
1,
),
),
source_id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
diff: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
location: "gix-sec/src/identity.rs",
relation: Some(
ChildOfParent(
2,
),
),
copy: false,
},
Rewrite {
source_location: "git-sec/src/lib.rs",
source_entry_mode: EntryMode(0o100644),
source_relation: Some(
ChildOfParent(
1,
),
),
source_id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
diff: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
location: "gix-sec/src/lib.rs",
relation: Some(
ChildOfParent(
2,
),
),
copy: false,
},
Rewrite {
source_location: "git-sec/src/permission.rs",
source_entry_mode: EntryMode(0o100644),
source_relation: Some(
ChildOfParent(
1,
),
),
source_id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
diff: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
location: "gix-sec/src/permission.rs",
relation: Some(
ChildOfParent(
2,
),
),
copy: false,
},
Rewrite {
source_location: "git-sec/src/trust.rs",
source_entry_mode: EntryMode(0o100644),
source_relation: Some(
ChildOfParent(
1,
),
),
source_id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
diff: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
location: "gix-sec/src/trust.rs",
relation: Some(
ChildOfParent(
2,
),
),
copy: false,
},
Rewrite {
source_location: "git-sec/tests/sec.rs",
source_entry_mode: EntryMode(0o100644),
source_relation: Some(
ChildOfParent(
1,
),
),
source_id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
diff: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
location: "gix-sec/tests/sec.rs",
relation: Some(
ChildOfParent(
2,
),
),
copy: false,
},
Rewrite {
source_location: "git-sec/tests/identity/mod.rs",
source_entry_mode: EntryMode(0o100644),
source_relation: Some(
ChildOfParent(
1,
),
),
source_id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
diff: None,
entry_mode: EntryMode(0o100644),
id: Sha1(e69de29bb2d1d6434b8b29ae775ad8c2e48c5391),
location: "gix-sec/tests/identity/mod.rs",
relation: Some(
ChildOfParent(
2,
),
),
copy: false,
},
]
"#);
#[cfg(not(windows))]
{
let expected = r#"commit d78c63c5ea3149040767e4387e7fc743cda118fd
Author: author <author@example.com>
Date: Sat Jan 1 00:00:00 2000 +0000
r2-change
diff --git a/git-sec/CHANGELOG.md b/gix-sec/CHANGELOG.md
similarity index 100%
rename from git-sec/CHANGELOG.md
rename to gix-sec/CHANGELOG.md
diff --git a/git-sec/Cargo.toml b/gix-sec/Cargo.toml
similarity index 100%
rename from git-sec/Cargo.toml
rename to gix-sec/Cargo.toml
diff --git a/git-sec/src/identity.rs b/gix-sec/src/identity.rs
similarity index 100%
rename from git-sec/src/identity.rs
rename to gix-sec/src/identity.rs
diff --git a/git-sec/src/lib.rs b/gix-sec/src/lib.rs
similarity index 100%
rename from git-sec/src/lib.rs
rename to gix-sec/src/lib.rs
diff --git a/git-sec/src/permission.rs b/gix-sec/src/permission.rs
similarity index 100%
rename from git-sec/src/permission.rs
rename to gix-sec/src/permission.rs
diff --git a/git-sec/src/trust.rs b/gix-sec/src/trust.rs
similarity index 100%
rename from git-sec/src/trust.rs
rename to gix-sec/src/trust.rs
diff --git a/git-sec/tests/identity/mod.rs b/gix-sec/tests/identity/mod.rs
similarity index 100%
rename from git-sec/tests/identity/mod.rs
rename to gix-sec/tests/identity/mod.rs
diff --git a/git-sec/tests/sec.rs b/gix-sec/tests/sec.rs
similarity index 100%
rename from git-sec/tests/sec.rs
rename to gix-sec/tests/sec.rs
"#;
assert_eq!(
std::fs::read_to_string(repo_workdir()?.join("baseline-2.with-renames"))?,
expected
);
}
let out = out.expect("tracking enabled");
assert_eq!(
out.num_similarity_checks, 0,
"similarity checks disabled, and not necessary"
);
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 realistic_renames_3_without_identity() -> crate::Result {
let (changes, out) = collect_changes_opts(
"r4-base",
"r4-dir-rename-non-identity",
Options {
location: Some(Location::Path),
rewrites: Some(Rewrites {
copies: None,
percentage: None,
limit: 0,
track_empty: false,
}),
},
)?;
// Look how nicely it captures and associates this directory rename.
insta::assert_debug_snapshot!(changes.into_iter()
.filter(|c| !c.entry_mode().is_tree() ||
c.relation().is_some_and(|r| matches!(r, Relation::Parent(_)))
).collect::<Vec<_>>(), @r#"
[
Rewrite {
source_location: "src/plumbing/options.rs",
source_entry_mode: EntryMode(0o100644),
source_relation: Some(
ChildOfParent(
2,
),
),
source_id: Sha1(00750edc07d6415dcc07ae0351e9397b0222b7ba),
diff: None,
entry_mode: EntryMode(0o100644),
id: Sha1(00750edc07d6415dcc07ae0351e9397b0222b7ba),
location: "src/plumbing-renamed/options/mod.rs",
relation: Some(
ChildOfParent(
1,
),
),
copy: false,
},
Rewrite {
source_location: "src/plumbing/mod.rs",
source_entry_mode: EntryMode(0o100644),
source_relation: Some(
ChildOfParent(
2,
),
),
source_id: Sha1(0cfbf08886fca9a91cb753ec8734c84fcbe52c9f),
diff: None,
entry_mode: EntryMode(0o100644),
id: Sha1(0cfbf08886fca9a91cb753ec8734c84fcbe52c9f),
location: "src/plumbing-renamed/mod.rs",
relation: Some(
ChildOfParent(
1,
),
),
copy: false,
},
Rewrite {
source_location: "src/plumbing/main.rs",
source_entry_mode: EntryMode(0o100644),
source_relation: Some(
ChildOfParent(
2,
),
),
source_id: Sha1(d00491fd7e5bb6fa28c517a0bb32b8b506539d4d),
diff: None,
entry_mode: EntryMode(0o100644),
id: Sha1(d00491fd7e5bb6fa28c517a0bb32b8b506539d4d),
location: "src/plumbing-renamed/main.rs",
relation: Some(
ChildOfParent(
1,
),
),
copy: false,
},
Rewrite {
source_location: "src/plumbing",
source_entry_mode: EntryMode(0o40000),
source_relation: Some(
Parent(
2,
),
),
source_id: Sha1(b9d41dcdbd92fcab2fb6594d04f2ad99b3472621),
diff: None,
entry_mode: EntryMode(0o40000),
id: Sha1(202702465d7bb291153629dc2e8b353afe9cbdae),
location: "src/plumbing-renamed",
relation: Some(
Parent(
1,
),
),
copy: false,
},
]
"#);
let out = out.expect("tracking enabled");
assert_eq!(
out.num_similarity_checks, 0,
"similarity checks disabled, and not necessary"
);
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(())
}
mod util {
use gix_diff::rewrites;
use gix_object::{FindExt, TreeRefIter};
use std::convert::Infallible;
use std::path::{Path, PathBuf};
pub fn repo_workdir() -> crate::Result<PathBuf> {
gix_testtools::scripted_fixture_read_only_standalone("make_diff_for_rewrites_repo.sh")
}
pub fn repo_with_trees(
lhs: impl Into<Option<&'static str>>,
rhs: impl Into<Option<&'static str>>,
) -> gix_testtools::Result<(Vec<u8>, Vec<u8>, gix_diff::blob::Platform, gix_odb::Handle)> {
let root = repo_workdir()?;
let odb = gix_odb::at(root.join(".git/objects"))?;
let lhs = read_tree(&odb, &root, lhs.into())?;
let rhs = read_tree(&odb, &root, rhs.into())?;
let cache = gix_diff::blob::Platform::new(
Default::default(),
gix_diff::blob::Pipeline::new(Default::default(), Default::default(), Vec::new(), Default::default()),
Default::default(),
gix_worktree::Stack::new(
&root,
gix_worktree::stack::State::AttributesStack(gix_worktree::stack::state::Attributes::default()),
Default::default(),
Vec::new(),
Vec::new(),
),
);
Ok((lhs, rhs, cache, odb))
}
pub fn collect_changes(
lhs: impl Into<Option<&'static str>>,
rhs: impl Into<Option<&'static str>>,
) -> gix_testtools::Result<(Vec<gix_diff::tree_with_rewrites::Change>, Option<rewrites::Outcome>)> {
let options = gix_diff::tree_with_rewrites::Options {
location: Some(gix_diff::tree::recorder::Location::Path),
rewrites: None,
};
collect_changes_opts(lhs, rhs, options)
}
pub fn collect_changes_opts(
lhs: impl Into<Option<&'static str>>,
rhs: impl Into<Option<&'static str>>,
options: gix_diff::tree_with_rewrites::Options,
) -> gix_testtools::Result<(Vec<gix_diff::tree_with_rewrites::Change>, Option<rewrites::Outcome>)> {
let (from, to, mut cache, odb) = repo_with_trees(lhs, rhs)?;
let mut out = Vec::new();
let rewrites_info = gix_diff::tree_with_rewrites(
TreeRefIter::from_bytes(&from),
TreeRefIter::from_bytes(&to),
&mut cache,
&mut Default::default(),
&odb,
|change| -> Result<_, Infallible> {
out.push(change.into_owned());
Ok(gix_diff::tree_with_rewrites::Action::Continue)
},
options,
)?;
Ok((out, rewrites_info))
}
fn read_tree(odb: &dyn gix_object::Find, root: &Path, tree: Option<&str>) -> gix_testtools::Result<Vec<u8>> {
let Some(tree) = tree else { return Ok(Vec::new()) };
let tree_id_path = root.join(tree).with_extension("tree");
let hex_id = std::fs::read_to_string(&tree_id_path).map_err(|err| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!("Could not read '{}': {}", tree_id_path.display(), err),
)
})?;
let tree_id = gix_hash::ObjectId::from_hex(hex_id.trim().as_bytes())?;
let mut buf = Vec::new();
odb.find_tree(&tree_id, &mut buf)?;
Ok(buf)
}
}
use util::{collect_changes, collect_changes_opts, repo_with_trees, repo_workdir};