summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/git2/diff.h7
-rw-r--r--src/diff.c46
-rw-r--r--src/iterator.c115
-rw-r--r--src/iterator.h7
-rw-r--r--src/merge.c5
-rw-r--r--tests/repo/iterator.c248
6 files changed, 405 insertions, 23 deletions
diff --git a/include/git2/diff.h b/include/git2/diff.h
index 0abbc7f06..c3589bb13 100644
--- a/include/git2/diff.h
+++ b/include/git2/diff.h
@@ -163,6 +163,13 @@ typedef enum {
/** Include unreadable files in the diff */
GIT_DIFF_INCLUDE_UNREADABLE_AS_UNTRACKED = (1u << 17),
+ /** Use literal path matching in the iterators. This is more broad
+ * than the DISABLE_PATHSPEC_MATCH flag. The caller must provide an
+ * array of paths (no patterns or prefixes). Only values included in
+ * that list will be returned.
+ */
+ GIT_DIFF_ENABLE_FILELIST_MATCH = (1u << 18),
+
/*
* Options controlling how output will be generated
*/
diff --git a/src/diff.c b/src/diff.c
index 58004db21..d87738fb3 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -74,6 +74,24 @@ static int diff_insert_delta(
return error;
}
+static bool diff_pathspec_match(
+ const char **matched_pathspec, git_diff *diff, const char *path)
+{
+ /* The iterator has filtered out paths for us, so the fact that we're
+ * seeing this patch means that it must match the given path list.
+ */
+ if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_ENABLE_FILELIST_MATCH)) {
+ *matched_pathspec = path;
+ return true;
+ }
+
+ return git_pathspec__match(
+ &diff->pathspec, path,
+ DIFF_FLAG_IS_SET(diff, GIT_DIFF_DISABLE_PATHSPEC_MATCH),
+ DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_CASE),
+ matched_pathspec, NULL);
+}
+
static int diff_delta__from_one(
git_diff *diff,
git_delta_t status,
@@ -110,11 +128,7 @@ static int diff_delta__from_one(
DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_INCLUDE_UNREADABLE))
return 0;
- if (!git_pathspec__match(
- &diff->pathspec, entry->path,
- DIFF_FLAG_IS_SET(diff, GIT_DIFF_DISABLE_PATHSPEC_MATCH),
- DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_CASE),
- &matched_pathspec, NULL))
+ if (!diff_pathspec_match(&matched_pathspec, diff, entry->path))
return 0;
delta = diff_delta__alloc(diff, status, entry->path);
@@ -755,11 +769,7 @@ static int maybe_modified(
const char *matched_pathspec;
int error = 0;
- if (!git_pathspec__match(
- &diff->pathspec, oitem->path,
- DIFF_FLAG_IS_SET(diff, GIT_DIFF_DISABLE_PATHSPEC_MATCH),
- DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_CASE),
- &matched_pathspec, NULL))
+ if (!diff_pathspec_match(&matched_pathspec, diff, oitem->path))
return 0;
memset(&noid, 0, sizeof(noid));
@@ -1266,7 +1276,9 @@ cleanup:
#define DIFF_FROM_ITERATORS(MAKE_FIRST, FLAGS_FIRST, MAKE_SECOND, FLAGS_SECOND) do { \
git_iterator *a = NULL, *b = NULL; \
- char *pfx = opts ? git_pathspec_prefix(&opts->pathspec) : NULL; \
+ git_vector pathlist = GIT_VECTOR_INIT; \
+ char *pfx = (opts && !(opts->flags & GIT_DIFF_ENABLE_FILELIST_MATCH)) ? \
+ git_pathspec_prefix(&opts->pathspec) : NULL; \
git_iterator_options a_opts = GIT_ITERATOR_OPTIONS_INIT, \
b_opts = GIT_ITERATOR_OPTIONS_INIT; \
a_opts.flags = FLAGS_FIRST; \
@@ -1276,9 +1288,19 @@ cleanup:
b_opts.start = pfx; \
b_opts.end = pfx; \
GITERR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options"); \
- if (!(error = MAKE_FIRST) && !(error = MAKE_SECOND)) \
+ if (opts && (opts->flags & GIT_DIFF_ENABLE_FILELIST_MATCH) && opts->pathspec.count) { \
+ size_t __i; \
+ error = git_vector_init(&pathlist, opts->pathspec.count, NULL); \
+ for (__i = 0; !error && __i < opts->pathspec.count; __i++) { \
+ error = git_vector_insert(&pathlist, opts->pathspec.strings[__i]); \
+ } \
+ a_opts.pathlist = &pathlist; \
+ b_opts.pathlist = &pathlist; \
+ } \
+ if (!error && !(error = MAKE_FIRST) && !(error = MAKE_SECOND)) \
error = git_diff__from_iterators(diff, repo, a, b, opts); \
git__free(pfx); git_iterator_free(a); git_iterator_free(b); \
+ git_vector_free(&pathlist); \
} while (0)
int git_diff_tree_to_tree(
diff --git a/src/iterator.c b/src/iterator.c
index 374caf96d..28629c708 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -42,6 +42,8 @@
(P)->base.flags = options ? options->flags & ~ITERATOR_CASE_FLAGS : 0; \
if ((P)->base.flags & GIT_ITERATOR_DONT_AUTOEXPAND) \
(P)->base.flags |= GIT_ITERATOR_INCLUDE_TREES; \
+ if (options && options->pathlist) \
+ (P)->base.pathlist = options->pathlist; \
} while (0)
#define iterator__flag(I,F) ((((git_iterator *)(I))->flags & GIT_ITERATOR_ ## F) != 0)
@@ -106,6 +108,12 @@ static int iterator__update_ignore_case(
iter->prefixcomp = iterator__ignore_case(iter) ?
git__prefixcmp_icase : git__prefixcmp;
+ if (iter->pathlist) {
+ git_vector_set_cmp(iter->pathlist, iterator__ignore_case(iter) ?
+ git__strcasecmp : git__strcmp);
+ git_vector_sort(iter->pathlist);
+ }
+
return error;
}
@@ -616,6 +624,9 @@ int git_iterator_for_tree(
if (tree == NULL)
return git_iterator_for_nothing(iter, options);
+ /* not yet supported */
+ assert (!options || !options->pathlist);
+
if ((error = git_object_dup((git_object **)&tree, (git_object *)tree)) < 0)
return error;
@@ -668,15 +679,47 @@ static const git_index_entry *index_iterator__index_entry(index_iterator *ii)
return ie;
}
-static const git_index_entry *index_iterator__advance_over_conflicts(index_iterator *ii)
+static const git_index_entry *index_iterator__advance_over_unwanted(index_iterator *ii)
{
const git_index_entry *ie = index_iterator__index_entry(ii);
+ const char *p;
+ int cmp;
- if (!iterator__include_conflicts(ii)) {
- while (ie && git_index_entry_is_conflict(ie)) {
+ while (ie) {
+ if (!iterator__include_conflicts(ii) &&
+ git_index_entry_is_conflict(ie)) {
ii->current++;
ie = index_iterator__index_entry(ii);
+ continue;
}
+
+ /* if we have a pathlist, this entry's path must be in it to be
+ * returned. otherwise, advance the pathlist entry or the iterator
+ * until we find the next path that we want to return.
+ */
+ if (ii->base.pathlist) {
+ if (ii->base.pathlist_idx >= ii->base.pathlist->length) {
+ ii->current = SIZE_MAX;
+ ie = NULL;
+ break;
+ }
+
+ p = ii->base.pathlist->contents[ii->base.pathlist_idx];
+ cmp = ii->base.pathlist->_cmp(p, ie->path);
+
+ if (cmp < 0) {
+ ii->base.pathlist_idx++;
+ continue;
+ }
+
+ if (cmp > 0) {
+ ii->current++;
+ ie = index_iterator__index_entry(ii);
+ continue;
+ }
+ }
+
+ break;
}
return ie;
@@ -705,7 +748,7 @@ static void index_iterator__next_prefix_tree(index_iterator *ii)
static int index_iterator__first_prefix_tree(index_iterator *ii)
{
- const git_index_entry *ie = index_iterator__advance_over_conflicts(ii);
+ const git_index_entry *ie = index_iterator__advance_over_unwanted(ii);
const char *scan, *prior, *slash;
if (!ie || !iterator__include_trees(ii))
@@ -818,17 +861,22 @@ static int index_iterator__reset(
{
index_iterator *ii = (index_iterator *)self;
const git_index_entry *ie;
+ size_t pathlist_idx = 0;
if (iterator__reset_range(self, start, end) < 0)
return -1;
ii->current = 0;
+ ii->base.pathlist_idx = 0;
+ /* if we're given a start prefix, find it; if we're given a pathlist, find
+ * the first of those. start at the later of the two.
+ */
if (ii->base.start)
git_index_snapshot_find(
&ii->current, &ii->entries, ii->entry_srch, ii->base.start, 0, 0);
- if ((ie = index_iterator__advance_over_conflicts(ii)) == NULL)
+ if ((ie = index_iterator__advance_over_unwanted(ii)) == NULL)
return 0;
if (git_buf_sets(&ii->partial, ie->path) < 0)
@@ -1004,25 +1052,60 @@ static void fs_iterator__seek_frame_start(
ff->index = 0;
}
+typedef enum {
+ DIRLOAD_PATHLIST_NONE = 0,
+ DIRLOAD_PATHLIST_EXACT = 1,
+ DIRLOAD_PATHLIST_DIRECTORY = 2,
+} dirload_pathlist_match_t;
+
+static dirload_pathlist_match_t dirload_pathlist_match(
+ git_vector *pathlist,
+ const char *path,
+ size_t path_len,
+ int (*prefixcomp)(const char *a, const char *b))
+{
+ const char *matched;
+ size_t idx;
+
+ if (git_vector_bsearch2(
+ &idx, pathlist, pathlist->_cmp, path) != GIT_ENOTFOUND)
+ return DIRLOAD_PATHLIST_EXACT;
+
+ /* the explicit path we searched for was not found, but this may be
+ * a directory and the pathlist contains a file in it. check.
+ */
+ if ((matched = git_vector_get(pathlist, idx)) != NULL &&
+ prefixcomp(matched, path) == 0 &&
+ matched[path_len] == '/')
+ return DIRLOAD_PATHLIST_DIRECTORY;
+
+ return DIRLOAD_PATHLIST_NONE;
+}
+
static int dirload_with_stat(
+ git_vector *contents,
const char *dirpath,
size_t prefix_len,
unsigned int flags,
const char *start_stat,
const char *end_stat,
- git_vector *contents)
+ git_vector *pathlist)
{
git_path_diriter diriter = GIT_PATH_DIRITER_INIT;
const char *path;
int (*strncomp)(const char *a, const char *b, size_t sz);
+ int (*prefixcomp)(const char *a, const char *b);
size_t start_len = start_stat ? strlen(start_stat) : 0;
size_t end_len = end_stat ? strlen(end_stat) : 0;
fs_iterator_path_with_stat *ps;
size_t path_len, cmp_len, ps_size;
+ dirload_pathlist_match_t pathlist_match = DIRLOAD_PATHLIST_EXACT;
int error;
strncomp = (flags & GIT_PATH_DIR_IGNORE_CASE) != 0 ?
git__strncasecmp : git__strncmp;
+ prefixcomp = (flags & GIT_PATH_DIR_IGNORE_CASE) != 0 ?
+ git__prefixcmp_icase : git__prefixcmp;
/* Any error here is equivalent to the dir not existing, skip over it */
if ((error = git_path_diriter_init(&diriter, dirpath, flags)) < 0) {
@@ -1044,10 +1127,20 @@ static int dirload_with_stat(
cmp_len = min(start_len, path_len);
if (cmp_len && strncomp(path, start_stat, cmp_len) < 0)
continue;
+ /* skip if after end_stat */
cmp_len = min(end_len, path_len);
if (cmp_len && strncomp(path, end_stat, cmp_len) > 0)
continue;
+ /* skip if we have a pathlist and this isn't in it. note that we
+ * haven't stat'd yet to know if it's a file or a directory, so this
+ * match for files like `foo` when we're looking for `foo/bar`
+ */
+ if (pathlist &&
+ !(pathlist_match = dirload_pathlist_match(
+ pathlist, path, path_len, prefixcomp)))
+ continue;
+
/* Make sure to append two bytes, one for the path's null
* termination, one for a possible trailing '/' for folders.
*/
@@ -1068,6 +1161,12 @@ static int dirload_with_stat(
continue;
}
+ if (pathlist_match == DIRLOAD_PATHLIST_DIRECTORY) {
+ /* were looking for a directory, but this is a file */
+ git__free(ps);
+ continue;
+ }
+
/* Treat the file as unreadable if we get any other error */
memset(&ps->st, 0, sizeof(ps->st));
ps->st.st_mode = GIT_FILEMODE_UNREADABLE;
@@ -1113,9 +1212,9 @@ static int fs_iterator__expand_dir(fs_iterator *fi)
ff = fs_iterator__alloc_frame(fi);
GITERR_CHECK_ALLOC(ff);
- error = dirload_with_stat(
+ error = dirload_with_stat(&ff->entries,
fi->path.ptr, fi->root_len, fi->dirload_flags,
- fi->base.start, fi->base.end, &ff->entries);
+ fi->base.start, fi->base.end, fi->base.pathlist);
if (error < 0) {
git_error_state last_error = { 0 };
diff --git a/src/iterator.h b/src/iterator.h
index 46e96f044..0ea2bc053 100644
--- a/src/iterator.h
+++ b/src/iterator.h
@@ -43,6 +43,11 @@ typedef struct {
const char *start;
const char *end;
+ /* paths to include in the iterator (literal). any paths not listed
+ * will be excluded. note that this vector may be resorted!
+ */
+ git_vector *pathlist;
+
/* flags, from above */
unsigned int flags;
} git_iterator_options;
@@ -65,6 +70,8 @@ struct git_iterator {
git_repository *repo;
char *start;
char *end;
+ git_vector *pathlist;
+ size_t pathlist_idx;
int (*prefixcomp)(const char *str, const char *prefix);
size_t stat_calls;
unsigned int flags;
diff --git a/src/merge.c b/src/merge.c
index 16cd2aee0..1460a5040 100644
--- a/src/merge.c
+++ b/src/merge.c
@@ -2356,10 +2356,8 @@ static int merge_check_index(size_t *conflicts, git_repository *repo, git_index
goto done;
}
- opts.pathspec.count = staged_paths.length;
- opts.pathspec.strings = (char **)staged_paths.contents;
-
iter_opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE;
+ iter_opts.pathlist = &staged_paths;
if ((error = git_iterator_for_index(&iter_repo, index_repo, &iter_opts)) < 0 ||
(error = git_iterator_for_index(&iter_new, index_new, &iter_opts)) < 0 ||
@@ -2406,6 +2404,7 @@ static int merge_check_workdir(size_t *conflicts, git_repository *repo, git_inde
* will be applied by the merge (including conflicts). Ensure that there
* are no changes in the workdir to these paths.
*/
+ opts.flags |= GIT_DIFF_ENABLE_FILELIST_MATCH;
opts.pathspec.count = merged_paths->length;
opts.pathspec.strings = (char **)merged_paths->contents;
diff --git a/tests/repo/iterator.c b/tests/repo/iterator.c
index 4d0d12be1..8af7bc533 100644
--- a/tests/repo/iterator.c
+++ b/tests/repo/iterator.c
@@ -1073,3 +1073,251 @@ void test_repo_iterator__skips_fifos_and_such(void)
git_iterator_free(i);
#endif
}
+
+void test_repo_iterator__indexfilelist(void)
+{
+ git_iterator *i;
+ git_iterator_options i_opts = GIT_ITERATOR_OPTIONS_INIT;
+ git_index *index;
+ git_vector filelist;
+ int default_icase;
+ int expect;
+
+ cl_git_pass(git_vector_init(&filelist, 100, &git__strcmp_cb));
+ cl_git_pass(git_vector_insert(&filelist, "a"));
+ cl_git_pass(git_vector_insert(&filelist, "B"));
+ cl_git_pass(git_vector_insert(&filelist, "c"));
+ cl_git_pass(git_vector_insert(&filelist, "D"));
+ cl_git_pass(git_vector_insert(&filelist, "e"));
+ cl_git_pass(git_vector_insert(&filelist, "k/1"));
+ cl_git_pass(git_vector_insert(&filelist, "k/a"));
+ cl_git_pass(git_vector_insert(&filelist, "L/1"));
+
+ g_repo = cl_git_sandbox_init("icase");
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+ /* In this test we DO NOT force a case setting on the index. */
+ default_icase = ((git_index_caps(index) & GIT_INDEXCAP_IGNORE_CASE) != 0);
+
+ i_opts.pathlist = &filelist;
+
+ /* All indexfilelist iterator tests are "autoexpand with no tree entries" */
+
+ cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ expect_iterator_items(i, 8, NULL, 8, NULL);
+ git_iterator_free(i);
+
+ i_opts.start = "c";
+ i_opts.end = NULL;
+
+ cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ /* (c D e k/1 k/a L ==> 6) vs (c e k/1 k/a ==> 4) */
+ expect = ((default_icase) ? 6 : 4);
+ expect_iterator_items(i, expect, NULL, expect, NULL);
+ git_iterator_free(i);
+
+ i_opts.start = NULL;
+ i_opts.end = "e";
+
+ cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ /* (a B c D e ==> 5) vs (B D L/1 a c e ==> 6) */
+ expect = ((default_icase) ? 5 : 6);
+ expect_iterator_items(i, expect, NULL, expect, NULL);
+ git_iterator_free(i);
+
+ git_index_free(index);
+ git_vector_free(&filelist);
+}
+
+void test_repo_iterator__indexfilelist_2(void)
+{
+ git_iterator *i;
+ git_iterator_options i_opts = GIT_ITERATOR_OPTIONS_INIT;
+ git_index *index;
+ git_vector filelist = GIT_VECTOR_INIT;
+
+ g_repo = cl_git_sandbox_init("icase");
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+
+ cl_git_pass(git_vector_init(&filelist, 100, &git__strcmp_cb));
+ cl_git_pass(git_vector_insert(&filelist, "0"));
+ cl_git_pass(git_vector_insert(&filelist, "c"));
+ cl_git_pass(git_vector_insert(&filelist, "D"));
+ cl_git_pass(git_vector_insert(&filelist, "e"));
+ cl_git_pass(git_vector_insert(&filelist, "k/a"));
+
+ i_opts.pathlist = &filelist;
+
+ i_opts.start = "b";
+ i_opts.end = "k/D";
+
+ cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ expect_iterator_items(i, 4, NULL, 4, NULL);
+ git_iterator_free(i);
+
+ git_index_free(index);
+ git_vector_free(&filelist);
+}
+
+void test_repo_iterator__indexfilelist_icase(void)
+{
+ git_iterator *i;
+ git_iterator_options i_opts = GIT_ITERATOR_OPTIONS_INIT;
+ git_index *index;
+ int caps;
+ git_vector filelist;
+
+ cl_git_pass(git_vector_init(&filelist, 100, &git__strcmp_cb));
+ cl_git_pass(git_vector_insert(&filelist, "a"));
+ cl_git_pass(git_vector_insert(&filelist, "B"));
+ cl_git_pass(git_vector_insert(&filelist, "c"));
+ cl_git_pass(git_vector_insert(&filelist, "D"));
+ cl_git_pass(git_vector_insert(&filelist, "e"));
+ cl_git_pass(git_vector_insert(&filelist, "k/1"));
+ cl_git_pass(git_vector_insert(&filelist, "k/a"));
+ cl_git_pass(git_vector_insert(&filelist, "L/1"));
+
+ g_repo = cl_git_sandbox_init("icase");
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+ caps = git_index_caps(index);
+
+ /* force case sensitivity */
+ cl_git_pass(git_index_set_caps(index, caps & ~GIT_INDEXCAP_IGNORE_CASE));
+
+ /* All indexfilelist iterator tests are "autoexpand with no tree entries" */
+
+ i_opts.pathlist = &filelist;
+
+ i_opts.start = "c";
+ i_opts.end = "k/D";
+ cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ expect_iterator_items(i, 3, NULL, 3, NULL);
+ git_iterator_free(i);
+
+ i_opts.start = "k";
+ i_opts.end = "k/Z";
+ cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ expect_iterator_items(i, 1, NULL, 1, NULL);
+ git_iterator_free(i);
+
+ /* force case insensitivity */
+ cl_git_pass(git_index_set_caps(index, caps | GIT_INDEXCAP_IGNORE_CASE));
+
+ i_opts.start = "c";
+ i_opts.end = "k/D";
+ cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ expect_iterator_items(i, 5, NULL, 5, NULL);
+ git_iterator_free(i);
+
+ i_opts.start = "k";
+ i_opts.end = "k/Z";
+ cl_git_pass(git_iterator_for_index(&i, index, &i_opts));
+ expect_iterator_items(i, 2, NULL, 2, NULL);
+ git_iterator_free(i);
+
+ cl_git_pass(git_index_set_caps(index, caps));
+ git_index_free(index);
+ git_vector_free(&filelist);
+}
+
+void test_repo_iterator__workdirfilelist(void)
+{
+ git_iterator *i;
+ git_iterator_options i_opts = GIT_ITERATOR_OPTIONS_INIT;
+ git_vector filelist;
+ bool default_icase;
+ int expect;
+
+ cl_git_pass(git_vector_init(&filelist, 100, &git__strcmp_cb));
+ cl_git_pass(git_vector_insert(&filelist, "a"));
+ cl_git_pass(git_vector_insert(&filelist, "B"));
+ cl_git_pass(git_vector_insert(&filelist, "c"));
+ cl_git_pass(git_vector_insert(&filelist, "D"));
+ cl_git_pass(git_vector_insert(&filelist, "e"));
+ cl_git_pass(git_vector_insert(&filelist, "k/1"));
+ cl_git_pass(git_vector_insert(&filelist, "k/a"));
+ cl_git_pass(git_vector_insert(&filelist, "L/1"));
+
+ g_repo = cl_git_sandbox_init("icase");
+
+ /* All indexfilelist iterator tests are "autoexpand with no tree entries" */
+ /* In this test we DO NOT force a case on the iteratords and verify default behavior. */
+
+ i_opts.pathlist = &filelist;
+
+ cl_git_pass(git_iterator_for_workdir(&i, g_repo, NULL, NULL, &i_opts));
+ expect_iterator_items(i, 8, NULL, 8, NULL);
+ git_iterator_free(i);
+
+ i_opts.start = "c";
+ i_opts.end = NULL;
+ cl_git_pass(git_iterator_for_workdir(&i, g_repo, NULL, NULL, &i_opts));
+ default_icase = git_iterator_ignore_case(i);
+ /* (c D e k/1 k/a L ==> 6) vs (c e k/1 k/a ==> 4) */
+ expect = ((default_icase) ? 6 : 4);
+ expect_iterator_items(i, expect, NULL, expect, NULL);
+ git_iterator_free(i);
+
+ i_opts.start = NULL;
+ i_opts.end = "e";
+ cl_git_pass(git_iterator_for_workdir(&i, g_repo, NULL, NULL, &i_opts));
+ default_icase = git_iterator_ignore_case(i);
+ /* (a B c D e ==> 5) vs (B D L/1 a c e ==> 6) */
+ expect = ((default_icase) ? 5 : 6);
+ expect_iterator_items(i, expect, NULL, expect, NULL);
+ git_iterator_free(i);
+
+ git_vector_free(&filelist);
+}
+
+void test_repo_iterator__workdirfilelist_icase(void)
+{
+ git_iterator *i;
+ git_iterator_options i_opts = GIT_ITERATOR_OPTIONS_INIT;
+ git_vector filelist;
+
+ cl_git_pass(git_vector_init(&filelist, 100, &git__strcmp_cb));
+ cl_git_pass(git_vector_insert(&filelist, "a"));
+ cl_git_pass(git_vector_insert(&filelist, "B"));
+ cl_git_pass(git_vector_insert(&filelist, "c"));
+ cl_git_pass(git_vector_insert(&filelist, "D"));
+ cl_git_pass(git_vector_insert(&filelist, "e"));
+ cl_git_pass(git_vector_insert(&filelist, "k/1"));
+ cl_git_pass(git_vector_insert(&filelist, "k/a"));
+ cl_git_pass(git_vector_insert(&filelist, "L/1"));
+
+ g_repo = cl_git_sandbox_init("icase");
+
+ i_opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE;
+ i_opts.pathlist = &filelist;
+
+ i_opts.start = "c";
+ i_opts.end = "k/D";
+ cl_git_pass(git_iterator_for_workdir(&i, g_repo, NULL, NULL, &i_opts));
+ expect_iterator_items(i, 3, NULL, 3, NULL);
+ git_iterator_free(i);
+
+ i_opts.start = "k";
+ i_opts.end = "k/Z";
+ cl_git_pass(git_iterator_for_workdir(&i, g_repo, NULL, NULL, &i_opts));
+ expect_iterator_items(i, 1, NULL, 1, NULL);
+ git_iterator_free(i);
+
+ i_opts.flags = GIT_ITERATOR_IGNORE_CASE;
+
+ i_opts.start = "c";
+ i_opts.end = "k/D";
+ cl_git_pass(git_iterator_for_workdir(&i, g_repo, NULL, NULL, &i_opts));
+ expect_iterator_items(i, 5, NULL, 5, NULL);
+ git_iterator_free(i);
+
+ i_opts.start = "k";
+ i_opts.end = "k/Z";
+ cl_git_pass(git_iterator_for_workdir(&i, g_repo, NULL, NULL, &i_opts));
+ expect_iterator_items(i, 2, NULL, 2, NULL);
+ git_iterator_free(i);
+
+ git_vector_free(&filelist);
+}