#![allow(
clippy::unwrap_used,
clippy::expect_used,
clippy::uninlined_format_args
)]
use pathfinder_common::git::{GitRunner, SystemGit};
use std::process::Command;
use tempfile::TempDir;
fn git_repo_with_initial_commit() -> TempDir {
let dir = tempfile::tempdir().expect("failed to create tempdir");
let root = dir.path();
Command::new("git")
.args(["init", "--initial-branch=main"])
.current_dir(root)
.output()
.expect("git init failed");
Command::new("git")
.args(["config", "user.email", "test@test.com"])
.current_dir(root)
.output()
.expect("git config user.email failed");
Command::new("git")
.args(["config", "user.name", "Test User"])
.current_dir(root)
.output()
.expect("git config user.name failed");
std::fs::write(root.join("initial.rs"), "// initial file").expect("write failed");
Command::new("git")
.args(["add", "."])
.current_dir(root)
.output()
.expect("git add failed");
Command::new("git")
.args(["commit", "-m", "initial commit"])
.current_dir(root)
.output()
.expect("git commit failed");
dir
}
#[tokio::test]
async fn test_system_git_diff_detects_changed_and_new_files() {
let repo = git_repo_with_initial_commit();
let root = repo.path();
std::fs::write(root.join("initial.rs"), "// modified").expect("write failed");
std::fs::write(root.join("added.rs"), "// new file").expect("write failed");
Command::new("git")
.args(["add", "."])
.current_dir(root)
.output()
.expect("git add failed");
Command::new("git")
.args(["commit", "-m", "second commit"])
.current_dir(root)
.output()
.expect("git commit failed");
let git = SystemGit;
let raw = git
.diff_name_only(root, "HEAD~1")
.await
.expect("diff_name_only failed");
let output = std::str::from_utf8(&raw).expect("non-UTF8 git output");
let files: Vec<&str> = output.lines().collect();
assert!(
files.contains(&"initial.rs"),
"modified file must appear in diff, files: {:?}",
files
);
assert!(
files.contains(&"added.rs"),
"new file must appear in diff, files: {:?}",
files
);
}
#[tokio::test]
async fn test_system_git_diff_empty_when_no_changes() {
let repo = git_repo_with_initial_commit();
let root = repo.path();
Command::new("git")
.args(["commit", "--allow-empty", "-m", "empty commit"])
.current_dir(root)
.output()
.expect("git commit failed");
let git = SystemGit;
let raw = git
.diff_name_only(root, "HEAD~1")
.await
.expect("diff_name_only failed");
let output = std::str::from_utf8(&raw).expect("non-UTF8 git output");
assert!(
output.trim().is_empty(),
"empty commit should produce no diff output, got: {output:?}"
);
}
#[tokio::test]
async fn test_system_git_diff_detects_deleted_files() {
let repo = git_repo_with_initial_commit();
let root = repo.path();
std::fs::remove_file(root.join("initial.rs")).expect("remove failed");
Command::new("git")
.args(["add", "."])
.current_dir(root)
.output()
.expect("git add failed");
Command::new("git")
.args(["commit", "-m", "delete file"])
.current_dir(root)
.output()
.expect("git commit failed");
let git = SystemGit;
let raw = git
.diff_name_only(root, "HEAD~1")
.await
.expect("diff_name_only failed");
let output = std::str::from_utf8(&raw).expect("non-UTF8 git output");
let files: Vec<&str> = output.lines().collect();
assert!(
files.contains(&"initial.rs"),
"deleted file must appear in diff, files: {:?}",
files
);
}
#[tokio::test]
async fn test_system_git_diff_fails_outside_repo() {
let not_a_repo = tempfile::tempdir().expect("failed to create tempdir");
let git = SystemGit;
let result = git.diff_name_only(not_a_repo.path(), "HEAD~1").await;
assert!(
result.is_err(),
"diff_name_only must fail outside a git repository"
);
}