458 lines · 12.0 KB · Rust
RawDownload
use std::collections::HashMap; use rangemap::RangeMap;use unindent::Unindent as _;use warp_editor::multiline::{MultilineStr, MultilineString}; use super::{DiffModel, compute_unified_diff};use crate::code::editor::diff::ChangeType; #[test]fn test_diff_generation() {    use warpui::App;    App::test((), |_| async move {        let (change_mapping, deletion_mapping) = DiffModel::compute_diff_internal(            MultilineStr::try_new("Hello World\nThis is the second line.\nThis is the third.")                .unwrap(),            MultilineStr::try_new(                "Hallo Welt\nThis is the second line.\nThis is life.\nMoar and more",            )            .unwrap(),        )        .await;        assert_eq!(            change_mapping,            RangeMap::from_iter([                (                    0..1,                    ChangeType::Replacement {                        replaced_range: 0..1,                        insertion: vec![0..5, 6..10],                        deletion: vec![0..5, 6..11]                    }                ),                (                    2..4,                    ChangeType::Replacement {                        replaced_range: 2..3,                        insertion: vec![8..13, 14..22, 23..27,],                        deletion: vec![8..11, 12..18]                    }                )            ])        );        assert!(deletion_mapping.is_empty());         let (change_mapping, deletion_mapping) = DiffModel::compute_diff_internal(            MultilineStr::try_new("Hello World\nThis is the second line.\nThis is the third.")                .unwrap(),            MultilineStr::try_new("Hello World\nThis is the third.").unwrap(),        )        .await;        assert!(change_mapping.is_empty());        assert_eq!(deletion_mapping, HashMap::from([(1, 1..2)]));         let (change_mapping, deletion_mapping) = DiffModel::compute_diff_internal(            MultilineStr::try_new("Hello\nWorld\n").unwrap(),            MultilineStr::try_new("Hallo\nWorlds\n").unwrap(),        )        .await;         assert_eq!(            change_mapping,            RangeMap::from_iter([(                0..2,                ChangeType::Replacement {                    replaced_range: 0..2,                    insertion: vec![0..5, 6..12],                    deletion: vec![0..5, 6..11]                }            ),])        );        assert!(deletion_mapping.is_empty());    });} #[test]fn test_reverse_action() {    use warpui::App;    App::test((), |_| async move {        let mut diff_model = DiffModel::new();        diff_model.set_base(MultilineString::apply(            "Hello World\nThis is the second line\n",        ));        diff_model            .compute_diff_for_test("Hallo World\nThis is the second line\nNew".to_string())            .await;         assert_eq!(diff_model.diff_hunk_count(), 2);        assert_eq!(            diff_model.reverse_action_by_diff_hunk_index(0),            Some((0..1, "Hello World\n".to_string()))        );         assert_eq!(            diff_model.reverse_action_by_diff_hunk_index(1),            Some((2..3, "".to_string()))        );         diff_model            .compute_diff_for_test("Hello World\n".to_string())            .await;        assert_eq!(            diff_model.reverse_action_by_diff_hunk_index(0),            Some((1..1, "This is the second line\n".to_string()))        );    });} #[test]fn test_reverse_action_replaced_newlines() {    use warpui::App;    App::test((), |_| async move {        let mut diff_model = DiffModel::new();        let base_text = r"             abc            def             ghi             jkl            mno              pqr             stu         "        .unindent();        diff_model.set_base(MultilineString::apply(&base_text));         // Replace with text:        // * Leading newline before "abc"        // * "def" and the following line        // * Newline between "def" and "ghi"        // * "pqr" and the preceding line        // * Trailing newline at end of file        let modified_text = r"            replaced first empty line            abc            changed def            changed line after def            ghi            changed line between ghi and jkl            jkl            mno             changed line before pqr            changed pqr             stu            replaced last empty line        "        .unindent();        diff_model.compute_diff_for_test(modified_text).await;         assert_eq!(diff_model.diff_hunk_count(), 5);         // Reversing the leading newline change        assert_eq!(            diff_model.reverse_action_by_diff_hunk_index(0),            Some((0..1, "\n".to_string()))        );         // Reversing "def" and following newline        assert_eq!(            diff_model.reverse_action_by_diff_hunk_index(1),            Some((2..4, "def\n\n".to_string()))        );         // Reversing the line changed between "ghi" and "jkl"        assert_eq!(            diff_model.reverse_action_by_diff_hunk_index(2),            Some((5..6, "\n".to_string()))        );         // Reversing changing "pqr" and the line before it        assert_eq!(            diff_model.reverse_action_by_diff_hunk_index(3),            Some((9..11, "\npqr\n".to_string()))        );         // Reversing changing the last line        assert_eq!(            diff_model.reverse_action_by_diff_hunk_index(4),            Some((13..14, "\n".to_string()))        );    });} #[test]fn test_reverse_action_replaced_text() {    use warpui::App;    App::test((), |_| async move {        let mut diff_model = DiffModel::new();        let base_text = r"            abc            def            ghi             jkl            mno            pqr             stu            vwx            yz        "        .unindent();        diff_model.set_base(MultilineString::apply(&base_text));         // Replace with a newline:        // * First line "abc"        // * "ghi", which is followed by a newline        // * "mno"        // * "stu", which is preceded by a newline        // * Last line "yz"        let modified_text = r"             def              jkl             pqr              vwx         "        .unindent();        diff_model.compute_diff_for_test(modified_text).await;         assert_eq!(diff_model.diff_hunk_count(), 5);         // Reversing the leading newline change        assert_eq!(            diff_model.reverse_action_by_diff_hunk_index(0),            Some((0..1, "abc\n".to_string()))        );         // Reversing "ghi"        assert_eq!(            diff_model.reverse_action_by_diff_hunk_index(1),            Some((3..4, "ghi\n".to_string()))        );         // Reversing "mno"        assert_eq!(            diff_model.reverse_action_by_diff_hunk_index(2),            Some((5..6, "mno\n".to_string()))        );         // Reversing "stu"        assert_eq!(            diff_model.reverse_action_by_diff_hunk_index(3),            Some((8..9, "stu\n".to_string()))        );         // Reversing changing the last line        assert_eq!(            diff_model.reverse_action_by_diff_hunk_index(4),            Some((10..11, "yz\n".to_string()))        );    });} #[test]fn test_reverse_action_deleted_lines() {    use warpui::App;    App::test((), |_| async move {        let mut diff_model = DiffModel::new();        let base_text = r"             abc            def             ghi             jkl            mno              pqr              stu            vwx             yz         "        .unindent();        diff_model.set_base(MultilineString::apply(&base_text));         // Delete:        // * Leading newline before "abc"        // * Newline between "def" and "ghi"        // * "mno" followed by a newline        // * newline followed by "stu"        // * Trailing newline after "yz"        let modified_text = r"            abc            def            ghi             jkl             pqr             vwx             yz        "        .unindent();        diff_model.compute_diff_for_test(modified_text).await;         assert_eq!(diff_model.diff_hunk_count(), 5);         // Reversing the leading newline deletion        assert_eq!(            diff_model.reverse_action_by_diff_hunk_index(0),            Some((0..0, "\n".to_string()))        );         // Reversing the newline deletion between "def" and "ghi"        assert_eq!(            diff_model.reverse_action_by_diff_hunk_index(1),            Some((2..2, "\n".to_string()))        );         // Reversing the deletion of "mno" followed by a newline        assert_eq!(            diff_model.reverse_action_by_diff_hunk_index(2),            Some((5..5, "mno\n\n".to_string()))        );         // Reversing the deletion of a newline followed by "stu"        assert_eq!(            diff_model.reverse_action_by_diff_hunk_index(3),            Some((8..8, "\nstu\n".to_string()))        );         // Reversing the trailing newline deletion        assert_eq!(            diff_model.reverse_action_by_diff_hunk_index(4),            Some((11..11, "\n".to_string()))        );    });} #[test]fn test_diff_count_before_line() {    use warpui::App;    App::test((), |_| async move {        let mut diff_model = DiffModel::new();        diff_model.set_base(            "Hello World\nThis is the second line\n"                .to_owned()                .try_into()                .unwrap(),        );        diff_model            .compute_diff_for_test("Hallo World\nThis is the second line\nNew".to_string())            .await;        assert_eq!(diff_model.diff_hunk_count_before_line(0), 0);        assert_eq!(diff_model.diff_hunk_count_before_line(1), 1);        assert_eq!(diff_model.diff_hunk_count_before_line(2), 1);    });} #[test]fn test_unified_diff() {    use warpui::App;    App::test((), |_| async move {        let diff = compute_unified_diff(            MultilineStr::try_new("Hello World\nThis is the second line.\nThis is the third.")                .unwrap(),            MultilineStr::try_new(                "Hallo Welt\nThis is the second line.\nThis is life.\nMoar and more",            )            .unwrap(),            "test.rs",        )        .await;        assert_eq!(            diff.unified_diff,            "--- test.rs\n+++ test.rs\n@@ -1,3 +1,4 @@\n-Hello World\n+Hallo Welt\n This is the second line.\n-This is the third.\n+This is life.\n+Moar and more\n"        );        assert_eq!(diff.lines_added, 3);        assert_eq!(diff.lines_removed, 2);    });} /// Test coalesce_replacements with a case where the `similar` library is known/// to produce duplicate deletion and insertion hunks for what is logically a replacement.#[test]fn test_coalesce_replacements() {    use warpui::App;    App::test((), |_| async move {        let mut diff_model = DiffModel::new();        let base_text = r"            abc            def            ghi             jkl            mno            pqr             stu            vwx            yz        "        .unindent();        diff_model.set_base(MultilineString::apply(&base_text));         // Replace with a newline:        // * First line "abc"        // * "ghi", which is followed by a newline        // * "mno"        // * "stu", which is preceded by a newline        // * Last line "yz"        let modified_text = r"             def              jkl             pqr              vwx         "        .unindent();        diff_model.compute_diff_for_test(modified_text).await;         assert_eq!(diff_model.diff_hunk_count(), 5);         // Replacing "abc"        assert_eq!(diff_model.diff_by_index(0), Some((0..1, true)));         // Replacing "ghi"        assert_eq!(diff_model.diff_by_index(1), Some((3..4, true)));         // Replacing "mno"        assert_eq!(diff_model.diff_by_index(2), Some((5..6, true)));         // Replacing "stu"        assert_eq!(diff_model.diff_by_index(3), Some((8..9, true)));         // Replacing "yz"        assert_eq!(diff_model.diff_by_index(4), Some((10..11, true)));    });}