void test_diff_workdir__submodules(void) { const char *a_commit = "873585b94bdeabccea991ea5e3ec1a277895b698"; git_tree *a; git_diff_options opts = {0}; git_diff_list *diff = NULL; diff_expects exp; g_repo = cl_git_sandbox_init("submod2"); cl_fixture_sandbox("submod2_target"); p_rename("submod2_target/.gitted", "submod2_target/.git"); rewrite_gitmodules(git_repository_workdir(g_repo)); p_rename("submod2/not_submodule/.gitted", "submod2/not_submodule/.git"); cl_fixture_cleanup("submod2_target"); a = resolve_commit_oid_to_tree(g_repo, a_commit); opts.flags = GIT_DIFF_INCLUDE_UNTRACKED | GIT_DIFF_RECURSE_UNTRACKED_DIRS | GIT_DIFF_INCLUDE_UNTRACKED_CONTENT; cl_git_pass(git_diff_workdir_to_tree(g_repo, &opts, a, &diff)); /* diff_print(stderr, diff); */ /* essentially doing: git diff 873585b94bdeabccea991ea5e3ec1a277895b698 */ memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn)); /* the following differs from "git diff 873585" by one "untracked" file * because the diff list includes the "not_submodule/" directory which * is not displayed in the text diff. */ cl_assert_equal_i(10, exp.files); cl_assert_equal_i(0, exp.file_adds); cl_assert_equal_i(0, exp.file_dels); cl_assert_equal_i(1, exp.file_mods); cl_assert_equal_i(0, exp.file_ignored); cl_assert_equal_i(9, exp.file_untracked); /* the following numbers match "git diff 873585" exactly */ cl_assert_equal_i(9, exp.hunks); cl_assert_equal_i(33, exp.lines); cl_assert_equal_i(2, exp.line_ctxt); cl_assert_equal_i(30, exp.line_adds); cl_assert_equal_i(1, exp.line_dels); git_diff_list_free(diff); git_tree_free(a); }
void test_diff_workdir__cannot_diff_against_a_bare_repository(void) { git_diff_options opts = {0}; git_diff_list *diff = NULL; git_tree *tree; g_repo = cl_git_sandbox_init("testrepo.git"); cl_assert_equal_i(GIT_EBAREREPO, git_diff_workdir_to_index(g_repo, &opts, &diff)); cl_git_pass(git_repository_head_tree(&tree, g_repo)); cl_assert_equal_i(GIT_EBAREREPO, git_diff_workdir_to_tree(g_repo, &opts, tree, &diff)); git_tree_free(tree); }
void test_diff_workdir__to_tree(void) { /* grabbed a couple of commit oids from the history of the attr repo */ const char *a_commit = "26a125ee1bf"; /* the current HEAD */ const char *b_commit = "0017bd4ab1ec3"; /* the start */ git_tree *a = resolve_commit_oid_to_tree(g_repo, a_commit); git_tree *b = resolve_commit_oid_to_tree(g_repo, b_commit); git_diff_options opts = {0}; git_diff_list *diff = NULL; git_diff_list *diff2 = NULL; diff_expects exp; opts.context_lines = 3; opts.interhunk_lines = 1; opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; memset(&exp, 0, sizeof(exp)); /* You can't really generate the equivalent of git_diff_workdir_to_tree() * using C git. It really wants to interpose the index into the diff. * * To validate the following results with command line git, I ran the * following: * - git ls-tree 26a125 * - find . ! -path ./.git/\* -a -type f | git hash-object --stdin-paths * The results are documented at the bottom of this file in the * long comment entitled "PREPARATION OF TEST DATA". */ cl_git_pass(git_diff_workdir_to_tree(g_repo, &opts, a, &diff)); cl_git_pass(git_diff_foreach( diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn)); cl_assert(exp.files == 13); cl_assert(exp.file_adds == 0); cl_assert(exp.file_dels == 4); cl_assert(exp.file_mods == 4); cl_assert(exp.file_ignored == 1); cl_assert(exp.file_untracked == 4); /* Since there is no git diff equivalent, let's just assume that the * text diffs produced by git_diff_foreach are accurate here. We will * do more apples-to-apples test comparison below. */ git_diff_list_free(diff); diff = NULL; memset(&exp, 0, sizeof(exp)); /* This is a compatible emulation of "git diff <sha>" which looks like * a workdir to tree diff (even though it is not really). This is what * you would get from "git diff --name-status 26a125ee1bf" */ cl_git_pass(git_diff_index_to_tree(g_repo, &opts, a, &diff)); cl_git_pass(git_diff_workdir_to_index(g_repo, &opts, &diff2)); cl_git_pass(git_diff_merge(diff, diff2)); git_diff_list_free(diff2); cl_git_pass(git_diff_foreach( diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn)); cl_assert(exp.files == 14); cl_assert(exp.file_adds == 2); cl_assert(exp.file_dels == 5); cl_assert(exp.file_mods == 4); cl_assert(exp.file_ignored == 1); cl_assert(exp.file_untracked == 2); cl_assert(exp.hunks == 11); cl_assert(exp.lines == 17); cl_assert(exp.line_ctxt == 4); cl_assert(exp.line_adds == 8); cl_assert(exp.line_dels == 5); git_diff_list_free(diff); diff = NULL; memset(&exp, 0, sizeof(exp)); /* Again, emulating "git diff <sha>" for testing purposes using * "git diff --name-status 0017bd4ab1ec3" instead. */ cl_git_pass(git_diff_index_to_tree(g_repo, &opts, b, &diff)); cl_git_pass(git_diff_workdir_to_index(g_repo, &opts, &diff2)); cl_git_pass(git_diff_merge(diff, diff2)); git_diff_list_free(diff2); cl_git_pass(git_diff_foreach( diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn)); cl_assert(exp.files == 15); cl_assert(exp.file_adds == 5); cl_assert(exp.file_dels == 4); cl_assert(exp.file_mods == 3); cl_assert(exp.file_ignored == 1); cl_assert(exp.file_untracked == 2); cl_assert(exp.hunks == 12); cl_assert(exp.lines == 19); cl_assert(exp.line_ctxt == 3); cl_assert(exp.line_adds == 12); cl_assert(exp.line_dels == 4); git_diff_list_free(diff); git_tree_free(a); git_tree_free(b); }
void test_diff_workdir__larger_hunks(void) { const char *a_commit = "d70d245ed97ed2aa596dd1af6536e4bfdb047b69"; const char *b_commit = "7a9e0b02e63179929fed24f0a3e0f19168114d10"; git_tree *a, *b; git_diff_options opts = {0}; size_t i, d, num_d, h, num_h, l, num_l, header_len, line_len; g_repo = cl_git_sandbox_init("diff"); cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL); cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL); opts.context_lines = 1; opts.interhunk_lines = 0; for (i = 0; i <= 2; ++i) { git_diff_list *diff = NULL; git_diff_patch *patch; const git_diff_range *range; const char *header, *line; char origin; /* okay, this is a bit silly, but oh well */ switch (i) { case 0: cl_git_pass(git_diff_workdir_to_index(g_repo, &opts, &diff)); break; case 1: cl_git_pass(git_diff_workdir_to_tree(g_repo, &opts, a, &diff)); break; case 2: cl_git_pass(git_diff_workdir_to_tree(g_repo, &opts, b, &diff)); break; } num_d = git_diff_num_deltas(diff); cl_assert_equal_i(2, (int)num_d); for (d = 0; d < num_d; ++d) { cl_git_pass(git_diff_get_patch(&patch, NULL, diff, d)); cl_assert(patch); num_h = git_diff_patch_num_hunks(patch); for (h = 0; h < num_h; h++) { cl_git_pass(git_diff_patch_get_hunk( &range, &header, &header_len, &num_l, patch, h)); for (l = 0; l < num_l; ++l) { cl_git_pass(git_diff_patch_get_line_in_hunk( &origin, &line, &line_len, NULL, NULL, patch, h, l)); cl_assert(line); } /* confirm fail after the last item */ cl_git_fail(git_diff_patch_get_line_in_hunk( &origin, &line, &line_len, NULL, NULL, patch, h, num_l)); } /* confirm fail after the last item */ cl_git_fail(git_diff_patch_get_hunk( &range, &header, &header_len, &num_l, patch, num_h)); git_diff_patch_free(patch); } git_diff_list_free(diff); } git_tree_free(a); git_tree_free(b); }