summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests-clar/diff/diff_helpers.c10
-rw-r--r--tests-clar/diff/diff_helpers.h7
-rw-r--r--tests-clar/diff/workdir.c187
3 files changed, 203 insertions, 1 deletions
diff --git a/tests-clar/diff/diff_helpers.c b/tests-clar/diff/diff_helpers.c
index 19c005e2e..e7f97c034 100644
--- a/tests-clar/diff/diff_helpers.c
+++ b/tests-clar/diff/diff_helpers.c
@@ -28,7 +28,15 @@ int diff_file_cb(
{
diff_expects *e = payload;
- GIT_UNUSED(progress);
+ if (e->debug)
+ fprintf(stderr, "%c %s (%.3f)\n",
+ git_diff_status_char(delta->status),
+ delta->old_file.path, progress);
+
+ if (e->names)
+ cl_assert_equal_s(e->names[e->files], delta->old_file.path);
+ if (e->statuses)
+ cl_assert_equal_i(e->statuses[e->files], (int)delta->status);
e->files++;
diff --git a/tests-clar/diff/diff_helpers.h b/tests-clar/diff/diff_helpers.h
index 674fd8e19..b39a69d1d 100644
--- a/tests-clar/diff/diff_helpers.h
+++ b/tests-clar/diff/diff_helpers.h
@@ -18,6 +18,13 @@ typedef struct {
int line_ctxt;
int line_adds;
int line_dels;
+
+ /* optional arrays of expected specific values */
+ const char **names;
+ int *statuses;
+
+ int debug;
+
} diff_expects;
typedef struct {
diff --git a/tests-clar/diff/workdir.c b/tests-clar/diff/workdir.c
index 435bd4f2c..94fd7165d 100644
--- a/tests-clar/diff/workdir.c
+++ b/tests-clar/diff/workdir.c
@@ -1033,3 +1033,190 @@ void test_diff_workdir__to_tree_issue_1397(void)
git_diff_list_free(diff);
git_tree_free(a);
}
+
+void test_diff_workdir__untracked_directory_scenarios(void)
+{
+ git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
+ git_diff_list *diff = NULL;
+ diff_expects exp;
+ char *pathspec = NULL;
+ static const char *files0[] = {
+ "subdir/deleted_file",
+ "subdir/modified_file",
+ "subdir/new_file",
+ NULL
+ };
+ static const char *files1[] = {
+ "subdir/deleted_file",
+ "subdir/directory/",
+ "subdir/modified_file",
+ "subdir/new_file",
+ NULL
+ };
+ static const char *files2[] = {
+ "subdir/deleted_file",
+ "subdir/directory/more/notignored",
+ "subdir/modified_file",
+ "subdir/new_file",
+ NULL
+ };
+
+ g_repo = cl_git_sandbox_init("status");
+ cl_git_mkfile("status/.gitignore", "ignored\n");
+
+ opts.context_lines = 3;
+ opts.interhunk_lines = 1;
+ opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED;
+ opts.pathspec.strings = &pathspec;
+ opts.pathspec.count = 1;
+ pathspec = "subdir";
+
+ /* baseline for "subdir" pathspec */
+
+ memset(&exp, 0, sizeof(exp));
+ exp.names = files0;
+
+ cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+
+ cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp));
+
+ cl_assert_equal_i(3, exp.files);
+ cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
+ cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]);
+ cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
+ cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]);
+ cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]);
+
+ git_diff_list_free(diff);
+
+ /* empty directory */
+
+ cl_git_pass(p_mkdir("status/subdir/directory", 0777));
+
+ memset(&exp, 0, sizeof(exp));
+ exp.names = files1;
+
+ cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+
+ cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp));
+
+ cl_assert_equal_i(4, exp.files);
+ cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
+ cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]);
+ cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
+ cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]);
+ cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]);
+
+ git_diff_list_free(diff);
+
+ /* directory with only ignored files */
+
+ cl_git_pass(p_mkdir("status/subdir/directory/deeper", 0777));
+ cl_git_mkfile("status/subdir/directory/deeper/ignored", "ignore me\n");
+
+ cl_git_pass(p_mkdir("status/subdir/directory/another", 0777));
+ cl_git_mkfile("status/subdir/directory/another/ignored", "ignore me\n");
+
+ memset(&exp, 0, sizeof(exp));
+ exp.names = files1;
+
+ cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+
+ cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp));
+
+ cl_assert_equal_i(4, exp.files);
+ cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
+ cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]);
+ cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
+ cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]);
+ cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]);
+
+ git_diff_list_free(diff);
+
+ /* directory with ignored directory (contents irrelevant) */
+
+ cl_git_pass(p_mkdir("status/subdir/directory/more", 0777));
+ cl_git_pass(p_mkdir("status/subdir/directory/more/ignored", 0777));
+ cl_git_mkfile("status/subdir/directory/more/ignored/notignored",
+ "inside ignored dir\n");
+
+ memset(&exp, 0, sizeof(exp));
+ exp.names = files1;
+
+ cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+
+ cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp));
+
+ cl_assert_equal_i(4, exp.files);
+ cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
+ cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]);
+ cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
+ cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]);
+ cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]);
+
+ git_diff_list_free(diff);
+
+ /* quick version avoids directory scan */
+
+ opts.flags = opts.flags | GIT_DIFF_FAST_UNTRACKED_DIRS;
+
+ memset(&exp, 0, sizeof(exp));
+ exp.names = files1;
+
+ cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+
+ cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp));
+
+ cl_assert_equal_i(4, exp.files);
+ cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
+ cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]);
+ cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
+ cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]);
+ cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNTRACKED]);
+
+ git_diff_list_free(diff);
+
+ /* directory with nested non-ignored content */
+
+ opts.flags = opts.flags & ~GIT_DIFF_FAST_UNTRACKED_DIRS;
+
+ cl_git_mkfile("status/subdir/directory/more/notignored",
+ "not ignored deep under untracked\n");
+
+ memset(&exp, 0, sizeof(exp));
+ exp.names = files1;
+
+ cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+
+ cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp));
+
+ cl_assert_equal_i(4, exp.files);
+ cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
+ cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]);
+ cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
+ cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]);
+ cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNTRACKED]);
+
+ git_diff_list_free(diff);
+
+ /* use RECURSE_UNTRACKED_DIRS to get actual untracked files (no ignores) */
+
+ opts.flags = opts.flags & ~GIT_DIFF_INCLUDE_IGNORED;
+ opts.flags = opts.flags | GIT_DIFF_RECURSE_UNTRACKED_DIRS;
+
+ memset(&exp, 0, sizeof(exp));
+ exp.names = files2;
+
+ cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+
+ cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp));
+
+ cl_assert_equal_i(4, exp.files);
+ cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
+ cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]);
+ cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
+ cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]);
+ cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNTRACKED]);
+
+ git_diff_list_free(diff);
+}