diff options
author | Russell Belfer <rb@github.com> | 2013-06-12 11:55:27 -0700 |
---|---|---|
committer | Russell Belfer <rb@github.com> | 2013-06-12 11:55:27 -0700 |
commit | f9c824c592d7a23f7cc385c25c95a5d0c5c8687e (patch) | |
tree | a9041574778f0bb2341d97c56357d280ed71f06c | |
parent | 54faddd299ccb6187a9747c1d3ee18d33e5edf7a (diff) | |
download | libgit2-f9c824c592d7a23f7cc385c25c95a5d0c5c8687e.tar.gz |
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.
-rw-r--r-- | include/git2/diff.h | 47 | ||||
-rw-r--r-- | src/diff_patch.c | 195 | ||||
-rw-r--r-- | tests-clar/diff/blob.c | 238 |
3 files changed, 428 insertions, 52 deletions
diff --git a/include/git2/diff.h b/include/git2/diff.h index 40e65b1e4..8113a56be 100644 --- a/include/git2/diff.h +++ b/include/git2/diff.h @@ -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, @@ -1001,6 +1001,26 @@ GIT_EXTERN(int) git_diff_blobs( 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. * * As with `git_diff_blobs`, comparing a blob and buffer lacks some context, @@ -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 /** @} */ diff --git a/src/diff_patch.c b/src/diff_patch.c index fe22d678c..4c0b9a70c 100644 --- a/src/diff_patch.c +++ b/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,24 +298,23 @@ static int diff_single_generate(diff_single_info *info) 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 *new_blob, - 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) + const git_diff_options *opts) { int error = 0; - diff_single_info info; 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) /* return two NULL items as UNMODIFIED delta */ return 0; if (opts && (opts->flags & GIT_DIFF_REVERSE) != 0) { @@ -325,64 +323,163 @@ int git_diff_blobs( 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, - opts, file_cb, hunk_cb, data_cb, payload); - git_xdiff_init(&info.xo, opts); + return diff_single_generate(pd, xo); +} - 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); +int git_diff_blobs( + const git_blob *old_blob, + const git_blob *new_blob, + 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_blobs(&pd, &xo, old_blob, new_blob, opts); + + git_diff_patch_free((git_diff_patch *)&pd); 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 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) + const git_diff_options *opts) { int error = 0; - diff_single_info info; git_repository *repo = old_blob ? git_object_owner((const git_object *)old_blob) : NULL; GITERR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options"); - if (!repo && !buf) /* Hmm, given NULLs, silently do no callbacks? */ - return 0; - - memset(&info, 0, sizeof(info)); + pd->patch.delta = &pd->delta; - diff_output_init((git_diff_output *)&info.xo, - opts, file_cb, hunk_cb, data_cb, payload); - git_xdiff_init(&info.xo, opts); + if (!repo && !buf) /* return two NULL items as UNMODIFIED delta */ + return 0; if (opts && (opts->flags & GIT_DIFF_REVERSE) != 0) { 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( - &info.patch.nfile, repo, opts, old_blob); + &pd->patch.nfile, repo, opts, old_blob); } else { 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( - &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; } @@ -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; } diff --git a/tests-clar/diff/blob.c b/tests-clar/diff/blob.c index 2ac8dbc51..b12186d98 100644 --- a/tests-clar/diff/blob.c +++ b/tests-clar/diff/blob.c @@ -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) { |