mirror of
https://github.com/sharkdp/bat
synced 2026-07-19 16:23:20 +00:00
Add more tests for git diff
This commit is contained in:
+108
-15
@@ -2,14 +2,12 @@
|
||||
|
||||
use gix::diff::blob::pipeline::{Mode, WorktreeRoots};
|
||||
use gix::diff::blob::{Algorithm, HunkIter, ResourceKind};
|
||||
use gix::index::hash::Kind;
|
||||
use gix::object::tree::EntryKind;
|
||||
use gix::{self, ObjectId};
|
||||
use path_abs::PathInfo;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum LineChange {
|
||||
Added,
|
||||
RemovedAbove,
|
||||
@@ -44,9 +42,13 @@ fn collect_changes_from_hunks(hunks: HunkIter) -> Option<LineChanges> {
|
||||
|
||||
pub fn get_git_diff(filename: &Path) -> Option<LineChanges> {
|
||||
let filepath_absolute = filename.canonicalize().ok()?;
|
||||
let repository = gix::discover(filepath_absolute.parent().ok()?).unwrap();
|
||||
let repository = gix::discover(filepath_absolute.parent().ok()?).ok()?;
|
||||
let repo_path_absolute = repository.workdir()?.canonicalize().ok()?;
|
||||
let filepath_relative_to_repo = filepath_absolute.strip_prefix(&repo_path_absolute).ok()?;
|
||||
let filepath_relative_to_repo = gix::path::to_unix_separators_on_windows(
|
||||
gix::path::into_bstr(filepath_absolute.strip_prefix(&repo_path_absolute).ok()?)
|
||||
);
|
||||
let index = repository.index_or_load_from_head_or_empty().ok()?;
|
||||
let index_entry = index.entry_by_path(filepath_relative_to_repo.as_ref())?;
|
||||
let mut cache = repository
|
||||
.diff_resource_cache(
|
||||
Mode::ToGit,
|
||||
@@ -58,23 +60,18 @@ pub fn get_git_diff(filename: &Path) -> Option<LineChanges> {
|
||||
.ok()?;
|
||||
cache
|
||||
.set_resource(
|
||||
repository
|
||||
.head_tree()
|
||||
.ok()?
|
||||
.lookup_entry_by_path(filepath_relative_to_repo.to_str()?)
|
||||
.ok()??
|
||||
.object_id(),
|
||||
EntryKind::Blob,
|
||||
filepath_relative_to_repo.to_str()?.into(),
|
||||
index_entry.id,
|
||||
index_entry.mode.to_tree_entry_mode()?.kind(),
|
||||
filepath_relative_to_repo.as_ref(),
|
||||
ResourceKind::OldOrSource,
|
||||
&repository,
|
||||
)
|
||||
.ok()?;
|
||||
cache
|
||||
.set_resource(
|
||||
ObjectId::null(Kind::Sha1),
|
||||
repository.object_hash().null(),
|
||||
EntryKind::Blob,
|
||||
filepath_relative_to_repo.to_str()?.into(),
|
||||
filepath_relative_to_repo.as_ref(),
|
||||
ResourceKind::NewOrDestination,
|
||||
&repository,
|
||||
)
|
||||
@@ -86,3 +83,99 @@ pub fn get_git_diff(filename: &Path) -> Option<LineChanges> {
|
||||
|
||||
collect_changes_from_hunks(diff.hunks())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{get_git_diff, LineChange};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
fn git(repo: &Path, args: &[&str]) {
|
||||
let output = Command::new("git")
|
||||
.args(args)
|
||||
.current_dir(repo)
|
||||
.output()
|
||||
.expect("git command can run");
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"git {args:?} failed\nstdout: {}\nstderr: {}",
|
||||
String::from_utf8_lossy(&output.stdout),
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
}
|
||||
|
||||
fn setup_repo() -> tempfile::TempDir {
|
||||
let dir = tempfile::tempdir().expect("can create temporary directory");
|
||||
let repo = dir.path();
|
||||
git(repo, &["init"]);
|
||||
git(repo, &["config", "user.email", "test@test.test"]);
|
||||
git(repo, &["config", "user.name", "Test"]);
|
||||
dir
|
||||
}
|
||||
|
||||
fn create_and_track_file(repo: &tempfile::TempDir, filename: &str) -> PathBuf {
|
||||
let filepath = repo.path().join(filename);
|
||||
std::fs::write(&filepath, "file\n").expect("can write file");
|
||||
git(repo.path(), &["add", &filename]);
|
||||
git(repo.path(), &["commit", "-m", "initial"]);
|
||||
|
||||
filepath.to_owned()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_a_git_repository() {
|
||||
let dir = tempfile::tempdir().expect("can create temporary directory");
|
||||
let file = dir.path().join("file.txt");
|
||||
std::fs::write(&file, "line 1\n").expect("can write file");
|
||||
|
||||
assert_eq!(get_git_diff(&file), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn diff_is_calculated_against_index() {
|
||||
let repo = setup_repo();
|
||||
let file = create_and_track_file(&repo, "file.txt");
|
||||
|
||||
std::fs::write(&file, "line 1\nline 2 modified\n").expect("can write file");
|
||||
// Add modified file to index -> should find 0 changes but not none
|
||||
git(repo.path(), &["add", "file.txt"]);
|
||||
|
||||
assert_eq!(get_git_diff(&file).expect("empty map").len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn diff_is_calculated_against_index_2() {
|
||||
let repo = setup_repo();
|
||||
let file = create_and_track_file(&repo, "file.txt");
|
||||
|
||||
std::fs::write(&file, "line 1\nline 2 modified\n").expect("can write file");
|
||||
git(repo.path(), &["add", "file.txt"]);
|
||||
// modify the second line again which should show a single change
|
||||
std::fs::write(&file, "line 1\nline 2 modified again\n").expect("can write file");
|
||||
|
||||
assert_eq!(get_git_diff(&file).expect("one change").len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn diff_is_calculated_correctly() {
|
||||
let repo = setup_repo();
|
||||
create_and_track_file(&repo, "committed.txt");
|
||||
let filename = "committed2.txt";
|
||||
let file = create_and_track_file(&repo, filename);
|
||||
|
||||
std::fs::write(&file, "file\nline 2 added\n").expect("can write file");
|
||||
let mut changes = get_git_diff(&file).expect("multiple changes");
|
||||
assert_eq!(changes.get(&2), Some(&LineChange::Added));
|
||||
git(repo.path(), &["add", filename]);
|
||||
|
||||
std::fs::write(&file, "file\nline 2 modified\n").expect("can write file");
|
||||
changes = get_git_diff(&file).expect("multiple changes");
|
||||
assert_eq!(changes.get(&2), Some(&LineChange::Modified));
|
||||
git(repo.path(), &["add", filename]);
|
||||
|
||||
std::fs::write(&file, "line 2 modified\nline 3 added").expect("can write file");
|
||||
changes = get_git_diff(&file).expect("multiple changes");
|
||||
assert_eq!(changes.get(&1), Some(&LineChange::RemovedAbove));
|
||||
assert_eq!(changes.get(&2), Some(&LineChange::Added));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user