#[path = "common/mod.rs"]
mod common;
use common::TestRepo;
use tij::jj::JjExecutor;
use tij::model::RebaseMode;
#[test]
fn test_abandon_removes_change() {
skip_if_no_jj!();
let repo = TestRepo::new();
repo.jj(&["new", "-m", "base"]);
repo.jj(&["new", "-m", "to-abandon"]);
let abandon_id = repo.current_change_id();
repo.jj(&["new", "-m", "current"]);
let before = repo.count_changes("all()");
let executor = JjExecutor::with_repo_path(repo.path());
executor
.abandon(&abandon_id)
.expect("abandon should succeed");
let after = repo.count_changes("all()");
assert_eq!(
after,
before - 1,
"Should have one less change after abandon"
);
}
#[test]
fn test_abandon_rebases_descendants() {
skip_if_no_jj!();
let repo = TestRepo::new();
repo.jj(&["new", "-m", "middle"]);
let middle_id = repo.current_change_id();
repo.jj(&["new", "-m", "child"]);
let executor = JjExecutor::with_repo_path(repo.path());
executor
.abandon(&middle_id)
.expect("abandon should succeed");
let parent_desc = repo.get_description("@-");
assert_ne!(
parent_desc, "middle",
"middle should be removed from ancestry"
);
}
#[test]
fn test_rebase_moves_change() {
skip_if_no_jj!();
let repo = TestRepo::new();
repo.write_file("a.txt", "a");
repo.jj(&["describe", "-m", "A"]);
repo.jj(&["new", "-m", "B"]);
repo.write_file("b.txt", "b");
repo.jj(&["new", "-m", "C"]);
repo.write_file("c.txt", "c");
let c_id = repo.current_change_id();
let a_id = repo
.jj(&["log", "-r", "@--", "--no-graph", "-T", "change_id.short(8)"])
.trim()
.to_string();
let executor = JjExecutor::with_repo_path(repo.path());
executor
.rebase_unified(RebaseMode::Revision, &c_id, &a_id, &[])
.expect("rebase should succeed");
let parent_desc = repo.get_description("@-");
assert_eq!(parent_desc, "A", "C's parent should now be A");
}
#[test]
fn test_rebase_with_conflict() {
skip_if_no_jj!();
let repo = TestRepo::new();
repo.write_file("file.txt", "original");
repo.jj(&["describe", "-m", "A"]);
repo.jj(&["new", "-m", "B"]);
repo.write_file("file.txt", "modified by B");
let b_id = repo.current_change_id();
repo.jj(&["edit", "@-"]);
repo.jj(&["new", "-m", "C"]);
repo.write_file("file.txt", "modified by C");
let c_id = repo.current_change_id();
let executor = JjExecutor::with_repo_path(repo.path());
let result = executor.rebase_unified(RebaseMode::Revision, &c_id, &b_id, &[]);
assert!(result.is_ok(), "rebase should complete");
let has_conflict = executor.has_conflict(&c_id).unwrap_or(false);
assert!(has_conflict, "Should have conflict after rebase");
}
#[test]
fn test_abandon_current_change() {
skip_if_no_jj!();
let repo = TestRepo::new();
repo.jj(&["new", "-m", "A"]);
repo.jj(&["new", "-m", "B"]);
let b_id = repo.current_change_id();
let executor = JjExecutor::with_repo_path(repo.path());
executor
.abandon(&b_id)
.expect("abandon current should succeed");
let parent_desc = repo.get_description("@-");
assert_eq!(parent_desc, "A", "Parent should be A after abandoning B");
let current_desc = repo.get_description("@");
assert!(
current_desc.is_empty(),
"New current change should have no description"
);
}
#[test]
fn test_rebase_source_moves_descendants() {
skip_if_no_jj!();
let repo = TestRepo::new();
repo.write_file("a.txt", "a");
repo.jj(&["describe", "-m", "A"]);
repo.jj(&["new", "-m", "B"]);
repo.write_file("b.txt", "b");
let b_id = repo.current_change_id();
repo.jj(&["new", "-m", "C"]);
repo.write_file("c.txt", "c");
let c_id = repo.current_change_id();
repo.jj(&["new", "root()", "-m", "D"]);
repo.write_file("d.txt", "d");
let d_id = repo.current_change_id();
let executor = JjExecutor::with_repo_path(repo.path());
executor
.rebase_unified(RebaseMode::Source, &b_id, &d_id, &[])
.expect("rebase_source should succeed");
let b_parent = repo
.jj(&[
"log",
"-r",
&format!("{}-", b_id),
"--no-graph",
"-T",
"description.first_line()",
])
.trim()
.to_string();
assert_eq!(b_parent, "D", "B's parent should now be D");
let c_parent = repo
.jj(&[
"log",
"-r",
&format!("{}-", c_id),
"--no-graph",
"-T",
"description.first_line()",
])
.trim()
.to_string();
assert_eq!(c_parent, "B", "C's parent should still be B");
}
#[test]
fn test_rebase_insert_after() {
skip_if_no_jj!();
let repo = TestRepo::new();
repo.write_file("j.txt", "j");
repo.jj(&["describe", "-m", "J"]);
let j_id = repo.current_change_id();
repo.jj(&["new", "-m", "K"]);
repo.write_file("k.txt", "k");
let k_id = repo.current_change_id();
repo.jj(&["new", &j_id, "-m", "L"]);
repo.write_file("l.txt", "l");
let l_id = repo.current_change_id();
repo.jj(&["new", "-m", "M"]);
repo.write_file("m.txt", "m");
let executor = JjExecutor::with_repo_path(repo.path());
executor
.rebase_unified(RebaseMode::InsertAfter, &k_id, &l_id, &[])
.expect("rebase_insert_after should succeed");
let k_parent_desc = repo
.jj(&[
"log",
"-r",
&format!("{}-", k_id),
"--no-graph",
"-T",
"description.first_line()",
])
.trim()
.to_string();
assert_eq!(k_parent_desc, "L", "K's parent should now be L");
}
#[test]
fn test_rebase_insert_before() {
skip_if_no_jj!();
let repo = TestRepo::new();
repo.write_file("j.txt", "j");
repo.jj(&["describe", "-m", "J"]);
let j_id = repo.current_change_id();
repo.jj(&["new", "-m", "L"]);
repo.write_file("l.txt", "l");
let l_id = repo.current_change_id();
repo.jj(&["new", "-m", "M"]);
repo.write_file("m.txt", "m");
repo.jj(&["new", &j_id, "-m", "K"]);
repo.write_file("k.txt", "k");
let k_id = repo.current_change_id();
let executor = JjExecutor::with_repo_path(repo.path());
executor
.rebase_unified(RebaseMode::InsertBefore, &k_id, &l_id, &[])
.expect("rebase_insert_before should succeed");
let k_parent_desc = repo
.jj(&[
"log",
"-r",
&format!("{}-", k_id),
"--no-graph",
"-T",
"description.first_line()",
])
.trim()
.to_string();
assert_eq!(k_parent_desc, "J", "K's parent should be J");
let l_parent_desc = repo
.jj(&[
"log",
"-r",
&format!("{}-", l_id),
"--no-graph",
"-T",
"description.first_line()",
])
.trim()
.to_string();
assert_eq!(l_parent_desc, "K", "L's parent should now be K");
}