use gix_diff::blob::UnifiedDiff;use gix_diff::blob::unified_diff::ConsumeBinaryHunk;use gix_diff::blob::{ Algorithm, unified_diff::{ConsumeHunk, ContextSize, DiffLineKind, HunkHeader},};use gix_object::bstr::BString; #[test]fn removed_modified_added() -> crate::Result { let a = "1\n2\n3\n4\n5\n6\n7\n8\n9\n10"; let b = "2\n3\n4\n5\nsix\n7\n8\n9\n10\neleven\ntwelve"; let interner = gix_diff::blob::InternedInput::new( gix_diff::blob::platform::resource::ByteLinesWithoutTerminator::new(a.as_bytes()), gix_diff::blob::platform::resource::ByteLinesWithoutTerminator::new(b.as_bytes()), ); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(3), )?; // merged by context. insta::assert_snapshot!(actual, @r" @@ -1,10 +1,11 @@ -1 2 3 4 5 -6 +six 7 8 9 10 +eleven +twelve "); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(1), )?; // Small context lines keeps hunks separate. insta::assert_snapshot!(actual, @r" @@ -1,2 +1,1 @@ -1 2 @@ -5,3 +4,3 @@ 5 -6 +six 7 @@ -10,1 +9,3 @@ 10 +eleven +twelve "); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(0), )?; // No context is also fine insta::assert_snapshot!(actual, @r" @@ -1,1 +1,0 @@ -1 @@ -6,1 +5,1 @@ -6 +six @@ -11,0 +10,2 @@ +eleven +twelve "); let actual = render( Algorithm::Myers, &interner, Recorder::new("\n"), ContextSize::symmetrical(1), )?; assert_eq!( actual, &[ ((1, 2), (1, 1), "@@ -1,2 +1,1 @@\n".to_string()), ((5, 3), (4, 3), "@@ -5,3 +4,3 @@\n".into()), ((10, 1), (9, 3), "@@ -10,1 +9,3 @@\n".into()) ] ); Ok(())} #[test]fn context_overlap_by_one_line_move_up() -> crate::Result { let a = "2\n3\n4\n5\n6\n7\n"; let b = "7\n2\n3\n4\n5\n6\n"; let interner = gix_diff::blob::InternedInput::new(a, b); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(3), )?; // merged by context. insta::assert_snapshot!(actual, @r" @@ -1,6 +1,6 @@ +7 2 3 4 5 6 -7 "); Ok(())} #[test]fn non_utf8() -> crate::Result { let a = &b"\xC0\x80"[..]; let b = b"ascii"; let interner = gix_diff::blob::InternedInput::new(a, b); let err = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(3), ) .unwrap_err(); assert_eq!( err.to_string(), "invalid UTF-8 found at byte offset 1", "strings enforce an encoding, which fails here" ); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(BString::default(), "\n"), ContextSize::symmetrical(3), )?; insta::assert_snapshot!(actual, @r" @@ -1,1 +1,1 @@ -�� +ascii "); Ok(())} #[test]fn context_overlap_by_one_line_move_down() -> crate::Result { let a = "2\n3\n4\n5\n6\n7\n"; let b = "7\n2\n3\n4\n5\n6\n"; let interner = gix_diff::blob::InternedInput::new(b, a); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(3), )?; // merged by context. insta::assert_snapshot!(actual, @r" @@ -1,6 +1,6 @@ -7 2 3 4 5 6 +7 "); Ok(())} #[test]fn added_on_top_keeps_context_correctly_sized() -> crate::Result { let a = "1\n2\n3\n4\n5\n6\n7\n8\n9\n10"; let b = "1\n2\n3\n4\n4.5\n5\n6\n7\n8\n9\n10"; let a = gix_diff::blob::sources::byte_lines(a.as_bytes()); let b = gix_diff::blob::sources::byte_lines(b.as_bytes()); let interner = gix_diff::blob::InternedInput::new(a, b); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(3), )?; // TODO: fix this insta::assert_snapshot!(actual, @r" @@ -2,6 +2,7 @@ 2 3 4 +4.5 5 6 7 "); let a = "1\n2\n3\n4\n5\n6\n7\n8\n9\n10"; let b = "1\n2\n3\n4\n5\n6\n6.5\n7\n8\n9\n10"; let a = gix_diff::blob::sources::byte_lines(a.as_bytes()); let b = gix_diff::blob::sources::byte_lines(b.as_bytes()); let interner = gix_diff::blob::InternedInput::new(a, b); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(3), )?; insta::assert_snapshot!(actual, @r" @@ -4,6 +4,7 @@ 4 5 6 +6.5 7 8 9 "); let a = "1\n2\n3\n4\n5\n6\n7\n8\n9\n10"; let b = "1\n2\n3\n3.5\n4\n5\n6\n7\n8\n9\n10"; let a = gix_diff::blob::sources::byte_lines(a.as_bytes()); let b = gix_diff::blob::sources::byte_lines(b.as_bytes()); let interner = gix_diff::blob::InternedInput::new(a, b); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(3), )?; insta::assert_snapshot!(actual, @r" @@ -1,6 +1,7 @@ 1 2 3 +3.5 4 5 6 "); // From the end, for good measure let a = "1\n2\n3\n4\n5\n6\n7\n8\n9\n10"; let b = "1\n2\n3\n4\n5\n6\n7\n7.5\n8\n9\n10"; let a = gix_diff::blob::sources::byte_lines(a.as_bytes()); let b = gix_diff::blob::sources::byte_lines(b.as_bytes()); let interner = gix_diff::blob::InternedInput::new(a, b); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(3), )?; insta::assert_snapshot!(actual, @r" @@ -5,6 +5,7 @@ 5 6 7 +7.5 8 9 10 "); Ok(())} #[test]fn removed_modified_added_with_newlines_in_tokens() -> crate::Result { let a = "1\n2\n3\n4\n5\n6\n7\n8\n9\n10"; let b = "2\n3\n4\n5\nsix\n7\n8\n9\n10\neleven\ntwelve"; let a = gix_diff::blob::sources::byte_lines(a.as_bytes()); let b = gix_diff::blob::sources::byte_lines(b.as_bytes()); let interner = gix_diff::blob::InternedInput::new(a, b); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(3), )?; // merged by context. // newline diffs differently. insta::assert_snapshot!(actual, @r" @@ -1,10 +1,11 @@ -1 2 3 4 5 -6 +six 7 8 9 -10 +10 +eleven +twelve "); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(1), )?; // Small context lines keeps hunks separate. insta::assert_snapshot!(actual, @r" @@ -1,2 +1,1 @@ -1 2 @@ -5,3 +4,3 @@ 5 -6 +six 7 @@ -9,2 +8,4 @@ 9 -10 +10 +eleven +twelve "); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(0), )?; // No context is also fine insta::assert_snapshot!(actual, @r" @@ -1,1 +1,0 @@ -1 @@ -6,1 +5,1 @@ -6 +six @@ -10,1 +9,3 @@ -10 +10 +eleven +twelve "); let actual = render( Algorithm::Myers, &interner, Recorder::new("\r\n"), ContextSize::symmetrical(1), )?; assert_eq!( actual, &[ ((1, 2), (1, 1), "@@ -1,2 +1,1 @@\r\n".to_string()), ((5, 3), (4, 3), "@@ -5,3 +4,3 @@\r\n".into()), ((9, 2), (8, 4), "@@ -9,2 +8,4 @@\r\n".into()) ] ); let actual = render( Algorithm::Myers, &interner, DiffLineKindRecorder::default(), ContextSize::symmetrical(1), )?; assert_eq!( actual, &[ vec![DiffLineKind::Remove, DiffLineKind::Context], vec![ DiffLineKind::Context, DiffLineKind::Remove, DiffLineKind::Add, DiffLineKind::Context ], vec![ DiffLineKind::Context, DiffLineKind::Remove, DiffLineKind::Add, DiffLineKind::Add, DiffLineKind::Add ] ] ); Ok(())} #[test]fn all_added_or_removed() -> crate::Result { let content = "1\n2\n3\n4\n5"; let samples = [0, 1, 3, 100]; for context_lines in samples { let interner = gix_diff::blob::InternedInput::new("", content); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(context_lines), )?; assert_eq!( actual, r#"@@ -1,0 +1,5 @@+1+2+3+4+5"#, "context lines don't matter here" ); } for context_lines in samples { let interner = gix_diff::blob::InternedInput::new(content, ""); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(context_lines), )?; assert_eq!( actual, r"@@ -1,5 +1,0 @@-1-2-3-4-5", "context lines don't matter here" ); } Ok(())} #[test]fn empty() -> crate::Result { let interner = gix_diff::blob::InternedInput::new(&b""[..], &b""[..]); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(3), )?; insta::assert_snapshot!(actual, @r""); Ok(())} fn render<T, D>( algorithm: Algorithm, input: &gix_diff::blob::InternedInput<T>, delegate: D, context_size: ContextSize,) -> std::io::Result<D::Out>where T: AsRef<[u8]> + std::hash::Hash + Eq, D: ConsumeHunk,{ let diff = gix_diff::blob::Diff::compute(algorithm, input); UnifiedDiff::new(&diff, input, delegate, context_size).consume()} struct Recorder { #[allow(clippy::type_complexity)] hunks: Vec<((u32, u32), (u32, u32), String)>, newline: &'static str,} impl Recorder { pub fn new(newline: &'static str) -> Self { Recorder {Lines 1–500 of 544. Load more
use gix_diff::blob::UnifiedDiff; use gix_diff::blob::unified_diff::ConsumeBinaryHunk; use gix_diff::blob::{ Algorithm, unified_diff::{ConsumeHunk, ContextSize, DiffLineKind, HunkHeader}, }; use gix_object::bstr::BString; #[test] fn removed_modified_added() -> crate::Result { let a = "1\n2\n3\n4\n5\n6\n7\n8\n9\n10"; let b = "2\n3\n4\n5\nsix\n7\n8\n9\n10\neleven\ntwelve"; let interner = gix_diff::blob::InternedInput::new( gix_diff::blob::platform::resource::ByteLinesWithoutTerminator::new(a.as_bytes()), gix_diff::blob::platform::resource::ByteLinesWithoutTerminator::new(b.as_bytes()), ); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(3), )?; // merged by context. insta::assert_snapshot!(actual, @r" @@ -1,10 +1,11 @@ -1 2 3 4 5 -6 +six 7 8 9 10 +eleven +twelve "); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(1), )?; // Small context lines keeps hunks separate. insta::assert_snapshot!(actual, @r" @@ -1,2 +1,1 @@ -1 2 @@ -5,3 +4,3 @@ 5 -6 +six 7 @@ -10,1 +9,3 @@ 10 +eleven +twelve "); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(0), )?; // No context is also fine insta::assert_snapshot!(actual, @r" @@ -1,1 +1,0 @@ -1 @@ -6,1 +5,1 @@ -6 +six @@ -11,0 +10,2 @@ +eleven +twelve "); let actual = render( Algorithm::Myers, &interner, Recorder::new("\n"), ContextSize::symmetrical(1), )?; assert_eq!( actual, &[ ((1, 2), (1, 1), "@@ -1,2 +1,1 @@\n".to_string()), ((5, 3), (4, 3), "@@ -5,3 +4,3 @@\n".into()), ((10, 1), (9, 3), "@@ -10,1 +9,3 @@\n".into()) ] ); Ok(()) } #[test] fn context_overlap_by_one_line_move_up() -> crate::Result { let a = "2\n3\n4\n5\n6\n7\n"; let b = "7\n2\n3\n4\n5\n6\n"; let interner = gix_diff::blob::InternedInput::new(a, b); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(3), )?; // merged by context. insta::assert_snapshot!(actual, @r" @@ -1,6 +1,6 @@ +7 2 3 4 5 6 -7 "); Ok(()) } #[test] fn non_utf8() -> crate::Result { let a = &b"\xC0\x80"[..]; let b = b"ascii"; let interner = gix_diff::blob::InternedInput::new(a, b); let err = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(3), ) .unwrap_err(); assert_eq!( err.to_string(), "invalid UTF-8 found at byte offset 1", "strings enforce an encoding, which fails here" ); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(BString::default(), "\n"), ContextSize::symmetrical(3), )?; insta::assert_snapshot!(actual, @r" @@ -1,1 +1,1 @@ -�� +ascii "); Ok(()) } #[test] fn context_overlap_by_one_line_move_down() -> crate::Result { let a = "2\n3\n4\n5\n6\n7\n"; let b = "7\n2\n3\n4\n5\n6\n"; let interner = gix_diff::blob::InternedInput::new(b, a); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(3), )?; // merged by context. insta::assert_snapshot!(actual, @r" @@ -1,6 +1,6 @@ -7 2 3 4 5 6 +7 "); Ok(()) } #[test] fn added_on_top_keeps_context_correctly_sized() -> crate::Result { let a = "1\n2\n3\n4\n5\n6\n7\n8\n9\n10"; let b = "1\n2\n3\n4\n4.5\n5\n6\n7\n8\n9\n10"; let a = gix_diff::blob::sources::byte_lines(a.as_bytes()); let b = gix_diff::blob::sources::byte_lines(b.as_bytes()); let interner = gix_diff::blob::InternedInput::new(a, b); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(3), )?; // TODO: fix this insta::assert_snapshot!(actual, @r" @@ -2,6 +2,7 @@ 2 3 4 +4.5 5 6 7 "); let a = "1\n2\n3\n4\n5\n6\n7\n8\n9\n10"; let b = "1\n2\n3\n4\n5\n6\n6.5\n7\n8\n9\n10"; let a = gix_diff::blob::sources::byte_lines(a.as_bytes()); let b = gix_diff::blob::sources::byte_lines(b.as_bytes()); let interner = gix_diff::blob::InternedInput::new(a, b); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(3), )?; insta::assert_snapshot!(actual, @r" @@ -4,6 +4,7 @@ 4 5 6 +6.5 7 8 9 "); let a = "1\n2\n3\n4\n5\n6\n7\n8\n9\n10"; let b = "1\n2\n3\n3.5\n4\n5\n6\n7\n8\n9\n10"; let a = gix_diff::blob::sources::byte_lines(a.as_bytes()); let b = gix_diff::blob::sources::byte_lines(b.as_bytes()); let interner = gix_diff::blob::InternedInput::new(a, b); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(3), )?; insta::assert_snapshot!(actual, @r" @@ -1,6 +1,7 @@ 1 2 3 +3.5 4 5 6 "); // From the end, for good measure let a = "1\n2\n3\n4\n5\n6\n7\n8\n9\n10"; let b = "1\n2\n3\n4\n5\n6\n7\n7.5\n8\n9\n10"; let a = gix_diff::blob::sources::byte_lines(a.as_bytes()); let b = gix_diff::blob::sources::byte_lines(b.as_bytes()); let interner = gix_diff::blob::InternedInput::new(a, b); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(3), )?; insta::assert_snapshot!(actual, @r" @@ -5,6 +5,7 @@ 5 6 7 +7.5 8 9 10 "); Ok(()) } #[test] fn removed_modified_added_with_newlines_in_tokens() -> crate::Result { let a = "1\n2\n3\n4\n5\n6\n7\n8\n9\n10"; let b = "2\n3\n4\n5\nsix\n7\n8\n9\n10\neleven\ntwelve"; let a = gix_diff::blob::sources::byte_lines(a.as_bytes()); let b = gix_diff::blob::sources::byte_lines(b.as_bytes()); let interner = gix_diff::blob::InternedInput::new(a, b); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(3), )?; // merged by context. // newline diffs differently. insta::assert_snapshot!(actual, @r" @@ -1,10 +1,11 @@ -1 2 3 4 5 -6 +six 7 8 9 -10 +10 +eleven +twelve "); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(1), )?; // Small context lines keeps hunks separate. insta::assert_snapshot!(actual, @r" @@ -1,2 +1,1 @@ -1 2 @@ -5,3 +4,3 @@ 5 -6 +six 7 @@ -9,2 +8,4 @@ 9 -10 +10 +eleven +twelve "); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(0), )?; // No context is also fine insta::assert_snapshot!(actual, @r" @@ -1,1 +1,0 @@ -1 @@ -6,1 +5,1 @@ -6 +six @@ -10,1 +9,3 @@ -10 +10 +eleven +twelve "); let actual = render( Algorithm::Myers, &interner, Recorder::new("\r\n"), ContextSize::symmetrical(1), )?; assert_eq!( actual, &[ ((1, 2), (1, 1), "@@ -1,2 +1,1 @@\r\n".to_string()), ((5, 3), (4, 3), "@@ -5,3 +4,3 @@\r\n".into()), ((9, 2), (8, 4), "@@ -9,2 +8,4 @@\r\n".into()) ] ); let actual = render( Algorithm::Myers, &interner, DiffLineKindRecorder::default(), ContextSize::symmetrical(1), )?; assert_eq!( actual, &[ vec![DiffLineKind::Remove, DiffLineKind::Context], vec![ DiffLineKind::Context, DiffLineKind::Remove, DiffLineKind::Add, DiffLineKind::Context ], vec![ DiffLineKind::Context, DiffLineKind::Remove, DiffLineKind::Add, DiffLineKind::Add, DiffLineKind::Add ] ] ); Ok(()) } #[test] fn all_added_or_removed() -> crate::Result { let content = "1\n2\n3\n4\n5"; let samples = [0, 1, 3, 100]; for context_lines in samples { let interner = gix_diff::blob::InternedInput::new("", content); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(context_lines), )?; assert_eq!( actual, r#"@@ -1,0 +1,5 @@ +1 +2 +3 +4 +5 "#, "context lines don't matter here" ); } for context_lines in samples { let interner = gix_diff::blob::InternedInput::new(content, ""); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(context_lines), )?; assert_eq!( actual, r"@@ -1,5 +1,0 @@ -1 -2 -3 -4 -5 ", "context lines don't matter here" ); } Ok(()) } #[test] fn empty() -> crate::Result { let interner = gix_diff::blob::InternedInput::new(&b""[..], &b""[..]); let actual = render( Algorithm::Myers, &interner, ConsumeBinaryHunk::new(String::new(), "\n"), ContextSize::symmetrical(3), )?; insta::assert_snapshot!(actual, @r""); Ok(()) } fn render<T, D>( algorithm: Algorithm, input: &gix_diff::blob::InternedInput<T>, delegate: D, context_size: ContextSize, ) -> std::io::Result<D::Out> where T: AsRef<[u8]> + std::hash::Hash + Eq, D: ConsumeHunk, { let diff = gix_diff::blob::Diff::compute(algorithm, input); UnifiedDiff::new(&diff, input, delegate, context_size).consume() } struct Recorder { #[allow(clippy::type_complexity)] hunks: Vec<((u32, u32), (u32, u32), String)>, newline: &'static str, } impl Recorder { pub fn new(newline: &'static str) -> Self { Recorder {