// 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::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::conflicts::ConflictMarkerStyle;use jj_lib::conflicts::MIN_CONFLICT_MARKER_LEN;use jj_lib::merge::Merge;use jj_lib::repo::Repo as _;use jj_lib::repo_path::RepoPath;use jj_lib::store::Store;use pollster::FutureExt as _;use testutils::TestRepo; #[test]fn test_materialize_conflict_basic() { let test_repo = TestRepo::init(); let store = test_repo.repo.store(); let path = RepoPath::from_internal_string("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 = RepoPath::from_internal_string("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 = RepoPath::from_internal_string("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 = RepoPath::from_internal_string("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 line 2 >>>>>>> Conflict 1 of 2 ends line 3 <<<<<<< Conflict 2 of 2 %%%%%%% Changes from base to side #1 line 4 -line 5Lines 1–500 of 2457. Load more
// 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::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::conflicts::ConflictMarkerStyle; use jj_lib::conflicts::MIN_CONFLICT_MARKER_LEN; use jj_lib::merge::Merge; use jj_lib::repo::Repo as _; use jj_lib::repo_path::RepoPath; use jj_lib::store::Store; use pollster::FutureExt as _; use testutils::TestRepo; #[test] fn test_materialize_conflict_basic() { let test_repo = TestRepo::init(); let store = test_repo.repo.store(); let path = RepoPath::from_internal_string("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 = RepoPath::from_internal_string("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 = RepoPath::from_internal_string("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 = RepoPath::from_internal_string("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 line 2 >>>>>>> Conflict 1 of 2 ends line 3 <<<<<<< Conflict 2 of 2 %%%%%%% Changes from base to side #1 line 4 -line 5