use super::*;
fn repository(at: &Path) {
std::fs::create_dir_all(at).expect("the directory is created");
run_git(at, &["init", "--quiet"]);
run_git(at, &["config", "user.email", "test@example.invalid"]);
run_git(at, &["config", "user.name", "Test"]);
run_git(at, &["config", "core.autocrlf", "false"]);
std::fs::write(at.join("tracked.txt"), "committed\n").expect("the file is written");
run_git(at, &["add", "tracked.txt"]);
run_git(at, &["commit", "--quiet", "-m", "first"]);
}
fn run_git(at: &Path, args: &[&str]) {
let status = crate::git_backend::git_command()
.args(args)
.current_dir(at)
.status()
.expect("git runs");
assert!(status.success(), "git {args:?} failed in {}", at.display());
}
fn options() -> Options {
Options {
untracked: false,
assume_yes: true,
dry_run: false,
}
}
#[test]
fn test9890_a_clean_worktree_is_not_dirty() {
let dir = tempfile::tempdir().expect("a scratch directory");
let root = crate::platform::canonicalize(&dir.path()).expect("resolves");
repository(&root);
let dirty = find_dirty(&root).expect("the walk succeeds");
assert!(
dirty.is_empty(),
"a repository with nothing changed has nothing to discard"
);
}
#[test]
fn test9891_every_kind_of_tracked_change_is_found() {
let dir = tempfile::tempdir().expect("a scratch directory");
let root = crate::platform::canonicalize(&dir.path()).expect("resolves");
repository(&root);
std::fs::write(root.join("gone.txt"), "doomed\n").expect("written");
run_git(&root, &["add", "gone.txt"]);
run_git(&root, &["commit", "--quiet", "-m", "second"]);
std::fs::remove_file(root.join("gone.txt")).expect("removed");
std::fs::write(root.join("tracked.txt"), "edited\n").expect("written");
std::fs::write(root.join("staged.txt"), "new\n").expect("written");
run_git(&root, &["add", "staged.txt"]);
let dirty = find_dirty(&root).expect("the walk succeeds");
assert_eq!(dirty.len(), 1, "one worktree is dirty");
let mut found = dirty[0].tracked.clone();
found.sort();
assert_eq!(
found,
vec!["gone.txt", "staged.txt", "tracked.txt"],
"an edit, a staged addition and a deletion are all local changes"
);
}
#[test]
fn test9892_untracked_files_are_kept_unless_asked_for() {
let dir = tempfile::tempdir().expect("a scratch directory");
let root = crate::platform::canonicalize(&dir.path()).expect("resolves");
repository(&root);
std::fs::write(root.join("tracked.txt"), "edited\n").expect("written");
std::fs::write(root.join("scratch.txt"), "never committed\n").expect("written");
let dirty = find_dirty(&root).expect("the walk succeeds");
assert_eq!(dirty[0].untracked, vec!["scratch.txt"]);
discard(&dirty, &options()).expect("the discard succeeds");
assert_eq!(
std::fs::read_to_string(root.join("tracked.txt")).expect("readable"),
"committed\n",
"the tracked edit went back to what HEAD holds"
);
assert!(
root.join("scratch.txt").exists(),
"an untracked file must survive a discard that was not told to delete it"
);
}
#[test]
fn test9893_untracked_files_go_when_asked_for() {
let dir = tempfile::tempdir().expect("a scratch directory");
let root = crate::platform::canonicalize(&dir.path()).expect("resolves");
repository(&root);
std::fs::write(root.join("scratch.txt"), "never committed\n").expect("written");
std::fs::create_dir(root.join("scratchdir")).expect("created");
std::fs::write(root.join("scratchdir/inside.txt"), "also new\n").expect("written");
let dirty = find_dirty(&root).expect("the walk succeeds");
discard(
&dirty,
&Options {
untracked: true,
..options()
},
)
.expect("the discard succeeds");
assert!(!root.join("scratch.txt").exists(), "the untracked file went");
assert!(
!root.join("scratchdir").exists(),
"and the directory that held only untracked files went with it"
);
}
#[test]
fn test9894_ignored_files_are_left_alone() {
let dir = tempfile::tempdir().expect("a scratch directory");
let root = crate::platform::canonicalize(&dir.path()).expect("resolves");
repository(&root);
std::fs::write(root.join(".gitignore"), "/.wsb/\n/target/\n").expect("written");
run_git(&root, &["add", ".gitignore"]);
run_git(&root, &["commit", "--quiet", "-m", "ignore"]);
std::fs::create_dir(root.join(".wsb")).expect("created");
std::fs::write(root.join(".wsb/secrets.wsbs"), "not really\n").expect("written");
std::fs::write(root.join("tracked.txt"), "edited\n").expect("written");
let dirty = find_dirty(&root).expect("the walk succeeds");
assert!(
!dirty[0]
.untracked
.iter()
.any(|path| path.contains(".wsb")),
"an ignored path is not a local change: {:?}",
dirty[0].untracked
);
discard(
&dirty,
&Options {
untracked: true,
..options()
},
)
.expect("the discard succeeds");
assert!(
root.join(".wsb/secrets.wsbs").exists(),
"the secret store must survive `wsb discard --untracked`"
);
}
#[test]
fn test9895_dirty_submodules_are_found_too() {
let dir = tempfile::tempdir().expect("a scratch directory");
let root = crate::platform::canonicalize(&dir.path()).expect("resolves");
let inner = root.join("child");
repository(&root);
repository(&inner);
run_git(
&root,
&[
"-c",
"protocol.file.allow=always",
"submodule",
"add",
"--quiet",
"./child",
"child",
],
);
run_git(&root, &["commit", "--quiet", "-m", "add submodule"]);
std::fs::write(inner.join("tracked.txt"), "edited in the submodule\n").expect("written");
let dirty = find_dirty(&root).expect("the walk succeeds");
let child = dirty
.iter()
.find(|worktree| worktree.label == "child")
.expect("the submodule's own changes were not found");
assert_eq!(child.tracked, vec!["tracked.txt"]);
discard(&dirty, &options()).expect("the discard succeeds");
assert_eq!(
std::fs::read_to_string(inner.join("tracked.txt")).expect("readable"),
"committed\n",
"the submodule's worktree was restored too"
);
}
#[test]
fn test9896_a_moved_submodule_is_not_reported_as_a_discarded_file() {
let dir = tempfile::tempdir().expect("a scratch directory");
let root = crate::platform::canonicalize(&dir.path()).expect("resolves");
let inner = root.join("child");
repository(&root);
repository(&inner);
run_git(
&root,
&[
"-c",
"protocol.file.allow=always",
"submodule",
"add",
"--quiet",
"./child",
"child",
],
);
run_git(&root, &["commit", "--quiet", "-m", "add submodule"]);
std::fs::write(inner.join("tracked.txt"), "moved on\n").expect("written");
run_git(&inner, &["commit", "--quiet", "-am", "second"]);
let dirty = find_dirty(&root).expect("the walk succeeds");
let parent = dirty
.iter()
.find(|worktree| worktree.label == ".")
.expect("the parent has a moved submodule to report");
assert_eq!(
parent.moved_submodules,
vec!["child"],
"a moved submodule is its own kind of change"
);
assert!(
parent.tracked.is_empty(),
"and it must not be listed among the files a reset would restore: {:?}",
parent.tracked
);
}