mirror of
https://git.proxmox.com/git/libgit2
synced 2025-06-19 01:30:51 +00:00
Add patch from blobs API
This adds two new public APIs: git_diff_patch_from_blobs and git_diff_patch_from_blob_and_buffer, plus it refactors the code for git_diff_blobs and git_diff_blob_to_buffer so that they code is almost entirely shared between these APIs, and adds tests for the new APIs.
This commit is contained in:
parent
54faddd299
commit
f9c824c592
@ -860,7 +860,7 @@ GIT_EXTERN(size_t) git_diff_patch_num_hunks(
|
||||
* @param total_additions Count of addition lines in output, can be NULL.
|
||||
* @param total_deletions Count of deletion lines in output, can be NULL.
|
||||
* @param patch The git_diff_patch object
|
||||
* @return Number of lines in hunk or -1 if invalid hunk index
|
||||
* @return 0 on success, <0 on error
|
||||
*/
|
||||
GIT_EXTERN(int) git_diff_patch_line_stats(
|
||||
size_t *total_context,
|
||||
@ -1000,6 +1000,26 @@ GIT_EXTERN(int) git_diff_blobs(
|
||||
git_diff_data_cb line_cb,
|
||||
void *payload);
|
||||
|
||||
/**
|
||||
* Directly generate a patch from the difference between two blobs.
|
||||
*
|
||||
* This is just like `git_diff_blobs()` except it generates a patch object
|
||||
* for the difference instead of directly making callbacks. You can use the
|
||||
* standard `git_diff_patch` accessor functions to read the patch data, and
|
||||
* you must call `git_diff_patch_free()` on the patch when done.
|
||||
*
|
||||
* @param out The generated patch; NULL on error
|
||||
* @param old_blob Blob for old side of diff, or NULL for empty blob
|
||||
* @param new_blob Blob for new side of diff, or NULL for empty blob
|
||||
* @param options Options for diff, or NULL for default options
|
||||
* @return 0 on success or error code < 0
|
||||
*/
|
||||
GIT_EXTERN(int) git_diff_patch_from_blobs(
|
||||
git_diff_patch **out,
|
||||
const git_blob *old_blob,
|
||||
const git_blob *new_blob,
|
||||
const git_diff_options *opts);
|
||||
|
||||
/**
|
||||
* Directly run a diff between a blob and a buffer.
|
||||
*
|
||||
@ -1013,7 +1033,7 @@ GIT_EXTERN(int) git_diff_blobs(
|
||||
* the reverse, with GIT_DELTA_REMOVED and blob content removed.
|
||||
*
|
||||
* @param old_blob Blob for old side of diff, or NULL for empty blob
|
||||
* @param buffer Raw data for new side of diff
|
||||
* @param buffer Raw data for new side of diff, or NULL for empty
|
||||
* @param buffer_len Length of raw data for new side of diff
|
||||
* @param options Options for diff, or NULL for default options
|
||||
* @param file_cb Callback for "file"; made once if there is a diff; can be NULL
|
||||
@ -1032,6 +1052,29 @@ GIT_EXTERN(int) git_diff_blob_to_buffer(
|
||||
git_diff_data_cb data_cb,
|
||||
void *payload);
|
||||
|
||||
/**
|
||||
* Directly generate a patch from the difference between a blob and a buffer.
|
||||
*
|
||||
* This is just like `git_diff_blob_to_buffer()` except it generates a patch
|
||||
* object for the difference instead of directly making callbacks. You can
|
||||
* use the standard `git_diff_patch` accessor functions to read the patch
|
||||
* data, and you must call `git_diff_patch_free()` on the patch when done.
|
||||
*
|
||||
* @param out The generated patch; NULL on error
|
||||
* @param old_blob Blob for old side of diff, or NULL for empty blob
|
||||
* @param buffer Raw data for new side of diff, or NULL for empty
|
||||
* @param buffer_len Length of raw data for new side of diff
|
||||
* @param options Options for diff, or NULL for default options
|
||||
* @return 0 on success or error code < 0
|
||||
*/
|
||||
GIT_EXTERN(int) git_diff_patch_from_blob_and_buffer(
|
||||
git_diff_patch **out,
|
||||
const git_blob *old_blob,
|
||||
const char *buf,
|
||||
size_t buflen,
|
||||
const git_diff_options *opts);
|
||||
|
||||
|
||||
GIT_END_DECL
|
||||
|
||||
/** @} */
|
||||
|
207
src/diff_patch.c
207
src/diff_patch.c
@ -265,33 +265,32 @@ int git_diff_foreach(
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
git_xdiff_output xo;
|
||||
git_diff_patch patch;
|
||||
git_diff_delta delta;
|
||||
} diff_single_info;
|
||||
} diff_patch_with_delta;
|
||||
|
||||
static int diff_single_generate(diff_single_info *info)
|
||||
static int diff_single_generate(diff_patch_with_delta *pd, git_xdiff_output *xo)
|
||||
{
|
||||
int error = 0;
|
||||
git_diff_patch *patch = &info->patch;
|
||||
git_diff_patch *patch = &pd->patch;
|
||||
bool has_old = ((patch->ofile.file.flags & GIT_DIFF_FLAG__NO_DATA) == 0);
|
||||
bool has_new = ((patch->nfile.file.flags & GIT_DIFF_FLAG__NO_DATA) == 0);
|
||||
|
||||
info->delta.status = has_new ?
|
||||
pd->delta.status = has_new ?
|
||||
(has_old ? GIT_DELTA_MODIFIED : GIT_DELTA_ADDED) :
|
||||
(has_old ? GIT_DELTA_DELETED : GIT_DELTA_UNTRACKED);
|
||||
|
||||
if (git_oid_equal(&patch->nfile.file.oid, &patch->ofile.file.oid))
|
||||
info->delta.status = GIT_DELTA_UNMODIFIED;
|
||||
pd->delta.status = GIT_DELTA_UNMODIFIED;
|
||||
|
||||
patch->delta = &info->delta;
|
||||
patch->delta = &pd->delta;
|
||||
|
||||
diff_patch_init_common(patch);
|
||||
|
||||
error = diff_patch_file_callback(patch, (git_diff_output *)&info->xo);
|
||||
error = diff_patch_file_callback(patch, (git_diff_output *)xo);
|
||||
|
||||
if (!error)
|
||||
error = diff_patch_generate(patch, (git_diff_output *)&info->xo);
|
||||
error = diff_patch_generate(patch, (git_diff_output *)xo);
|
||||
|
||||
if (error == GIT_EUSER)
|
||||
giterr_clear(); /* don't leave error message set invalidly */
|
||||
@ -299,6 +298,40 @@ static int diff_single_generate(diff_single_info *info)
|
||||
return error;
|
||||
}
|
||||
|
||||
static int diff_patch_from_blobs(
|
||||
diff_patch_with_delta *pd,
|
||||
git_xdiff_output *xo,
|
||||
const git_blob *old_blob,
|
||||
const git_blob *new_blob,
|
||||
const git_diff_options *opts)
|
||||
{
|
||||
int error = 0;
|
||||
git_repository *repo =
|
||||
new_blob ? git_object_owner((const git_object *)new_blob) :
|
||||
old_blob ? git_object_owner((const git_object *)old_blob) : NULL;
|
||||
|
||||
GITERR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options");
|
||||
|
||||
pd->patch.delta = &pd->delta;
|
||||
|
||||
if (!repo) /* return two NULL items as UNMODIFIED delta */
|
||||
return 0;
|
||||
|
||||
if (opts && (opts->flags & GIT_DIFF_REVERSE) != 0) {
|
||||
const git_blob *swap = old_blob;
|
||||
old_blob = new_blob;
|
||||
new_blob = swap;
|
||||
}
|
||||
|
||||
if ((error = diff_file_content_init_from_blob(
|
||||
&pd->patch.ofile, repo, opts, old_blob)) < 0 ||
|
||||
(error = diff_file_content_init_from_blob(
|
||||
&pd->patch.nfile, repo, opts, new_blob)) < 0)
|
||||
return error;
|
||||
|
||||
return diff_single_generate(pd, xo);
|
||||
}
|
||||
|
||||
int git_diff_blobs(
|
||||
const git_blob *old_blob,
|
||||
const git_blob *new_blob,
|
||||
@ -309,37 +342,85 @@ int git_diff_blobs(
|
||||
void *payload)
|
||||
{
|
||||
int error = 0;
|
||||
diff_single_info info;
|
||||
diff_patch_with_delta pd;
|
||||
git_xdiff_output xo;
|
||||
|
||||
memset(&pd, 0, sizeof(pd));
|
||||
memset(&xo, 0, sizeof(xo));
|
||||
|
||||
diff_output_init(
|
||||
(git_diff_output *)&xo, opts, file_cb, hunk_cb, data_cb, payload);
|
||||
git_xdiff_init(&xo, opts);
|
||||
|
||||
error = diff_patch_from_blobs(&pd, &xo, old_blob, new_blob, opts);
|
||||
|
||||
git_diff_patch_free((git_diff_patch *)&pd);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_diff_patch_from_blobs(
|
||||
git_diff_patch **out,
|
||||
const git_blob *old_blob,
|
||||
const git_blob *new_blob,
|
||||
const git_diff_options *opts)
|
||||
{
|
||||
int error = 0;
|
||||
diff_patch_with_delta *pd;
|
||||
git_xdiff_output xo;
|
||||
|
||||
assert(out);
|
||||
*out = NULL;
|
||||
|
||||
pd = git__calloc(1, sizeof(*pd));
|
||||
GITERR_CHECK_ALLOC(pd);
|
||||
pd->patch.flags = GIT_DIFF_PATCH_ALLOCATED;
|
||||
|
||||
memset(&xo, 0, sizeof(xo));
|
||||
|
||||
diff_output_to_patch((git_diff_output *)&xo, &pd->patch);
|
||||
git_xdiff_init(&xo, opts);
|
||||
|
||||
if (!(error = diff_patch_from_blobs(pd, &xo, old_blob, new_blob, opts)))
|
||||
*out = (git_diff_patch *)pd;
|
||||
else
|
||||
git_diff_patch_free((git_diff_patch *)pd);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int diff_patch_from_blob_and_buffer(
|
||||
diff_patch_with_delta *pd,
|
||||
git_xdiff_output *xo,
|
||||
const git_blob *old_blob,
|
||||
const char *buf,
|
||||
size_t buflen,
|
||||
const git_diff_options *opts)
|
||||
{
|
||||
int error = 0;
|
||||
git_repository *repo =
|
||||
new_blob ? git_object_owner((const git_object *)new_blob) :
|
||||
old_blob ? git_object_owner((const git_object *)old_blob) : NULL;
|
||||
|
||||
GITERR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options");
|
||||
|
||||
if (!repo) /* Hmm, given two NULL blobs, silently do no callbacks? */
|
||||
pd->patch.delta = &pd->delta;
|
||||
|
||||
if (!repo && !buf) /* return two NULL items as UNMODIFIED delta */
|
||||
return 0;
|
||||
|
||||
if (opts && (opts->flags & GIT_DIFF_REVERSE) != 0) {
|
||||
const git_blob *swap = old_blob;
|
||||
old_blob = new_blob;
|
||||
new_blob = swap;
|
||||
if (!(error = diff_file_content_init_from_raw(
|
||||
&pd->patch.ofile, repo, opts, buf, buflen)))
|
||||
error = diff_file_content_init_from_blob(
|
||||
&pd->patch.nfile, repo, opts, old_blob);
|
||||
} else {
|
||||
if (!(error = diff_file_content_init_from_blob(
|
||||
&pd->patch.ofile, repo, opts, old_blob)))
|
||||
error = diff_file_content_init_from_raw(
|
||||
&pd->patch.nfile, repo, opts, buf, buflen);
|
||||
}
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
|
||||
diff_output_init((git_diff_output *)&info.xo,
|
||||
opts, file_cb, hunk_cb, data_cb, payload);
|
||||
git_xdiff_init(&info.xo, opts);
|
||||
|
||||
if (!(error = diff_file_content_init_from_blob(
|
||||
&info.patch.ofile, repo, opts, old_blob)) &&
|
||||
!(error = diff_file_content_init_from_blob(
|
||||
&info.patch.nfile, repo, opts, new_blob)))
|
||||
error = diff_single_generate(&info);
|
||||
|
||||
git_diff_patch_free(&info.patch);
|
||||
|
||||
return error;
|
||||
return diff_single_generate(pd, xo);
|
||||
}
|
||||
|
||||
int git_diff_blob_to_buffer(
|
||||
@ -353,36 +434,52 @@ int git_diff_blob_to_buffer(
|
||||
void *payload)
|
||||
{
|
||||
int error = 0;
|
||||
diff_single_info info;
|
||||
git_repository *repo =
|
||||
old_blob ? git_object_owner((const git_object *)old_blob) : NULL;
|
||||
diff_patch_with_delta pd;
|
||||
git_xdiff_output xo;
|
||||
|
||||
GITERR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options");
|
||||
memset(&pd, 0, sizeof(pd));
|
||||
memset(&xo, 0, sizeof(xo));
|
||||
|
||||
if (!repo && !buf) /* Hmm, given NULLs, silently do no callbacks? */
|
||||
return 0;
|
||||
diff_output_init(
|
||||
(git_diff_output *)&xo, opts, file_cb, hunk_cb, data_cb, payload);
|
||||
git_xdiff_init(&xo, opts);
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
error = diff_patch_from_blob_and_buffer(
|
||||
&pd, &xo, old_blob, buf, buflen, opts);
|
||||
|
||||
diff_output_init((git_diff_output *)&info.xo,
|
||||
opts, file_cb, hunk_cb, data_cb, payload);
|
||||
git_xdiff_init(&info.xo, opts);
|
||||
git_diff_patch_free((git_diff_patch *)&pd);
|
||||
|
||||
if (opts && (opts->flags & GIT_DIFF_REVERSE) != 0) {
|
||||
if (!(error = diff_file_content_init_from_raw(
|
||||
&info.patch.ofile, repo, opts, buf, buflen)))
|
||||
error = diff_file_content_init_from_blob(
|
||||
&info.patch.nfile, repo, opts, old_blob);
|
||||
} else {
|
||||
if (!(error = diff_file_content_init_from_blob(
|
||||
&info.patch.ofile, repo, opts, old_blob)))
|
||||
error = diff_file_content_init_from_raw(
|
||||
&info.patch.nfile, repo, opts, buf, buflen);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
error = diff_single_generate(&info);
|
||||
int git_diff_patch_from_blob_and_buffer(
|
||||
git_diff_patch **out,
|
||||
const git_blob *old_blob,
|
||||
const char *buf,
|
||||
size_t buflen,
|
||||
const git_diff_options *opts)
|
||||
{
|
||||
int error = 0;
|
||||
diff_patch_with_delta *pd;
|
||||
git_xdiff_output xo;
|
||||
|
||||
git_diff_patch_free(&info.patch);
|
||||
assert(out);
|
||||
*out = NULL;
|
||||
|
||||
pd = git__calloc(1, sizeof(*pd));
|
||||
GITERR_CHECK_ALLOC(pd);
|
||||
pd->patch.flags = GIT_DIFF_PATCH_ALLOCATED;
|
||||
|
||||
memset(&xo, 0, sizeof(xo));
|
||||
|
||||
diff_output_to_patch((git_diff_output *)&xo, &pd->patch);
|
||||
git_xdiff_init(&xo, opts);
|
||||
|
||||
if (!(error = diff_patch_from_blob_and_buffer(
|
||||
pd, &xo, old_blob, buf, buflen, opts)))
|
||||
*out = (git_diff_patch *)pd;
|
||||
else
|
||||
git_diff_patch_free((git_diff_patch *)pd);
|
||||
|
||||
return error;
|
||||
}
|
||||
@ -599,9 +696,7 @@ static int diff_patch_file_cb(
|
||||
float progress,
|
||||
void *payload)
|
||||
{
|
||||
GIT_UNUSED(delta);
|
||||
GIT_UNUSED(progress);
|
||||
GIT_UNUSED(payload);
|
||||
GIT_UNUSED(delta); GIT_UNUSED(progress); GIT_UNUSED(payload);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -120,6 +120,93 @@ void test_diff_blob__can_compare_text_blobs(void)
|
||||
git_blob_free(c);
|
||||
}
|
||||
|
||||
void test_diff_blob__can_compare_text_blobs_with_patch(void)
|
||||
{
|
||||
git_blob *a, *b, *c;
|
||||
git_oid a_oid, b_oid, c_oid;
|
||||
git_diff_patch *p;
|
||||
size_t tc, ta, td;
|
||||
|
||||
/* tests/resources/attr/root_test1 */
|
||||
cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8));
|
||||
cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 4));
|
||||
|
||||
/* tests/resources/attr/root_test2 */
|
||||
cl_git_pass(git_oid_fromstrn(&b_oid, "4d713dc4", 8));
|
||||
cl_git_pass(git_blob_lookup_prefix(&b, g_repo, &b_oid, 4));
|
||||
|
||||
/* tests/resources/attr/root_test3 */
|
||||
cl_git_pass(git_oid_fromstrn(&c_oid, "c96bbb2c2557a832", 16));
|
||||
cl_git_pass(git_blob_lookup_prefix(&c, g_repo, &c_oid, 8));
|
||||
|
||||
/* Doing the equivalent of a `git diff -U1` on these files */
|
||||
|
||||
/* diff on tests/resources/attr/root_test1 */
|
||||
cl_git_pass(git_diff_patch_from_blobs(&p, a, b, &opts));
|
||||
|
||||
cl_assert(p != NULL);
|
||||
cl_assert_equal_i(GIT_DELTA_MODIFIED, git_diff_patch_delta(p)->status);
|
||||
cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p));
|
||||
cl_assert_equal_i(6, git_diff_patch_num_lines_in_hunk(p, 0));
|
||||
|
||||
cl_git_pass(git_diff_patch_line_stats(&tc, &ta, &td, p));
|
||||
cl_assert_equal_i(1, (int)tc);
|
||||
cl_assert_equal_i(5, (int)ta);
|
||||
cl_assert_equal_i(0, (int)td);
|
||||
|
||||
git_diff_patch_free(p);
|
||||
|
||||
/* diff on tests/resources/attr/root_test2 */
|
||||
cl_git_pass(git_diff_patch_from_blobs(&p, b, c, &opts));
|
||||
|
||||
cl_assert(p != NULL);
|
||||
cl_assert_equal_i(GIT_DELTA_MODIFIED, git_diff_patch_delta(p)->status);
|
||||
cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p));
|
||||
cl_assert_equal_i(15, git_diff_patch_num_lines_in_hunk(p, 0));
|
||||
|
||||
cl_git_pass(git_diff_patch_line_stats(&tc, &ta, &td, p));
|
||||
cl_assert_equal_i(3, (int)tc);
|
||||
cl_assert_equal_i(9, (int)ta);
|
||||
cl_assert_equal_i(3, (int)td);
|
||||
|
||||
git_diff_patch_free(p);
|
||||
|
||||
/* diff on tests/resources/attr/root_test3 */
|
||||
cl_git_pass(git_diff_patch_from_blobs(&p, a, c, &opts));
|
||||
|
||||
cl_assert(p != NULL);
|
||||
cl_assert_equal_i(GIT_DELTA_MODIFIED, git_diff_patch_delta(p)->status);
|
||||
cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p));
|
||||
cl_assert_equal_i(13, git_diff_patch_num_lines_in_hunk(p, 0));
|
||||
|
||||
cl_git_pass(git_diff_patch_line_stats(&tc, &ta, &td, p));
|
||||
cl_assert_equal_i(0, (int)tc);
|
||||
cl_assert_equal_i(12, (int)ta);
|
||||
cl_assert_equal_i(1, (int)td);
|
||||
|
||||
git_diff_patch_free(p);
|
||||
|
||||
/* one more */
|
||||
cl_git_pass(git_diff_patch_from_blobs(&p, c, d, &opts));
|
||||
|
||||
cl_assert(p != NULL);
|
||||
cl_assert_equal_i(GIT_DELTA_MODIFIED, git_diff_patch_delta(p)->status);
|
||||
cl_assert_equal_i(2, (int)git_diff_patch_num_hunks(p));
|
||||
cl_assert_equal_i(5, git_diff_patch_num_lines_in_hunk(p, 0));
|
||||
cl_assert_equal_i(9, git_diff_patch_num_lines_in_hunk(p, 1));
|
||||
|
||||
cl_git_pass(git_diff_patch_line_stats(&tc, &ta, &td, p));
|
||||
cl_assert_equal_i(4, (int)tc);
|
||||
cl_assert_equal_i(6, (int)ta);
|
||||
cl_assert_equal_i(4, (int)td);
|
||||
|
||||
git_diff_patch_free(p);
|
||||
|
||||
git_blob_free(a);
|
||||
git_blob_free(b);
|
||||
git_blob_free(c);
|
||||
}
|
||||
|
||||
void test_diff_blob__can_compare_against_null_blobs(void)
|
||||
{
|
||||
git_blob *e = NULL;
|
||||
@ -175,6 +262,66 @@ void test_diff_blob__can_compare_against_null_blobs(void)
|
||||
cl_assert_equal_i(0, expected.lines);
|
||||
}
|
||||
|
||||
void test_diff_blob__can_compare_against_null_blobs_with_patch(void)
|
||||
{
|
||||
git_blob *e = NULL;
|
||||
git_diff_patch *p;
|
||||
int line;
|
||||
char origin;
|
||||
|
||||
cl_git_pass(git_diff_patch_from_blobs(&p, d, e, &opts));
|
||||
|
||||
cl_assert(p != NULL);
|
||||
cl_assert_equal_i(GIT_DELTA_DELETED, git_diff_patch_delta(p)->status);
|
||||
cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p));
|
||||
cl_assert_equal_i(14, git_diff_patch_num_lines_in_hunk(p, 0));
|
||||
|
||||
for (line = 0; line < git_diff_patch_num_lines_in_hunk(p, 0); ++line) {
|
||||
cl_git_pass(git_diff_patch_get_line_in_hunk(
|
||||
&origin, NULL, NULL, NULL, NULL, p, 0, line));
|
||||
cl_assert_equal_i(GIT_DIFF_LINE_DELETION, (int)origin);
|
||||
}
|
||||
|
||||
git_diff_patch_free(p);
|
||||
|
||||
opts.flags |= GIT_DIFF_REVERSE;
|
||||
|
||||
cl_git_pass(git_diff_patch_from_blobs(&p, d, e, &opts));
|
||||
|
||||
cl_assert(p != NULL);
|
||||
cl_assert_equal_i(GIT_DELTA_ADDED, git_diff_patch_delta(p)->status);
|
||||
cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p));
|
||||
cl_assert_equal_i(14, git_diff_patch_num_lines_in_hunk(p, 0));
|
||||
|
||||
for (line = 0; line < git_diff_patch_num_lines_in_hunk(p, 0); ++line) {
|
||||
cl_git_pass(git_diff_patch_get_line_in_hunk(
|
||||
&origin, NULL, NULL, NULL, NULL, p, 0, line));
|
||||
cl_assert_equal_i(GIT_DIFF_LINE_ADDITION, (int)origin);
|
||||
}
|
||||
|
||||
git_diff_patch_free(p);
|
||||
|
||||
opts.flags ^= GIT_DIFF_REVERSE;
|
||||
|
||||
cl_git_pass(git_diff_patch_from_blobs(&p, alien, NULL, &opts));
|
||||
|
||||
cl_assert(p != NULL);
|
||||
cl_assert_equal_i(GIT_DELTA_DELETED, git_diff_patch_delta(p)->status);
|
||||
cl_assert((git_diff_patch_delta(p)->flags & GIT_DIFF_FLAG_BINARY) != 0);
|
||||
cl_assert_equal_i(0, (int)git_diff_patch_num_hunks(p));
|
||||
|
||||
git_diff_patch_free(p);
|
||||
|
||||
cl_git_pass(git_diff_patch_from_blobs(&p, NULL, alien, &opts));
|
||||
|
||||
cl_assert(p != NULL);
|
||||
cl_assert_equal_i(GIT_DELTA_ADDED, git_diff_patch_delta(p)->status);
|
||||
cl_assert((git_diff_patch_delta(p)->flags & GIT_DIFF_FLAG_BINARY) != 0);
|
||||
cl_assert_equal_i(0, (int)git_diff_patch_num_hunks(p));
|
||||
|
||||
git_diff_patch_free(p);
|
||||
}
|
||||
|
||||
static void assert_identical_blobs_comparison(diff_expects *expected)
|
||||
{
|
||||
cl_assert_equal_i(1, expected->files);
|
||||
@ -206,6 +353,29 @@ void test_diff_blob__can_compare_identical_blobs(void)
|
||||
assert_identical_blobs_comparison(&expected);
|
||||
}
|
||||
|
||||
void test_diff_blob__can_compare_identical_blobs_with_patch(void)
|
||||
{
|
||||
git_diff_patch *p;
|
||||
|
||||
cl_git_pass(git_diff_patch_from_blobs(&p, d, d, &opts));
|
||||
cl_assert(p != NULL);
|
||||
cl_assert_equal_i(GIT_DELTA_UNMODIFIED, git_diff_patch_delta(p)->status);
|
||||
cl_assert_equal_i(0, (int)git_diff_patch_num_hunks(p));
|
||||
git_diff_patch_free(p);
|
||||
|
||||
cl_git_pass(git_diff_patch_from_blobs(&p, NULL, NULL, &opts));
|
||||
cl_assert(p != NULL);
|
||||
cl_assert_equal_i(GIT_DELTA_UNMODIFIED, git_diff_patch_delta(p)->status);
|
||||
cl_assert_equal_i(0, (int)git_diff_patch_num_hunks(p));
|
||||
git_diff_patch_free(p);
|
||||
|
||||
cl_git_pass(git_diff_patch_from_blobs(&p, alien, alien, &opts));
|
||||
cl_assert(p != NULL);
|
||||
cl_assert_equal_i(GIT_DELTA_UNMODIFIED, git_diff_patch_delta(p)->status);
|
||||
cl_assert_equal_i(0, (int)git_diff_patch_num_hunks(p));
|
||||
git_diff_patch_free(p);
|
||||
}
|
||||
|
||||
static void assert_binary_blobs_comparison(diff_expects *expected)
|
||||
{
|
||||
cl_assert(expected->files_binary > 0);
|
||||
@ -428,6 +598,74 @@ void test_diff_blob__can_compare_blob_to_buffer(void)
|
||||
git_blob_free(a);
|
||||
}
|
||||
|
||||
void test_diff_blob__can_compare_blob_to_buffer_with_patch(void)
|
||||
{
|
||||
git_diff_patch *p;
|
||||
git_blob *a;
|
||||
git_oid a_oid;
|
||||
const char *a_content = "Hello from the root\n";
|
||||
const char *b_content = "Hello from the root\n\nSome additional lines\n\nDown here below\n\n";
|
||||
size_t tc, ta, td;
|
||||
|
||||
/* tests/resources/attr/root_test1 */
|
||||
cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8));
|
||||
cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 4));
|
||||
|
||||
/* diff from blob a to content of b */
|
||||
cl_git_pass(git_diff_patch_from_blob_and_buffer(
|
||||
&p, a, b_content, strlen(b_content), &opts));
|
||||
|
||||
cl_assert(p != NULL);
|
||||
cl_assert_equal_i(GIT_DELTA_MODIFIED, git_diff_patch_delta(p)->status);
|
||||
cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p));
|
||||
cl_assert_equal_i(6, git_diff_patch_num_lines_in_hunk(p, 0));
|
||||
|
||||
cl_git_pass(git_diff_patch_line_stats(&tc, &ta, &td, p));
|
||||
cl_assert_equal_i(1, (int)tc);
|
||||
cl_assert_equal_i(5, (int)ta);
|
||||
cl_assert_equal_i(0, (int)td);
|
||||
|
||||
git_diff_patch_free(p);
|
||||
|
||||
/* diff from blob a to content of a */
|
||||
cl_git_pass(git_diff_patch_from_blob_and_buffer(
|
||||
&p, a, a_content, strlen(a_content), &opts));
|
||||
cl_assert(p != NULL);
|
||||
cl_assert_equal_i(GIT_DELTA_UNMODIFIED, git_diff_patch_delta(p)->status);
|
||||
cl_assert_equal_i(0, (int)git_diff_patch_num_hunks(p));
|
||||
git_diff_patch_free(p);
|
||||
|
||||
/* diff from NULL blob to content of a */
|
||||
cl_git_pass(git_diff_patch_from_blob_and_buffer(
|
||||
&p, NULL, a_content, strlen(a_content), &opts));
|
||||
cl_assert(p != NULL);
|
||||
cl_assert_equal_i(GIT_DELTA_ADDED, git_diff_patch_delta(p)->status);
|
||||
cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p));
|
||||
cl_assert_equal_i(1, git_diff_patch_num_lines_in_hunk(p, 0));
|
||||
git_diff_patch_free(p);
|
||||
|
||||
/* diff from blob a to NULL buffer */
|
||||
cl_git_pass(git_diff_patch_from_blob_and_buffer(
|
||||
&p, a, NULL, 0, &opts));
|
||||
cl_assert(p != NULL);
|
||||
cl_assert_equal_i(GIT_DELTA_DELETED, git_diff_patch_delta(p)->status);
|
||||
cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p));
|
||||
cl_assert_equal_i(1, git_diff_patch_num_lines_in_hunk(p, 0));
|
||||
git_diff_patch_free(p);
|
||||
|
||||
/* diff with reverse */
|
||||
opts.flags ^= GIT_DIFF_REVERSE;
|
||||
|
||||
cl_git_pass(git_diff_patch_from_blob_and_buffer(
|
||||
&p, a, NULL, 0, &opts));
|
||||
cl_assert(p != NULL);
|
||||
cl_assert_equal_i(GIT_DELTA_ADDED, git_diff_patch_delta(p)->status);
|
||||
cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p));
|
||||
cl_assert_equal_i(1, git_diff_patch_num_lines_in_hunk(p, 0));
|
||||
git_diff_patch_free(p);
|
||||
|
||||
git_blob_free(a);
|
||||
}
|
||||
|
||||
static void assert_one_modified_with_lines(diff_expects *expected, int lines)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user