Commit 4742148d by Russell Belfer

Add more diff rename detection tests

This adds a bunch more rename detection tests including checks
vs the working directory, the new exact match options, some more
whitespace variants, etc.

This also adds a git_futils_writebuffer helper function and uses
it in checkout.  This is mainly added because I wanted an easy
way to write out a git_buf to disk inside my test code.
parent 9be5be47
...@@ -676,33 +676,26 @@ static int buffer_to_file( ...@@ -676,33 +676,26 @@ static int buffer_to_file(
int file_open_flags, int file_open_flags,
mode_t file_mode) mode_t file_mode)
{ {
int fd, error; int error;
if ((error = git_futils_mkpath2file(path, dir_mode)) < 0) if ((error = git_futils_mkpath2file(path, dir_mode)) < 0)
return error; return error;
if ((fd = p_open(path, file_open_flags, file_mode)) < 0) { if ((error = git_futils_writebuffer(
giterr_set(GITERR_OS, "Could not open '%s' for writing", path); buffer, path, file_open_flags, file_mode)) < 0)
return fd; return error;
}
if ((error = p_write(fd, git_buf_cstr(buffer), git_buf_len(buffer))) < 0) {
giterr_set(GITERR_OS, "Could not write to '%s'", path);
(void)p_close(fd);
} else {
if ((error = p_close(fd)) < 0)
giterr_set(GITERR_OS, "Error while closing '%s'", path);
if ((error = p_stat(path, st)) < 0) if (st != NULL && (error = p_stat(path, st)) < 0) {
giterr_set(GITERR_OS, "Error while statting '%s'", path); giterr_set(GITERR_OS, "Error while statting '%s'", path);
return error;
} }
if (!error && if ((file_mode & 0100) != 0 && (error = p_chmod(path, file_mode)) < 0) {
(file_mode & 0100) != 0 &&
(error = p_chmod(path, file_mode)) < 0)
giterr_set(GITERR_OS, "Failed to set permissions on '%s'", path); giterr_set(GITERR_OS, "Failed to set permissions on '%s'", path);
return error;
}
return error; return 0;
} }
static int blob_content_to_file( static int blob_content_to_file(
......
...@@ -202,6 +202,32 @@ int git_futils_readbuffer(git_buf *buf, const char *path) ...@@ -202,6 +202,32 @@ int git_futils_readbuffer(git_buf *buf, const char *path)
return git_futils_readbuffer_updated(buf, path, NULL, NULL, NULL); return git_futils_readbuffer_updated(buf, path, NULL, NULL, NULL);
} }
int git_futils_writebuffer(
const git_buf *buf, const char *path, int flags, mode_t mode)
{
int fd, error = 0;
if (flags <= 0)
flags = O_CREAT | O_TRUNC | O_WRONLY;
if (!mode)
mode = GIT_FILEMODE_BLOB;
if ((fd = p_open(path, flags, mode)) < 0) {
giterr_set(GITERR_OS, "Could not open '%s' for writing", path);
return fd;
}
if ((error = p_write(fd, git_buf_cstr(buf), git_buf_len(buf))) < 0) {
giterr_set(GITERR_OS, "Could not write to '%s'", path);
(void)p_close(fd);
}
if ((error = p_close(fd)) < 0)
giterr_set(GITERR_OS, "Error while closing '%s'", path);
return error;
}
int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmode) int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmode)
{ {
if (git_futils_mkpath2file(to, dirmode) < 0) if (git_futils_mkpath2file(to, dirmode) < 0)
......
...@@ -22,6 +22,9 @@ extern int git_futils_readbuffer_updated( ...@@ -22,6 +22,9 @@ extern int git_futils_readbuffer_updated(
git_buf *obj, const char *path, time_t *mtime, size_t *size, int *updated); git_buf *obj, const char *path, time_t *mtime, size_t *size, int *updated);
extern int git_futils_readbuffer_fd(git_buf *obj, git_file fd, size_t len); extern int git_futils_readbuffer_fd(git_buf *obj, git_file fd, size_t len);
extern int git_futils_writebuffer(
const git_buf *buf, const char *path, int open_flags, mode_t mode);
/** /**
* File utils * File utils
* *
......
#include "clar_libgit2.h" #include "clar_libgit2.h"
#include "diff_helpers.h" #include "diff_helpers.h"
#include "buf_text.h"
static git_repository *g_repo = NULL; static git_repository *g_repo = NULL;
...@@ -388,9 +389,152 @@ void test_diff_rename__handles_small_files(void) ...@@ -388,9 +389,152 @@ void test_diff_rename__handles_small_files(void)
void test_diff_rename__working_directory_changes(void) void test_diff_rename__working_directory_changes(void)
{ {
/* let's rewrite some files in the working directory on demand */ const char *sha0 = "2bc7f351d20b53f1c72c16c4b036e491c478c49a";
const char *blobsha = "66311f5cfbe7836c27510a3ba2f43e282e2c8bba";
git_oid id;
git_tree *tree;
git_blob *blob;
git_diff_list *diff;
git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT;
git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT;
diff_expects exp;
git_buf old_content = GIT_BUF_INIT, content = GIT_BUF_INIT;;
tree = resolve_commit_oid_to_tree(g_repo, sha0);
diffopts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED | GIT_DIFF_INCLUDE_UNTRACKED;
/*
$ git cat-file -p 2bc7f351d20b53f1c72c16c4b036e491c478c49a^{tree}
100644 blob 66311f5cfbe7836c27510a3ba2f43e282e2c8bba sevencities.txt
100644 blob ad0a8e55a104ac54a8a29ed4b84b49e76837a113 sixserving.txt
100644 blob 66311f5cfbe7836c27510a3ba2f43e282e2c8bba songofseven.txt
$ for f in *.txt; do
echo `git hash-object -t blob $f` $f
done
eaf4a3e3bfe68585e90cada20736ace491cd100b ikeepsix.txt
f90d4fc20ecddf21eebe6a37e9225d244339d2b5 sixserving.txt
4210ffd5c390b21dd5483375e75288dea9ede512 songof7cities.txt
9a69d960ae94b060f56c2a8702545e2bb1abb935 untimely.txt
*/
cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &diffopts));
/* git diff --no-renames 2bc7f351d20b53f1c72c16c4b036e491c478c49a */
memset(&exp, 0, sizeof(exp));
cl_git_pass(git_diff_foreach(
diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
cl_assert_equal_i(6, exp.files);
cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
cl_assert_equal_i(3, exp.file_status[GIT_DELTA_UNTRACKED]);
cl_assert_equal_i(2, exp.file_status[GIT_DELTA_DELETED]);
/* git diff -M 2bc7f351d20b53f1c72c16c4b036e491c478c49a */
opts.flags = GIT_DIFF_FIND_ALL;
cl_git_pass(git_diff_find_similar(diff, &opts));
memset(&exp, 0, sizeof(exp));
cl_git_pass(git_diff_foreach(
diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
cl_assert_equal_i(5, exp.files);
cl_assert_equal_i(3, exp.file_status[GIT_DELTA_RENAMED]);
cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNTRACKED]);
git_diff_list_free(diff);
/* rewrite files in the working directory with / without CRLF changes */
cl_git_pass(
git_futils_readbuffer(&old_content, "renames/songof7cities.txt"));
cl_git_pass(
git_buf_text_lf_to_crlf(&content, &old_content));
cl_git_pass(
git_futils_writebuffer(&content, "renames/songof7cities.txt", 0, 0));
cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &diffopts));
/* git diff -M 2bc7f351d20b53f1c72c16c4b036e491c478c49a */
opts.flags = GIT_DIFF_FIND_ALL;
cl_git_pass(git_diff_find_similar(diff, &opts));
memset(&exp, 0, sizeof(exp));
cl_git_pass(git_diff_foreach(
diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
cl_assert_equal_i(5, exp.files);
cl_assert_equal_i(3, exp.file_status[GIT_DELTA_RENAMED]);
cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNTRACKED]);
git_diff_list_free(diff);
/* and with / without CRLF changes */ /* try a different whitespace option */
cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &diffopts));
opts.flags = GIT_DIFF_FIND_ALL | GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE;
cl_git_pass(git_diff_find_similar(diff, &opts));
memset(&exp, 0, sizeof(exp));
cl_git_pass(git_diff_foreach(
diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
cl_assert_equal_i(6, exp.files);
cl_assert_equal_i(1, exp.file_status[GIT_DELTA_RENAMED]);
cl_assert_equal_i(2, exp.file_status[GIT_DELTA_DELETED]);
cl_assert_equal_i(3, exp.file_status[GIT_DELTA_UNTRACKED]);
git_diff_list_free(diff);
/* try a different matching option */
cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &diffopts));
opts.flags = GIT_DIFF_FIND_ALL | GIT_DIFF_FIND_EXACT_MATCH_ONLY;
cl_git_pass(git_diff_find_similar(diff, &opts));
memset(&exp, 0, sizeof(exp));
cl_git_pass(git_diff_foreach(
diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
cl_assert_equal_i(6, exp.files);
cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
cl_assert_equal_i(3, exp.file_status[GIT_DELTA_UNTRACKED]);
cl_assert_equal_i(2, exp.file_status[GIT_DELTA_DELETED]);
git_diff_list_free(diff);
/* again with exact match blob */
cl_git_pass(git_oid_fromstr(&id, blobsha));
cl_git_pass(git_blob_lookup(&blob, g_repo, &id));
cl_git_pass(git_buf_set(
&content, git_blob_rawcontent(blob), git_blob_rawsize(blob)));
cl_git_rewritefile("renames/songof7cities.txt", content.ptr);
git_blob_free(blob);
cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &diffopts));
opts.flags = GIT_DIFF_FIND_ALL | GIT_DIFF_FIND_EXACT_MATCH_ONLY;
cl_git_pass(git_diff_find_similar(diff, &opts));
memset(&exp, 0, sizeof(exp));
cl_git_pass(git_diff_foreach(
diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
cl_assert_equal_i(5, exp.files);
cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
cl_assert_equal_i(2, exp.file_status[GIT_DELTA_RENAMED]);
cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNTRACKED]);
git_diff_list_free(diff);
git_tree_free(tree);
git_buf_free(&content);
git_buf_free(&old_content);
} }
void test_diff_rename__patch(void) void test_diff_rename__patch(void)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment