aboutsummaryrefslogtreecommitdiff
path: root/helix-vcs/src/git
diff options
context:
space:
mode:
authorPascal Kuthe2022-12-01 08:35:23 +0000
committerGitHub2022-12-01 08:35:23 +0000
commit5a3ff742218aac32c3af08993f0edb623631fc72 (patch)
tree55c09d58aef9284daf63224e1d3afaac6da26ee8 /helix-vcs/src/git
parent67415e096ea70173d30550803559eb2347ed04d6 (diff)
Show (git) diff signs in gutter (#3890)
* Show (git) diff signs in gutter (#3890) Avoid string allocation when git diffing Incrementally diff using changesets refactor diffs to be provider indepndent and improve git implementation remove dependency on zlib-ng switch to asynchronus diffing with similar Update helix-vcs/Cargo.toml fix toml formatting Co-authored-by: Ivan Tham <pickfire@riseup.net> fix typo in documentation use ropey reexpors from helix-core fix crash when creating new file remove useless use if io::Cursor fix spelling mistakes implement suggested improvement to repository loading improve git test isolation remove lefover comments Co-authored-by: univerz <univerz@fu-solution.com> fixed spelling mistake minor cosmetic changes fix: set self.differ to None if decoding the diff_base fails fixup formatting Co-authored-by: Ivan Tham <pickfire@riseup.net> reload diff_base when file is reloaded from disk switch to imara-diff Fixup formatting Co-authored-by: Blaž Hrastnik <blaz@mxxn.io> Redraw buffer whenever a diff is updated. Only store hunks instead of changes for individual lines to easily allow jumping between them Update to latest gitoxide version Change default diff gutter position Only update gutter after timeout * update diff gutter synchronously, with a timeout * Apply suggestions from code review Co-authored-by: Blaž Hrastnik <blaz@mxxn.io> Co-authored-by: Michael Davis <mcarsondavis@gmail.com> * address review comments and ensure lock is always aquired * remove configuration for redraw timeout Co-authored-by: Blaž Hrastnik <blaz@mxxn.io> Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
Diffstat (limited to 'helix-vcs/src/git')
-rw-r--r--helix-vcs/src/git/test.rs121
1 files changed, 121 insertions, 0 deletions
diff --git a/helix-vcs/src/git/test.rs b/helix-vcs/src/git/test.rs
new file mode 100644
index 00000000..d6e9af08
--- /dev/null
+++ b/helix-vcs/src/git/test.rs
@@ -0,0 +1,121 @@
+use std::{fs::File, io::Write, path::Path, process::Command};
+
+use tempfile::TempDir;
+
+use crate::{DiffProvider, Git};
+
+fn exec_git_cmd(args: &str, git_dir: &Path) {
+ let res = Command::new("git")
+ .arg("-C")
+ .arg(git_dir) // execute the git command in this directory
+ .args(args.split_whitespace())
+ .env_remove("GIT_DIR")
+ .env_remove("GIT_ASKPASS")
+ .env_remove("SSH_ASKPASS")
+ .env("GIT_TERMINAL_PROMPT", "false")
+ .env("GIT_AUTHOR_DATE", "2000-01-01 00:00:00 +0000")
+ .env("GIT_AUTHOR_EMAIL", "author@example.com")
+ .env("GIT_AUTHOR_NAME", "author")
+ .env("GIT_COMMITTER_DATE", "2000-01-02 00:00:00 +0000")
+ .env("GIT_COMMITTER_EMAIL", "committer@example.com")
+ .env("GIT_COMMITTER_NAME", "committer")
+ .env("GIT_CONFIG_COUNT", "2")
+ .env("GIT_CONFIG_KEY_0", "commit.gpgsign")
+ .env("GIT_CONFIG_VALUE_0", "false")
+ .env("GIT_CONFIG_KEY_1", "init.defaultBranch")
+ .env("GIT_CONFIG_VALUE_1", "main")
+ .output()
+ .unwrap_or_else(|_| panic!("`git {args}` failed"));
+ if !res.status.success() {
+ println!("{}", String::from_utf8_lossy(&res.stdout));
+ eprintln!("{}", String::from_utf8_lossy(&res.stderr));
+ panic!("`git {args}` failed (see output above)")
+ }
+}
+
+fn create_commit(repo: &Path, add_modified: bool) {
+ if add_modified {
+ exec_git_cmd("add -A", repo);
+ }
+ exec_git_cmd("commit -m message", repo);
+}
+
+fn empty_git_repo() -> TempDir {
+ let tmp = tempfile::tempdir().expect("create temp dir for git testing");
+ exec_git_cmd("init", tmp.path());
+ exec_git_cmd("config user.email test@helix.org", tmp.path());
+ exec_git_cmd("config user.name helix-test", tmp.path());
+ tmp
+}
+
+#[test]
+fn missing_file() {
+ let temp_git = empty_git_repo();
+ let file = temp_git.path().join("file.txt");
+ File::create(&file).unwrap().write_all(b"foo").unwrap();
+
+ assert_eq!(Git.get_diff_base(&file), None);
+}
+
+#[test]
+fn unmodified_file() {
+ let temp_git = empty_git_repo();
+ let file = temp_git.path().join("file.txt");
+ let contents = b"foo".as_slice();
+ File::create(&file).unwrap().write_all(contents).unwrap();
+ create_commit(temp_git.path(), true);
+ assert_eq!(Git.get_diff_base(&file), Some(Vec::from(contents)));
+}
+
+#[test]
+fn modified_file() {
+ let temp_git = empty_git_repo();
+ let file = temp_git.path().join("file.txt");
+ let contents = b"foo".as_slice();
+ File::create(&file).unwrap().write_all(contents).unwrap();
+ create_commit(temp_git.path(), true);
+ File::create(&file).unwrap().write_all(b"bar").unwrap();
+
+ assert_eq!(Git.get_diff_base(&file), Some(Vec::from(contents)));
+}
+
+/// Test that `get_file_head` does not return content for a directory.
+/// This is important to correctly cover cases where a directory is removed and replaced by a file.
+/// If the contents of the directory object were returned a diff between a path and the directory children would be produced.
+#[test]
+fn directory() {
+ let temp_git = empty_git_repo();
+ let dir = temp_git.path().join("file.txt");
+ std::fs::create_dir(&dir).expect("");
+ let file = dir.join("file.txt");
+ let contents = b"foo".as_slice();
+ File::create(&file).unwrap().write_all(contents).unwrap();
+
+ create_commit(temp_git.path(), true);
+
+ std::fs::remove_dir_all(&dir).unwrap();
+ File::create(&dir).unwrap().write_all(b"bar").unwrap();
+ assert_eq!(Git.get_diff_base(&dir), None);
+}
+
+/// Test that `get_file_head` does not return content for a symlink.
+/// This is important to correctly cover cases where a symlink is removed and replaced by a file.
+/// If the contents of the symlink object were returned a diff between a path and the actual file would be produced (bad ui).
+#[cfg(any(unix, windows))]
+#[test]
+fn symlink() {
+ #[cfg(unix)]
+ use std::os::unix::fs::symlink;
+ #[cfg(not(unix))]
+ use std::os::windows::fs::symlink_file as symlink;
+ let temp_git = empty_git_repo();
+ let file = temp_git.path().join("file.txt");
+ let contents = b"foo".as_slice();
+ File::create(&file).unwrap().write_all(contents).unwrap();
+ let file_link = temp_git.path().join("file_link.txt");
+ symlink("file.txt", &file_link).unwrap();
+
+ create_commit(temp_git.path(), true);
+ assert_eq!(Git.get_diff_base(&file_link), None);
+ assert_eq!(Git.get_diff_base(&file), Some(Vec::from(contents)));
+}