use super::*;
use crate::command_commit::parse_commit_region;
use crate::index_writer_coordination::CoordinationFailure;
use crate::test_support::{fixture, remove};
fn region(values: &[&str]) -> CommitRegion {
let tokens: Vec<OsString> = values.iter().map(OsString::from).collect();
return parse_commit_region(tokens.as_slice(), &[]).expect("a region Git's table reads");
}
fn selection(values: &[&str]) -> Selection {
return decide_selection(®ion(values), Conclusion::None);
}
#[test]
fn the_mode_follows_the_selection() {
assert_eq!(selection(&["-m", "x"]).mode, TransactionMode::Index);
assert_eq!(selection(&["-m", "x", "a.txt"]).mode, TransactionMode::ExplicitPath);
assert_eq!(selection(&["-m", "x", "--", "a.txt"]).mode, TransactionMode::ExplicitPath);
assert_eq!(selection(&["-m", "x", "--no-only", "a.txt"]).mode, TransactionMode::Index);
assert_eq!(selection(&["-m", "x", "-o", "a.txt"]).mode, TransactionMode::ExplicitPath);
assert_eq!(selection(&["-a", "-m", "x"]).mode, TransactionMode::Index);
assert_eq!(selection(&["-a", "-m", "x", "a.txt"]).mode, TransactionMode::Index);
assert_eq!(selection(&["-i", "-m", "x", "a.txt"]).mode, TransactionMode::Index);
assert_eq!(selection(&["--pathspec-from-file=list", "-m", "x"]).mode, TransactionMode::ExplicitPath);
assert_eq!(decide_selection(®ion(&["-m", "x", "a.txt"]), Conclusion::Merge).mode, TransactionMode::Index);
assert_eq!(decide_selection(®ion(&["-m", "x", "a.txt"]), Conclusion::Amend).mode, TransactionMode::ExplicitPath);
}
#[test]
fn only_a_merge_cherry_pick_or_revert_concludes_a_sequencer() {
let plain: CommitRegion = region(&["-m", "x"]);
assert!(!decide_selection(&plain, Conclusion::None).concludes_sequencer);
assert!(!decide_selection(&plain, Conclusion::Amend).concludes_sequencer);
assert!(decide_selection(&plain, Conclusion::Merge).concludes_sequencer);
assert!(decide_selection(&plain, Conclusion::CherryPick).concludes_sequencer);
assert!(decide_selection(&plain, Conclusion::Revert).concludes_sequencer);
}
#[test]
fn the_selection_flags_follow_the_options() {
assert!(selection(&["-i", "a.txt"]).read_only);
assert!(selection(&["-p"]).read_only);
assert!(selection(&["--interactive"]).read_only);
assert!(!selection(&["-m", "x"]).read_only);
assert!(selection(&["-a", "-m", "x"]).staged_all);
assert!(!selection(&["-m", "x"]).staged_all);
assert!(!selection(&["-a", "a.txt"]).staged_all);
assert!(!selection(&["-a", "-i"]).staged_all);
assert!(!selection(&["-a", "-o"]).staged_all);
assert!(selection(&["a.txt"]).selects_paths);
assert!(selection(&["--pathspec-from-file=list"]).selects_paths);
assert!(!selection(&["-m", "x"]).selects_paths);
}
#[test]
fn the_candidate_request_names_paths_literally() {
let request: CandidateRequest = staged_at_base(None, &[String::from("a[1].txt"), String::from("dir/b.txt")]);
assert_eq!(
request,
CandidateRequest::StagedAtBase {
base: None,
pathspecs: vec![
OsString::from(":(top,literal)a[1].txt"),
OsString::from(":(top,literal)dir/b.txt"),
],
}
);
}
#[test]
fn the_transaction_directory_is_the_registry_entry() {
assert_eq!(transaction_directory(Path::new("/r"), "abc"), PathBuf::from("/r/abc"));
}
#[test]
fn a_journal_record_is_written_exclusively() {
let root: PathBuf = fixture("transaction-journal");
write_journal_record(root.as_path(), "record.json", "{}\n").expect("first write");
assert_eq!(std::fs::read_to_string(root.join("record.json")).expect("record"), "{}\n");
assert!(matches!(
write_journal_record(root.as_path(), "record.json", "{}\n"),
Err(TransactionStop::Failed { code: EngineFailureCode::TransactionFailed, .. })
));
assert!(write_journal_record(root.join("missing").as_path(), "record.json", "{}\n").is_err());
remove(root.as_path());
}
#[test]
fn failures_map_to_their_endings() {
assert!(matches!(
TransactionStop::from(GitFailure(String::from("boom"))),
TransactionStop::Message(text) if text == "boom"
));
assert!(matches!(
TransactionStop::from(LandingError::Git(GitFailure(String::from("git"))),),
TransactionStop::Message(text) if text == "git"
));
assert!(matches!(
TransactionStop::from(LandingError::Lock(CoordinationFailure::UnprovenOwner(String::from("who")))),
TransactionStop::Failed { code: EngineFailureCode::IndexLockUnprovenOwner, message } if message == "who"
));
assert!(matches!(
TransactionStop::from(LandingError::Journal(String::from("journal"))),
TransactionStop::Failed { code: EngineFailureCode::TransactionFailed, message } if message == "journal"
));
assert!(matches!(
TransactionStop::from(CaptureOrderError::Git(GitFailure(String::from("capture")))),
TransactionStop::Message(text) if text == "capture"
));
assert!(matches!(
TransactionStop::from(CaptureOrderError::Write(String::from("write"))),
TransactionStop::Failed { code: EngineFailureCode::TransactionFailed, message } if message == "write"
));
assert!(matches!(
failed(String::from("x")),
TransactionStop::Failed { code: EngineFailureCode::TransactionFailed, .. }
));
}
#[test]
fn the_base_object_follows_the_capture() {
use crate::capture_invocation::InvocationLayout;
use crate::transaction_journal::{RefFormat, SymbolicHead};
let capture = |base: Base| {
return InvocationCapture {
base,
layout: InvocationLayout {
symbolic_head: SymbolicHead::Branch(String::from("refs/heads/main")),
target_ref: String::from("refs/heads/main"),
conclusion: Conclusion::None,
repository_root: PathBuf::from("/r"),
git_dir: PathBuf::from("/r/.git"),
common_dir: PathBuf::from("/r/.git"),
real_index_path: PathBuf::from("/r/.git/index"),
object_directory: PathBuf::from("/r/.git/objects"),
registry_root: PathBuf::from("/r/.git/cli-git-transactions"),
ref_format: RefFormat::Files,
object_format: String::from("sha1"),
empty_tree_oid: "4".repeat(40),
invoked_at: String::from("2026-10-11T00:00:00.000Z"),
},
};
};
assert_eq!(base_object(&capture(Base::Unborn)).expect("unborn"), None);
let oid: String = "a".repeat(40);
assert_eq!(
base_object(&capture(Base::Commit(oid.clone()))).expect("commit").map(|found| { return String::from(found.as_str()); }),
Some(oid)
);
assert!(base_object(&capture(Base::Commit(String::from("nope")))).is_err());
}
#[test]
fn only_a_settled_convergence_counts_passes() {
assert_eq!(settled_passes(&Convergence::Settled { changed_passes: 3 }), 3);
assert_eq!(settled_passes(&Convergence::Settled { changed_passes: 0 }), 0);
assert_eq!(settled_passes(&Convergence::Blocked), 0);
assert_eq!(settled_passes(&Convergence::FixCycle), 0);
assert_eq!(settled_passes(&Convergence::FixPassLimit), 0);
}
#[test]
fn a_capture_lists_worktree_changes_for_all_or_include() {
assert!(stages_worktree(true, false));
assert!(stages_worktree(false, true));
assert!(stages_worktree(true, true));
assert!(!stages_worktree(false, false));
}