184 lines · 6.0 KB · Rust
RawDownload
// Copyright 2024 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 std::collections::HashMap; use itertools::Itertools as _;use jj_lib::backend::CommitId;use jj_lib::repo::Repo as _;use jj_lib::rewrite::duplicate_commits;use jj_lib::transaction::Transaction;use pollster::FutureExt as _;use testutils::TestRepo;use testutils::create_tree;use testutils::repo_path; #[test]fn test_duplicate_linear_contents() {    let test_repo = TestRepo::init();    let repo = &test_repo.repo;     let path_1 = repo_path("file1");    let path_2 = repo_path("file2");    let empty_tree_id = repo.store().empty_merged_tree_id();    let tree_1 = create_tree(repo, &[(path_1, "content1")]);    let tree_2 = create_tree(repo, &[(path_2, "content2")]);    let tree_1_2 = create_tree(repo, &[(path_1, "content1"), (path_2, "content2")]);     // E [=file2]    // D [-file1, =file2]    // C [=file1, +file2]    // B [+file1]    // A []    let mut tx = repo.start_transaction();    let commit_a = tx        .repo_mut()        .new_commit(            vec![repo.store().root_commit_id().clone()],            empty_tree_id.clone(),        )        .write()        .unwrap();    let commit_b = tx        .repo_mut()        .new_commit(vec![commit_a.id().clone()], tree_1.id())        .write()        .unwrap();    let commit_c = tx        .repo_mut()        .new_commit(vec![commit_b.id().clone()], tree_1_2.id())        .write()        .unwrap();    let commit_d = tx        .repo_mut()        .new_commit(vec![commit_c.id().clone()], tree_2.id())        .write()        .unwrap();    let commit_e = tx        .repo_mut()        .new_commit(vec![commit_d.id().clone()], tree_2.id())        .write()        .unwrap();    let repo = tx.commit("test").unwrap();     let duplicate_in_between = |tx: &mut Transaction,                                target_commits: &[&CommitId],                                parent_commit_ids: &[&CommitId],                                children_commit_ids: &[&CommitId]| {        duplicate_commits(            tx.repo_mut(),            &target_commits.iter().copied().cloned().collect_vec(),            &HashMap::new(),            &parent_commit_ids.iter().copied().cloned().collect_vec(),            &children_commit_ids.iter().copied().cloned().collect_vec(),        )        .block_on()        .unwrap()    };    let duplicate_onto =        |tx: &mut Transaction, target_commits: &[&CommitId], parent_commit_ids: &[&CommitId]| {            duplicate_in_between(tx, target_commits, parent_commit_ids, &[])        };     // Duplicate empty commit onto empty ancestor tree    let mut tx = repo.start_transaction();    let stats = duplicate_onto(&mut tx, &[commit_e.id()], &[commit_a.id()]);    assert_eq!(        stats.duplicated_commits[commit_e.id()].tree_id(),        &empty_tree_id    );     // Duplicate empty commit onto non-empty ancestor tree    let mut tx = repo.start_transaction();    let stats = duplicate_onto(&mut tx, &[commit_e.id()], &[commit_b.id()]);    assert_eq!(        stats.duplicated_commits[commit_e.id()].tree_id(),        &tree_1.id()    );     // Duplicate non-empty commit onto empty ancestor tree    let mut tx = repo.start_transaction();    let stats = duplicate_onto(&mut tx, &[commit_c.id()], &[commit_a.id()]);    assert_eq!(        stats.duplicated_commits[commit_c.id()].tree_id(),        &tree_2.id()    );     // Duplicate non-empty commit onto non-empty ancestor tree    let mut tx = repo.start_transaction();    let stats = duplicate_onto(&mut tx, &[commit_d.id()], &[commit_b.id()]);    assert_eq!(        stats.duplicated_commits[commit_d.id()].tree_id(),        &empty_tree_id    );     // Duplicate non-empty commit onto non-empty descendant tree    let mut tx = repo.start_transaction();    let stats = duplicate_onto(&mut tx, &[commit_b.id()], &[commit_d.id()]);    assert_eq!(        stats.duplicated_commits[commit_b.id()].tree_id(),        &tree_1_2.id()    );     // Duplicate multiple contiguous commits    let mut tx = repo.start_transaction();    let stats = duplicate_onto(&mut tx, &[commit_e.id(), commit_d.id()], &[commit_b.id()]);    assert_eq!(        stats.duplicated_commits[commit_d.id()].tree_id(),        &empty_tree_id    );    assert_eq!(        stats.duplicated_commits[commit_e.id()].tree_id(),        &empty_tree_id    );     // Duplicate multiple non-contiguous commits    let mut tx = repo.start_transaction();    let stats = duplicate_onto(&mut tx, &[commit_e.id(), commit_c.id()], &[commit_a.id()]);    assert_eq!(        stats.duplicated_commits[commit_c.id()].tree_id(),        &tree_2.id()    );    assert_eq!(        stats.duplicated_commits[commit_e.id()].tree_id(),        &tree_2.id()    );     // Duplicate onto multiple parents    let mut tx = repo.start_transaction();    let stats = duplicate_onto(&mut tx, &[commit_d.id()], &[commit_c.id(), commit_b.id()]);    assert_eq!(        stats.duplicated_commits[commit_d.id()].tree_id(),        &tree_2.id()    );     // Insert duplicated commit    let mut tx = repo.start_transaction();    let stats = duplicate_in_between(        &mut tx,        &[commit_b.id()],        &[commit_d.id()],        &[commit_e.id()],    );    assert_eq!(        stats.duplicated_commits[commit_b.id()].tree_id(),        &tree_1_2.id()    );    let [head_id] = tx.repo().view().heads().iter().collect_array().unwrap();    assert_ne!(head_id, commit_e.id());    assert_eq!(        tx.repo().store().get_commit(head_id).unwrap().tree_id(),        &tree_1_2.id()    );}