Skip to content

Commit b0691db

Browse files
committed
tests: diff: verify that we are able to diff with empty subtrees
While it is not allowed for a tree to have an empty tree as child (e.g. an empty directory), libgit2's tree builder makes it easy to create such trees. As a result, some applications may inadvertently end up with such an invalid tree, and we should try our best and handle them. One such case is when diffing two trees, where one of both trees has such an empty subtree. It was reported that this will cause our diff code to fail. While I wasn't able to reproduce this error, let's still add a test that verifies we continue to handle them correctly.
1 parent 03ac24b commit b0691db

File tree

1 file changed

+49
-0
lines changed

1 file changed

+49
-0
lines changed

tests/diff/tree.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,3 +524,52 @@ void test_diff_tree__diff_configs(void)
524524
cl_assert_equal_i(7, expect.line_adds);
525525
cl_assert_equal_i(15, expect.line_dels);
526526
}
527+
528+
void test_diff_tree__diff_tree_with_empty_dir_entry_succeeds(void)
529+
{
530+
const char *content = "This is a blob\n";
531+
const git_diff_delta *delta;
532+
git_oid empty_tree, invalid_tree, blob;
533+
git_buf patch = GIT_BUF_INIT;
534+
git_treebuilder *builder;
535+
536+
g_repo = cl_git_sandbox_init("empty_standard_repo");
537+
538+
cl_git_pass(git_blob_create_from_buffer(&blob, g_repo, content, strlen(content)));
539+
cl_git_pass(git_treebuilder_new(&builder, g_repo, NULL));
540+
cl_git_pass(git_treebuilder_write(&empty_tree, builder));
541+
cl_git_pass(git_treebuilder_insert(NULL, builder, "empty_tree", &empty_tree, GIT_FILEMODE_TREE));
542+
cl_git_pass(git_treebuilder_insert(NULL, builder, "blob", &blob, GIT_FILEMODE_BLOB));
543+
cl_git_pass(git_treebuilder_write(&invalid_tree, builder));
544+
545+
cl_git_pass(git_tree_lookup(&a, g_repo, &empty_tree));
546+
cl_git_pass(git_tree_lookup(&b, g_repo, &invalid_tree));
547+
cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, NULL));
548+
549+
cl_git_pass(git_diff_foreach(diff,
550+
diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expect));
551+
cl_assert_equal_i(1, expect.files);
552+
cl_assert_equal_i(0, expect.file_status[GIT_DELTA_MODIFIED]);
553+
cl_assert_equal_i(1, expect.hunks);
554+
cl_assert_equal_i(1, expect.lines);
555+
cl_assert_equal_i(0, expect.line_ctxt);
556+
cl_assert_equal_i(1, expect.line_adds);
557+
cl_assert_equal_i(0, expect.line_dels);
558+
559+
cl_git_pass(git_diff_to_buf(&patch, diff, GIT_DIFF_FORMAT_PATCH));
560+
cl_assert_equal_s(patch.ptr,
561+
"diff --git a/blob b/blob\n"
562+
"new file mode 100644\n"
563+
"index 0000000..bbf2e80\n"
564+
"--- /dev/null\n"
565+
"+++ b/blob\n"
566+
"@@ -0,0 +1 @@\n"
567+
"+This is a blob\n");
568+
569+
cl_assert_equal_i(git_diff_num_deltas(diff), 1);
570+
delta = git_diff_get_delta(diff, 0);
571+
cl_assert_equal_s(delta->new_file.path, "blob");
572+
573+
git_treebuilder_free(builder);
574+
git_buf_dispose(&patch);
575+
}

0 commit comments

Comments
 (0)