use super::*;
#[test]
fn test_status_clean_repo() {
let dir = TempDir::new().unwrap();
init_git_repo_with_committed_file(dir.path(), "a.txt", "hello\n");
Command::cargo_bin("patchloom")
.unwrap()
.arg("--cwd")
.arg(dir.path().to_str().unwrap())
.arg("status")
.assert()
.code(0); }
#[test]
fn test_status_outside_git_repo_shows_actionable_hint() {
let dir = TempDir::new().unwrap();
Command::cargo_bin("patchloom")
.unwrap()
.arg("--cwd")
.arg(dir.path().to_str().unwrap())
.arg("status")
.assert()
.failure()
.stderr(predicate::str::contains("git status failed:"))
.stderr(predicate::str::contains(
"hint: run `git init` first, or run patchloom status from inside an existing git repository",
));
}
#[test]
fn test_status_modified_file() {
let dir = TempDir::new().unwrap();
init_git_repo_with_committed_file(dir.path(), "a.txt", "hello\n");
fs::write(dir.path().join("a.txt"), "changed\n").unwrap();
Command::cargo_bin("patchloom")
.unwrap()
.arg("--cwd")
.arg(dir.path().to_str().unwrap())
.arg("status")
.assert()
.code(2); }
#[test]
fn test_status_jsonl_output() {
let dir = TempDir::new().unwrap();
init_git_repo_with_committed_file(dir.path(), "a.txt", "hello\n");
fs::write(dir.path().join("new.txt"), "new\n").unwrap();
let output = Command::cargo_bin("patchloom")
.unwrap()
.arg("--jsonl")
.arg("--cwd")
.arg(dir.path().to_str().unwrap())
.arg("status")
.output()
.unwrap();
assert_eq!(output.status.code(), Some(2));
let json: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap();
assert_eq!(json["ok"], true);
assert_eq!(json["total_changes"], 1);
assert!(
json["created"]
.as_array()
.unwrap()
.iter()
.any(|v| v == "new.txt")
);
}
#[test]
fn test_status_json_output() {
let dir = TempDir::new().unwrap();
init_git_repo_with_committed_file(dir.path(), "a.txt", "hello\n");
fs::write(dir.path().join("new.txt"), "new\n").unwrap();
let output = Command::cargo_bin("patchloom")
.unwrap()
.arg("--json")
.arg("--cwd")
.arg(dir.path().to_str().unwrap())
.arg("status")
.output()
.unwrap();
let json: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap();
assert_eq!(json["ok"], true);
assert_eq!(json["total_changes"], 1);
assert!(
json["created"]
.as_array()
.unwrap()
.iter()
.any(|v| v.as_str().unwrap() == "new.txt")
);
}
#[test]
fn test_status_deleted_file() {
let dir = TempDir::new().unwrap();
init_git_repo_with_committed_file(dir.path(), "doomed.txt", "bye\n");
git_ok(dir.path(), &["rm", "doomed.txt"]);
let output = Command::cargo_bin("patchloom")
.unwrap()
.arg("--json")
.arg("--cwd")
.arg(dir.path().to_str().unwrap())
.arg("status")
.output()
.unwrap();
assert_eq!(output.status.code().unwrap(), 2); let json: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap();
assert!(
json["deleted"]
.as_array()
.unwrap()
.iter()
.any(|v| v.as_str().unwrap() == "doomed.txt")
);
}
#[test]
fn test_status_glob_matches_filename_with_spaces() {
let dir = TempDir::new().unwrap();
init_git_repo_with_committed_file(dir.path(), "a.txt", "hello\n");
fs::write(dir.path().join("file name.txt"), "new\n").unwrap();
let output = Command::cargo_bin("patchloom")
.unwrap()
.arg("--json")
.arg("--glob")
.arg("*.txt")
.arg("--cwd")
.arg(dir.path().to_str().unwrap())
.arg("status")
.output()
.unwrap();
assert_eq!(output.status.code(), Some(2));
let json: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap();
let created = json["created"].as_array().unwrap();
assert!(
created.iter().any(|v| v.as_str() == Some("file name.txt")),
"glob-filtered status should report the unquoted filename, got: {json}"
);
}
#[test]
fn test_status_glob_matches_nested_relative_pattern() {
let dir = TempDir::new().unwrap();
init_git_repo_with_committed_file(dir.path(), "a.txt", "hello\n");
fs::create_dir_all(dir.path().join("sub")).unwrap();
fs::write(dir.path().join("sub/keep.txt"), "new\n").unwrap();
fs::write(dir.path().join("other.txt"), "new\n").unwrap();
let output = Command::cargo_bin("patchloom")
.unwrap()
.arg("--json")
.arg("--glob")
.arg("sub/*.txt")
.arg("--cwd")
.arg(dir.path().to_str().unwrap())
.arg("status")
.output()
.unwrap();
assert_eq!(output.status.code(), Some(2));
let json: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap();
let created = json["created"].as_array().unwrap();
assert!(created.iter().any(|v| v.as_str() == Some("sub/keep.txt")));
assert!(!created.iter().any(|v| v.as_str() == Some("other.txt")));
}
#[test]
fn test_status_staged_new_file_shows_as_created() {
let dir = TempDir::new().unwrap();
init_git_repo_with_committed_file(dir.path(), "init.txt", "init\n");
fs::write(dir.path().join("new.txt"), "new content\n").unwrap();
git_ok(dir.path(), &["add", "new.txt"]);
let output = Command::cargo_bin("patchloom")
.unwrap()
.arg("--cwd")
.arg(dir.path().to_str().unwrap())
.arg("status")
.arg("--json")
.output()
.unwrap();
assert_eq!(output.status.code(), Some(2)); let json: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap();
let created = json["created"].as_array().unwrap();
assert!(
created.iter().any(|v| v.as_str() == Some("new.txt")),
"staged new file should appear in created list, got: {json}"
);
}
#[test]
fn test_status_quiet_suppresses_output() {
let dir = TempDir::new().unwrap();
init_git_repo_with_committed_file(dir.path(), "a.txt", "hello\n");
fs::write(dir.path().join("a.txt"), "changed\n").unwrap();
let output = Command::cargo_bin("patchloom")
.unwrap()
.arg("--quiet")
.arg("--cwd")
.arg(dir.path().to_str().unwrap())
.arg("status")
.output()
.unwrap();
assert_eq!(output.status.code(), Some(2)); assert!(
output.stdout.is_empty(),
"--quiet should suppress stdout, got: {}",
String::from_utf8_lossy(&output.stdout)
);
}
#[test]
fn test_status_excludes_patchloom_backup_dir_after_apply() {
let dir = TempDir::new().unwrap();
init_git_repo_with_committed_file(dir.path(), "a.txt", "hello\n");
Command::cargo_bin("patchloom")
.unwrap()
.arg("--cwd")
.arg(dir.path().to_str().unwrap())
.arg("replace")
.arg("hello")
.arg("--new")
.arg("world")
.arg("a.txt")
.arg("--apply")
.assert()
.code(0);
assert!(
dir.path().join(".patchloom/backups").is_dir(),
"apply should create backup sessions"
);
let output = Command::cargo_bin("patchloom")
.unwrap()
.arg("--json")
.arg("--cwd")
.arg(dir.path().to_str().unwrap())
.arg("status")
.output()
.unwrap();
assert_eq!(output.status.code(), Some(2));
let json: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap();
let all: Vec<&str> = ["modified", "created", "deleted"]
.iter()
.flat_map(|k| {
json[k]
.as_array()
.into_iter()
.flatten()
.filter_map(|v| v.as_str())
})
.collect();
assert!(
all.iter()
.any(|p| *p == "a.txt" || p.ends_with("/a.txt") || p.ends_with("a.txt")),
"modified a.txt should appear: {json}"
);
assert!(
!all.iter().any(|p| p.contains(".patchloom")),
"status must omit .patchloom backups, got: {all:?}"
);
assert_eq!(
json["total_changes"].as_u64(),
Some(1),
"only a.txt should count: {json}"
);
}