2398 lines · 59.1 KB · Rust
RawDownload
// Copyright 2021 The Jujutsu Authors//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at//// https://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License. use indoc::indoc;use itertools::Itertools as _;use jj_lib::backend::FileId;use jj_lib::conflicts::ConflictMarkerStyle;use jj_lib::conflicts::ConflictMaterializeOptions;use jj_lib::conflicts::MIN_CONFLICT_MARKER_LEN;use jj_lib::conflicts::choose_materialized_conflict_marker_len;use jj_lib::conflicts::extract_as_single_hunk;use jj_lib::conflicts::materialize_merge_result_to_bytes;use jj_lib::conflicts::parse_conflict;use jj_lib::conflicts::update_from_content;use jj_lib::files::FileMergeHunkLevel;use jj_lib::merge::Merge;use jj_lib::merge::SameChange;use jj_lib::repo::Repo as _;use jj_lib::repo_path::RepoPath;use jj_lib::store::Store;use jj_lib::tree_merge::MergeOptions;use pollster::FutureExt as _;use test_case::test_case;use testutils::TestRepo;use testutils::read_file;use testutils::repo_path; #[test]fn test_materialize_conflict_basic() {    let test_repo = TestRepo::init();    let store = test_repo.repo.store();     let path = repo_path("file");    let base_id = testutils::write_file(        store,        path,        indoc! {"            line 1            line 2            line 3            line 4            line 5        "},    );    let left_id = testutils::write_file(        store,        path,        indoc! {"            line 1            line 2            left 3.1            left 3.2            left 3.3            line 4            line 5        "},    );    let right_id = testutils::write_file(        store,        path,        indoc! {"            line 1            line 2            right 3.1            line 4            line 5        "},    );     // The left side should come first. The diff should be use the smaller (right)    // side, and the left side should be a snapshot.    let conflict = Merge::from_removes_adds(        vec![Some(base_id.clone())],        vec![Some(left_id.clone()), Some(right_id.clone())],    );    insta::assert_snapshot!(        &materialize_conflict_string(store, path, &conflict, ConflictMarkerStyle::Diff),        @r"    line 1    line 2    <<<<<<< Conflict 1 of 1    +++++++ Contents of side #1    left 3.1    left 3.2    left 3.3    %%%%%%% Changes from base to side #2    -line 3    +right 3.1    >>>>>>> Conflict 1 of 1 ends    line 4    line 5    "    );    // Swap the positive terms in the conflict. The diff should still use the right    // side, but now the right side should come first.    let conflict = Merge::from_removes_adds(        vec![Some(base_id.clone())],        vec![Some(right_id.clone()), Some(left_id.clone())],    );    insta::assert_snapshot!(        &materialize_conflict_string(store, path, &conflict, ConflictMarkerStyle::Diff),        @r"    line 1    line 2    <<<<<<< Conflict 1 of 1    %%%%%%% Changes from base to side #1    -line 3    +right 3.1    +++++++ Contents of side #2    left 3.1    left 3.2    left 3.3    >>>>>>> Conflict 1 of 1 ends    line 4    line 5    "    );    // Test materializing "snapshot" conflict markers    let conflict = Merge::from_removes_adds(        vec![Some(base_id.clone())],        vec![Some(left_id.clone()), Some(right_id.clone())],    );    insta::assert_snapshot!(        &materialize_conflict_string(store, path, &conflict, ConflictMarkerStyle::Snapshot),        @r"    line 1    line 2    <<<<<<< Conflict 1 of 1    +++++++ Contents of side #1    left 3.1    left 3.2    left 3.3    ------- Contents of base    line 3    +++++++ Contents of side #2    right 3.1    >>>>>>> Conflict 1 of 1 ends    line 4    line 5    "    );    // Test materializing "git" conflict markers    let conflict = Merge::from_removes_adds(        vec![Some(base_id.clone())],        vec![Some(left_id.clone()), Some(right_id.clone())],    );    insta::assert_snapshot!(        &materialize_conflict_string(store, path, &conflict, ConflictMarkerStyle::Git),        @r"    line 1    line 2    <<<<<<< Side #1 (Conflict 1 of 1)    left 3.1    left 3.2    left 3.3    ||||||| Base    line 3    =======    right 3.1    >>>>>>> Side #2 (Conflict 1 of 1 ends)    line 4    line 5    "    );} #[test]fn test_materialize_conflict_three_sides() {    let test_repo = TestRepo::init();    let store = test_repo.repo.store();     let path = repo_path("file");    let base_1_id = testutils::write_file(        store,        path,        indoc! {"            line 1            line 2 base            line 3 base            line 4 base            line 5        "},    );    let base_2_id = testutils::write_file(        store,        path,        indoc! {"            line 1            line 2 base            line 5        "},    );    let a_id = testutils::write_file(        store,        path,        indoc! {"            line 1            line 2 a.1            line 3 a.2            line 4 base            line 5        "},    );    let b_id = testutils::write_file(        store,        path,        indoc! {"            line 1            line 2 b.1            line 3 base            line 4 b.2            line 5        "},    );    let c_id = testutils::write_file(        store,        path,        indoc! {"            line 1            line 2 base            line 3 c.2            line 5        "},    );     let conflict = Merge::from_removes_adds(        vec![Some(base_1_id.clone()), Some(base_2_id.clone())],        vec![Some(a_id.clone()), Some(b_id.clone()), Some(c_id.clone())],    );    // Test materializing "diff" conflict markers    insta::assert_snapshot!(        &materialize_conflict_string(store, path, &conflict, ConflictMarkerStyle::Diff),        @r"    line 1    <<<<<<< Conflict 1 of 1    %%%%%%% Changes from base #1 to side #1    -line 2 base    -line 3 base    +line 2 a.1    +line 3 a.2     line 4 base    +++++++ Contents of side #2    line 2 b.1    line 3 base    line 4 b.2    %%%%%%% Changes from base #2 to side #3     line 2 base    +line 3 c.2    >>>>>>> Conflict 1 of 1 ends    line 5    "    );    // Test materializing "snapshot" conflict markers    insta::assert_snapshot!(        &materialize_conflict_string(store, path, &conflict, ConflictMarkerStyle::Snapshot),        @r"    line 1    <<<<<<< Conflict 1 of 1    +++++++ Contents of side #1    line 2 a.1    line 3 a.2    line 4 base    ------- Contents of base #1    line 2 base    line 3 base    line 4 base    +++++++ Contents of side #2    line 2 b.1    line 3 base    line 4 b.2    ------- Contents of base #2    line 2 base    +++++++ Contents of side #3    line 2 base    line 3 c.2    >>>>>>> Conflict 1 of 1 ends    line 5    "    );    // Test materializing "git" conflict markers (falls back to "snapshot" since    // "git" conflict markers don't support more than 2 sides)    insta::assert_snapshot!(        &materialize_conflict_string(store, path, &conflict, ConflictMarkerStyle::Git),        @r"    line 1    <<<<<<< Conflict 1 of 1    +++++++ Contents of side #1    line 2 a.1    line 3 a.2    line 4 base    ------- Contents of base #1    line 2 base    line 3 base    line 4 base    +++++++ Contents of side #2    line 2 b.1    line 3 base    line 4 b.2    ------- Contents of base #2    line 2 base    +++++++ Contents of side #3    line 2 base    line 3 c.2    >>>>>>> Conflict 1 of 1 ends    line 5    "    );} #[test]fn test_materialize_conflict_multi_rebase_conflicts() {    let test_repo = TestRepo::init();    let store = test_repo.repo.store();     // Create changes (a, b, c) on top of the base, and linearize them.    let path = repo_path("file");    let base_id = testutils::write_file(        store,        path,        indoc! {"            line 1            line 2 base            line 3        "},    );    let a_id = testutils::write_file(        store,        path,        indoc! {"            line 1            line 2 a.1            line 2 a.2            line 2 a.3            line 3        "},    );    let b_id = testutils::write_file(        store,        path,        indoc! {"            line 1            line 2 b.1            line 2 b.2            line 3        "},    );    let c_id = testutils::write_file(        store,        path,        indoc! {"            line 1            line 2 c.1            line 3        "},    );     // The order of (a, b, c) should be preserved. For all cases, the "a" side    // should be a snapshot.    let conflict = Merge::from_removes_adds(        vec![Some(base_id.clone()), Some(base_id.clone())],        vec![Some(a_id.clone()), Some(b_id.clone()), Some(c_id.clone())],    );    insta::assert_snapshot!(        &materialize_conflict_string(store, path, &conflict, ConflictMarkerStyle::Diff),        @r"    line 1    <<<<<<< Conflict 1 of 1    +++++++ Contents of side #1    line 2 a.1    line 2 a.2    line 2 a.3    %%%%%%% Changes from base #1 to side #2    -line 2 base    +line 2 b.1    +line 2 b.2    %%%%%%% Changes from base #2 to side #3    -line 2 base    +line 2 c.1    >>>>>>> Conflict 1 of 1 ends    line 3    "    );    let conflict = Merge::from_removes_adds(        vec![Some(base_id.clone()), Some(base_id.clone())],        vec![Some(c_id.clone()), Some(b_id.clone()), Some(a_id.clone())],    );    insta::assert_snapshot!(        &materialize_conflict_string(store, path, &conflict, ConflictMarkerStyle::Diff),        @r"    line 1    <<<<<<< Conflict 1 of 1    %%%%%%% Changes from base #1 to side #1    -line 2 base    +line 2 c.1    %%%%%%% Changes from base #2 to side #2    -line 2 base    +line 2 b.1    +line 2 b.2    +++++++ Contents of side #3    line 2 a.1    line 2 a.2    line 2 a.3    >>>>>>> Conflict 1 of 1 ends    line 3    "    );    let conflict = Merge::from_removes_adds(        vec![Some(base_id.clone()), Some(base_id.clone())],        vec![Some(c_id.clone()), Some(a_id.clone()), Some(b_id.clone())],    );    insta::assert_snapshot!(        &materialize_conflict_string(store, path, &conflict, ConflictMarkerStyle::Diff),        @r"    line 1    <<<<<<< Conflict 1 of 1    %%%%%%% Changes from base #1 to side #1    -line 2 base    +line 2 c.1    +++++++ Contents of side #2    line 2 a.1    line 2 a.2    line 2 a.3    %%%%%%% Changes from base #2 to side #3    -line 2 base    +line 2 b.1    +line 2 b.2    >>>>>>> Conflict 1 of 1 ends    line 3    "    );} //  TODO: With options#[test]fn test_materialize_parse_roundtrip() {    let test_repo = TestRepo::init();    let store = test_repo.repo.store();     let path = repo_path("file");    let base_id = testutils::write_file(        store,        path,        indoc! {"            line 1            line 2            line 3            line 4            line 5        "},    );    let left_id = testutils::write_file(        store,        path,        indoc! {"            line 1 left            line 2 left            line 3            line 4            line 5 left        "},    );    let right_id = testutils::write_file(        store,        path,        indoc! {"            line 1 right            line 2            line 3            line 4 right            line 5 right        "},    );     let conflict = Merge::from_removes_adds(        vec![Some(base_id.clone())],        vec![Some(left_id.clone()), Some(right_id.clone())],    );    let materialized =        materialize_conflict_string(store, path, &conflict, ConflictMarkerStyle::Diff);    insta::assert_snapshot!(        materialized,        @r"    <<<<<<< Conflict 1 of 2    +++++++ Contents of side #1    line 1 left    line 2 left    %%%%%%% Changes from base to side #2    -line 1    +line 1 right

Lines 1–500 of 2398.