use crate::RepositoryLayout;
use crate::fsutil::{TestFailPoint, fail_once_for_test};
use crate::test_support::unique_temp_dir;
use crate::worktree_marker::{clear_worktree_dirty, mark_worktree_dirty, worktree_is_dirty};
#[test]
fn marker_is_created_clean_at_init_and_round_trips_dirty_and_clean() {
let root = unique_temp_dir("worktree-marker-round-trip");
let layout = RepositoryLayout::init(root.clone());
assert!(layout.is_ok());
if let Ok(layout) = layout {
assert!(layout.worktree_unclean_shutdown_marker_path().exists());
assert!(worktree_is_dirty(&layout).is_ok_and(|dirty| !dirty));
assert!(mark_worktree_dirty(&layout).is_ok());
assert!(worktree_is_dirty(&layout).is_ok_and(|dirty| dirty));
assert!(clear_worktree_dirty(&layout).is_ok());
assert!(worktree_is_dirty(&layout).is_ok_and(|dirty| !dirty));
}
let _ = std::fs::remove_dir_all(root);
}
#[test]
fn marker_dirty_set_appends_rather_than_replaces() {
let root = unique_temp_dir("worktree-marker-append-not-replace");
let layout = RepositoryLayout::init(root.clone());
assert!(layout.is_ok());
if let Ok(layout) = layout {
assert!(mark_worktree_dirty(&layout).is_ok());
let after_first = std::fs::read(layout.worktree_unclean_shutdown_marker_path());
assert!(after_first.is_ok());
assert!(mark_worktree_dirty(&layout).is_ok());
let after_second = std::fs::read(layout.worktree_unclean_shutdown_marker_path());
if let (Ok(first), Ok(second)) = (after_first, after_second) {
assert!(!first.is_empty());
assert_eq!(second.len(), first.len() * 2);
assert!(second.starts_with(&first));
}
assert!(worktree_is_dirty(&layout).is_ok_and(|dirty| dirty));
}
let _ = std::fs::remove_dir_all(root);
}
#[test]
fn crash_during_clear_leaves_the_marker_dirty_not_clean() {
let root = unique_temp_dir("worktree-marker-crash-during-clear");
let layout = RepositoryLayout::init(root.clone());
assert!(layout.is_ok());
if let Ok(layout) = layout {
assert!(mark_worktree_dirty(&layout).is_ok());
assert!(worktree_is_dirty(&layout).is_ok_and(|dirty| dirty));
fail_once_for_test(TestFailPoint::Truncate);
assert!(clear_worktree_dirty(&layout).is_err());
assert!(
worktree_is_dirty(&layout).is_ok_and(|dirty| dirty),
"a failed clear must leave the marker dirty, not clean"
);
assert!(clear_worktree_dirty(&layout).is_ok());
assert!(worktree_is_dirty(&layout).is_ok_and(|dirty| !dirty));
}
let _ = std::fs::remove_dir_all(root);
}
#[test]
fn missing_marker_file_reads_as_clean() {
let root = unique_temp_dir("worktree-marker-missing-reads-clean");
let layout = RepositoryLayout::init(root.clone());
assert!(layout.is_ok());
if let Ok(layout) = layout {
assert!(std::fs::remove_file(layout.worktree_unclean_shutdown_marker_path()).is_ok());
assert!(worktree_is_dirty(&layout).is_ok_and(|dirty| !dirty));
}
let _ = std::fs::remove_dir_all(root);
}