Commit f9c824c5 by Russell Belfer

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.
parent 54faddd2
...@@ -860,7 +860,7 @@ GIT_EXTERN(size_t) git_diff_patch_num_hunks( ...@@ -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_additions Count of addition lines in output, can be NULL.
* @param total_deletions Count of deletion 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 * @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( GIT_EXTERN(int) git_diff_patch_line_stats(
size_t *total_context, size_t *total_context,
...@@ -1001,6 +1001,26 @@ GIT_EXTERN(int) git_diff_blobs( ...@@ -1001,6 +1001,26 @@ GIT_EXTERN(int) git_diff_blobs(
void *payload); 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. * Directly run a diff between a blob and a buffer.
* *
* As with `git_diff_blobs`, comparing a blob and buffer lacks some context, * As with `git_diff_blobs`, comparing a blob and buffer lacks some context,
...@@ -1013,7 +1033,7 @@ GIT_EXTERN(int) git_diff_blobs( ...@@ -1013,7 +1033,7 @@ GIT_EXTERN(int) git_diff_blobs(
* the reverse, with GIT_DELTA_REMOVED and blob content removed. * 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 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 buffer_len Length of raw data for new side of diff
* @param options Options for diff, or NULL for default options * @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 * @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( ...@@ -1032,6 +1052,29 @@ GIT_EXTERN(int) git_diff_blob_to_buffer(
git_diff_data_cb data_cb, git_diff_data_cb data_cb,
void *payload); 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 GIT_END_DECL
/** @} */ /** @} */
......
...@@ -265,33 +265,32 @@ int git_diff_foreach( ...@@ -265,33 +265,32 @@ int git_diff_foreach(
} }
typedef struct { typedef struct {
git_xdiff_output xo;
git_diff_patch patch; git_diff_patch patch;
git_diff_delta delta; 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; 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_old = ((patch->ofile.file.flags & GIT_DIFF_FLAG__NO_DATA) == 0);
bool has_new = ((patch->nfile.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_MODIFIED : GIT_DELTA_ADDED) :
(has_old ? GIT_DELTA_DELETED : GIT_DELTA_UNTRACKED); (has_old ? GIT_DELTA_DELETED : GIT_DELTA_UNTRACKED);
if (git_oid_equal(&patch->nfile.file.oid, &patch->ofile.file.oid)) 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); 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) 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) if (error == GIT_EUSER)
giterr_clear(); /* don't leave error message set invalidly */ giterr_clear(); /* don't leave error message set invalidly */
...@@ -299,24 +298,23 @@ static int diff_single_generate(diff_single_info *info) ...@@ -299,24 +298,23 @@ static int diff_single_generate(diff_single_info *info)
return error; return error;
} }
int git_diff_blobs( static int diff_patch_from_blobs(
diff_patch_with_delta *pd,
git_xdiff_output *xo,
const git_blob *old_blob, const git_blob *old_blob,
const git_blob *new_blob, const git_blob *new_blob,
const git_diff_options *opts, const git_diff_options *opts)
git_diff_file_cb file_cb,
git_diff_hunk_cb hunk_cb,
git_diff_data_cb data_cb,
void *payload)
{ {
int error = 0; int error = 0;
diff_single_info info;
git_repository *repo = git_repository *repo =
new_blob ? git_object_owner((const git_object *)new_blob) : new_blob ? git_object_owner((const git_object *)new_blob) :
old_blob ? git_object_owner((const git_object *)old_blob) : NULL; old_blob ? git_object_owner((const git_object *)old_blob) : NULL;
GITERR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options"); 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) /* return two NULL items as UNMODIFIED delta */
return 0; return 0;
if (opts && (opts->flags & GIT_DIFF_REVERSE) != 0) { if (opts && (opts->flags & GIT_DIFF_REVERSE) != 0) {
...@@ -325,64 +323,163 @@ int git_diff_blobs( ...@@ -325,64 +323,163 @@ int git_diff_blobs(
new_blob = swap; new_blob = swap;
} }
memset(&info, 0, sizeof(info)); 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;
diff_output_init((git_diff_output *)&info.xo, return diff_single_generate(pd, xo);
opts, file_cb, hunk_cb, data_cb, payload); }
git_xdiff_init(&info.xo, opts);
if (!(error = diff_file_content_init_from_blob( int git_diff_blobs(
&info.patch.ofile, repo, opts, old_blob)) && const git_blob *old_blob,
!(error = diff_file_content_init_from_blob( const git_blob *new_blob,
&info.patch.nfile, repo, opts, new_blob))) const git_diff_options *opts,
error = diff_single_generate(&info); git_diff_file_cb file_cb,
git_diff_hunk_cb hunk_cb,
git_diff_data_cb data_cb,
void *payload)
{
int error = 0;
diff_patch_with_delta pd;
git_xdiff_output xo;
git_diff_patch_free(&info.patch); 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; return error;
} }
int git_diff_blob_to_buffer( 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 git_blob *old_blob,
const char *buf, const char *buf,
size_t buflen, size_t buflen,
const git_diff_options *opts, const git_diff_options *opts)
git_diff_file_cb file_cb,
git_diff_hunk_cb hunk_cb,
git_diff_data_cb data_cb,
void *payload)
{ {
int error = 0; int error = 0;
diff_single_info info;
git_repository *repo = git_repository *repo =
old_blob ? git_object_owner((const git_object *)old_blob) : NULL; old_blob ? git_object_owner((const git_object *)old_blob) : NULL;
GITERR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options"); GITERR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options");
if (!repo && !buf) /* Hmm, given NULLs, silently do no callbacks? */ pd->patch.delta = &pd->delta;
return 0;
memset(&info, 0, sizeof(info));
diff_output_init((git_diff_output *)&info.xo, if (!repo && !buf) /* return two NULL items as UNMODIFIED delta */
opts, file_cb, hunk_cb, data_cb, payload); return 0;
git_xdiff_init(&info.xo, opts);
if (opts && (opts->flags & GIT_DIFF_REVERSE) != 0) { if (opts && (opts->flags & GIT_DIFF_REVERSE) != 0) {
if (!(error = diff_file_content_init_from_raw( if (!(error = diff_file_content_init_from_raw(
&info.patch.ofile, repo, opts, buf, buflen))) &pd->patch.ofile, repo, opts, buf, buflen)))
error = diff_file_content_init_from_blob( error = diff_file_content_init_from_blob(
&info.patch.nfile, repo, opts, old_blob); &pd->patch.nfile, repo, opts, old_blob);
} else { } else {
if (!(error = diff_file_content_init_from_blob( if (!(error = diff_file_content_init_from_blob(
&info.patch.ofile, repo, opts, old_blob))) &pd->patch.ofile, repo, opts, old_blob)))
error = diff_file_content_init_from_raw( error = diff_file_content_init_from_raw(
&info.patch.nfile, repo, opts, buf, buflen); &pd->patch.nfile, repo, opts, buf, buflen);
} }
error = diff_single_generate(&info); return diff_single_generate(pd, xo);
}
int git_diff_blob_to_buffer(
const git_blob *old_blob,
const char *buf,
size_t buflen,
const git_diff_options *opts,
git_diff_file_cb file_cb,
git_diff_hunk_cb hunk_cb,
git_diff_data_cb data_cb,
void *payload)
{
int error = 0;
diff_patch_with_delta pd;
git_xdiff_output xo;
git_diff_patch_free(&info.patch); 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_blob_and_buffer(
&pd, &xo, old_blob, buf, buflen, opts);
git_diff_patch_free((git_diff_patch *)&pd);
return error;
}
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;
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; return error;
} }
...@@ -599,9 +696,7 @@ static int diff_patch_file_cb( ...@@ -599,9 +696,7 @@ static int diff_patch_file_cb(
float progress, float progress,
void *payload) void *payload)
{ {
GIT_UNUSED(delta); GIT_UNUSED(delta); GIT_UNUSED(progress); GIT_UNUSED(payload);
GIT_UNUSED(progress);
GIT_UNUSED(payload);
return 0; return 0;
} }
......
...@@ -120,6 +120,93 @@ void test_diff_blob__can_compare_text_blobs(void) ...@@ -120,6 +120,93 @@ void test_diff_blob__can_compare_text_blobs(void)
git_blob_free(c); 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) void test_diff_blob__can_compare_against_null_blobs(void)
{ {
git_blob *e = NULL; git_blob *e = NULL;
...@@ -175,6 +262,66 @@ void test_diff_blob__can_compare_against_null_blobs(void) ...@@ -175,6 +262,66 @@ void test_diff_blob__can_compare_against_null_blobs(void)
cl_assert_equal_i(0, expected.lines); 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) static void assert_identical_blobs_comparison(diff_expects *expected)
{ {
cl_assert_equal_i(1, expected->files); cl_assert_equal_i(1, expected->files);
...@@ -206,6 +353,29 @@ void test_diff_blob__can_compare_identical_blobs(void) ...@@ -206,6 +353,29 @@ void test_diff_blob__can_compare_identical_blobs(void)
assert_identical_blobs_comparison(&expected); 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) static void assert_binary_blobs_comparison(diff_expects *expected)
{ {
cl_assert(expected->files_binary > 0); cl_assert(expected->files_binary > 0);
...@@ -428,6 +598,74 @@ void test_diff_blob__can_compare_blob_to_buffer(void) ...@@ -428,6 +598,74 @@ void test_diff_blob__can_compare_blob_to_buffer(void)
git_blob_free(a); 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) static void assert_one_modified_with_lines(diff_expects *expected, int lines)
{ {
......
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