use std::path::Path;
use similar_asserts::assert_eq;
use xshell::{Shell, cmd};
use zenops::git::{Git, GitFileStatus};
use zenops_safe_relative_path::{SafeRelativePath, srpath};
use test_env::paths;
mod test_env;
fn status_in(dir: &Path) -> Vec<GitFileStatus> {
let sh = Shell::new().unwrap();
Git::new(dir, &sh).status().expect("git status succeeds")
}
#[test]
fn status_reports_modified_for_a_changed_tracked_file() {
let env = test_env::TestEnv::load();
env.init_config("");
env.append_zenops_file(srpath!("config.toml"), "\n# touched", None);
let zenops = env.resolve_path(paths::ZENOPS_DIR);
let entries = status_in(&zenops);
assert_eq!(
entries,
vec![GitFileStatus::Modified(
SafeRelativePath::from_relative_path("config.toml")
.unwrap()
.into()
)],
);
}
#[test]
fn status_reports_added_for_a_staged_only_new_file() {
let env = test_env::TestEnv::load();
env.init_config("");
env.write_zenops_file(srpath!("staged.txt"), "stuff\n", None);
let zenops = env.resolve_path(paths::ZENOPS_DIR);
let sh = Shell::new().unwrap();
let _dir = sh.push_dir(&zenops);
cmd!(sh, "git add staged.txt").run().unwrap();
let entries = status_in(&zenops);
assert_eq!(
entries,
vec![GitFileStatus::Added(
SafeRelativePath::from_relative_path("staged.txt")
.unwrap()
.into()
)],
);
}
#[test]
fn status_reports_deleted_for_a_removed_tracked_file() {
let env = test_env::TestEnv::load();
env.init_config("");
env.write_zenops_file(srpath!("doomed.txt"), "bye\n", Some("add doomed"));
env.delete_file(paths::ZENOPS_DIR.safe_join(srpath!("doomed.txt")));
let zenops = env.resolve_path(paths::ZENOPS_DIR);
let entries = status_in(&zenops);
assert_eq!(
entries,
vec![GitFileStatus::Deleted(
SafeRelativePath::from_relative_path("doomed.txt")
.unwrap()
.into()
)],
);
}
#[test]
fn status_reports_untracked_for_a_brand_new_file() {
let env = test_env::TestEnv::load();
env.init_config("");
env.write_file(
paths::ZENOPS_DIR.safe_join(srpath!("never_added.txt")),
"hi\n",
);
let zenops = env.resolve_path(paths::ZENOPS_DIR);
let entries = status_in(&zenops);
assert_eq!(
entries,
vec![GitFileStatus::Untracked(
SafeRelativePath::from_relative_path("never_added.txt")
.unwrap()
.into()
)],
);
}
#[test]
fn status_reports_modified_at_new_path_after_rename() {
let env = test_env::TestEnv::load();
env.init_config("");
env.write_zenops_file(srpath!("old.txt"), "data\n", Some("add old"));
let zenops = env.resolve_path(paths::ZENOPS_DIR);
let sh = Shell::new().unwrap();
let _dir = sh.push_dir(&zenops);
cmd!(sh, "git mv old.txt new.txt").run().unwrap();
let entries = status_in(&zenops);
assert_eq!(
entries,
vec![GitFileStatus::Modified(
SafeRelativePath::from_relative_path("new.txt")
.unwrap()
.into()
)],
);
}
#[test]
fn status_returns_empty_for_a_clean_repo() {
let env = test_env::TestEnv::load();
env.init_config("");
let zenops = env.resolve_path(paths::ZENOPS_DIR);
let entries = status_in(&zenops);
assert!(entries.is_empty(), "expected empty status, got {entries:?}");
}
#[test]
fn is_git_repo_true_inside_work_tree_false_outside() {
let env = test_env::TestEnv::load();
env.init_config("");
let sh = Shell::new().unwrap();
let zenops = env.resolve_path(paths::ZENOPS_DIR);
assert!(Git::new(&zenops, &sh).is_git_repo().unwrap());
let home = env.resolve_path(paths::HOME_DIR);
assert!(!Git::new(&home, &sh).is_git_repo().unwrap());
}
#[test]
fn has_uncommitted_changes_flips_with_a_modification() {
let env = test_env::TestEnv::load();
env.init_config("");
let sh = Shell::new().unwrap();
let zenops = env.resolve_path(paths::ZENOPS_DIR);
assert!(!Git::new(&zenops, &sh).has_uncommitted_changes().unwrap());
env.append_zenops_file(srpath!("config.toml"), "\n# touched", None);
assert!(Git::new(&zenops, &sh).has_uncommitted_changes().unwrap());
}