diff options
author | Vicent Marti <tanoku@gmail.com> | 2014-06-20 14:42:16 +0200 |
---|---|---|
committer | Vicent Marti <tanoku@gmail.com> | 2014-06-20 14:42:16 +0200 |
commit | 28f087c8642ff9c8dd6964e101e6d8539db6281a (patch) | |
tree | 3518d1bf420e92c964bed03074575d8a1db88654 /tests/diff | |
parent | 4b0a36e881506a02b43a4ae3c19c93c919b36eeb (diff) | |
parent | 1589aa0c4d48fb130d8a5db28c45cd3d173cde6d (diff) | |
download | libgit2-28f087c8642ff9c8dd6964e101e6d8539db6281a.tar.gz |
libgit2 v0.21.0v0.21.0
Diffstat (limited to 'tests/diff')
-rw-r--r-- | tests/diff/binary.c | 263 | ||||
-rw-r--r-- | tests/diff/blob.c | 317 | ||||
-rw-r--r-- | tests/diff/diff_helpers.c | 29 | ||||
-rw-r--r-- | tests/diff/diffiter.c | 8 | ||||
-rw-r--r-- | tests/diff/drivers.c | 141 | ||||
-rw-r--r-- | tests/diff/format_email.c | 467 | ||||
-rw-r--r-- | tests/diff/index.c | 4 | ||||
-rw-r--r-- | tests/diff/iterator.c | 67 | ||||
-rw-r--r-- | tests/diff/notify.c | 8 | ||||
-rw-r--r-- | tests/diff/patch.c | 83 | ||||
-rw-r--r-- | tests/diff/rename.c | 322 | ||||
-rw-r--r-- | tests/diff/stats.c | 289 | ||||
-rw-r--r-- | tests/diff/submodules.c | 94 | ||||
-rw-r--r-- | tests/diff/tree.c | 2 | ||||
-rw-r--r-- | tests/diff/workdir.c | 234 |
15 files changed, 2010 insertions, 318 deletions
diff --git a/tests/diff/binary.c b/tests/diff/binary.c new file mode 100644 index 000000000..cb574a588 --- /dev/null +++ b/tests/diff/binary.c @@ -0,0 +1,263 @@ +#include "clar_libgit2.h" + +#include "buffer.h" +#include "filebuf.h" + +static git_repository *repo; + +void test_diff_binary__initialize(void) +{ +} + +void test_diff_binary__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_patch( + const char *one, + const char *two, + const git_diff_options *opts, + const char *expected) +{ + git_oid id_one, id_two; + git_index *index = NULL; + git_commit *commit_one, *commit_two = NULL; + git_tree *tree_one, *tree_two; + git_diff *diff; + git_patch *patch; + git_buf actual = GIT_BUF_INIT; + + cl_git_pass(git_oid_fromstr(&id_one, one)); + cl_git_pass(git_commit_lookup(&commit_one, repo, &id_one)); + cl_git_pass(git_commit_tree(&tree_one, commit_one)); + + if (two) { + cl_git_pass(git_oid_fromstr(&id_two, two)); + cl_git_pass(git_commit_lookup(&commit_two, repo, &id_two)); + cl_git_pass(git_commit_tree(&tree_two, commit_two)); + } else { + cl_git_pass(git_repository_index(&index, repo)); + cl_git_pass(git_index_write_tree(&id_two, index)); + cl_git_pass(git_tree_lookup(&tree_two, repo, &id_two)); + } + + cl_git_pass(git_diff_tree_to_tree(&diff, repo, tree_one, tree_two, opts)); + + cl_git_pass(git_patch_from_diff(&patch, diff, 0)); + cl_git_pass(git_patch_to_buf(&actual, patch)); + + cl_assert_equal_s(expected, actual.ptr); + + git_buf_free(&actual); + git_patch_free(patch); + git_diff_free(diff); + git_tree_free(tree_one); + git_tree_free(tree_two); + git_commit_free(commit_one); + git_commit_free(commit_two); + git_index_free(index); +} + +void test_diff_binary__add_normal(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + const char *expected = + "diff --git a/binary.bin b/binary.bin\n" \ + "new file mode 100644\n" \ + "index 0000000..bd474b2\n" \ + "Binary files /dev/null and b/binary.bin differ\n"; + + repo = cl_git_sandbox_init("diff_format_email"); + test_patch( + "873806f6f27e631eb0b23e4b56bea2bfac14a373", + "897d3af16ca9e420cd071b1c4541bd2b91d04c8c", + &opts, + expected); +} + +void test_diff_binary__add(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + const char *expected = + "diff --git a/binary.bin b/binary.bin\n" \ + "new file mode 100644\n" \ + "index 0000000000000000000000000000000000000000..bd474b2519cc15eab801ff851cc7d50f0dee49a1\n" \ + "GIT binary patch\n" \ + "literal 3\n" \ + "Kc${Nk-~s>u4FC%O\n" + "\n" \ + "literal 0\n" \ + "Hc$@<O00001\n"; + + opts.flags = GIT_DIFF_SHOW_BINARY; + opts.id_abbrev = GIT_OID_HEXSZ; + + repo = cl_git_sandbox_init("diff_format_email"); + test_patch( + "873806f6f27e631eb0b23e4b56bea2bfac14a373", + "897d3af16ca9e420cd071b1c4541bd2b91d04c8c", + &opts, + expected); +} + +void test_diff_binary__modify_normal(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + const char *expected = + "diff --git a/binary.bin b/binary.bin\n" \ + "index bd474b2..9ac35ff 100644\n" \ + "Binary files a/binary.bin and b/binary.bin differ\n"; + + repo = cl_git_sandbox_init("diff_format_email"); + test_patch( + "897d3af16ca9e420cd071b1c4541bd2b91d04c8c", + "8d7523f6fcb2404257889abe0d96f093d9f524f9", + &opts, + expected); +} + +void test_diff_binary__modify(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + const char *expected = + "diff --git a/binary.bin b/binary.bin\n" \ + "index bd474b2519cc15eab801ff851cc7d50f0dee49a1..9ac35ff15cd8864aeafd889e4826a3150f0b06c4 100644\n" \ + "GIT binary patch\n" \ + "literal 5\n" \ + "Mc${NkU}WL~000&M4gdfE\n" \ + "\n" \ + "literal 3\n" \ + "Kc${Nk-~s>u4FC%O\n"; + + opts.flags = GIT_DIFF_SHOW_BINARY; + + repo = cl_git_sandbox_init("diff_format_email"); + test_patch( + "897d3af16ca9e420cd071b1c4541bd2b91d04c8c", + "8d7523f6fcb2404257889abe0d96f093d9f524f9", + &opts, + expected); +} + +void test_diff_binary__delete_normal(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + const char *expected = + "diff --git a/binary.bin b/binary.bin\n" \ + "deleted file mode 100644\n" \ + "index bd474b2..0000000\n" \ + "Binary files a/binary.bin and /dev/null differ\n"; + + repo = cl_git_sandbox_init("diff_format_email"); + test_patch( + "897d3af16ca9e420cd071b1c4541bd2b91d04c8c", + "873806f6f27e631eb0b23e4b56bea2bfac14a373", + &opts, + expected); +} + +void test_diff_binary__delete(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + const char *expected = + "diff --git a/binary.bin b/binary.bin\n" \ + "deleted file mode 100644\n" \ + "index bd474b2519cc15eab801ff851cc7d50f0dee49a1..0000000000000000000000000000000000000000\n" \ + "GIT binary patch\n" \ + "literal 0\n" \ + "Hc$@<O00001\n" \ + "\n" \ + "literal 3\n" \ + "Kc${Nk-~s>u4FC%O\n"; + + opts.flags = GIT_DIFF_SHOW_BINARY; + opts.id_abbrev = GIT_OID_HEXSZ; + + repo = cl_git_sandbox_init("diff_format_email"); + test_patch( + "897d3af16ca9e420cd071b1c4541bd2b91d04c8c", + "873806f6f27e631eb0b23e4b56bea2bfac14a373", + &opts, + expected); +} + +void test_diff_binary__delta(void) +{ + git_index *index; + git_buf contents = GIT_BUF_INIT; + size_t i; + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + const char *expected = + "diff --git a/songof7cities.txt b/songof7cities.txt\n" \ + "index 4210ffd5c390b21dd5483375e75288dea9ede512..cc84ec183351c9944ed90a619ca08911924055b5 100644\n" \ + "GIT binary patch\n" \ + "delta 198\n" \ + "zc$}LmI8{(0BqLQJI6p64AwNwaIJGP_Pa)Ye#M3o+qJ$<Jl;sX*mF<MGCYv&*L7AHu\n" \ + "zGA1*^gt?gYVN82wTbPO_W)+x<&1+cP;HrPHR>PQ;Y(X&QMK*C5^Br3bjG4d=XI^5@\n" \ + "JfH567LIG)KJdFSV\n" \ + "\n" \ + "delta 198\n" \ + "zc$}LmI8{(0BqLQJI6p64AwNwaIJGP_Pr*5}Br~;mqJ$<Jl;sX*mF<MGCYv&*L7AHu\n" \ + "zGA1*^gt?gYVN82wTbPO_W)+x<&1+cP;HrPHR>PQ;Y(X&QMK*C5^Br3bjG4d=XI^5@\n" \ + "JfH567LIF3FM2!Fd\n"; + + opts.flags = GIT_DIFF_SHOW_BINARY | GIT_DIFF_FORCE_BINARY; + opts.id_abbrev = GIT_OID_HEXSZ; + + repo = cl_git_sandbox_init("renames"); + cl_git_pass(git_repository_index(&index, repo)); + + cl_git_pass(git_futils_readbuffer(&contents, "renames/songof7cities.txt")); + + for (i = 0; i < contents.size - 6; i++) { + if (strncmp(&contents.ptr[i], "Cities", 6) == 0) + memcpy(&contents.ptr[i], "cITIES", 6); + } + + cl_git_rewritefile("renames/songof7cities.txt", contents.ptr); + cl_git_pass(git_index_add_bypath(index, "songof7cities.txt")); + cl_git_pass(git_index_write(index)); + + test_patch( + "19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13", + NULL, + &opts, + expected); + + git_index_free(index); + git_buf_free(&contents); +} + +void test_diff_binary__delta_append(void) +{ + git_index *index; + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + const char *expected = + "diff --git a/untimely.txt b/untimely.txt\n" \ + "index 9a69d960ae94b060f56c2a8702545e2bb1abb935..1111d4f11f4b35bf6759e0fb714fe09731ef0840 100644\n" \ + "GIT binary patch\n" \ + "delta 32\n" \ + "nc%1vf+QYWt3zLL@hC)e3Vu?a>QDRl4f_G*?PG(-ZA}<#J$+QbW\n" \ + "\n" \ + "delta 7\n" \ + "Oc%18D`@*{63ljhg(E~C7\n"; + + opts.flags = GIT_DIFF_SHOW_BINARY | GIT_DIFF_FORCE_BINARY; + opts.id_abbrev = GIT_OID_HEXSZ; + + repo = cl_git_sandbox_init("renames"); + cl_git_pass(git_repository_index(&index, repo)); + + cl_git_append2file("renames/untimely.txt", "Oh that crazy Kipling!\r\n"); + cl_git_pass(git_index_add_bypath(index, "untimely.txt")); + cl_git_pass(git_index_write(index)); + + test_patch( + "19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13", + NULL, + &opts, + expected); + + git_index_free(index); +} diff --git a/tests/diff/blob.c b/tests/diff/blob.c index 93f20711c..527007965 100644 --- a/tests/diff/blob.c +++ b/tests/diff/blob.c @@ -26,7 +26,7 @@ void test_diff_blob__initialize(void) g_repo = cl_git_sandbox_init("attr"); - cl_git_pass(git_diff_options_init(&opts, GIT_DIFF_OPTIONS_VERSION)); + cl_git_pass(git_diff_init_options(&opts, GIT_DIFF_OPTIONS_VERSION)); opts.context_lines = 1; memset(&expected, 0, sizeof(expected)); @@ -51,6 +51,20 @@ void test_diff_blob__cleanup(void) cl_git_sandbox_cleanup(); } +static void assert_one_modified( + int hunks, int lines, int ctxt, int adds, int dels, diff_expects *exp) +{ + cl_assert_equal_i(1, exp->files); + cl_assert_equal_i(1, exp->file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(0, exp->files_binary); + + cl_assert_equal_i(hunks, exp->hunks); + cl_assert_equal_i(lines, exp->lines); + cl_assert_equal_i(ctxt, exp->line_ctxt); + cl_assert_equal_i(adds, exp->line_adds); + cl_assert_equal_i(dels, exp->line_dels); +} + void test_diff_blob__can_compare_text_blobs(void) { git_blob *a, *b, *c; @@ -71,79 +85,81 @@ void test_diff_blob__can_compare_text_blobs(void) /* Doing the equivalent of a `git diff -U1` on these files */ /* diff on tests/resources/attr/root_test1 */ + memset(&expected, 0, sizeof(expected)); cl_git_pass(git_diff_blobs( a, NULL, b, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); + assert_one_modified(1, 6, 1, 5, 0, &expected); - cl_assert_equal_i(1, expected.files); - cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]); - cl_assert_equal_i(0, expected.files_binary); - - cl_assert_equal_i(1, expected.hunks); - cl_assert_equal_i(6, expected.lines); - cl_assert_equal_i(1, expected.line_ctxt); - cl_assert_equal_i(5, expected.line_adds); - cl_assert_equal_i(0, expected.line_dels); + /* same diff but use direct buffers */ + memset(&expected, 0, sizeof(expected)); + cl_git_pass(git_diff_buffers( + git_blob_rawcontent(a), (size_t)git_blob_rawsize(a), NULL, + git_blob_rawcontent(b), (size_t)git_blob_rawsize(b), NULL, &opts, + diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); + assert_one_modified(1, 6, 1, 5, 0, &expected); /* diff on tests/resources/attr/root_test2 */ memset(&expected, 0, sizeof(expected)); cl_git_pass(git_diff_blobs( b, NULL, c, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); - - cl_assert_equal_i(1, expected.files); - cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]); - cl_assert_equal_i(0, expected.files_binary); - - cl_assert_equal_i(1, expected.hunks); - cl_assert_equal_i(15, expected.lines); - cl_assert_equal_i(3, expected.line_ctxt); - cl_assert_equal_i(9, expected.line_adds); - cl_assert_equal_i(3, expected.line_dels); + assert_one_modified(1, 15, 3, 9, 3, &expected); /* diff on tests/resources/attr/root_test3 */ memset(&expected, 0, sizeof(expected)); cl_git_pass(git_diff_blobs( a, NULL, c, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); - - cl_assert_equal_i(1, expected.files); - cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]); - cl_assert_equal_i(0, expected.files_binary); - - cl_assert_equal_i(1, expected.hunks); - cl_assert_equal_i(13, expected.lines); - cl_assert_equal_i(0, expected.line_ctxt); - cl_assert_equal_i(12, expected.line_adds); - cl_assert_equal_i(1, expected.line_dels); + assert_one_modified(1, 13, 0, 12, 1, &expected); memset(&expected, 0, sizeof(expected)); cl_git_pass(git_diff_blobs( c, NULL, d, NULL, &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); - - cl_assert_equal_i(1, expected.files); - cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]); - cl_assert_equal_i(0, expected.files_binary); - - cl_assert_equal_i(2, expected.hunks); - cl_assert_equal_i(14, expected.lines); - cl_assert_equal_i(4, expected.line_ctxt); - cl_assert_equal_i(6, expected.line_adds); - cl_assert_equal_i(4, expected.line_dels); + assert_one_modified(2, 14, 4, 6, 4, &expected); git_blob_free(a); git_blob_free(b); git_blob_free(c); } +static void assert_patch_matches_blobs( + git_patch *p, git_blob *a, git_blob *b, + int hunks, int l0, int l1, int ctxt, int adds, int dels) +{ + const git_diff_delta *delta; + size_t tc, ta, td; + + cl_assert(p != NULL); + + delta = git_patch_get_delta(p); + cl_assert(delta != NULL); + + cl_assert_equal_i(GIT_DELTA_MODIFIED, delta->status); + cl_assert(git_oid_equal(git_blob_id(a), &delta->old_file.id)); + cl_assert_equal_sz(git_blob_rawsize(a), delta->old_file.size); + cl_assert(git_oid_equal(git_blob_id(b), &delta->new_file.id)); + cl_assert_equal_sz(git_blob_rawsize(b), delta->new_file.size); + + cl_assert_equal_i(hunks, (int)git_patch_num_hunks(p)); + + if (hunks > 0) + cl_assert_equal_i(l0, git_patch_num_lines_in_hunk(p, 0)); + if (hunks > 1) + cl_assert_equal_i(l1, git_patch_num_lines_in_hunk(p, 1)); + + cl_git_pass(git_patch_line_stats(&tc, &ta, &td, p)); + cl_assert_equal_i(ctxt, (int)tc); + cl_assert_equal_i(adds, (int)ta); + cl_assert_equal_i(dels, (int)td); +} + 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_patch *p; - const git_diff_delta *delta; - size_t tc, ta, td; /* tests/resources/attr/root_test1 */ cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8)); @@ -161,92 +177,22 @@ void test_diff_blob__can_compare_text_blobs_with_patch(void) /* diff on tests/resources/attr/root_test1 */ cl_git_pass(git_patch_from_blobs(&p, a, NULL, b, NULL, &opts)); - - cl_assert(p != NULL); - - delta = git_patch_get_delta(p); - cl_assert(delta != NULL); - cl_assert_equal_i(GIT_DELTA_MODIFIED, delta->status); - cl_assert(git_oid_equal(git_blob_id(a), &delta->old_file.oid)); - cl_assert_equal_sz(git_blob_rawsize(a), delta->old_file.size); - cl_assert(git_oid_equal(git_blob_id(b), &delta->new_file.oid)); - cl_assert_equal_sz(git_blob_rawsize(b), delta->new_file.size); - - cl_assert_equal_i(1, (int)git_patch_num_hunks(p)); - cl_assert_equal_i(6, git_patch_num_lines_in_hunk(p, 0)); - - cl_git_pass(git_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); - + assert_patch_matches_blobs(p, a, b, 1, 6, 0, 1, 5, 0); git_patch_free(p); /* diff on tests/resources/attr/root_test2 */ cl_git_pass(git_patch_from_blobs(&p, b, NULL, c, NULL, &opts)); - - cl_assert(p != NULL); - - delta = git_patch_get_delta(p); - cl_assert(delta != NULL); - cl_assert_equal_i(GIT_DELTA_MODIFIED, delta->status); - cl_assert(git_oid_equal(git_blob_id(b), &delta->old_file.oid)); - cl_assert_equal_sz(git_blob_rawsize(b), delta->old_file.size); - cl_assert(git_oid_equal(git_blob_id(c), &delta->new_file.oid)); - cl_assert_equal_sz(git_blob_rawsize(c), delta->new_file.size); - - cl_assert_equal_i(1, (int)git_patch_num_hunks(p)); - cl_assert_equal_i(15, git_patch_num_lines_in_hunk(p, 0)); - - cl_git_pass(git_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); - + assert_patch_matches_blobs(p, b, c, 1, 15, 0, 3, 9, 3); git_patch_free(p); /* diff on tests/resources/attr/root_test3 */ cl_git_pass(git_patch_from_blobs(&p, a, NULL, c, NULL, &opts)); - - cl_assert(p != NULL); - - delta = git_patch_get_delta(p); - cl_assert(delta != NULL); - cl_assert_equal_i(GIT_DELTA_MODIFIED, delta->status); - cl_assert(git_oid_equal(git_blob_id(a), &delta->old_file.oid)); - cl_assert_equal_sz(git_blob_rawsize(a), delta->old_file.size); - cl_assert(git_oid_equal(git_blob_id(c), &delta->new_file.oid)); - cl_assert_equal_sz(git_blob_rawsize(c), delta->new_file.size); - - cl_git_pass(git_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); - + assert_patch_matches_blobs(p, a, c, 1, 13, 0, 0, 12, 1); git_patch_free(p); /* one more */ cl_git_pass(git_patch_from_blobs(&p, c, NULL, d, NULL, &opts)); - - cl_assert(p != NULL); - - delta = git_patch_get_delta(p); - cl_assert(delta != NULL); - cl_assert_equal_i(GIT_DELTA_MODIFIED, delta->status); - cl_assert(git_oid_equal(git_blob_id(c), &delta->old_file.oid)); - cl_assert_equal_sz(git_blob_rawsize(c), delta->old_file.size); - cl_assert(git_oid_equal(git_blob_id(d), &delta->new_file.oid)); - cl_assert_equal_sz(git_blob_rawsize(d), delta->new_file.size); - - cl_assert_equal_i(2, (int)git_patch_num_hunks(p)); - cl_assert_equal_i(5, git_patch_num_lines_in_hunk(p, 0)); - cl_assert_equal_i(9, git_patch_num_lines_in_hunk(p, 1)); - - cl_git_pass(git_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); - + assert_patch_matches_blobs(p, c, d, 2, 5, 9, 4, 6, 4); git_patch_free(p); git_blob_free(a); @@ -328,9 +274,9 @@ void test_diff_blob__can_compare_against_null_blobs_with_patch(void) delta = git_patch_get_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_DELETED, delta->status); - cl_assert(git_oid_equal(git_blob_id(d), &delta->old_file.oid)); + cl_assert(git_oid_equal(git_blob_id(d), &delta->old_file.id)); cl_assert_equal_sz(git_blob_rawsize(d), delta->old_file.size); - cl_assert(git_oid_iszero(&delta->new_file.oid)); + cl_assert(git_oid_iszero(&delta->new_file.id)); cl_assert_equal_sz(0, delta->new_file.size); cl_assert_equal_i(1, (int)git_patch_num_hunks(p)); @@ -353,9 +299,9 @@ void test_diff_blob__can_compare_against_null_blobs_with_patch(void) delta = git_patch_get_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_ADDED, delta->status); - cl_assert(git_oid_iszero(&delta->old_file.oid)); + cl_assert(git_oid_iszero(&delta->old_file.id)); cl_assert_equal_sz(0, delta->old_file.size); - cl_assert(git_oid_equal(git_blob_id(d), &delta->new_file.oid)); + cl_assert(git_oid_equal(git_blob_id(d), &delta->new_file.id)); cl_assert_equal_sz(git_blob_rawsize(d), delta->new_file.size); cl_assert_equal_i(1, (int)git_patch_num_hunks(p)); @@ -446,9 +392,9 @@ void test_diff_blob__can_compare_identical_blobs_with_patch(void) cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_UNMODIFIED, delta->status); cl_assert_equal_sz(delta->old_file.size, git_blob_rawsize(d)); - cl_assert(git_oid_equal(git_blob_id(d), &delta->old_file.oid)); + cl_assert(git_oid_equal(git_blob_id(d), &delta->old_file.id)); cl_assert_equal_sz(delta->new_file.size, git_blob_rawsize(d)); - cl_assert(git_oid_equal(git_blob_id(d), &delta->new_file.oid)); + cl_assert(git_oid_equal(git_blob_id(d), &delta->new_file.id)); cl_assert_equal_i(0, (int)git_patch_num_hunks(p)); git_patch_free(p); @@ -460,9 +406,9 @@ void test_diff_blob__can_compare_identical_blobs_with_patch(void) cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_UNMODIFIED, delta->status); cl_assert_equal_sz(0, delta->old_file.size); - cl_assert(git_oid_iszero(&delta->old_file.oid)); + cl_assert(git_oid_iszero(&delta->old_file.id)); cl_assert_equal_sz(0, delta->new_file.size); - cl_assert(git_oid_iszero(&delta->new_file.oid)); + cl_assert(git_oid_iszero(&delta->new_file.id)); cl_assert_equal_i(0, (int)git_patch_num_hunks(p)); git_patch_free(p); @@ -656,14 +602,7 @@ void test_diff_blob__can_compare_blob_to_buffer(void) /* diff from blob a to content of b */ quick_diff_blob_to_str(a, NULL, b_content, 0, NULL); - cl_assert_equal_i(1, expected.files); - cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]); - cl_assert_equal_i(0, expected.files_binary); - cl_assert_equal_i(1, expected.hunks); - cl_assert_equal_i(6, expected.lines); - cl_assert_equal_i(1, expected.line_ctxt); - cl_assert_equal_i(5, expected.line_adds); - cl_assert_equal_i(0, expected.line_dels); + assert_one_modified(1, 6, 1, 5, 0, &expected); /* diff from blob a to content of a */ opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED; @@ -853,7 +792,7 @@ void test_diff_blob__using_path_and_attributes(void) size_t bin_len = 33; const char *changed; git_patch *p; - char *pout; + git_buf buf = GIT_BUF_INIT; /* set up custom diff drivers and 'diff' attribute mappings for them */ @@ -861,15 +800,15 @@ void test_diff_blob__using_path_and_attributes(void) cl_git_pass(git_config_set_bool(cfg, "diff.iam_binary.binary", 1)); cl_git_pass(git_config_set_bool(cfg, "diff.iam_text.binary", 0)); cl_git_pass(git_config_set_string( - cfg, "diff.iam_alphactx.xfuncname", "^[A-Za-z]")); + cfg, "diff.iam_alphactx.xfuncname", "^[A-Za-z].*$")); cl_git_pass(git_config_set_bool(cfg, "diff.iam_textalpha.binary", 0)); cl_git_pass(git_config_set_string( - cfg, "diff.iam_textalpha.xfuncname", "^[A-Za-z]")); + cfg, "diff.iam_textalpha.xfuncname", "^[A-Za-z].*$")); cl_git_pass(git_config_set_string( - cfg, "diff.iam_numctx.funcname", "^[0-9]")); + cfg, "diff.iam_numctx.funcname", "^[0-9][0-9]*")); cl_git_pass(git_config_set_bool(cfg, "diff.iam_textnum.binary", 0)); cl_git_pass(git_config_set_string( - cfg, "diff.iam_textnum.funcname", "^[0-9]")); + cfg, "diff.iam_textnum.funcname", "^[0-9][0-9]*")); git_config_free(cfg); cl_git_append2file( @@ -910,14 +849,7 @@ void test_diff_blob__using_path_and_attributes(void) changed = "Hello from the root\nMore lines\nAnd more\nGo here\n"; quick_diff_blob_to_str(nonbin, NULL, changed, 0, NULL); - cl_assert_equal_i(1, expected.files); - cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]); - cl_assert_equal_i(0, expected.files_binary); - cl_assert_equal_i(1, expected.hunks); - cl_assert_equal_i(3, expected.lines); - cl_assert_equal_i(0, expected.line_ctxt); - cl_assert_equal_i(3, expected.line_adds); - cl_assert_equal_i(0, expected.line_dels); + assert_one_modified(1, 3, 0, 3, 0, &expected); quick_diff_blob_to_str(nonbin, "foo/bar.binary", changed, 0, NULL); cl_assert_equal_i(1, expected.files); @@ -925,33 +857,16 @@ void test_diff_blob__using_path_and_attributes(void) cl_assert_equal_i(1, expected.files_binary); cl_assert_equal_i(0, expected.hunks); cl_assert_equal_i(0, expected.lines); - cl_assert_equal_i(0, expected.line_ctxt); - cl_assert_equal_i(0, expected.line_adds); - cl_assert_equal_i(0, expected.line_dels); quick_diff_blob_to_str(nonbin, "foo/bar.textary", changed, 0, NULL); - cl_assert_equal_i(1, expected.files); - cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]); - cl_assert_equal_i(0, expected.files_binary); - cl_assert_equal_i(1, expected.hunks); - cl_assert_equal_i(3, expected.lines); - cl_assert_equal_i(0, expected.line_ctxt); - cl_assert_equal_i(3, expected.line_adds); - cl_assert_equal_i(0, expected.line_dels); + assert_one_modified(1, 3, 0, 3, 0, &expected); quick_diff_blob_to_str(nonbin, "foo/bar.alphary", changed, 0, NULL); - cl_assert_equal_i(1, expected.files); - cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]); - cl_assert_equal_i(0, expected.files_binary); - cl_assert_equal_i(1, expected.hunks); - cl_assert_equal_i(3, expected.lines); - cl_assert_equal_i(0, expected.line_ctxt); - cl_assert_equal_i(3, expected.line_adds); - cl_assert_equal_i(0, expected.line_dels); + assert_one_modified(1, 3, 0, 3, 0, &expected); cl_git_pass(git_patch_from_blob_and_buffer( &p, nonbin, "zzz.normal", changed, strlen(changed), NULL, &opts)); - cl_git_pass(git_patch_to_str(&pout, p)); + cl_git_pass(git_patch_to_buf(&buf, p)); cl_assert_equal_s( "diff --git a/zzz.normal b/zzz.normal\n" "index 45141a7..75b0dbb 100644\n" @@ -960,23 +875,23 @@ void test_diff_blob__using_path_and_attributes(void) "@@ -1,0 +2,3 @@ Hello from the root\n" "+More lines\n" "+And more\n" - "+Go here\n", pout); - git__free(pout); + "+Go here\n", buf.ptr); + git_buf_clear(&buf); git_patch_free(p); cl_git_pass(git_patch_from_blob_and_buffer( &p, nonbin, "zzz.binary", changed, strlen(changed), NULL, &opts)); - cl_git_pass(git_patch_to_str(&pout, p)); + cl_git_pass(git_patch_to_buf(&buf, p)); cl_assert_equal_s( "diff --git a/zzz.binary b/zzz.binary\n" "index 45141a7..75b0dbb 100644\n" - "Binary files a/zzz.binary and b/zzz.binary differ\n", pout); - git__free(pout); + "Binary files a/zzz.binary and b/zzz.binary differ\n", buf.ptr); + git_buf_clear(&buf); git_patch_free(p); cl_git_pass(git_patch_from_blob_and_buffer( &p, nonbin, "zzz.alphary", changed, strlen(changed), NULL, &opts)); - cl_git_pass(git_patch_to_str(&pout, p)); + cl_git_pass(git_patch_to_buf(&buf, p)); cl_assert_equal_s( "diff --git a/zzz.alphary b/zzz.alphary\n" "index 45141a7..75b0dbb 100644\n" @@ -985,13 +900,13 @@ void test_diff_blob__using_path_and_attributes(void) "@@ -1,0 +2,3 @@ Hello from the root\n" "+More lines\n" "+And more\n" - "+Go here\n", pout); - git__free(pout); + "+Go here\n", buf.ptr); + git_buf_clear(&buf); git_patch_free(p); cl_git_pass(git_patch_from_blob_and_buffer( &p, nonbin, "zzz.numary", changed, strlen(changed), NULL, &opts)); - cl_git_pass(git_patch_to_str(&pout, p)); + cl_git_pass(git_patch_to_buf(&buf, p)); cl_assert_equal_s( "diff --git a/zzz.numary b/zzz.numary\n" "index 45141a7..75b0dbb 100644\n" @@ -1000,8 +915,8 @@ void test_diff_blob__using_path_and_attributes(void) "@@ -1,0 +2,3 @@\n" "+More lines\n" "+And more\n" - "+Go here\n", pout); - git__free(pout); + "+Go here\n", buf.ptr); + git_buf_clear(&buf); git_patch_free(p); /* "0123456789\n\x01\x02\x03\x04\x05\x06\x07\x08\x09\x00\n0123456789\n" @@ -1012,17 +927,17 @@ void test_diff_blob__using_path_and_attributes(void) cl_git_pass(git_patch_from_blob_and_buffer( &p, bin, "zzz.normal", changed, 37, NULL, &opts)); - cl_git_pass(git_patch_to_str(&pout, p)); + cl_git_pass(git_patch_to_buf(&buf, p)); cl_assert_equal_s( "diff --git a/zzz.normal b/zzz.normal\n" "index b435cd5..1604519 100644\n" - "Binary files a/zzz.normal and b/zzz.normal differ\n", pout); - git__free(pout); + "Binary files a/zzz.normal and b/zzz.normal differ\n", buf.ptr); + git_buf_clear(&buf); git_patch_free(p); cl_git_pass(git_patch_from_blob_and_buffer( &p, bin, "zzz.textary", changed, 37, NULL, &opts)); - cl_git_pass(git_patch_to_str(&pout, p)); + cl_git_pass(git_patch_to_buf(&buf, p)); cl_assert_equal_s( "diff --git a/zzz.textary b/zzz.textary\n" "index b435cd5..1604519 100644\n" @@ -1030,13 +945,13 @@ void test_diff_blob__using_path_and_attributes(void) "+++ b/zzz.textary\n" "@@ -3 +3 @@\n" "-0123456789\n" - "+replace a line\n", pout); - git__free(pout); + "+replace a line\n", buf.ptr); + git_buf_clear(&buf); git_patch_free(p); cl_git_pass(git_patch_from_blob_and_buffer( &p, bin, "zzz.textalphary", changed, 37, NULL, &opts)); - cl_git_pass(git_patch_to_str(&pout, p)); + cl_git_pass(git_patch_to_buf(&buf, p)); cl_assert_equal_s( "diff --git a/zzz.textalphary b/zzz.textalphary\n" "index b435cd5..1604519 100644\n" @@ -1044,13 +959,13 @@ void test_diff_blob__using_path_and_attributes(void) "+++ b/zzz.textalphary\n" "@@ -3 +3 @@\n" "-0123456789\n" - "+replace a line\n", pout); - git__free(pout); + "+replace a line\n", buf.ptr); + git_buf_clear(&buf); git_patch_free(p); cl_git_pass(git_patch_from_blob_and_buffer( &p, bin, "zzz.textnumary", changed, 37, NULL, &opts)); - cl_git_pass(git_patch_to_str(&pout, p)); + cl_git_pass(git_patch_to_buf(&buf, p)); cl_assert_equal_s( "diff --git a/zzz.textnumary b/zzz.textnumary\n" "index b435cd5..1604519 100644\n" @@ -1058,10 +973,36 @@ void test_diff_blob__using_path_and_attributes(void) "+++ b/zzz.textnumary\n" "@@ -3 +3 @@ 0123456789\n" "-0123456789\n" - "+replace a line\n", pout); - git__free(pout); + "+replace a line\n", buf.ptr); + git_buf_clear(&buf); git_patch_free(p); + git_buf_free(&buf); git_blob_free(nonbin); git_blob_free(bin); } + +void test_diff_blob__can_compare_buffer_to_buffer(void) +{ + const char *a = "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\n"; + const char *b = "a\nB\nc\nd\nE\nF\nh\nj\nk\n"; + + opts.interhunk_lines = 0; + opts.context_lines = 0; + + memset(&expected, 0, sizeof(expected)); + + cl_git_pass(git_diff_buffers( + a, strlen(a), NULL, b, strlen(b), NULL, + &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); + assert_one_modified(4, 9, 0, 4, 5, &expected); + + opts.flags ^= GIT_DIFF_REVERSE; + + memset(&expected, 0, sizeof(expected)); + + cl_git_pass(git_diff_buffers( + a, strlen(a), NULL, b, strlen(b), NULL, + &opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected)); + assert_one_modified(4, 9, 0, 5, 4, &expected); +} diff --git a/tests/diff/diff_helpers.c b/tests/diff/diff_helpers.c index 33bb561f6..279cb20c5 100644 --- a/tests/diff/diff_helpers.c +++ b/tests/diff/diff_helpers.c @@ -1,5 +1,6 @@ #include "clar_libgit2.h" #include "diff_helpers.h" +#include "git2/sys/diff.h" git_tree *resolve_commit_oid_to_tree( git_repository *repo, @@ -215,32 +216,16 @@ abort: return GIT_EUSER; } -static int diff_print_cb( - const git_diff_delta *delta, - const git_diff_hunk *hunk, - const git_diff_line *line, - void *payload) -{ - FILE *fp = payload; - - GIT_UNUSED(delta); GIT_UNUSED(hunk); - - if (line->origin == GIT_DIFF_LINE_CONTEXT || - line->origin == GIT_DIFF_LINE_ADDITION || - line->origin == GIT_DIFF_LINE_DELETION) - fputc(line->origin, fp); - fwrite(line->content, 1, line->content_len, fp); - return 0; -} - void diff_print(FILE *fp, git_diff *diff) { - cl_git_pass(git_diff_print( - diff, GIT_DIFF_FORMAT_PATCH, diff_print_cb, fp ? fp : stderr)); + cl_git_pass( + git_diff_print(diff, GIT_DIFF_FORMAT_PATCH, + git_diff_print_callback__to_file_handle, fp ? fp : stderr)); } void diff_print_raw(FILE *fp, git_diff *diff) { - cl_git_pass(git_diff_print( - diff, GIT_DIFF_FORMAT_RAW, diff_print_cb, fp ? fp : stderr)); + cl_git_pass( + git_diff_print(diff, GIT_DIFF_FORMAT_RAW, + git_diff_print_callback__to_file_handle, fp ? fp : stderr)); } diff --git a/tests/diff/diffiter.c b/tests/diff/diffiter.c index f886e1baa..c976e30e2 100644 --- a/tests/diff/diffiter.c +++ b/tests/diff/diffiter.c @@ -414,16 +414,16 @@ void test_diff_diffiter__iterate_and_generate_patch_text(void) for (d = 0; d < num_d; ++d) { git_patch *patch; - char *text; + git_buf buf = GIT_BUF_INIT; cl_git_pass(git_patch_from_diff(&patch, diff, d)); cl_assert(patch != NULL); - cl_git_pass(git_patch_to_str(&text, patch)); + cl_git_pass(git_patch_to_buf(&buf, patch)); - cl_assert_equal_s(expected_patch_text[d], text); + cl_assert_equal_s(expected_patch_text[d], buf.ptr); - git__free(text); + git_buf_free(&buf); git_patch_free(patch); } diff --git a/tests/diff/drivers.c b/tests/diff/drivers.c index fbd1dff81..8b12368ea 100644 --- a/tests/diff/drivers.c +++ b/tests/diff/drivers.c @@ -15,6 +15,23 @@ void test_diff_drivers__cleanup(void) g_repo = NULL; } +static void overwrite_filemode(const char *expected, git_buf *actual) +{ + size_t offset; + char *found; + + found = strstr(expected, "100644"); + if (!found) + return; + + offset = ((const char *)found) - expected; + if (actual->size < offset + 6) + return; + + if (memcmp(&actual->ptr[offset], "100644", 6) != 0) + memcpy(&actual->ptr[offset], "100644", 6); +} + void test_diff_drivers__patterns(void) { git_config *cfg; @@ -22,7 +39,7 @@ void test_diff_drivers__patterns(void) git_tree *one; git_diff *diff; git_patch *patch; - char *text; + git_buf actual = GIT_BUF_INIT; const char *expected0 = "diff --git a/untimely.txt b/untimely.txt\nindex 9a69d96..57fd0cf 100644\n--- a/untimely.txt\n+++ b/untimely.txt\n@@ -22,3 +22,5 @@ Comes through the blood of the vanguards who\n dreamed--too soon--it had sounded.\r\n \r\n -- Rudyard Kipling\r\n+\r\n+Some new stuff\r\n"; const char *expected1 = "diff --git a/untimely.txt b/untimely.txt\nindex 9a69d96..57fd0cf 100644\nBinary files a/untimely.txt and b/untimely.txt differ\n"; const char *expected2 = "diff --git a/untimely.txt b/untimely.txt\nindex 9a69d96..57fd0cf 100644\n--- a/untimely.txt\n+++ b/untimely.txt\n@@ -22,3 +22,5 @@ Heaven delivers on earth the Hour that cannot be\n dreamed--too soon--it had sounded.\r\n \r\n -- Rudyard Kipling\r\n+\r\n+Some new stuff\r\n"; @@ -45,10 +62,10 @@ void test_diff_drivers__patterns(void) cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); cl_git_pass(git_patch_from_diff(&patch, diff, 0)); - cl_git_pass(git_patch_to_str(&text, patch)); - cl_assert_equal_s(expected0, text); + cl_git_pass(git_patch_to_buf(&actual, patch)); + cl_assert_equal_s(expected0, actual.ptr); - git__free(text); + git_buf_free(&actual); git_patch_free(patch); git_diff_free(diff); @@ -60,10 +77,10 @@ void test_diff_drivers__patterns(void) cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); cl_git_pass(git_patch_from_diff(&patch, diff, 0)); - cl_git_pass(git_patch_to_str(&text, patch)); - cl_assert_equal_s(expected1, text); + cl_git_pass(git_patch_to_buf(&actual, patch)); + cl_assert_equal_s(expected1, actual.ptr); - git__free(text); + git_buf_free(&actual); git_patch_free(patch); git_diff_free(diff); @@ -75,10 +92,10 @@ void test_diff_drivers__patterns(void) cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); cl_git_pass(git_patch_from_diff(&patch, diff, 0)); - cl_git_pass(git_patch_to_str(&text, patch)); - cl_assert_equal_s(expected0, text); + cl_git_pass(git_patch_to_buf(&actual, patch)); + cl_assert_equal_s(expected0, actual.ptr); - git__free(text); + git_buf_free(&actual); git_patch_free(patch); git_diff_free(diff); @@ -92,10 +109,10 @@ void test_diff_drivers__patterns(void) cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); cl_git_pass(git_patch_from_diff(&patch, diff, 0)); - cl_git_pass(git_patch_to_str(&text, patch)); - cl_assert_equal_s(expected1, text); + cl_git_pass(git_patch_to_buf(&actual, patch)); + cl_assert_equal_s(expected1, actual.ptr); - git__free(text); + git_buf_free(&actual); git_patch_free(patch); git_diff_free(diff); @@ -106,17 +123,17 @@ void test_diff_drivers__patterns(void) cl_git_pass(git_repository_config(&cfg, g_repo)); cl_git_pass(git_config_set_bool(cfg, "diff.kipling0.binary", 0)); - cl_git_pass(git_config_set_string(cfg, "diff.kipling0.xfuncname", "^H")); + cl_git_pass(git_config_set_string(cfg, "diff.kipling0.xfuncname", "^H.*$")); git_config_free(cfg); cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, one, NULL)); cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); cl_git_pass(git_patch_from_diff(&patch, diff, 0)); - cl_git_pass(git_patch_to_str(&text, patch)); - cl_assert_equal_s(expected2, text); + cl_git_pass(git_patch_to_buf(&actual, patch)); + cl_assert_equal_s(expected2, actual.ptr); - git__free(text); + git_buf_free(&actual); git_patch_free(patch); git_diff_free(diff); @@ -129,7 +146,7 @@ void test_diff_drivers__long_lines(void) git_index *idx; git_diff *diff; git_patch *patch; - char *actual; + git_buf actual = GIT_BUF_INIT; const char *expected = "diff --git a/longlines.txt b/longlines.txt\nindex c1ce6ef..0134431 100644\n--- a/longlines.txt\n+++ b/longlines.txt\n@@ -3,3 +3,5 @@ Phasellus eget erat odio. Praesent at est iaculis, ultricies augue vel, dignissi\n Nam eget dolor fermentum, aliquet nisl at, convallis tellus. Pellentesque rhoncus erat enim, id porttitor elit euismod quis.\n Mauris sollicitudin magna odio, non egestas libero vehicula ut. Etiam et quam velit. Fusce eget libero rhoncus, ultricies felis sit amet, egestas purus.\n Aliquam in semper tellus. Pellentesque adipiscing rutrum velit, quis malesuada lacus consequat eget.\n+newline\n+newline\n"; g_repo = cl_git_sandbox_init("empty_standard_repo"); @@ -145,19 +162,91 @@ void test_diff_drivers__long_lines(void) cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, NULL)); cl_assert_equal_sz(1, git_diff_num_deltas(diff)); cl_git_pass(git_patch_from_diff(&patch, diff, 0)); - cl_git_pass(git_patch_to_str(&actual, patch)); + cl_git_pass(git_patch_to_buf(&actual, patch)); /* if chmod not supported, overwrite mode bits since anything is possible */ - if (!cl_is_chmod_supported()) { - size_t actual_len = strlen(actual); - if (actual_len > 72 && memcmp(&actual[66], "100644", 6) != 0) - memcpy(&actual[66], "100644", 6); - } + overwrite_filemode(expected, &actual); - cl_assert_equal_s(expected, actual); + cl_assert_equal_s(expected, actual.ptr); - free(actual); + git_buf_free(&actual); git_patch_free(patch); git_diff_free(diff); } +void test_diff_drivers__builtins(void) +{ + git_diff *diff; + git_patch *patch; + git_buf file = GIT_BUF_INIT, actual = GIT_BUF_INIT, expected = GIT_BUF_INIT; + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_vector files = GIT_VECTOR_INIT; + size_t i; + char *path, *extension; + + g_repo = cl_git_sandbox_init("userdiff"); + + cl_git_pass(git_path_dirload("userdiff/files", 9, 0, 0, &files)); + + opts.interhunk_lines = 1; + opts.context_lines = 1; + opts.pathspec.count = 1; + + git_vector_foreach(&files, i, path) { + if (git__prefixcmp(path, "files/file.")) + continue; + extension = path + strlen("files/file."); + opts.pathspec.strings = &path; + + /* do diff with no special driver */ + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + cl_assert_equal_sz(1, git_diff_num_deltas(diff)); + cl_git_pass(git_patch_from_diff(&patch, diff, 0)); + cl_git_pass(git_patch_to_buf(&actual, patch)); + + git_buf_sets(&expected, "userdiff/expected/nodriver/diff."); + git_buf_puts(&expected, extension); + cl_git_pass(git_futils_readbuffer(&expected, expected.ptr)); + + overwrite_filemode(expected.ptr, &actual); + + cl_assert_equal_s(expected.ptr, actual.ptr); + + git_buf_clear(&actual); + git_patch_free(patch); + git_diff_free(diff); + + /* do diff with driver */ + + { + FILE *fp = fopen("userdiff/.gitattributes", "w"); + fprintf(fp, "*.%s diff=%s\n", extension, extension); + fclose(fp); + } + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + cl_assert_equal_sz(1, git_diff_num_deltas(diff)); + cl_git_pass(git_patch_from_diff(&patch, diff, 0)); + cl_git_pass(git_patch_to_buf(&actual, patch)); + + git_buf_sets(&expected, "userdiff/expected/driver/diff."); + git_buf_puts(&expected, extension); + cl_git_pass(git_futils_readbuffer(&expected, expected.ptr)); + + overwrite_filemode(expected.ptr, &actual); + + cl_assert_equal_s(expected.ptr, actual.ptr); + + git_buf_clear(&actual); + git_patch_free(patch); + git_diff_free(diff); + + git__free(path); + } + + git_buf_free(&file); + git_buf_free(&actual); + git_buf_free(&expected); + git_vector_free(&files); +} diff --git a/tests/diff/format_email.c b/tests/diff/format_email.c new file mode 100644 index 000000000..18ad99bd5 --- /dev/null +++ b/tests/diff/format_email.c @@ -0,0 +1,467 @@ +#include "clar.h" +#include "clar_libgit2.h" + +#include "buffer.h" +#include "commit.h" +#include "diff.h" + +static git_repository *repo; + +void test_diff_format_email__initialize(void) +{ + repo = cl_git_sandbox_init("diff_format_email"); +} + +void test_diff_format_email__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +static void assert_email_match( + const char *expected, + const char *oidstr, + git_diff_format_email_options *opts) +{ + git_oid oid; + git_commit *commit = NULL; + git_diff *diff = NULL; + git_buf buf = GIT_BUF_INIT; + + git_oid_fromstr(&oid, oidstr); + + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + + opts->id = git_commit_id(commit); + opts->author = git_commit_author(commit); + if (!opts->summary) + opts->summary = git_commit_summary(commit); + + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + cl_git_pass(git_diff_format_email(&buf, diff, opts)); + + cl_assert_equal_s(expected, git_buf_cstr(&buf)); + git_buf_clear(&buf); + + cl_git_pass(git_diff_commit_as_email( + &buf, repo, commit, 1, 1, opts->flags, NULL)); + cl_assert_equal_s(expected, git_buf_cstr(&buf)); + + git_diff_free(diff); + git_commit_free(commit); + git_buf_free(&buf); +} + +void test_diff_format_email__simple(void) +{ + git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; + const char *email = + "From 9264b96c6d104d0e07ae33d3007b6a48246c6f92 Mon Sep 17 00:00:00 2001\n" \ + "From: Jacques Germishuys <jacquesg@striata.com>\n" \ + "Date: Wed, 9 Apr 2014 20:57:01 +0200\n" \ + "Subject: [PATCH] Modify some content\n" \ + "\n" \ + "---\n" \ + " file1.txt | 8 +++++---\n" \ + " 1 file changed, 5 insertions(+), 3 deletions(-)\n" \ + "\n" \ + "diff --git a/file1.txt b/file1.txt\n" \ + "index 94aaae8..af8f41d 100644\n" \ + "--- a/file1.txt\n" \ + "+++ b/file1.txt\n" \ + "@@ -1,15 +1,17 @@\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + "+_file1.txt_\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + "+\n" \ + "+\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "+_file1.txt_\n" \ + "+_file1.txt_\n" \ + " file1.txt\n" \ + "--\n" \ + "libgit2 " LIBGIT2_VERSION "\n" \ + "\n"; + + assert_email_match( + email, "9264b96c6d104d0e07ae33d3007b6a48246c6f92", &opts); +} + +void test_diff_format_email__multiple(void) +{ + git_oid oid; + git_commit *commit = NULL; + git_diff *diff = NULL; + git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; + git_buf buf = GIT_BUF_INIT; + + const char *email = + "From 10808fe9c9be5a190c0ba68d1a002233fb363508 Mon Sep 17 00:00:00 2001\n" \ + "From: Jacques Germishuys <jacquesg@striata.com>\n" \ + "Date: Thu, 10 Apr 2014 19:37:05 +0200\n" \ + "Subject: [PATCH 1/2] Added file2.txt file3.txt\n" \ + "\n" \ + "---\n" \ + " file2.txt | 5 +++++\n" \ + " file3.txt | 5 +++++\n" \ + " 2 files changed, 10 insertions(+), 0 deletions(-)\n" \ + " create mode 100644 file2.txt\n" \ + " create mode 100644 file3.txt\n" \ + "\n" \ + "diff --git a/file2.txt b/file2.txt\n" \ + "new file mode 100644\n" \ + "index 0000000..e909123\n" \ + "--- /dev/null\n" \ + "+++ b/file2.txt\n" \ + "@@ -0,0 +1,5 @@\n" \ + "+file2\n" \ + "+file2\n" \ + "+file2\n" \ + "+file2\n" \ + "+file2\n" \ + "diff --git a/file3.txt b/file3.txt\n" \ + "new file mode 100644\n" \ + "index 0000000..9435022\n" \ + "--- /dev/null\n" \ + "+++ b/file3.txt\n" \ + "@@ -0,0 +1,5 @@\n" \ + "+file3\n" \ + "+file3\n" \ + "+file3\n" \ + "+file3\n" \ + "+file3\n" \ + "--\n" \ + "libgit2 " LIBGIT2_VERSION "\n" \ + "\n" \ + "From 873806f6f27e631eb0b23e4b56bea2bfac14a373 Mon Sep 17 00:00:00 2001\n" \ + "From: Jacques Germishuys <jacquesg@striata.com>\n" \ + "Date: Thu, 10 Apr 2014 19:37:36 +0200\n" \ + "Subject: [PATCH 2/2] Modified file2.txt, file3.txt\n" \ + "\n" \ + "---\n" \ + " file2.txt | 2 +-\n" \ + " file3.txt | 2 +-\n" \ + " 2 files changed, 2 insertions(+), 2 deletions(-)\n" \ + "\n" \ + "diff --git a/file2.txt b/file2.txt\n" \ + "index e909123..7aff11d 100644\n" \ + "--- a/file2.txt\n" \ + "+++ b/file2.txt\n" \ + "@@ -1,5 +1,5 @@\n" \ + " file2\n" \ + " file2\n" \ + " file2\n" \ + "-file2\n" \ + "+file2!\n" \ + " file2\n" \ + "diff --git a/file3.txt b/file3.txt\n" \ + "index 9435022..9a2d780 100644\n" \ + "--- a/file3.txt\n" \ + "+++ b/file3.txt\n" \ + "@@ -1,5 +1,5 @@\n" \ + " file3\n" \ + "-file3\n" \ + "+file3!\n" \ + " file3\n" \ + " file3\n" \ + " file3\n" \ + "--\n" \ + "libgit2 " LIBGIT2_VERSION "\n" \ + "\n"; + + + git_oid_fromstr(&oid, "10808fe9c9be5a190c0ba68d1a002233fb363508"); + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + + opts.id = git_commit_id(commit); + opts.author = git_commit_author(commit); + opts.summary = git_commit_summary(commit); + opts.patch_no = 1; + opts.total_patches = 2; + + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + cl_git_pass(git_diff_format_email(&buf, diff, &opts)); + + git_diff_free(diff); + git_commit_free(commit); + diff = NULL; + commit = NULL; + + git_oid_fromstr(&oid, "873806f6f27e631eb0b23e4b56bea2bfac14a373"); + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + + opts.id = git_commit_id(commit); + opts.author = git_commit_author(commit); + opts.summary = git_commit_summary(commit); + opts.patch_no = 2; + opts.total_patches = 2; + + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + cl_git_pass(git_diff_format_email(&buf, diff, &opts)); + + cl_assert_equal_s(email, git_buf_cstr(&buf)); + + git_diff_free(diff); + git_commit_free(commit); + git_buf_free(&buf); +} + +void test_diff_format_email__exclude_marker(void) +{ + git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; + const char *email = + "From 9264b96c6d104d0e07ae33d3007b6a48246c6f92 Mon Sep 17 00:00:00 2001\n" \ + "From: Jacques Germishuys <jacquesg@striata.com>\n" \ + "Date: Wed, 9 Apr 2014 20:57:01 +0200\n" \ + "Subject: Modify some content\n" \ + "\n" \ + "---\n" \ + " file1.txt | 8 +++++---\n" \ + " 1 file changed, 5 insertions(+), 3 deletions(-)\n" \ + "\n" \ + "diff --git a/file1.txt b/file1.txt\n" \ + "index 94aaae8..af8f41d 100644\n" \ + "--- a/file1.txt\n" \ + "+++ b/file1.txt\n" \ + "@@ -1,15 +1,17 @@\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + "+_file1.txt_\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + "+\n" \ + "+\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "+_file1.txt_\n" \ + "+_file1.txt_\n" \ + " file1.txt\n" \ + "--\n" \ + "libgit2 " LIBGIT2_VERSION "\n" \ + "\n"; + + opts.flags |= GIT_DIFF_FORMAT_EMAIL_EXCLUDE_SUBJECT_PATCH_MARKER; + + assert_email_match( + email, "9264b96c6d104d0e07ae33d3007b6a48246c6f92", &opts); +} + +void test_diff_format_email__invalid_no(void) +{ + git_oid oid; + git_commit *commit = NULL; + git_diff *diff = NULL; + git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; + git_buf buf = GIT_BUF_INIT; + + git_oid_fromstr(&oid, "9264b96c6d104d0e07ae33d3007b6a48246c6f92"); + + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + + opts.id = git_commit_id(commit); + opts.author = git_commit_author(commit); + opts.summary = git_commit_summary(commit); + opts.patch_no = 2; + opts.total_patches = 1; + + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + cl_git_fail(git_diff_format_email(&buf, diff, &opts)); + cl_git_fail(git_diff_commit_as_email(&buf, repo, commit, 2, 1, 0, NULL)); + cl_git_fail(git_diff_commit_as_email(&buf, repo, commit, 0, 0, 0, NULL)); + + git_diff_free(diff); + git_commit_free(commit); + git_buf_free(&buf); +} + +void test_diff_format_email__mode_change(void) +{ + git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; + const char *email = + "From 7ade76dd34bba4733cf9878079f9fd4a456a9189 Mon Sep 17 00:00:00 2001\n" \ + "From: Jacques Germishuys <jacquesg@striata.com>\n" \ + "Date: Thu, 10 Apr 2014 10:05:03 +0200\n" \ + "Subject: [PATCH] Update permissions\n" \ + "\n" \ + "---\n" \ + " file1.txt.renamed | 0\n" \ + " 1 file changed, 0 insertions(+), 0 deletions(-)\n" \ + " mode change 100644 => 100755 file1.txt.renamed\n" \ + "\n" \ + "diff --git a/file1.txt.renamed b/file1.txt.renamed\n" \ + "old mode 100644\n" \ + "new mode 100755\n" \ + "index a97157a..a97157a\n" \ + "--- a/file1.txt.renamed\n" \ + "+++ b/file1.txt.renamed\n" \ + "--\n" \ + "libgit2 " LIBGIT2_VERSION "\n" \ + "\n"; + + assert_email_match( + email, "7ade76dd34bba4733cf9878079f9fd4a456a9189", &opts); +} + +void test_diff_format_email__rename_add_remove(void) +{ + git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; + const char *email = + "From 6e05acc5a5dab507d91a0a0cc0fb05a3dd98892d Mon Sep 17 00:00:00 2001\n" \ + "From: Jacques Germishuys <jacquesg@striata.com>\n" \ + "Date: Wed, 9 Apr 2014 21:15:56 +0200\n" \ + "Subject: [PATCH] Renamed file1.txt -> file1.txt.renamed\n" \ + "\n" \ + "---\n" \ + " file1.txt | 17 -----------------\n" \ + " file1.txt.renamed | 17 +++++++++++++++++\n" \ + " 2 files changed, 17 insertions(+), 17 deletions(-)\n" \ + " delete mode 100644 file1.txt\n" \ + " create mode 100644 file1.txt.renamed\n" \ + "\n" \ + "diff --git a/file1.txt b/file1.txt\n" \ + "deleted file mode 100644\n" \ + "index af8f41d..0000000\n" \ + "--- a/file1.txt\n" \ + "+++ /dev/null\n" \ + "@@ -1,17 +0,0 @@\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "-_file1.txt_\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "-\n" \ + "-\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "-_file1.txt_\n" \ + "-_file1.txt_\n" \ + "-file1.txt\n" \ + "diff --git a/file1.txt.renamed b/file1.txt.renamed\n" \ + "new file mode 100644\n" \ + "index 0000000..a97157a\n" \ + "--- /dev/null\n" \ + "+++ b/file1.txt.renamed\n" \ + "@@ -0,0 +1,17 @@\n" \ + "+file1.txt\n" \ + "+file1.txt\n" \ + "+_file1.txt_\n" \ + "+file1.txt\n" \ + "+file1.txt\n" \ + "+file1.txt_renamed\n" \ + "+file1.txt\n" \ + "+\n" \ + "+\n" \ + "+file1.txt\n" \ + "+file1.txt\n" \ + "+file1.txt_renamed\n" \ + "+file1.txt\n" \ + "+file1.txt\n" \ + "+_file1.txt_\n" \ + "+_file1.txt_\n" \ + "+file1.txt\n" \ + "--\n" \ + "libgit2 " LIBGIT2_VERSION "\n" \ + "\n"; + + assert_email_match( + email, "6e05acc5a5dab507d91a0a0cc0fb05a3dd98892d", &opts); +} + +void test_diff_format_email__multiline_summary(void) +{ + git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; + const char *email = + "From 9264b96c6d104d0e07ae33d3007b6a48246c6f92 Mon Sep 17 00:00:00 2001\n" \ + "From: Jacques Germishuys <jacquesg@striata.com>\n" \ + "Date: Wed, 9 Apr 2014 20:57:01 +0200\n" \ + "Subject: [PATCH] Modify some content\n" \ + "\n" \ + "---\n" \ + " file1.txt | 8 +++++---\n" \ + " 1 file changed, 5 insertions(+), 3 deletions(-)\n" \ + "\n" \ + "diff --git a/file1.txt b/file1.txt\n" \ + "index 94aaae8..af8f41d 100644\n" \ + "--- a/file1.txt\n" \ + "+++ b/file1.txt\n" \ + "@@ -1,15 +1,17 @@\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + "+_file1.txt_\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + "+\n" \ + "+\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "+_file1.txt_\n" \ + "+_file1.txt_\n" \ + " file1.txt\n" \ + "--\n" \ + "libgit2 " LIBGIT2_VERSION "\n" \ + "\n"; + + opts.summary = "Modify some content\nSome extra stuff here"; + + assert_email_match( + email, "9264b96c6d104d0e07ae33d3007b6a48246c6f92", &opts); +} + +void test_diff_format_email__binary(void) +{ + git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; + const char *email = + "From 8d7523f6fcb2404257889abe0d96f093d9f524f9 Mon Sep 17 00:00:00 2001\n" \ + "From: Jacques Germishuys <jacquesg@striata.com>\n" \ + "Date: Sun, 13 Apr 2014 18:10:18 +0200\n" \ + "Subject: [PATCH] Modified binary file\n" \ + "\n" \ + "---\n" \ + " binary.bin | Bin 3 -> 0 bytes\n" \ + " 1 file changed, 0 insertions(+), 0 deletions(-)\n" \ + "\n" \ + "diff --git a/binary.bin b/binary.bin\n" \ + "index bd474b2..9ac35ff 100644\n" \ + "Binary files a/binary.bin and b/binary.bin differ\n" \ + "--\n" \ + "libgit2 " LIBGIT2_VERSION "\n" \ + "\n"; + /* TODO: Actually 0 bytes here should be 5!. Seems like we don't load the new content for binary files? */ + + opts.summary = "Modified binary file"; + + assert_email_match( + email, "8d7523f6fcb2404257889abe0d96f093d9f524f9", &opts); +} + diff --git a/tests/diff/index.c b/tests/diff/index.c index 8f4567137..21afe8da2 100644 --- a/tests/diff/index.c +++ b/tests/diff/index.c @@ -128,9 +128,7 @@ void test_diff_index__1(void) cl_git_pass(git_diff_tree_to_index(&diff, g_repo, a, NULL, &opts)); cl_assert_equal_i( - GIT_EUSER, - git_diff_foreach(diff, diff_stop_after_2_files, NULL, NULL, &exp) - ); + 1, git_diff_foreach(diff, diff_stop_after_2_files, NULL, NULL, &exp) ); cl_assert_equal_i(2, exp.files); diff --git a/tests/diff/iterator.c b/tests/diff/iterator.c index bbdae8ad1..a2df1c7a7 100644 --- a/tests/diff/iterator.c +++ b/tests/diff/iterator.c @@ -355,6 +355,7 @@ static void index_iterator_test( const char *sandbox, const char *start, const char *end, + git_iterator_flag_t flags, int expected_count, const char **expected_names, const char **expected_oids) @@ -362,11 +363,13 @@ static void index_iterator_test( git_index *index; git_iterator *i; const git_index_entry *entry; - int error, count = 0; + int error, count = 0, caps; git_repository *repo = cl_git_sandbox_init(sandbox); cl_git_pass(git_repository_index(&index, repo)); - cl_git_pass(git_iterator_for_index(&i, index, 0, start, end)); + caps = git_index_caps(index); + + cl_git_pass(git_iterator_for_index(&i, index, flags, start, end)); while (!(error = git_iterator_advance(&entry, i))) { cl_assert(entry); @@ -377,7 +380,7 @@ static void index_iterator_test( if (expected_oids != NULL) { git_oid oid; cl_git_pass(git_oid_fromstr(&oid, expected_oids[count])); - cl_assert_equal_i(git_oid_cmp(&oid, &entry->oid), 0); + cl_assert_equal_i(git_oid_cmp(&oid, &entry->id), 0); } count++; @@ -388,6 +391,8 @@ static void index_iterator_test( cl_assert_equal_i(expected_count, count); git_iterator_free(i); + + cl_assert(caps == git_index_caps(index)); git_index_free(index); } @@ -446,7 +451,8 @@ static const char *expected_index_oids_0[] = { void test_diff_iterator__index_0(void) { index_iterator_test( - "attr", NULL, NULL, 23, expected_index_0, expected_index_oids_0); + "attr", NULL, NULL, 0, ARRAY_SIZE(expected_index_0), + expected_index_0, expected_index_oids_0); } static const char *expected_index_range[] = { @@ -466,25 +472,26 @@ static const char *expected_index_oids_range[] = { void test_diff_iterator__index_range(void) { index_iterator_test( - "attr", "root", "root", 4, expected_index_range, expected_index_oids_range); + "attr", "root", "root", 0, ARRAY_SIZE(expected_index_range), + expected_index_range, expected_index_oids_range); } void test_diff_iterator__index_range_empty_0(void) { index_iterator_test( - "attr", "empty", "empty", 0, NULL, NULL); + "attr", "empty", "empty", 0, 0, NULL, NULL); } void test_diff_iterator__index_range_empty_1(void) { index_iterator_test( - "attr", "z_empty_after", NULL, 0, NULL, NULL); + "attr", "z_empty_after", NULL, 0, 0, NULL, NULL); } void test_diff_iterator__index_range_empty_2(void) { index_iterator_test( - "attr", NULL, ".aaa_empty_before", 0, NULL, NULL); + "attr", NULL, ".aaa_empty_before", 0, 0, NULL, NULL); } static const char *expected_index_1[] = { @@ -522,9 +529,45 @@ static const char* expected_index_oids_1[] = { void test_diff_iterator__index_1(void) { index_iterator_test( - "status", NULL, NULL, 13, expected_index_1, expected_index_oids_1); + "status", NULL, NULL, 0, ARRAY_SIZE(expected_index_1), + expected_index_1, expected_index_oids_1); } +static const char *expected_index_cs[] = { + "B", "D", "F", "H", "J", "L/1", "L/B", "L/D", "L/a", "L/c", + "a", "c", "e", "g", "i", "k/1", "k/B", "k/D", "k/a", "k/c", +}; + +static const char *expected_index_ci[] = { + "a", "B", "c", "D", "e", "F", "g", "H", "i", "J", + "k/1", "k/a", "k/B", "k/c", "k/D", "L/1", "L/a", "L/B", "L/c", "L/D", +}; + +void test_diff_iterator__index_case_folding(void) +{ + git_buf path = GIT_BUF_INIT; + int fs_is_ci = 0; + + cl_git_pass(git_buf_joinpath(&path, cl_fixture("icase"), ".gitted/CoNfIg")); + fs_is_ci = git_path_exists(path.ptr); + git_buf_free(&path); + + index_iterator_test( + "icase", NULL, NULL, 0, ARRAY_SIZE(expected_index_cs), + fs_is_ci ? expected_index_ci : expected_index_cs, NULL); + + cl_git_sandbox_cleanup(); + + index_iterator_test( + "icase", NULL, NULL, GIT_ITERATOR_IGNORE_CASE, + ARRAY_SIZE(expected_index_ci), expected_index_ci, NULL); + + cl_git_sandbox_cleanup(); + + index_iterator_test( + "icase", NULL, NULL, GIT_ITERATOR_DONT_IGNORE_CASE, + ARRAY_SIZE(expected_index_cs), expected_index_cs, NULL); +} /* -- WORKDIR ITERATOR TESTS -- */ @@ -604,7 +647,7 @@ static void workdir_iterator_test( void test_diff_iterator__workdir_0(void) { - workdir_iterator_test("attr", NULL, NULL, 27, 1, NULL, "ign"); + workdir_iterator_test("attr", NULL, NULL, 23, 5, NULL, "ign"); } static const char *status_paths[] = { @@ -737,13 +780,13 @@ void test_diff_iterator__workdir_builtin_ignores(void) { "root_test2", false }, { "root_test3", false }, { "root_test4.txt", false }, - { "sub", false }, + { "sub/", false }, { "sub/.gitattributes", false }, { "sub/abc", false }, { "sub/dir/", true }, { "sub/file", false }, { "sub/ign/", true }, - { "sub/sub", false }, + { "sub/sub/", false }, { "sub/sub/.gitattributes", false }, { "sub/sub/dir", false }, /* file is not actually a dir */ { "sub/sub/file", false }, diff --git a/tests/diff/notify.c b/tests/diff/notify.c index cc33cb71c..da7390d3f 100644 --- a/tests/diff/notify.c +++ b/tests/diff/notify.c @@ -20,7 +20,7 @@ static int assert_called_notifications( { bool found = false; notify_expected *exp = (notify_expected*)payload; - notify_expected *e;; + notify_expected *e; GIT_UNUSED(diff_so_far); @@ -182,10 +182,12 @@ void test_diff_notify__notify_cb_can_abort_diff(void) opts.pathspec.count = 1; pathspec = "file_deleted"; - cl_git_fail(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + cl_git_fail_with( + git_diff_index_to_workdir(&diff, g_repo, NULL, &opts), -42); pathspec = "staged_changes_modified_file"; - cl_git_fail(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + cl_git_fail_with( + git_diff_index_to_workdir(&diff, g_repo, NULL, &opts), -42); } static int filter_all( diff --git a/tests/diff/patch.c b/tests/diff/patch.c index bd1598b21..1184d1968 100644 --- a/tests/diff/patch.c +++ b/tests/diff/patch.c @@ -2,6 +2,7 @@ #include "git2/sys/repository.h" #include "diff_helpers.h" +#include "diff.h" #include "repository.h" #include "buf_text.h" @@ -30,8 +31,6 @@ static int check_removal_cb( const git_diff_line *line, void *payload) { - GIT_UNUSED(payload); - switch (line->origin) { case GIT_DIFF_LINE_FILE_HDR: cl_assert_equal_s(EXPECTED_HEADER, line->content); @@ -40,10 +39,12 @@ static int check_removal_cb( case GIT_DIFF_LINE_HUNK_HDR: cl_assert_equal_s(EXPECTED_HUNK, line->content); - /* Fall through */ + goto check_hunk; case GIT_DIFF_LINE_CONTEXT: case GIT_DIFF_LINE_DELETION: + if (payload != NULL) + return *(int *)payload; goto check_hunk; default: @@ -101,6 +102,39 @@ void test_diff_patch__can_properly_display_the_removal_of_a_file(void) git_tree_free(one); } +void test_diff_patch__can_cancel_diff_print(void) +{ + const char *one_sha = "26a125e"; + const char *another_sha = "735b6a2"; + git_tree *one, *another; + git_diff *diff; + int fail_with; + + g_repo = cl_git_sandbox_init("status"); + + one = resolve_commit_oid_to_tree(g_repo, one_sha); + another = resolve_commit_oid_to_tree(g_repo, another_sha); + + cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, one, another, NULL)); + + fail_with = -2323; + + cl_git_fail_with(git_diff_print( + diff, GIT_DIFF_FORMAT_PATCH, check_removal_cb, &fail_with), + fail_with); + + fail_with = 45; + + cl_git_fail_with(git_diff_print( + diff, GIT_DIFF_FORMAT_PATCH, check_removal_cb, &fail_with), + fail_with); + + git_diff_free(diff); + + git_tree_free(another); + git_tree_free(one); +} + void test_diff_patch__to_string(void) { const char *one_sha = "26a125e"; @@ -108,7 +142,7 @@ void test_diff_patch__to_string(void) git_tree *one, *another; git_diff *diff; git_patch *patch; - char *text; + git_buf buf = GIT_BUF_INIT; const char *expected = "diff --git a/subdir.txt b/subdir.txt\ndeleted file mode 100644\nindex e8ee89e..0000000\n--- a/subdir.txt\n+++ /dev/null\n@@ -1,2 +0,0 @@\n-Is it a bird?\n-Is it a plane?\n"; g_repo = cl_git_sandbox_init("status"); @@ -122,16 +156,16 @@ void test_diff_patch__to_string(void) cl_git_pass(git_patch_from_diff(&patch, diff, 0)); - cl_git_pass(git_patch_to_str(&text, patch)); + cl_git_pass(git_patch_to_buf(&buf, patch)); - cl_assert_equal_s(expected, text); + cl_assert_equal_s(expected, buf.ptr); cl_assert_equal_sz(31, git_patch_size(patch, 0, 0, 0)); cl_assert_equal_sz(31, git_patch_size(patch, 1, 0, 0)); cl_assert_equal_sz(31 + 16, git_patch_size(patch, 1, 1, 0)); cl_assert_equal_sz(strlen(expected), git_patch_size(patch, 1, 1, 1)); - git__free(text); + git_buf_free(&buf); git_patch_free(patch); git_diff_free(diff); git_tree_free(another); @@ -145,7 +179,7 @@ void test_diff_patch__config_options(void) git_config *cfg; git_diff *diff; git_patch *patch; - char *text; + git_buf buf = GIT_BUF_INIT; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; char *onefile = "staged_changes_modified_file"; const char *expected1 = "diff --git c/staged_changes_modified_file i/staged_changes_modified_file\nindex 70bd944..906ee77 100644\n--- c/staged_changes_modified_file\n+++ i/staged_changes_modified_file\n@@ -1 +1,2 @@\n staged_changes_modified_file\n+staged_changes_modified_file\n"; @@ -166,10 +200,10 @@ void test_diff_patch__config_options(void) cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); cl_git_pass(git_patch_from_diff(&patch, diff, 0)); - cl_git_pass(git_patch_to_str(&text, patch)); - cl_assert_equal_s(expected1, text); + cl_git_pass(git_patch_to_buf(&buf, patch)); + cl_assert_equal_s(expected1, buf.ptr); - git__free(text); + git_buf_clear(&buf); git_patch_free(patch); git_diff_free(diff); @@ -177,10 +211,10 @@ void test_diff_patch__config_options(void) cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); cl_git_pass(git_patch_from_diff(&patch, diff, 0)); - cl_git_pass(git_patch_to_str(&text, patch)); - cl_assert_equal_s(expected2, text); + cl_git_pass(git_patch_to_buf(&buf, patch)); + cl_assert_equal_s(expected2, buf.ptr); - git__free(text); + git_buf_clear(&buf); git_patch_free(patch); git_diff_free(diff); @@ -191,10 +225,10 @@ void test_diff_patch__config_options(void) cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); cl_git_pass(git_patch_from_diff(&patch, diff, 0)); - cl_git_pass(git_patch_to_str(&text, patch)); - cl_assert_equal_s(expected3, text); + cl_git_pass(git_patch_to_buf(&buf, patch)); + cl_assert_equal_s(expected3, buf.ptr); - git__free(text); + git_buf_clear(&buf); git_patch_free(patch); git_diff_free(diff); @@ -205,13 +239,14 @@ void test_diff_patch__config_options(void) cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); cl_git_pass(git_patch_from_diff(&patch, diff, 0)); - cl_git_pass(git_patch_to_str(&text, patch)); - cl_assert_equal_s(expected4, text); + cl_git_pass(git_patch_to_buf(&buf, patch)); + cl_assert_equal_s(expected4, buf.ptr); - git__free(text); + git_buf_clear(&buf); git_patch_free(patch); git_diff_free(diff); + git_buf_free(&buf); git_tree_free(one); git_config_free(cfg); } @@ -432,10 +467,10 @@ static void check_single_patch_stats( cl_assert_equal_sz(dels, actual_dels); if (expected != NULL) { - char *text; - cl_git_pass(git_patch_to_str(&text, patch)); - cl_assert_equal_s(expected, text); - git__free(text); + git_buf buf = GIT_BUF_INIT; + cl_git_pass(git_patch_to_buf(&buf, patch)); + cl_assert_equal_s(expected, buf.ptr); + git_buf_free(&buf); cl_assert_equal_sz( strlen(expected), git_patch_size(patch, 1, 1, 1)); diff --git a/tests/diff/rename.c b/tests/diff/rename.c index 42bb65aa8..4bc3eb54c 100644 --- a/tests/diff/rename.c +++ b/tests/diff/rename.c @@ -111,6 +111,28 @@ void test_diff_rename__match_oid(void) git_diff_free(diff); + cl_git_pass(git_diff_tree_to_tree( + &diff, g_repo, old_tree, new_tree, &diffopts)); + + /* git diff --find-copies-harder -M100 -B100 \ + * 31e47d8c1fa36d7f8d537b96158e3f024de0a9f2 \ + * 2bc7f351d20b53f1c72c16c4b036e491c478c49a + */ + opts.flags = GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED | + 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(3, exp.files); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNMODIFIED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_COPIED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_RENAMED]); + + git_diff_free(diff); + git_tree_free(old_tree); git_tree_free(new_tree); } @@ -562,7 +584,7 @@ void test_diff_rename__patch(void) git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; git_patch *patch; const git_diff_delta *delta; - char *text; + git_buf buf = GIT_BUF_INIT; const char *expected = "diff --git a/sixserving.txt b/ikeepsix.txt\nindex ad0a8e5..36020db 100644\n--- a/sixserving.txt\n+++ b/ikeepsix.txt\n@@ -1,3 +1,6 @@\n+I Keep Six Honest Serving-Men\n+=============================\n+\n I KEEP six honest serving-men\n (They taught me all I knew);\n Their names are What and Why and When\n@@ -21,4 +24,4 @@ She sends'em abroad on her own affairs,\n One million Hows, two million Wheres,\n And seven million Whys!\n \n- -- Rudyard Kipling\n+ -- Rudyard Kipling\n"; old_tree = resolve_commit_oid_to_tree(g_repo, sha0); @@ -588,9 +610,9 @@ void test_diff_rename__patch(void) cl_assert((delta = git_patch_get_delta(patch)) != NULL); cl_assert_equal_i(GIT_DELTA_COPIED, (int)delta->status); - cl_git_pass(git_patch_to_str(&text, patch)); - cl_assert_equal_s(expected, text); - git__free(text); + cl_git_pass(git_patch_to_buf(&buf, patch)); + cl_assert_equal_s(expected, buf.ptr); + git_buf_free(&buf); git_patch_free(patch); @@ -907,7 +929,7 @@ void test_diff_rename__rejected_match_can_match_others(void) git_reference *head, *selfsimilar; git_index *index; git_tree *tree; - git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; + git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; git_diff *diff; git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; git_diff_find_options findopts = GIT_DIFF_FIND_OPTIONS_INIT; @@ -919,10 +941,11 @@ void test_diff_rename__rejected_match_can_match_others(void) char *ptr; opts.checkout_strategy = GIT_CHECKOUT_FORCE; + findopts.flags = GIT_DIFF_FIND_RENAMES; cl_git_pass(git_reference_lookup(&head, g_repo, "HEAD")); cl_git_pass(git_reference_symbolic_set_target( - &selfsimilar, head, "refs/heads/renames_similar")); + &selfsimilar, head, "refs/heads/renames_similar", NULL, NULL)); cl_git_pass(git_checkout_head(g_repo, &opts)); cl_git_pass(git_repository_index(&index, g_repo)); @@ -993,7 +1016,7 @@ void test_diff_rename__rejected_match_can_match_others_two(void) git_reference *head, *selfsimilar; git_index *index; git_tree *tree; - git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; + git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; git_diff *diff; git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; git_diff_find_options findopts = GIT_DIFF_FIND_OPTIONS_INIT; @@ -1003,10 +1026,11 @@ void test_diff_rename__rejected_match_can_match_others_two(void) struct rename_expected expect = { 2, status, sources, targets }; opts.checkout_strategy = GIT_CHECKOUT_FORCE; + findopts.flags = GIT_DIFF_FIND_RENAMES; cl_git_pass(git_reference_lookup(&head, g_repo, "HEAD")); cl_git_pass(git_reference_symbolic_set_target( - &selfsimilar, head, "refs/heads/renames_similar_two")); + &selfsimilar, head, "refs/heads/renames_similar_two", NULL, NULL)); cl_git_pass(git_checkout_head(g_repo, &opts)); cl_git_pass(git_repository_index(&index, g_repo)); @@ -1048,7 +1072,7 @@ void test_diff_rename__rejected_match_can_match_others_three(void) git_reference *head, *selfsimilar; git_index *index; git_tree *tree; - git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; + git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; git_diff *diff; git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; git_diff_find_options findopts = GIT_DIFF_FIND_OPTIONS_INIT; @@ -1060,10 +1084,11 @@ void test_diff_rename__rejected_match_can_match_others_three(void) struct rename_expected expect = { 2, status, sources, targets }; opts.checkout_strategy = GIT_CHECKOUT_FORCE; + findopts.flags = GIT_DIFF_FIND_RENAMES; cl_git_pass(git_reference_lookup(&head, g_repo, "HEAD")); cl_git_pass(git_reference_symbolic_set_target( - &selfsimilar, head, "refs/heads/renames_similar_two")); + &selfsimilar, head, "refs/heads/renames_similar_two", NULL, NULL)); cl_git_pass(git_checkout_head(g_repo, &opts)); cl_git_pass(git_repository_index(&index, g_repo)); @@ -1284,3 +1309,280 @@ void test_diff_rename__rewrite_on_single_file(void) git_diff_free(diff); git_index_free(index); } + +void test_diff_rename__can_find_copy_to_split(void) +{ + git_buf c1 = GIT_BUF_INIT; + git_index *index; + git_tree *tree; + git_diff *diff; + git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; + git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; + diff_expects exp; + + cl_git_pass(git_futils_readbuffer(&c1, "renames/songof7cities.txt")); + cl_git_pass(git_futils_writebuffer(&c1, "renames/untimely.txt", 0, 0)); + + cl_git_pass( + git_revparse_single((git_object **)&tree, g_repo, "HEAD^{tree}")); + + cl_git_pass(git_repository_index(&index, g_repo)); + cl_git_pass(git_index_read_tree(index, tree)); + cl_git_pass(git_index_add_bypath(index, "untimely.txt")); + + diffopts.flags = GIT_DIFF_INCLUDE_UNMODIFIED; + + cl_git_pass(git_diff_tree_to_index(&diff, g_repo, tree, index, &diffopts)); + + 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(4, exp.files); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(3, exp.file_status[GIT_DELTA_UNMODIFIED]); + + 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(1, exp.file_status[GIT_DELTA_DELETED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_COPIED]); + cl_assert_equal_i(3, exp.file_status[GIT_DELTA_UNMODIFIED]); + + git_diff_free(diff); + git_tree_free(tree); + git_index_free(index); + + git_buf_free(&c1); +} + +void test_diff_rename__can_delete_unmodified_deltas(void) +{ + git_buf c1 = GIT_BUF_INIT; + git_index *index; + git_tree *tree; + git_diff *diff; + git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; + git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; + diff_expects exp; + + cl_git_pass(git_futils_readbuffer(&c1, "renames/songof7cities.txt")); + cl_git_pass(git_futils_writebuffer(&c1, "renames/untimely.txt", 0, 0)); + + cl_git_pass( + git_revparse_single((git_object **)&tree, g_repo, "HEAD^{tree}")); + + cl_git_pass(git_repository_index(&index, g_repo)); + cl_git_pass(git_index_read_tree(index, tree)); + cl_git_pass(git_index_add_bypath(index, "untimely.txt")); + + diffopts.flags = GIT_DIFF_INCLUDE_UNMODIFIED; + + cl_git_pass(git_diff_tree_to_index(&diff, g_repo, tree, index, &diffopts)); + + 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(4, exp.files); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(3, exp.file_status[GIT_DELTA_UNMODIFIED]); + + opts.flags = GIT_DIFF_FIND_ALL | GIT_DIFF_FIND_REMOVE_UNMODIFIED; + 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(2, exp.files); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_COPIED]); + + git_diff_free(diff); + git_tree_free(tree); + git_index_free(index); + + git_buf_free(&c1); +} + +void test_diff_rename__matches_config_behavior(void) +{ + const char *sha0 = "31e47d8c1fa36d7f8d537b96158e3f024de0a9f2"; + const char *sha1 = "2bc7f351d20b53f1c72c16c4b036e491c478c49a"; + const char *sha2 = "1c068dee5790ef1580cfc4cd670915b48d790084"; + + git_tree *tree0, *tree1, *tree2; + git_config *cfg; + git_diff *diff; + git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; + git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; + diff_expects exp; + + opts.flags = GIT_DIFF_FIND_BY_CONFIG; + tree0 = resolve_commit_oid_to_tree(g_repo, sha0); + tree1 = resolve_commit_oid_to_tree(g_repo, sha1); + tree2 = resolve_commit_oid_to_tree(g_repo, sha2); + + diffopts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED; + cl_git_pass(git_repository_config(&cfg, g_repo)); + + /* diff.renames = false; no rename detection should happen */ + cl_git_pass(git_config_set_bool(cfg, "diff.renames", false)); + cl_git_pass(git_diff_tree_to_tree( + &diff, g_repo, tree0, tree1, &diffopts)); + memset(&exp, 0, sizeof(exp)); + cl_git_pass(git_diff_find_similar(diff, &opts)); + cl_git_pass(git_diff_foreach(diff, + diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); + cl_assert_equal_i(4, exp.files); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNMODIFIED]); + cl_assert_equal_i(2, exp.file_status[GIT_DELTA_ADDED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); + git_diff_free(diff); + + /* diff.renames = true; should act like -M */ + cl_git_pass(git_config_set_bool(cfg, "diff.renames", true)); + cl_git_pass(git_diff_tree_to_tree( + &diff, g_repo, tree0, tree1, &diffopts)); + memset(&exp, 0, sizeof(exp)); + cl_git_pass(git_diff_find_similar(diff, &opts)); + cl_git_pass(git_diff_foreach(diff, + diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); + cl_assert_equal_i(3, exp.files); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNMODIFIED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_ADDED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_RENAMED]); + git_diff_free(diff); + + /* diff.renames = copies; should act like -M -C */ + cl_git_pass(git_config_set_string(cfg, "diff.renames", "copies")); + cl_git_pass(git_diff_tree_to_tree( + &diff, g_repo, tree1, tree2, &diffopts)); + memset(&exp, 0, sizeof(exp)); + cl_git_pass(git_diff_find_similar(diff, &opts)); + cl_git_pass(git_diff_foreach(diff, + diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); + cl_assert_equal_i(4, exp.files); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNMODIFIED]); + cl_assert_equal_i(2, exp.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_COPIED]); + git_diff_free(diff); + + /* NULL find options is the same as GIT_DIFF_FIND_BY_CONFIG */ + cl_git_pass(git_diff_tree_to_tree( + &diff, g_repo, tree1, tree2, &diffopts)); + memset(&exp, 0, sizeof(exp)); + cl_git_pass(git_diff_find_similar(diff, NULL)); + cl_git_pass(git_diff_foreach(diff, + diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); + cl_assert_equal_i(4, exp.files); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNMODIFIED]); + cl_assert_equal_i(2, exp.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_COPIED]); + git_diff_free(diff); + + /* Cleanup */ + git_tree_free(tree0); + git_tree_free(tree1); + git_tree_free(tree2); + git_config_free(cfg); +} + +void test_diff_rename__can_override_thresholds_when_obeying_config(void) +{ + const char *sha1 = "2bc7f351d20b53f1c72c16c4b036e491c478c49a"; + const char *sha2 = "1c068dee5790ef1580cfc4cd670915b48d790084"; + + git_tree *tree1, *tree2; + git_config *cfg; + git_diff *diff; + git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; + git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; + diff_expects exp; + + tree1 = resolve_commit_oid_to_tree(g_repo, sha1); + tree2 = resolve_commit_oid_to_tree(g_repo, sha2); + + diffopts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED; + opts.flags = GIT_DIFF_FIND_BY_CONFIG; + + cl_git_pass(git_repository_config(&cfg, g_repo)); + cl_git_pass(git_config_set_string(cfg, "diff.renames", "copies")); + git_config_free(cfg); + + /* copy threshold = 96%, should see creation of ikeepsix.txt */ + opts.copy_threshold = 96; + cl_git_pass(git_diff_tree_to_tree( + &diff, g_repo, tree1, tree2, &diffopts)); + memset(&exp, 0, sizeof(exp)); + cl_git_pass(git_diff_find_similar(diff, &opts)); + cl_git_pass(git_diff_foreach(diff, + diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); + cl_assert_equal_i(4, exp.files); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNMODIFIED]); + cl_assert_equal_i(2, exp.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_ADDED]); + git_diff_free(diff); + + /* copy threshold = 20%, should see sixserving.txt => ikeepsix.txt */ + opts.copy_threshold = 20; + cl_git_pass(git_diff_tree_to_tree( + &diff, g_repo, tree1, tree2, &diffopts)); + memset(&exp, 0, sizeof(exp)); + cl_git_pass(git_diff_find_similar(diff, &opts)); + cl_git_pass(git_diff_foreach(diff, + diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); + cl_assert_equal_i(4, exp.files); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNMODIFIED]); + cl_assert_equal_i(2, exp.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_COPIED]); + git_diff_free(diff); + + /* Cleanup */ + git_tree_free(tree1); + git_tree_free(tree2); +} + +void test_diff_rename__by_config_doesnt_mess_with_whitespace_settings(void) +{ + const char *sha1 = "1c068dee5790ef1580cfc4cd670915b48d790084"; + const char *sha2 = "19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13"; + + git_tree *tree1, *tree2; + git_config *cfg; + git_diff *diff; + git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; + git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; + diff_expects exp; + + tree1 = resolve_commit_oid_to_tree(g_repo, sha1); + tree2 = resolve_commit_oid_to_tree(g_repo, sha2); + + diffopts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED; + opts.flags = GIT_DIFF_FIND_BY_CONFIG; + + cl_git_pass(git_repository_config(&cfg, g_repo)); + cl_git_pass(git_config_set_string(cfg, "diff.renames", "copies")); + git_config_free(cfg); + + /* Don't ignore whitespace; this should find a change in sixserving.txt */ + opts.flags |= 0 | GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE; + cl_git_pass(git_diff_tree_to_tree( + &diff, g_repo, tree1, tree2, &diffopts)); + memset(&exp, 0, sizeof(exp)); + cl_git_pass(git_diff_find_similar(diff, &opts)); + 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(2, exp.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_RENAMED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_ADDED]); + git_diff_free(diff); + + /* Cleanup */ + git_tree_free(tree1); + git_tree_free(tree2); +} diff --git a/tests/diff/stats.c b/tests/diff/stats.c new file mode 100644 index 000000000..f731997da --- /dev/null +++ b/tests/diff/stats.c @@ -0,0 +1,289 @@ +#include "clar.h" +#include "clar_libgit2.h" + +#include "buffer.h" +#include "commit.h" +#include "diff.h" + +static git_repository *_repo; +static git_diff_stats *_stats; + +void test_diff_stats__initialize(void) +{ + _repo = cl_git_sandbox_init("diff_format_email"); +} + +void test_diff_stats__cleanup(void) +{ + git_diff_stats_free(_stats); _stats = NULL; + cl_git_sandbox_cleanup(); +} + +static void diff_stats_from_commit_oid( + git_diff_stats **stats, const char *oidstr, bool rename) +{ + git_oid oid; + git_commit *commit; + git_diff *diff; + + git_oid_fromstr(&oid, oidstr); + cl_git_pass(git_commit_lookup(&commit, _repo, &oid)); + cl_git_pass(git_diff__commit(&diff, _repo, commit, NULL)); + if (rename) + cl_git_pass(git_diff_find_similar(diff, NULL)); + cl_git_pass(git_diff_get_stats(stats, diff)); + + git_diff_free(diff); + git_commit_free(commit); +} + +void test_diff_stats__stat(void) +{ + git_buf buf = GIT_BUF_INIT; + const char *stat = + " file1.txt | 8 +++++---\n" \ + " 1 file changed, 5 insertions(+), 3 deletions(-)\n"; + + diff_stats_from_commit_oid( + &_stats, "9264b96c6d104d0e07ae33d3007b6a48246c6f92", false); + + cl_assert_equal_sz(1, git_diff_stats_files_changed(_stats)); + cl_assert_equal_sz(5, git_diff_stats_insertions(_stats)); + cl_assert_equal_sz(3, git_diff_stats_deletions(_stats)); + + cl_git_pass(git_diff_stats_to_buf(&buf, _stats, GIT_DIFF_STATS_FULL, 0)); + cl_assert(strcmp(git_buf_cstr(&buf), stat) == 0); + git_buf_free(&buf); + + cl_git_pass(git_diff_stats_to_buf(&buf, _stats, GIT_DIFF_STATS_FULL, 80)); + cl_assert(strcmp(git_buf_cstr(&buf), stat) == 0); + git_buf_free(&buf); +} + +void test_diff_stats__multiple_hunks(void) +{ + git_buf buf = GIT_BUF_INIT; + const char *stat = + " file2.txt | 5 +++--\n" \ + " file3.txt | 6 ++++--\n" \ + " 2 files changed, 7 insertions(+), 4 deletions(-)\n"; + + diff_stats_from_commit_oid( + &_stats, "cd471f0d8770371e1bc78bcbb38db4c7e4106bd2", false); + + cl_assert_equal_sz(2, git_diff_stats_files_changed(_stats)); + cl_assert_equal_sz(7, git_diff_stats_insertions(_stats)); + cl_assert_equal_sz(4, git_diff_stats_deletions(_stats)); + + cl_git_pass(git_diff_stats_to_buf(&buf, _stats, GIT_DIFF_STATS_FULL, 0)); + cl_assert_equal_s(stat, git_buf_cstr(&buf)); + git_buf_free(&buf); +} + +void test_diff_stats__numstat(void) +{ + git_buf buf = GIT_BUF_INIT; + const char *stat = + "3 2 file2.txt\n" + "4 2 file3.txt\n"; + + diff_stats_from_commit_oid( + &_stats, "cd471f0d8770371e1bc78bcbb38db4c7e4106bd2", false); + + cl_git_pass(git_diff_stats_to_buf(&buf, _stats, GIT_DIFF_STATS_NUMBER, 0)); + cl_assert_equal_s(stat, git_buf_cstr(&buf)); + git_buf_free(&buf); +} + +void test_diff_stats__shortstat(void) +{ + git_buf buf = GIT_BUF_INIT; + const char *stat = + " 1 file changed, 5 insertions(+), 3 deletions(-)\n"; + + diff_stats_from_commit_oid( + &_stats, "9264b96c6d104d0e07ae33d3007b6a48246c6f92", false); + + cl_assert_equal_sz(1, git_diff_stats_files_changed(_stats)); + cl_assert_equal_sz(5, git_diff_stats_insertions(_stats)); + cl_assert_equal_sz(3, git_diff_stats_deletions(_stats)); + + cl_git_pass(git_diff_stats_to_buf(&buf, _stats, GIT_DIFF_STATS_SHORT, 0)); + cl_assert_equal_s(stat, git_buf_cstr(&buf)); + git_buf_free(&buf); +} + +void test_diff_stats__rename(void) +{ + git_buf buf = GIT_BUF_INIT; + const char *stat = + " file2.txt => file2.txt.renamed | 1 +\n" + " file3.txt => file3.txt.renamed | 4 +++-\n" + " 2 files changed, 4 insertions(+), 1 deletion(-)\n"; + + diff_stats_from_commit_oid( + &_stats, "8947a46e2097638ca6040ad4877246f4186ec3bd", true); + + cl_assert_equal_sz(2, git_diff_stats_files_changed(_stats)); + cl_assert_equal_sz(4, git_diff_stats_insertions(_stats)); + cl_assert_equal_sz(1, git_diff_stats_deletions(_stats)); + + cl_git_pass(git_diff_stats_to_buf(&buf, _stats, GIT_DIFF_STATS_FULL, 0)); + cl_assert_equal_s(stat, git_buf_cstr(&buf)); + git_buf_free(&buf); +} + +void test_diff_stats__rename_nochanges(void) +{ + git_buf buf = GIT_BUF_INIT; + const char *stat = + " file2.txt.renamed => file2.txt.renamed2 | 0\n" + " file3.txt.renamed => file3.txt.renamed2 | 0\n" + " 2 files changed, 0 insertions(+), 0 deletions(-)\n"; + + diff_stats_from_commit_oid( + &_stats, "3991dce9e71a0641ca49a6a4eea6c9e7ff402ed4", true); + + cl_assert_equal_sz(2, git_diff_stats_files_changed(_stats)); + cl_assert_equal_sz(0, git_diff_stats_insertions(_stats)); + cl_assert_equal_sz(0, git_diff_stats_deletions(_stats)); + + cl_git_pass(git_diff_stats_to_buf(&buf, _stats, GIT_DIFF_STATS_FULL, 0)); + cl_assert_equal_s(stat, git_buf_cstr(&buf)); + git_buf_free(&buf); +} + +void test_diff_stats__rename_and_modifiy(void) +{ + git_buf buf = GIT_BUF_INIT; + const char *stat = + " file2.txt.renamed2 | 2 +-\n" + " file3.txt.renamed2 => file3.txt.renamed | 0\n" + " 2 files changed, 1 insertion(+), 1 deletion(-)\n"; + + diff_stats_from_commit_oid( + &_stats, "4ca10087e696d2ba78d07b146a118e9a7096ed4f", true); + + cl_assert_equal_sz(2, git_diff_stats_files_changed(_stats)); + cl_assert_equal_sz(1, git_diff_stats_insertions(_stats)); + cl_assert_equal_sz(1, git_diff_stats_deletions(_stats)); + + cl_git_pass(git_diff_stats_to_buf(&buf, _stats, GIT_DIFF_STATS_FULL, 0)); + cl_assert_equal_s(stat, git_buf_cstr(&buf)); + git_buf_free(&buf); +} + +void test_diff_stats__rename_no_find(void) +{ + git_buf buf = GIT_BUF_INIT; + const char *stat = + " file2.txt | 5 -----\n" + " file2.txt.renamed | 6 ++++++\n" + " file3.txt | 5 -----\n" + " file3.txt.renamed | 7 +++++++\n" + " 4 files changed, 13 insertions(+), 10 deletions(-)\n"; + + diff_stats_from_commit_oid( + &_stats, "8947a46e2097638ca6040ad4877246f4186ec3bd", false); + + cl_assert_equal_sz(4, git_diff_stats_files_changed(_stats)); + cl_assert_equal_sz(13, git_diff_stats_insertions(_stats)); + cl_assert_equal_sz(10, git_diff_stats_deletions(_stats)); + + cl_git_pass(git_diff_stats_to_buf(&buf, _stats, GIT_DIFF_STATS_FULL, 0)); + cl_assert_equal_s(stat, git_buf_cstr(&buf)); + git_buf_free(&buf); +} + +void test_diff_stats__rename_nochanges_no_find(void) +{ + git_buf buf = GIT_BUF_INIT; + const char *stat = + " file2.txt.renamed | 6 ------\n" + " file2.txt.renamed2 | 6 ++++++\n" + " file3.txt.renamed | 7 -------\n" + " file3.txt.renamed2 | 7 +++++++\n" + " 4 files changed, 13 insertions(+), 13 deletions(-)\n"; + + diff_stats_from_commit_oid( + &_stats, "3991dce9e71a0641ca49a6a4eea6c9e7ff402ed4", false); + + cl_assert_equal_sz(4, git_diff_stats_files_changed(_stats)); + cl_assert_equal_sz(13, git_diff_stats_insertions(_stats)); + cl_assert_equal_sz(13, git_diff_stats_deletions(_stats)); + + cl_git_pass(git_diff_stats_to_buf(&buf, _stats, GIT_DIFF_STATS_FULL, 0)); + cl_assert_equal_s(stat, git_buf_cstr(&buf)); + git_buf_free(&buf); +} + +void test_diff_stats__rename_and_modifiy_no_find(void) +{ + git_buf buf = GIT_BUF_INIT; + const char *stat = + " file2.txt.renamed2 | 2 +-\n" + " file3.txt.renamed | 7 +++++++\n" + " file3.txt.renamed2 | 7 -------\n" + " 3 files changed, 8 insertions(+), 8 deletions(-)\n"; + + diff_stats_from_commit_oid( + &_stats, "4ca10087e696d2ba78d07b146a118e9a7096ed4f", false); + + cl_assert_equal_sz(3, git_diff_stats_files_changed(_stats)); + cl_assert_equal_sz(8, git_diff_stats_insertions(_stats)); + cl_assert_equal_sz(8, git_diff_stats_deletions(_stats)); + + cl_git_pass(git_diff_stats_to_buf(&buf, _stats, GIT_DIFF_STATS_FULL, 0)); + cl_assert_equal_s(stat, git_buf_cstr(&buf)); + git_buf_free(&buf); +} + +void test_diff_stats__binary(void) +{ + git_buf buf = GIT_BUF_INIT; + const char *stat = + " binary.bin | Bin 3 -> 0 bytes\n" + " 1 file changed, 0 insertions(+), 0 deletions(-)\n"; + /* TODO: Actually 0 bytes here should be 5!. Seems like we don't load the new content for binary files? */ + + diff_stats_from_commit_oid( + &_stats, "8d7523f6fcb2404257889abe0d96f093d9f524f9", false); + + cl_assert_equal_sz(1, git_diff_stats_files_changed(_stats)); + cl_assert_equal_sz(0, git_diff_stats_insertions(_stats)); + cl_assert_equal_sz(0, git_diff_stats_deletions(_stats)); + + cl_git_pass(git_diff_stats_to_buf(&buf, _stats, GIT_DIFF_STATS_FULL, 0)); + cl_assert_equal_s(stat, git_buf_cstr(&buf)); + git_buf_free(&buf); +} + +void test_diff_stats__binary_numstat(void) +{ + git_buf buf = GIT_BUF_INIT; + const char *stat = + "- - binary.bin\n"; + + diff_stats_from_commit_oid( + &_stats, "8d7523f6fcb2404257889abe0d96f093d9f524f9", false); + + cl_git_pass(git_diff_stats_to_buf(&buf, _stats, GIT_DIFF_STATS_NUMBER, 0)); + cl_assert_equal_s(stat, git_buf_cstr(&buf)); + git_buf_free(&buf); +} + +void test_diff_stats__mode_change(void) +{ + git_buf buf = GIT_BUF_INIT; + const char *stat = + " file1.txt.renamed | 0\n" \ + " 1 file changed, 0 insertions(+), 0 deletions(-)\n" \ + " mode change 100644 => 100755 file1.txt.renamed\n"; + + diff_stats_from_commit_oid( + &_stats, "7ade76dd34bba4733cf9878079f9fd4a456a9189", false); + + cl_git_pass(git_diff_stats_to_buf(&buf, _stats, GIT_DIFF_STATS_FULL | GIT_DIFF_STATS_INCLUDE_SUMMARY, 0)); + cl_assert_equal_s(stat, git_buf_cstr(&buf)); + git_buf_free(&buf); +} diff --git a/tests/diff/submodules.c b/tests/diff/submodules.c index 24545b2c7..02870ac86 100644 --- a/tests/diff/submodules.c +++ b/tests/diff/submodules.c @@ -1,6 +1,7 @@ #include "clar_libgit2.h" #include "repository.h" #include "posix.h" +#include "diff_helpers.h" #include "../submodule/submodule_helpers.h" static git_repository *g_repo = NULL; @@ -11,15 +12,18 @@ void test_diff_submodules__initialize(void) void test_diff_submodules__cleanup(void) { + cl_git_sandbox_cleanup(); } +#define get_buf_ptr(buf) ((buf)->asize ? (buf)->ptr : NULL) + static void check_diff_patches_at_line( git_diff *diff, const char **expected, const char *file, int line) { const git_diff_delta *delta; git_patch *patch = NULL; size_t d, num_d = git_diff_num_deltas(diff); - char *patch_text; + git_buf buf = GIT_BUF_INIT; for (d = 0; d < num_d; ++d, git_patch_free(patch)) { cl_git_pass(git_patch_from_diff(&patch, diff, d)); @@ -32,17 +36,21 @@ static void check_diff_patches_at_line( if (expected[d] && !strcmp(expected[d], "<SKIP>")) continue; + if (expected[d] && !strcmp(expected[d], "<UNTRACKED>")) { + cl_assert_at_line(delta->status == GIT_DELTA_UNTRACKED, file, line); + continue; + } if (expected[d] && !strcmp(expected[d], "<END>")) { - cl_git_pass(git_patch_to_str(&patch_text, patch)); + cl_git_pass(git_patch_to_buf(&buf, patch)); cl_assert_at_line(!strcmp(expected[d], "<END>"), file, line); } - cl_git_pass(git_patch_to_str(&patch_text, patch)); + cl_git_pass(git_patch_to_buf(&buf, patch)); clar__assert_equal( file, line, "expected diff did not match actual diff", 1, - "%s", expected[d], patch_text); - git__free(patch_text); + "%s", expected[d], get_buf_ptr(&buf)); + git_buf_free(&buf); } cl_assert_at_line(expected[d] && !strcmp(expected[d], "<END>"), file, line); @@ -113,7 +121,9 @@ void test_diff_submodules__dirty_submodule_2(void) git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff *diff = NULL, *diff2 = NULL; char *smpath = "testrepo"; - static const char *expected_none[] = { "<END>" }; + static const char *expected_none[] = { + "<END>" + }; static const char *expected_dirty[] = { "diff --git a/testrepo b/testrepo\nindex a65fedf..a65fedf 160000\n--- a/testrepo\n+++ b/testrepo\n@@ -1 +1 @@\n-Subproject commit a65fedf39aefe402d3bb6e24df4d4f5fe4547750\n+Subproject commit a65fedf39aefe402d3bb6e24df4d4f5fe4547750-dirty\n", /* testrepo.git */ "<END>" @@ -121,8 +131,6 @@ void test_diff_submodules__dirty_submodule_2(void) g_repo = setup_fixture_submodules(); - cl_git_pass(git_submodule_reload_all(g_repo)); - opts.flags = GIT_DIFF_INCLUDE_UNTRACKED | GIT_DIFF_SHOW_UNTRACKED_CONTENT | GIT_DIFF_RECURSE_UNTRACKED_DIRS | @@ -155,8 +163,6 @@ void test_diff_submodules__dirty_submodule_2(void) git_diff_free(diff); - cl_git_pass(git_submodule_reload_all(g_repo)); - cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); check_diff_patches(diff, expected_dirty); git_diff_free(diff); @@ -168,8 +174,12 @@ void test_diff_submodules__submod2_index_to_wd(void) git_diff *diff = NULL; static const char *expected[] = { "<SKIP>", /* .gitmodules */ + "<UNTRACKED>", /* not-submodule */ + "<UNTRACKED>", /* not */ "diff --git a/sm_changed_file b/sm_changed_file\nindex 4800958..4800958 160000\n--- a/sm_changed_file\n+++ b/sm_changed_file\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0-dirty\n", /* sm_changed_file */ "diff --git a/sm_changed_head b/sm_changed_head\nindex 4800958..3d9386c 160000\n--- a/sm_changed_head\n+++ b/sm_changed_head\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 3d9386c507f6b093471a3e324085657a3c2b4247\n", /* sm_changed_head */ + "<UNTRACKED>", /* sm_changed_head- */ + "<UNTRACKED>", /* sm_changed_head_ */ "diff --git a/sm_changed_index b/sm_changed_index\nindex 4800958..4800958 160000\n--- a/sm_changed_index\n+++ b/sm_changed_index\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0-dirty\n", /* sm_changed_index */ "diff --git a/sm_changed_untracked_file b/sm_changed_untracked_file\nindex 4800958..4800958 160000\n--- a/sm_changed_untracked_file\n+++ b/sm_changed_untracked_file\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0-dirty\n", /* sm_changed_untracked_file */ "diff --git a/sm_missing_commits b/sm_missing_commits\nindex 4800958..5e49635 160000\n--- a/sm_missing_commits\n+++ b/sm_missing_commits\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 5e4963595a9774b90524d35a807169049de8ccad\n", /* sm_missing_commits */ @@ -178,6 +188,10 @@ void test_diff_submodules__submod2_index_to_wd(void) g_repo = setup_fixture_submod2(); + /* bracket existing submodule with similarly named items */ + cl_git_mkfile("submod2/sm_changed_head-", "hello"); + cl_git_mkfile("submod2/sm_changed_head_", "hello"); + opts.flags = GIT_DIFF_INCLUDE_UNTRACKED; opts.old_prefix = "a"; opts.new_prefix = "b"; @@ -279,7 +293,8 @@ void test_diff_submodules__invalid_cache(void) check_diff_patches(diff, expected_dirty); git_diff_free(diff); - cl_git_pass(git_submodule_reload_all(g_repo)); + git_submodule_free(sm); + cl_git_pass(git_submodule_lookup(&sm, g_repo, smpath)); cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); @@ -332,6 +347,8 @@ void test_diff_submodules__invalid_cache(void) p_unlink("submod2/sm_changed_head/new_around_here"); + git_submodule_free(sm); + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); check_diff_patches(diff, expected_moved); git_diff_free(diff); @@ -347,6 +364,8 @@ void test_diff_submodules__diff_ignore_options(void) git_config *cfg; static const char *expected_normal[] = { "<SKIP>", /* .gitmodules */ + "<UNTRACKED>", /* not-submodule */ + "<UNTRACKED>", /* not */ "diff --git a/sm_changed_file b/sm_changed_file\nindex 4800958..4800958 160000\n--- a/sm_changed_file\n+++ b/sm_changed_file\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0-dirty\n", /* sm_changed_file */ "diff --git a/sm_changed_head b/sm_changed_head\nindex 4800958..3d9386c 160000\n--- a/sm_changed_head\n+++ b/sm_changed_head\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 3d9386c507f6b093471a3e324085657a3c2b4247\n", /* sm_changed_head */ "diff --git a/sm_changed_index b/sm_changed_index\nindex 4800958..4800958 160000\n--- a/sm_changed_index\n+++ b/sm_changed_index\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0-dirty\n", /* sm_changed_index */ @@ -356,10 +375,14 @@ void test_diff_submodules__diff_ignore_options(void) }; static const char *expected_ignore_all[] = { "<SKIP>", /* .gitmodules */ + "<UNTRACKED>", /* not-submodule */ + "<UNTRACKED>", /* not */ "<END>" }; static const char *expected_ignore_dirty[] = { "<SKIP>", /* .gitmodules */ + "<UNTRACKED>", /* not-submodule */ + "<UNTRACKED>", /* not */ "diff --git a/sm_changed_head b/sm_changed_head\nindex 4800958..3d9386c 160000\n--- a/sm_changed_head\n+++ b/sm_changed_head\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 3d9386c507f6b093471a3e324085657a3c2b4247\n", /* sm_changed_head */ "diff --git a/sm_missing_commits b/sm_missing_commits\nindex 4800958..5e49635 160000\n--- a/sm_missing_commits\n+++ b/sm_missing_commits\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 5e4963595a9774b90524d35a807169049de8ccad\n", /* sm_missing_commits */ "<END>" @@ -421,3 +444,52 @@ void test_diff_submodules__diff_ignore_options(void) git_config_free(cfg); } + +void test_diff_submodules__skips_empty_includes_used(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff *diff = NULL; + diff_expects exp; + + /* A side effect of of Git's handling of untracked directories and + * auto-ignoring of ".git" entries is that a newly initialized Git + * repo inside another repo will be skipped by diff, but one that + * actually has a commit it in will show as an untracked directory. + * Let's make sure that works. + */ + + g_repo = cl_git_sandbox_init("empty_standard_repo"); + + opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &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(0, exp.files); + git_diff_free(diff); + + { + git_repository *r2; + cl_git_pass(git_repository_init(&r2, "empty_standard_repo/subrepo", 0)); + git_repository_free(r2); + } + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &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(1, exp.files); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); + git_diff_free(diff); + + cl_git_mkfile("empty_standard_repo/subrepo/README.txt", "hello\n"); + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &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(1, exp.files); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); + git_diff_free(diff); +} diff --git a/tests/diff/tree.c b/tests/diff/tree.c index 582174b8b..6ab49fdb0 100644 --- a/tests/diff/tree.c +++ b/tests/diff/tree.c @@ -9,7 +9,7 @@ static diff_expects expect; void test_diff_tree__initialize(void) { - cl_git_pass(git_diff_options_init(&opts, GIT_DIFF_OPTIONS_VERSION)); + cl_git_pass(git_diff_init_options(&opts, GIT_DIFF_OPTIONS_VERSION)); memset(&expect, 0, sizeof(expect)); diff --git a/tests/diff/workdir.c b/tests/diff/workdir.c index 7cc032232..963be9481 100644 --- a/tests/diff/workdir.c +++ b/tests/diff/workdir.c @@ -1,13 +1,10 @@ #include "clar_libgit2.h" #include "diff_helpers.h" #include "repository.h" +#include "git2/sys/diff.h" static git_repository *g_repo = NULL; -void test_diff_workdir__initialize(void) -{ -} - void test_diff_workdir__cleanup(void) { cl_git_sandbox_cleanup(); @@ -60,6 +57,14 @@ void test_diff_workdir__to_index(void) cl_assert_equal_i(5, exp.line_dels); } + { + git_diff_perfdata perf = GIT_DIFF_PERFDATA_INIT; + cl_git_pass(git_diff_get_perfdata(&perf, diff)); + cl_assert_equal_sz( + 13 /* in root */ + 3 /* in subdir */, perf.stat_calls); + cl_assert_equal_sz(5, perf.oid_calculations); + } + git_diff_free(diff); } @@ -881,7 +886,7 @@ void test_diff_workdir__submodules(void) * only significant difference is that those Added items will show up * as Untracked items in the pure libgit2 diff. * - * Then add in the two extra ignored items "not" and "not-submodule" + * Then add in the two extra untracked items "not" and "not-submodule" * to get the 12 files reported here. */ @@ -890,8 +895,8 @@ void test_diff_workdir__submodules(void) cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_MODIFIED]); - cl_assert_equal_i(2, exp.file_status[GIT_DELTA_IGNORED]); - cl_assert_equal_i(8, exp.file_status[GIT_DELTA_UNTRACKED]); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); + cl_assert_equal_i(10, exp.file_status[GIT_DELTA_UNTRACKED]); /* the following numbers match "git diff 873585" exactly */ @@ -1375,7 +1380,7 @@ void test_diff_workdir__patience_diff(void) git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff *diff = NULL; git_patch *patch = NULL; - char *as_str = NULL; + git_buf buf = GIT_BUF_INIT; const char *expected_normal = "diff --git a/test.txt b/test.txt\nindex 34a5acc..d52725f 100644\n--- a/test.txt\n+++ b/test.txt\n@@ -1,10 +1,7 @@\n When I wrote this\n I did not know\n-how to create\n-a patience diff\n I did not know\n how to create\n+a patience diff\n another problem\n-I did not know\n-how to create\n a minimal diff\n"; const char *expected_patience = "diff --git a/test.txt b/test.txt\nindex 34a5acc..d52725f 100644\n--- a/test.txt\n+++ b/test.txt\n@@ -1,10 +1,7 @@\n When I wrote this\n I did not know\n+I did not know\n how to create\n a patience diff\n-I did not know\n-how to create\n another problem\n-I did not know\n-how to create\n a minimal diff\n"; @@ -1397,10 +1402,10 @@ void test_diff_workdir__patience_diff(void) cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); cl_assert_equal_i(1, git_diff_num_deltas(diff)); cl_git_pass(git_patch_from_diff(&patch, diff, 0)); - cl_git_pass(git_patch_to_str(&as_str, patch)); + cl_git_pass(git_patch_to_buf(&buf, patch)); - cl_assert_equal_s(expected_normal, as_str); - git__free(as_str); + cl_assert_equal_s(expected_normal, buf.ptr); + git_buf_clear(&buf); git_patch_free(patch); git_diff_free(diff); @@ -1409,10 +1414,12 @@ void test_diff_workdir__patience_diff(void) cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); cl_assert_equal_i(1, git_diff_num_deltas(diff)); cl_git_pass(git_patch_from_diff(&patch, diff, 0)); - cl_git_pass(git_patch_to_str(&as_str, patch)); + cl_git_pass(git_patch_to_buf(&buf, patch)); + + cl_assert_equal_s(expected_patience, buf.ptr); + git_buf_clear(&buf); - cl_assert_equal_s(expected_patience, as_str); - git__free(as_str); + git_buf_free(&buf); git_patch_free(patch); git_diff_free(diff); } @@ -1488,3 +1495,202 @@ void test_diff_workdir__with_stale_index(void) git_index_free(idx); } + +static int touch_file(void *payload, git_buf *path) +{ + int fd; + char b; + + GIT_UNUSED(payload); + if (git_path_isdir(path->ptr)) + return 0; + + cl_assert((fd = p_open(path->ptr, O_RDWR)) >= 0); + cl_assert_equal_i(1, p_read(fd, &b, 1)); + cl_must_pass(p_lseek(fd, 0, SEEK_SET)); + cl_must_pass(p_write(fd, &b, 1)); + cl_must_pass(p_close(fd)); + + return 0; +} + +static void basic_diff_status(git_diff **out, const git_diff_options *opts) +{ + diff_expects exp; + + cl_git_pass(git_diff_index_to_workdir(out, g_repo, NULL, opts)); + + memset(&exp, 0, sizeof(exp)); + + cl_git_pass(git_diff_foreach( + *out, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); + + cl_assert_equal_i(13, exp.files); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); + cl_assert_equal_i(4, exp.file_status[GIT_DELTA_DELETED]); + cl_assert_equal_i(4, exp.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); + cl_assert_equal_i(4, exp.file_status[GIT_DELTA_UNTRACKED]); +} + +void test_diff_workdir__can_update_index(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff *diff = NULL; + git_diff_perfdata perf = GIT_DIFF_PERFDATA_INIT; + + g_repo = cl_git_sandbox_init("status"); + + /* touch all the files so stat times are different */ + { + git_buf path = GIT_BUF_INIT; + cl_git_pass(git_buf_sets(&path, "status")); + cl_git_pass(git_path_direach(&path, 0, touch_file, NULL)); + git_buf_free(&path); + } + + opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; + + basic_diff_status(&diff, &opts); + + cl_git_pass(git_diff_get_perfdata(&perf, diff)); + cl_assert_equal_sz(13 + 3, perf.stat_calls); + cl_assert_equal_sz(5, perf.oid_calculations); + + git_diff_free(diff); + + /* now allow diff to update stat cache */ + opts.flags |= GIT_DIFF_UPDATE_INDEX; + + basic_diff_status(&diff, &opts); + + cl_git_pass(git_diff_get_perfdata(&perf, diff)); + cl_assert_equal_sz(13 + 3, perf.stat_calls); + cl_assert_equal_sz(5, perf.oid_calculations); + + git_diff_free(diff); + + /* now if we do it again, we should see fewer OID calculations */ + + basic_diff_status(&diff, &opts); + + cl_git_pass(git_diff_get_perfdata(&perf, diff)); + cl_assert_equal_sz(13 + 3, perf.stat_calls); + cl_assert_equal_sz(0, perf.oid_calculations); + + git_diff_free(diff); +} + +#define STR7 "0123456" +#define STR8 "01234567" +#define STR40 STR8 STR8 STR8 STR8 STR8 +#define STR200 STR40 STR40 STR40 STR40 STR40 +#define STR999Z STR200 STR200 STR200 STR200 STR40 STR40 STR40 STR40 \ + STR8 STR8 STR8 STR8 STR7 "\0" +#define STR1000 STR200 STR200 STR200 STR200 STR200 +#define STR3999Z STR1000 STR1000 STR1000 STR999Z +#define STR4000 STR1000 STR1000 STR1000 STR1000 + +static void assert_delta_binary(git_diff *diff, size_t idx, int is_binary) +{ + git_patch *patch; + const git_diff_delta *delta; + + cl_git_pass(git_patch_from_diff(&patch, diff, idx)); + delta = git_patch_get_delta(patch); + cl_assert_equal_b((delta->flags & GIT_DIFF_FLAG_BINARY), is_binary); + git_patch_free(patch); +} + +void test_diff_workdir__binary_detection(void) +{ + git_index *idx; + git_diff *diff = NULL; + git_buf b = GIT_BUF_INIT; + int i; + git_buf data[10] = { + { "1234567890", 0, 0 }, /* 0 - all ascii text control */ + { "\xC3\x85\xC3\xBC\xE2\x80\xA0\x48\xC3\xB8\xCF\x80\xCE\xA9", 0, 0 }, /* 1 - UTF-8 multibyte text */ + { "\xEF\xBB\xBF\xC3\x9C\xE2\xA4\x92\xC6\x92\x38\xC2\xA3\xE2\x82\xAC", 0, 0 }, /* 2 - UTF-8 with BOM */ + { STR999Z, 0, 1000 }, /* 3 - ASCII with NUL at 1000 */ + { STR3999Z, 0, 4000 }, /* 4 - ASCII with NUL at 4000 */ + { STR4000 STR3999Z "x", 0, 8001 }, /* 5 - ASCII with NUL at 8000 */ + { STR4000 STR4000 "\0", 0, 8001 }, /* 6 - ASCII with NUL at 8001 */ + { "\x00\xDC\x00\x6E\x21\x39\xFE\x0E\x00\x63\x00\xF8" + "\x00\x64\x00\x65\x20\x48", 0, 18 }, /* 7 - UTF-16 text */ + { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d" + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d", + 0, 26 }, /* 8 - All non-printable characters (no NUL) */ + { "Hello \x01\x02\x03\x04\x05\x06 World!\x01\x02\x03\x04" + "\x05\x06\x07", 0, 26 }, /* 9 - 50-50 non-printable (no NUL) */ + }; + + g_repo = cl_git_sandbox_init("empty_standard_repo"); + cl_git_pass(git_repository_index(&idx, g_repo)); + + /* We start with ASCII in index and test data in workdir, + * then we will try with test data in index and ASCII in workdir. + */ + + cl_git_pass(git_buf_sets(&b, "empty_standard_repo/0")); + for (i = 0; i < 10; ++i) { + b.ptr[b.size - 1] = '0' + i; + cl_git_mkfile(b.ptr, "baseline"); + cl_git_pass(git_index_add_bypath(idx, &b.ptr[b.size - 1])); + + if (data[i].size == 0) + data[i].size = strlen(data[i].ptr); + cl_git_write2file( + b.ptr, data[i].ptr, data[i].size, O_WRONLY|O_TRUNC, 0664); + } + git_index_write(idx); + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, NULL)); + + cl_assert_equal_i(10, git_diff_num_deltas(diff)); + + /* using diff binary detection (i.e. looking for NUL byte) */ + assert_delta_binary(diff, 0, false); + assert_delta_binary(diff, 1, false); + assert_delta_binary(diff, 2, false); + assert_delta_binary(diff, 3, true); + assert_delta_binary(diff, 4, true); + assert_delta_binary(diff, 5, true); + assert_delta_binary(diff, 6, false); + assert_delta_binary(diff, 7, true); + assert_delta_binary(diff, 8, false); + assert_delta_binary(diff, 9, false); + /* The above have been checked to match command-line Git */ + + git_diff_free(diff); + + cl_git_pass(git_buf_sets(&b, "empty_standard_repo/0")); + for (i = 0; i < 10; ++i) { + b.ptr[b.size - 1] = '0' + i; + cl_git_pass(git_index_add_bypath(idx, &b.ptr[b.size - 1])); + + cl_git_write2file(b.ptr, "baseline\n", 9, O_WRONLY|O_TRUNC, 0664); + } + git_index_write(idx); + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, NULL)); + + cl_assert_equal_i(10, git_diff_num_deltas(diff)); + + /* using diff binary detection (i.e. looking for NUL byte) */ + assert_delta_binary(diff, 0, false); + assert_delta_binary(diff, 1, false); + assert_delta_binary(diff, 2, false); + assert_delta_binary(diff, 3, true); + assert_delta_binary(diff, 4, true); + assert_delta_binary(diff, 5, true); + assert_delta_binary(diff, 6, false); + assert_delta_binary(diff, 7, true); + assert_delta_binary(diff, 8, false); + assert_delta_binary(diff, 9, false); + + git_diff_free(diff); + + git_index_free(idx); + git_buf_free(&b); +} |