use gix_diff::{ rewrites::{Copies, CopySource}, tree::{recorder::Location, visit::Relation}, tree_with_rewrites::{Change, Options}, Rewrites,};use gix_object::{bstr::BStr, 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::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);Lines 1–500 of 1871. Load more
use gix_diff::{ rewrites::{Copies, CopySource}, tree::{recorder::Location, visit::Relation}, tree_with_rewrites::{Change, Options}, Rewrites, }; use gix_object::{bstr::BStr, 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::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);