mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-08 19:51:31 +00:00

The .gitignore file allows for patterns which unignore previous ignore patterns. When unignoring a previous pattern, there are basically three cases how this is matched when no globbing is used: 1. when a previous file has been ignored, it can be unignored by using its exact name, e.g. foo/bar !foo/bar 2. when a file in a subdirectory has been ignored, it can be unignored by using its basename, e.g. foo/bar !bar 3. when all files with a basename are ignored, a specific file can be unignored again by specifying its path in a subdirectory, e.g. bar !foo/bar The first problem in libgit2 is that we did not correctly treat the second case. While we verified that the negative pattern matches the tail of the positive one, we did not verify if it only matches the basename of the positive pattern. So e.g. we would have also negated a pattern like foo/fruz_bar !bar Furthermore, we did not check for the third case, where a basename is being unignored in a certain subdirectory again. Both issues are fixed with this commit.
1080 lines
32 KiB
C
1080 lines
32 KiB
C
#include "clar_libgit2.h"
|
|
#include "fileops.h"
|
|
#include "git2/attr.h"
|
|
#include "ignore.h"
|
|
#include "attr.h"
|
|
#include "status_helpers.h"
|
|
|
|
static git_repository *g_repo = NULL;
|
|
|
|
void test_status_ignore__initialize(void)
|
|
{
|
|
}
|
|
|
|
void test_status_ignore__cleanup(void)
|
|
{
|
|
cl_git_sandbox_cleanup();
|
|
}
|
|
|
|
static void assert_ignored_(
|
|
bool expected, const char *filepath, const char *file, int line)
|
|
{
|
|
int is_ignored = 0;
|
|
cl_git_pass_(
|
|
git_status_should_ignore(&is_ignored, g_repo, filepath), file, line);
|
|
clar__assert(
|
|
(expected != 0) == (is_ignored != 0),
|
|
file, line, "expected != is_ignored", filepath, 1);
|
|
}
|
|
#define assert_ignored(expected, filepath) \
|
|
assert_ignored_(expected, filepath, __FILE__, __LINE__)
|
|
#define assert_is_ignored(filepath) \
|
|
assert_ignored_(true, filepath, __FILE__, __LINE__)
|
|
#define refute_is_ignored(filepath) \
|
|
assert_ignored_(false, filepath, __FILE__, __LINE__)
|
|
|
|
void test_status_ignore__0(void)
|
|
{
|
|
struct {
|
|
const char *path;
|
|
int expected;
|
|
} test_cases[] = {
|
|
/* pattern "ign" from .gitignore */
|
|
{ "file", 0 },
|
|
{ "ign", 1 },
|
|
{ "sub", 0 },
|
|
{ "sub/file", 0 },
|
|
{ "sub/ign", 1 },
|
|
{ "sub/ign/file", 1 },
|
|
{ "sub/ign/sub", 1 },
|
|
{ "sub/ign/sub/file", 1 },
|
|
{ "sub/sub", 0 },
|
|
{ "sub/sub/file", 0 },
|
|
{ "sub/sub/ign", 1 },
|
|
{ "sub/sub/sub", 0 },
|
|
/* pattern "dir/" from .gitignore */
|
|
{ "dir", 1 },
|
|
{ "dir/", 1 },
|
|
{ "sub/dir", 1 },
|
|
{ "sub/dir/", 1 },
|
|
{ "sub/dir/file", 1 }, /* contained in ignored parent */
|
|
{ "sub/sub/dir", 0 }, /* dir is not actually a dir, but a file */
|
|
{ NULL, 0 }
|
|
}, *one_test;
|
|
|
|
g_repo = cl_git_sandbox_init("attr");
|
|
|
|
for (one_test = test_cases; one_test->path != NULL; one_test++)
|
|
assert_ignored(one_test->expected, one_test->path);
|
|
|
|
/* confirm that ignore files were cached */
|
|
cl_assert(git_attr_cache__is_cached(
|
|
g_repo, GIT_ATTR_FILE__FROM_FILE, ".git/info/exclude"));
|
|
cl_assert(git_attr_cache__is_cached(
|
|
g_repo, GIT_ATTR_FILE__FROM_FILE, ".gitignore"));
|
|
}
|
|
|
|
|
|
void test_status_ignore__1(void)
|
|
{
|
|
g_repo = cl_git_sandbox_init("attr");
|
|
|
|
cl_git_rewritefile("attr/.gitignore", "/*.txt\n/dir/\n");
|
|
git_attr_cache_flush(g_repo);
|
|
|
|
assert_is_ignored("root_test4.txt");
|
|
refute_is_ignored("sub/subdir_test2.txt");
|
|
assert_is_ignored("dir");
|
|
assert_is_ignored("dir/");
|
|
refute_is_ignored("sub/dir");
|
|
refute_is_ignored("sub/dir/");
|
|
}
|
|
|
|
void test_status_ignore__empty_repo_with_gitignore_rewrite(void)
|
|
{
|
|
status_entry_single st;
|
|
|
|
g_repo = cl_git_sandbox_init("empty_standard_repo");
|
|
|
|
cl_git_mkfile(
|
|
"empty_standard_repo/look-ma.txt", "I'm going to be ignored!");
|
|
|
|
memset(&st, 0, sizeof(st));
|
|
cl_git_pass(git_status_foreach(g_repo, cb_status__single, &st));
|
|
cl_assert(st.count == 1);
|
|
cl_assert(st.status == GIT_STATUS_WT_NEW);
|
|
|
|
cl_git_pass(git_status_file(&st.status, g_repo, "look-ma.txt"));
|
|
cl_assert(st.status == GIT_STATUS_WT_NEW);
|
|
|
|
refute_is_ignored("look-ma.txt");
|
|
|
|
cl_git_rewritefile("empty_standard_repo/.gitignore", "*.nomatch\n");
|
|
|
|
memset(&st, 0, sizeof(st));
|
|
cl_git_pass(git_status_foreach(g_repo, cb_status__single, &st));
|
|
cl_assert(st.count == 2);
|
|
cl_assert(st.status == GIT_STATUS_WT_NEW);
|
|
|
|
cl_git_pass(git_status_file(&st.status, g_repo, "look-ma.txt"));
|
|
cl_assert(st.status == GIT_STATUS_WT_NEW);
|
|
|
|
refute_is_ignored("look-ma.txt");
|
|
|
|
cl_git_rewritefile("empty_standard_repo/.gitignore", "*.txt\n");
|
|
|
|
memset(&st, 0, sizeof(st));
|
|
cl_git_pass(git_status_foreach(g_repo, cb_status__single, &st));
|
|
cl_assert(st.count == 2);
|
|
cl_assert(st.status == GIT_STATUS_IGNORED);
|
|
|
|
cl_git_pass(git_status_file(&st.status, g_repo, "look-ma.txt"));
|
|
cl_assert(st.status == GIT_STATUS_IGNORED);
|
|
|
|
assert_is_ignored("look-ma.txt");
|
|
}
|
|
|
|
void test_status_ignore__ignore_pattern_contains_space(void)
|
|
{
|
|
unsigned int flags;
|
|
const mode_t mode = 0777;
|
|
|
|
g_repo = cl_git_sandbox_init("empty_standard_repo");
|
|
cl_git_rewritefile("empty_standard_repo/.gitignore", "foo bar.txt\n");
|
|
|
|
cl_git_mkfile(
|
|
"empty_standard_repo/foo bar.txt", "I'm going to be ignored!");
|
|
|
|
cl_git_pass(git_status_file(&flags, g_repo, "foo bar.txt"));
|
|
cl_assert(flags == GIT_STATUS_IGNORED);
|
|
|
|
cl_git_pass(git_futils_mkdir_r("empty_standard_repo/foo", mode));
|
|
cl_git_mkfile("empty_standard_repo/foo/look-ma.txt", "I'm not going to be ignored!");
|
|
|
|
cl_git_pass(git_status_file(&flags, g_repo, "foo/look-ma.txt"));
|
|
cl_assert(flags == GIT_STATUS_WT_NEW);
|
|
}
|
|
|
|
void test_status_ignore__ignore_pattern_ignorecase(void)
|
|
{
|
|
unsigned int flags;
|
|
bool ignore_case;
|
|
git_index *index;
|
|
|
|
g_repo = cl_git_sandbox_init("empty_standard_repo");
|
|
cl_git_rewritefile("empty_standard_repo/.gitignore", "a.txt\n");
|
|
|
|
cl_git_mkfile("empty_standard_repo/A.txt", "Differs in case");
|
|
|
|
cl_git_pass(git_repository_index(&index, g_repo));
|
|
ignore_case = (git_index_caps(index) & GIT_INDEXCAP_IGNORE_CASE) != 0;
|
|
git_index_free(index);
|
|
|
|
cl_git_pass(git_status_file(&flags, g_repo, "A.txt"));
|
|
cl_assert(flags == ignore_case ? GIT_STATUS_IGNORED : GIT_STATUS_WT_NEW);
|
|
}
|
|
|
|
void test_status_ignore__subdirectories(void)
|
|
{
|
|
status_entry_single st;
|
|
|
|
g_repo = cl_git_sandbox_init("empty_standard_repo");
|
|
|
|
cl_git_mkfile(
|
|
"empty_standard_repo/ignore_me", "I'm going to be ignored!");
|
|
|
|
cl_git_rewritefile("empty_standard_repo/.gitignore", "ignore_me\n");
|
|
|
|
memset(&st, 0, sizeof(st));
|
|
cl_git_pass(git_status_foreach(g_repo, cb_status__single, &st));
|
|
cl_assert_equal_i(2, st.count);
|
|
cl_assert(st.status == GIT_STATUS_IGNORED);
|
|
|
|
cl_git_pass(git_status_file(&st.status, g_repo, "ignore_me"));
|
|
cl_assert(st.status == GIT_STATUS_IGNORED);
|
|
|
|
assert_is_ignored("ignore_me");
|
|
|
|
/* I've changed libgit2 so that the behavior here now differs from
|
|
* core git but seems to make more sense. In core git, the following
|
|
* items are skipped completed, even if --ignored is passed to status.
|
|
* It you mirror these steps and run "git status -uall --ignored" then
|
|
* you will not see "test/ignore_me/" in the results.
|
|
*
|
|
* However, we had a couple reports of this as a bug, plus there is a
|
|
* similar circumstance where we were differing for core git when you
|
|
* used a rooted path for an ignore, so I changed this behavior.
|
|
*/
|
|
cl_git_pass(git_futils_mkdir_r(
|
|
"empty_standard_repo/test/ignore_me", 0775));
|
|
cl_git_mkfile(
|
|
"empty_standard_repo/test/ignore_me/file", "I'm going to be ignored!");
|
|
cl_git_mkfile(
|
|
"empty_standard_repo/test/ignore_me/file2", "Me, too!");
|
|
|
|
memset(&st, 0, sizeof(st));
|
|
cl_git_pass(git_status_foreach(g_repo, cb_status__single, &st));
|
|
cl_assert_equal_i(3, st.count);
|
|
|
|
cl_git_pass(git_status_file(&st.status, g_repo, "test/ignore_me/file"));
|
|
cl_assert(st.status == GIT_STATUS_IGNORED);
|
|
|
|
assert_is_ignored("test/ignore_me/file");
|
|
}
|
|
|
|
static void make_test_data(const char *reponame, const char **files)
|
|
{
|
|
const char **scan;
|
|
size_t repolen = strlen(reponame) + 1;
|
|
|
|
g_repo = cl_git_sandbox_init(reponame);
|
|
|
|
for (scan = files; *scan != NULL; ++scan) {
|
|
cl_git_pass(git_futils_mkdir_relative(
|
|
*scan + repolen, reponame,
|
|
0777, GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST, NULL));
|
|
cl_git_mkfile(*scan, "contents");
|
|
}
|
|
}
|
|
|
|
static const char *test_repo_1 = "empty_standard_repo";
|
|
static const char *test_files_1[] = {
|
|
"empty_standard_repo/dir/a/ignore_me",
|
|
"empty_standard_repo/dir/b/ignore_me",
|
|
"empty_standard_repo/dir/ignore_me",
|
|
"empty_standard_repo/ignore_also/file",
|
|
"empty_standard_repo/ignore_me",
|
|
"empty_standard_repo/test/ignore_me/file",
|
|
"empty_standard_repo/test/ignore_me/file2",
|
|
"empty_standard_repo/test/ignore_me/and_me/file",
|
|
NULL
|
|
};
|
|
|
|
void test_status_ignore__subdirectories_recursion(void)
|
|
{
|
|
/* Let's try again with recursing into ignored dirs turned on */
|
|
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
|
|
status_entry_counts counts;
|
|
static const char *paths_r[] = {
|
|
".gitignore",
|
|
"dir/a/ignore_me",
|
|
"dir/b/ignore_me",
|
|
"dir/ignore_me",
|
|
"ignore_also/file",
|
|
"ignore_me",
|
|
"test/ignore_me/and_me/file",
|
|
"test/ignore_me/file",
|
|
"test/ignore_me/file2",
|
|
};
|
|
static const unsigned int statuses_r[] = {
|
|
GIT_STATUS_WT_NEW, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED,
|
|
GIT_STATUS_IGNORED, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED,
|
|
GIT_STATUS_IGNORED, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED,
|
|
};
|
|
static const char *paths_nr[] = {
|
|
".gitignore",
|
|
"dir/a/ignore_me",
|
|
"dir/b/ignore_me",
|
|
"dir/ignore_me",
|
|
"ignore_also/",
|
|
"ignore_me",
|
|
"test/ignore_me/",
|
|
};
|
|
static const unsigned int statuses_nr[] = {
|
|
GIT_STATUS_WT_NEW,
|
|
GIT_STATUS_IGNORED, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED,
|
|
GIT_STATUS_IGNORED, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED,
|
|
};
|
|
|
|
make_test_data(test_repo_1, test_files_1);
|
|
cl_git_rewritefile("empty_standard_repo/.gitignore", "ignore_me\n/ignore_also\n");
|
|
|
|
memset(&counts, 0x0, sizeof(status_entry_counts));
|
|
counts.expected_entry_count = 9;
|
|
counts.expected_paths = paths_r;
|
|
counts.expected_statuses = statuses_r;
|
|
|
|
opts.flags = GIT_STATUS_OPT_DEFAULTS | GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
|
|
|
|
cl_git_pass(git_status_foreach_ext(
|
|
g_repo, &opts, cb_status__normal, &counts));
|
|
|
|
cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
|
|
cl_assert_equal_i(0, counts.wrong_status_flags_count);
|
|
cl_assert_equal_i(0, counts.wrong_sorted_path);
|
|
|
|
|
|
memset(&counts, 0x0, sizeof(status_entry_counts));
|
|
counts.expected_entry_count = 7;
|
|
counts.expected_paths = paths_nr;
|
|
counts.expected_statuses = statuses_nr;
|
|
|
|
opts.flags = GIT_STATUS_OPT_DEFAULTS;
|
|
|
|
cl_git_pass(git_status_foreach_ext(
|
|
g_repo, &opts, cb_status__normal, &counts));
|
|
|
|
cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
|
|
cl_assert_equal_i(0, counts.wrong_status_flags_count);
|
|
cl_assert_equal_i(0, counts.wrong_sorted_path);
|
|
}
|
|
|
|
void test_status_ignore__subdirectories_not_at_root(void)
|
|
{
|
|
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
|
|
status_entry_counts counts;
|
|
static const char *paths_1[] = {
|
|
"dir/.gitignore",
|
|
"dir/a/ignore_me",
|
|
"dir/b/ignore_me",
|
|
"dir/ignore_me",
|
|
"ignore_also/file",
|
|
"ignore_me",
|
|
"test/.gitignore",
|
|
"test/ignore_me/and_me/file",
|
|
"test/ignore_me/file",
|
|
"test/ignore_me/file2",
|
|
};
|
|
static const unsigned int statuses_1[] = {
|
|
GIT_STATUS_WT_NEW, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED,
|
|
GIT_STATUS_IGNORED, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW,
|
|
GIT_STATUS_WT_NEW, GIT_STATUS_IGNORED, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW,
|
|
};
|
|
|
|
make_test_data(test_repo_1, test_files_1);
|
|
cl_git_rewritefile("empty_standard_repo/dir/.gitignore", "ignore_me\n/ignore_also\n");
|
|
cl_git_rewritefile("empty_standard_repo/test/.gitignore", "and_me\n");
|
|
|
|
memset(&counts, 0x0, sizeof(status_entry_counts));
|
|
counts.expected_entry_count = 10;
|
|
counts.expected_paths = paths_1;
|
|
counts.expected_statuses = statuses_1;
|
|
|
|
opts.flags = GIT_STATUS_OPT_DEFAULTS | GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
|
|
|
|
cl_git_pass(git_status_foreach_ext(
|
|
g_repo, &opts, cb_status__normal, &counts));
|
|
|
|
cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
|
|
cl_assert_equal_i(0, counts.wrong_status_flags_count);
|
|
cl_assert_equal_i(0, counts.wrong_sorted_path);
|
|
}
|
|
|
|
void test_status_ignore__leading_slash_ignores(void)
|
|
{
|
|
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
|
|
status_entry_counts counts;
|
|
static const char *paths_2[] = {
|
|
"dir/.gitignore",
|
|
"dir/a/ignore_me",
|
|
"dir/b/ignore_me",
|
|
"dir/ignore_me",
|
|
"ignore_also/file",
|
|
"ignore_me",
|
|
"test/.gitignore",
|
|
"test/ignore_me/and_me/file",
|
|
"test/ignore_me/file",
|
|
"test/ignore_me/file2",
|
|
};
|
|
static const unsigned int statuses_2[] = {
|
|
GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW,
|
|
GIT_STATUS_IGNORED, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED,
|
|
GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW,
|
|
};
|
|
|
|
make_test_data(test_repo_1, test_files_1);
|
|
|
|
cl_fake_home();
|
|
cl_git_mkfile("home/.gitignore", "/ignore_me\n");
|
|
{
|
|
git_config *cfg;
|
|
cl_git_pass(git_repository_config(&cfg, g_repo));
|
|
cl_git_pass(git_config_set_string(
|
|
cfg, "core.excludesfile", "~/.gitignore"));
|
|
git_config_free(cfg);
|
|
}
|
|
|
|
cl_git_rewritefile("empty_standard_repo/.git/info/exclude", "/ignore_also\n");
|
|
cl_git_rewritefile("empty_standard_repo/dir/.gitignore", "/ignore_me\n");
|
|
cl_git_rewritefile("empty_standard_repo/test/.gitignore", "/and_me\n");
|
|
|
|
memset(&counts, 0x0, sizeof(status_entry_counts));
|
|
counts.expected_entry_count = 10;
|
|
counts.expected_paths = paths_2;
|
|
counts.expected_statuses = statuses_2;
|
|
|
|
opts.flags = GIT_STATUS_OPT_DEFAULTS | GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
|
|
|
|
cl_git_pass(git_status_foreach_ext(
|
|
g_repo, &opts, cb_status__normal, &counts));
|
|
|
|
cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
|
|
cl_assert_equal_i(0, counts.wrong_status_flags_count);
|
|
cl_assert_equal_i(0, counts.wrong_sorted_path);
|
|
}
|
|
|
|
void test_status_ignore__contained_dir_with_matching_name(void)
|
|
{
|
|
static const char *test_files[] = {
|
|
"empty_standard_repo/subdir_match/aaa/subdir_match/file",
|
|
"empty_standard_repo/subdir_match/zzz_ignoreme",
|
|
NULL
|
|
};
|
|
static const char *expected_paths[] = {
|
|
"subdir_match/.gitignore",
|
|
"subdir_match/aaa/subdir_match/file",
|
|
"subdir_match/zzz_ignoreme",
|
|
};
|
|
static const unsigned int expected_statuses[] = {
|
|
GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_IGNORED
|
|
};
|
|
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
|
|
status_entry_counts counts;
|
|
|
|
make_test_data("empty_standard_repo", test_files);
|
|
cl_git_mkfile(
|
|
"empty_standard_repo/subdir_match/.gitignore", "*_ignoreme\n");
|
|
|
|
refute_is_ignored("subdir_match/aaa/subdir_match/file");
|
|
assert_is_ignored("subdir_match/zzz_ignoreme");
|
|
|
|
memset(&counts, 0x0, sizeof(status_entry_counts));
|
|
counts.expected_entry_count = 3;
|
|
counts.expected_paths = expected_paths;
|
|
counts.expected_statuses = expected_statuses;
|
|
|
|
opts.flags = GIT_STATUS_OPT_DEFAULTS | GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
|
|
|
|
cl_git_pass(git_status_foreach_ext(
|
|
g_repo, &opts, cb_status__normal, &counts));
|
|
|
|
cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
|
|
cl_assert_equal_i(0, counts.wrong_status_flags_count);
|
|
cl_assert_equal_i(0, counts.wrong_sorted_path);
|
|
}
|
|
|
|
void test_status_ignore__trailing_slash_star(void)
|
|
{
|
|
static const char *test_files[] = {
|
|
"empty_standard_repo/file",
|
|
"empty_standard_repo/subdir/file",
|
|
"empty_standard_repo/subdir/sub2/sub3/file",
|
|
NULL
|
|
};
|
|
|
|
make_test_data("empty_standard_repo", test_files);
|
|
cl_git_mkfile(
|
|
"empty_standard_repo/subdir/.gitignore", "/**/*\n");
|
|
|
|
refute_is_ignored("file");
|
|
assert_is_ignored("subdir/sub2/sub3/file");
|
|
assert_is_ignored("subdir/file");
|
|
}
|
|
|
|
void test_status_ignore__adding_internal_ignores(void)
|
|
{
|
|
g_repo = cl_git_sandbox_init("empty_standard_repo");
|
|
|
|
refute_is_ignored("one.txt");
|
|
refute_is_ignored("two.bar");
|
|
|
|
cl_git_pass(git_ignore_add_rule(g_repo, "*.nomatch\n"));
|
|
|
|
refute_is_ignored("one.txt");
|
|
refute_is_ignored("two.bar");
|
|
|
|
cl_git_pass(git_ignore_add_rule(g_repo, "*.txt\n"));
|
|
|
|
assert_is_ignored("one.txt");
|
|
refute_is_ignored("two.bar");
|
|
|
|
cl_git_pass(git_ignore_add_rule(g_repo, "*.bar\n"));
|
|
|
|
assert_is_ignored("one.txt");
|
|
assert_is_ignored("two.bar");
|
|
|
|
cl_git_pass(git_ignore_clear_internal_rules(g_repo));
|
|
|
|
refute_is_ignored("one.txt");
|
|
refute_is_ignored("two.bar");
|
|
|
|
cl_git_pass(git_ignore_add_rule(
|
|
g_repo, "multiple\n*.rules\n# comment line\n*.bar\n"));
|
|
|
|
refute_is_ignored("one.txt");
|
|
assert_is_ignored("two.bar");
|
|
}
|
|
|
|
void test_status_ignore__add_internal_as_first_thing(void)
|
|
{
|
|
const char *add_me = "\n#################\n## Eclipse\n#################\n\n*.pydevproject\n.project\n.metadata\nbin/\ntmp/\n*.tmp\n\n";
|
|
|
|
g_repo = cl_git_sandbox_init("empty_standard_repo");
|
|
|
|
cl_git_pass(git_ignore_add_rule(g_repo, add_me));
|
|
|
|
assert_is_ignored("one.tmp");
|
|
refute_is_ignored("two.bar");
|
|
}
|
|
|
|
void test_status_ignore__internal_ignores_inside_deep_paths(void)
|
|
{
|
|
const char *add_me = "Debug\nthis/is/deep\npatterned*/dir\n";
|
|
|
|
g_repo = cl_git_sandbox_init("empty_standard_repo");
|
|
|
|
cl_git_pass(git_ignore_add_rule(g_repo, add_me));
|
|
|
|
assert_is_ignored("Debug");
|
|
assert_is_ignored("and/Debug");
|
|
assert_is_ignored("really/Debug/this/file");
|
|
assert_is_ignored("Debug/what/I/say");
|
|
|
|
refute_is_ignored("and/NoDebug");
|
|
refute_is_ignored("NoDebug/this");
|
|
refute_is_ignored("please/NoDebug/this");
|
|
|
|
assert_is_ignored("this/is/deep");
|
|
/* pattern containing slash gets FNM_PATHNAME so all slashes must match */
|
|
refute_is_ignored("and/this/is/deep");
|
|
assert_is_ignored("this/is/deep/too");
|
|
/* pattern containing slash gets FNM_PATHNAME so all slashes must match */
|
|
refute_is_ignored("but/this/is/deep/and/ignored");
|
|
|
|
refute_is_ignored("this/is/not/deep");
|
|
refute_is_ignored("is/this/not/as/deep");
|
|
refute_is_ignored("this/is/deepish");
|
|
refute_is_ignored("xthis/is/deep");
|
|
}
|
|
|
|
void test_status_ignore__automatically_ignore_bad_files(void)
|
|
{
|
|
g_repo = cl_git_sandbox_init("empty_standard_repo");
|
|
|
|
assert_is_ignored(".git");
|
|
assert_is_ignored("this/file/.");
|
|
assert_is_ignored("path/../funky");
|
|
refute_is_ignored("path/whatever.c");
|
|
|
|
cl_git_pass(git_ignore_add_rule(g_repo, "*.c\n"));
|
|
|
|
assert_is_ignored(".git");
|
|
assert_is_ignored("this/file/.");
|
|
assert_is_ignored("path/../funky");
|
|
assert_is_ignored("path/whatever.c");
|
|
|
|
cl_git_pass(git_ignore_clear_internal_rules(g_repo));
|
|
|
|
assert_is_ignored(".git");
|
|
assert_is_ignored("this/file/.");
|
|
assert_is_ignored("path/../funky");
|
|
refute_is_ignored("path/whatever.c");
|
|
}
|
|
|
|
void test_status_ignore__filenames_with_special_prefixes_do_not_interfere_with_status_retrieval(void)
|
|
{
|
|
status_entry_single st;
|
|
char *test_cases[] = {
|
|
"!file",
|
|
"#blah",
|
|
"[blah]",
|
|
"[attr]",
|
|
"[attr]blah",
|
|
NULL
|
|
};
|
|
int i;
|
|
|
|
for (i = 0; *(test_cases + i) != NULL; i++) {
|
|
git_buf file = GIT_BUF_INIT;
|
|
char *file_name = *(test_cases + i);
|
|
git_repository *repo = cl_git_sandbox_init("empty_standard_repo");
|
|
|
|
cl_git_pass(git_buf_joinpath(&file, "empty_standard_repo", file_name));
|
|
cl_git_mkfile(git_buf_cstr(&file), "Please don't ignore me!");
|
|
|
|
memset(&st, 0, sizeof(st));
|
|
cl_git_pass(git_status_foreach(repo, cb_status__single, &st));
|
|
cl_assert(st.count == 1);
|
|
cl_assert(st.status == GIT_STATUS_WT_NEW);
|
|
|
|
cl_git_pass(git_status_file(&st.status, repo, file_name));
|
|
cl_assert(st.status == GIT_STATUS_WT_NEW);
|
|
|
|
cl_git_sandbox_cleanup();
|
|
git_buf_free(&file);
|
|
}
|
|
}
|
|
|
|
void test_status_ignore__issue_1766_negated_ignores(void)
|
|
{
|
|
unsigned int status;
|
|
|
|
g_repo = cl_git_sandbox_init("empty_standard_repo");
|
|
|
|
cl_git_pass(git_futils_mkdir_r(
|
|
"empty_standard_repo/a", 0775));
|
|
cl_git_mkfile(
|
|
"empty_standard_repo/a/.gitignore", "*\n!.gitignore\n");
|
|
cl_git_mkfile(
|
|
"empty_standard_repo/a/ignoreme", "I should be ignored\n");
|
|
|
|
refute_is_ignored("a/.gitignore");
|
|
assert_is_ignored("a/ignoreme");
|
|
|
|
cl_git_pass(git_futils_mkdir_r(
|
|
"empty_standard_repo/b", 0775));
|
|
cl_git_mkfile(
|
|
"empty_standard_repo/b/.gitignore", "*\n!.gitignore\n");
|
|
cl_git_mkfile(
|
|
"empty_standard_repo/b/ignoreme", "I should be ignored\n");
|
|
|
|
refute_is_ignored("b/.gitignore");
|
|
assert_is_ignored("b/ignoreme");
|
|
|
|
/* shouldn't have changed results from first couple either */
|
|
refute_is_ignored("a/.gitignore");
|
|
assert_is_ignored("a/ignoreme");
|
|
|
|
/* status should find the two ignore files and nothing else */
|
|
|
|
cl_git_pass(git_status_file(&status, g_repo, "a/.gitignore"));
|
|
cl_assert_equal_i(GIT_STATUS_WT_NEW, (int)status);
|
|
|
|
cl_git_pass(git_status_file(&status, g_repo, "a/ignoreme"));
|
|
cl_assert_equal_i(GIT_STATUS_IGNORED, (int)status);
|
|
|
|
cl_git_pass(git_status_file(&status, g_repo, "b/.gitignore"));
|
|
cl_assert_equal_i(GIT_STATUS_WT_NEW, (int)status);
|
|
|
|
cl_git_pass(git_status_file(&status, g_repo, "b/ignoreme"));
|
|
cl_assert_equal_i(GIT_STATUS_IGNORED, (int)status);
|
|
|
|
{
|
|
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
|
|
status_entry_counts counts;
|
|
static const char *paths[] = {
|
|
"a/.gitignore",
|
|
"a/ignoreme",
|
|
"b/.gitignore",
|
|
"b/ignoreme",
|
|
};
|
|
static const unsigned int statuses[] = {
|
|
GIT_STATUS_WT_NEW,
|
|
GIT_STATUS_IGNORED,
|
|
GIT_STATUS_WT_NEW,
|
|
GIT_STATUS_IGNORED,
|
|
};
|
|
|
|
memset(&counts, 0x0, sizeof(status_entry_counts));
|
|
counts.expected_entry_count = 4;
|
|
counts.expected_paths = paths;
|
|
counts.expected_statuses = statuses;
|
|
|
|
opts.flags = GIT_STATUS_OPT_DEFAULTS;
|
|
|
|
cl_git_pass(git_status_foreach_ext(
|
|
g_repo, &opts, cb_status__normal, &counts));
|
|
|
|
cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
|
|
cl_assert_equal_i(0, counts.wrong_status_flags_count);
|
|
cl_assert_equal_i(0, counts.wrong_sorted_path);
|
|
}
|
|
}
|
|
|
|
static void add_one_to_index(const char *file)
|
|
{
|
|
git_index *index;
|
|
cl_git_pass(git_repository_index(&index, g_repo));
|
|
cl_git_pass(git_index_add_bypath(index, file));
|
|
git_index_free(index);
|
|
}
|
|
|
|
/* Some further broken scenarios that have been reported */
|
|
void test_status_ignore__more_breakage(void)
|
|
{
|
|
static const char *test_files[] = {
|
|
"empty_standard_repo/d1/pfx-d2/d3/d4/d5/tracked",
|
|
"empty_standard_repo/d1/pfx-d2/d3/d4/d5/untracked",
|
|
"empty_standard_repo/d1/pfx-d2/d3/d4/untracked",
|
|
NULL
|
|
};
|
|
|
|
make_test_data("empty_standard_repo", test_files);
|
|
cl_git_mkfile(
|
|
"empty_standard_repo/.gitignore",
|
|
"/d1/pfx-*\n"
|
|
"!/d1/pfx-d2/\n"
|
|
"/d1/pfx-d2/*\n"
|
|
"!/d1/pfx-d2/d3/\n"
|
|
"/d1/pfx-d2/d3/*\n"
|
|
"!/d1/pfx-d2/d3/d4/\n");
|
|
add_one_to_index("d1/pfx-d2/d3/d4/d5/tracked");
|
|
|
|
{
|
|
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
|
|
status_entry_counts counts;
|
|
static const char *files[] = {
|
|
".gitignore",
|
|
"d1/pfx-d2/d3/d4/d5/tracked",
|
|
"d1/pfx-d2/d3/d4/d5/untracked",
|
|
"d1/pfx-d2/d3/d4/untracked",
|
|
};
|
|
static const unsigned int statuses[] = {
|
|
GIT_STATUS_WT_NEW,
|
|
GIT_STATUS_INDEX_NEW,
|
|
GIT_STATUS_WT_NEW,
|
|
GIT_STATUS_WT_NEW,
|
|
};
|
|
|
|
memset(&counts, 0x0, sizeof(status_entry_counts));
|
|
counts.expected_entry_count = 4;
|
|
counts.expected_paths = files;
|
|
counts.expected_statuses = statuses;
|
|
opts.flags = GIT_STATUS_OPT_DEFAULTS |
|
|
GIT_STATUS_OPT_INCLUDE_IGNORED |
|
|
GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
|
|
cl_git_pass(git_status_foreach_ext(
|
|
g_repo, &opts, cb_status__normal, &counts));
|
|
|
|
cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
|
|
cl_assert_equal_i(0, counts.wrong_status_flags_count);
|
|
cl_assert_equal_i(0, counts.wrong_sorted_path);
|
|
}
|
|
|
|
refute_is_ignored("d1/pfx-d2/d3/d4/d5/tracked");
|
|
refute_is_ignored("d1/pfx-d2/d3/d4/d5/untracked");
|
|
refute_is_ignored("d1/pfx-d2/d3/d4/untracked");
|
|
}
|
|
|
|
void test_status_ignore__negative_ignores_inside_ignores(void)
|
|
{
|
|
static const char *test_files[] = {
|
|
"empty_standard_repo/top/mid/btm/tracked",
|
|
"empty_standard_repo/top/mid/btm/untracked",
|
|
"empty_standard_repo/zoo/bar",
|
|
"empty_standard_repo/zoo/foo/bar",
|
|
NULL
|
|
};
|
|
|
|
make_test_data("empty_standard_repo", test_files);
|
|
cl_git_mkfile(
|
|
"empty_standard_repo/.gitignore",
|
|
"top\n"
|
|
"!top/mid/btm\n"
|
|
"zoo/*\n"
|
|
"!zoo/bar\n"
|
|
"!zoo/foo/bar\n");
|
|
add_one_to_index("top/mid/btm/tracked");
|
|
|
|
{
|
|
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
|
|
status_entry_counts counts;
|
|
static const char *files[] = {
|
|
".gitignore", "top/mid/btm/tracked", "top/mid/btm/untracked",
|
|
"zoo/bar", "zoo/foo/bar",
|
|
};
|
|
static const unsigned int statuses[] = {
|
|
GIT_STATUS_WT_NEW, GIT_STATUS_INDEX_NEW, GIT_STATUS_IGNORED,
|
|
GIT_STATUS_WT_NEW, GIT_STATUS_IGNORED,
|
|
};
|
|
|
|
memset(&counts, 0x0, sizeof(status_entry_counts));
|
|
counts.expected_entry_count = 5;
|
|
counts.expected_paths = files;
|
|
counts.expected_statuses = statuses;
|
|
opts.flags = GIT_STATUS_OPT_DEFAULTS |
|
|
GIT_STATUS_OPT_INCLUDE_IGNORED |
|
|
GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
|
|
cl_git_pass(git_status_foreach_ext(
|
|
g_repo, &opts, cb_status__normal, &counts));
|
|
|
|
cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
|
|
cl_assert_equal_i(0, counts.wrong_status_flags_count);
|
|
cl_assert_equal_i(0, counts.wrong_sorted_path);
|
|
}
|
|
|
|
assert_is_ignored("top/mid/btm/tracked");
|
|
assert_is_ignored("top/mid/btm/untracked");
|
|
refute_is_ignored("foo/bar");
|
|
}
|
|
|
|
void test_status_ignore__negative_ignores_in_slash_star(void)
|
|
{
|
|
git_status_options status_opts = GIT_STATUS_OPTIONS_INIT;
|
|
git_status_list *list;
|
|
int found_look_ma = 0, found_what_about = 0;
|
|
size_t i;
|
|
static const char *test_files[] = {
|
|
"empty_standard_repo/bin/look-ma.txt",
|
|
"empty_standard_repo/bin/what-about-me.txt",
|
|
NULL
|
|
};
|
|
|
|
make_test_data("empty_standard_repo", test_files);
|
|
cl_git_mkfile(
|
|
"empty_standard_repo/.gitignore",
|
|
"bin/*\n"
|
|
"!bin/w*\n");
|
|
|
|
assert_is_ignored("bin/look-ma.txt");
|
|
refute_is_ignored("bin/what-about-me.txt");
|
|
|
|
status_opts.flags = GIT_STATUS_OPT_DEFAULTS;
|
|
cl_git_pass(git_status_list_new(&list, g_repo, &status_opts));
|
|
for (i = 0; i < git_status_list_entrycount(list); i++) {
|
|
const git_status_entry *entry = git_status_byindex(list, i);
|
|
|
|
if (!strcmp("bin/look-ma.txt", entry->index_to_workdir->new_file.path))
|
|
found_look_ma = 1;
|
|
|
|
if (!strcmp("bin/what-about-me.txt", entry->index_to_workdir->new_file.path))
|
|
found_what_about = 1;
|
|
}
|
|
git_status_list_free(list);
|
|
|
|
cl_assert(found_look_ma);
|
|
cl_assert(found_what_about);
|
|
}
|
|
|
|
void test_status_ignore__negative_ignores_without_trailing_slash_inside_ignores(void)
|
|
{
|
|
git_status_options status_opts = GIT_STATUS_OPTIONS_INIT;
|
|
git_status_list *list;
|
|
int found_parent_file = 0, found_parent_child1_file = 0, found_parent_child2_file = 0;
|
|
size_t i;
|
|
static const char *test_files[] = {
|
|
"empty_standard_repo/parent/file.txt",
|
|
"empty_standard_repo/parent/force.txt",
|
|
"empty_standard_repo/parent/child1/file.txt",
|
|
"empty_standard_repo/parent/child2/file.txt",
|
|
NULL
|
|
};
|
|
|
|
make_test_data("empty_standard_repo", test_files);
|
|
cl_git_mkfile(
|
|
"empty_standard_repo/.gitignore",
|
|
"parent/*\n"
|
|
"!parent/force.txt\n"
|
|
"!parent/child1\n"
|
|
"!parent/child2/\n");
|
|
|
|
add_one_to_index("parent/force.txt");
|
|
|
|
assert_is_ignored("parent/file.txt");
|
|
refute_is_ignored("parent/force.txt");
|
|
refute_is_ignored("parent/child1/file.txt");
|
|
refute_is_ignored("parent/child2/file.txt");
|
|
|
|
status_opts.flags = GIT_STATUS_OPT_DEFAULTS;
|
|
cl_git_pass(git_status_list_new(&list, g_repo, &status_opts));
|
|
for (i = 0; i < git_status_list_entrycount(list); i++) {
|
|
const git_status_entry *entry = git_status_byindex(list, i);
|
|
|
|
if (!entry->index_to_workdir)
|
|
continue;
|
|
|
|
if (!strcmp("parent/file.txt", entry->index_to_workdir->new_file.path))
|
|
found_parent_file = 1;
|
|
|
|
if (!strcmp("parent/force.txt", entry->index_to_workdir->new_file.path))
|
|
found_parent_file = 1;
|
|
|
|
if (!strcmp("parent/child1/file.txt", entry->index_to_workdir->new_file.path))
|
|
found_parent_child1_file = 1;
|
|
|
|
if (!strcmp("parent/child2/file.txt", entry->index_to_workdir->new_file.path))
|
|
found_parent_child2_file = 1;
|
|
}
|
|
git_status_list_free(list);
|
|
|
|
cl_assert(found_parent_file);
|
|
cl_assert(found_parent_child1_file);
|
|
cl_assert(found_parent_child2_file);
|
|
}
|
|
|
|
void test_status_ignore__negative_directory_ignores(void)
|
|
{
|
|
static const char *test_files[] = {
|
|
"empty_standard_repo/parent/child1/bar.txt",
|
|
"empty_standard_repo/parent/child2/bar.txt",
|
|
"empty_standard_repo/parent/child3/foo.txt",
|
|
"empty_standard_repo/parent/child4/bar.txt",
|
|
"empty_standard_repo/parent/nested/child5/bar.txt",
|
|
"empty_standard_repo/parent/nested/child6/bar.txt",
|
|
"empty_standard_repo/parent/nested/child7/bar.txt",
|
|
"empty_standard_repo/padded_parent/child8/bar.txt",
|
|
NULL
|
|
};
|
|
|
|
make_test_data("empty_standard_repo", test_files);
|
|
cl_git_mkfile(
|
|
"empty_standard_repo/.gitignore",
|
|
"foo.txt\n"
|
|
"parent/child1\n"
|
|
"parent/child2\n"
|
|
"parent/child4\n"
|
|
"parent/nested/child5\n"
|
|
"nested/child6\n"
|
|
"nested/child7\n"
|
|
"padded_parent/child8\n"
|
|
/* test simple exact match */
|
|
"!parent/child1\n"
|
|
/* test negating file without negating dir */
|
|
"!parent/child2/bar.txt\n"
|
|
/* test negative pattern on dir with its content
|
|
* being ignored */
|
|
"!parent/child3\n"
|
|
/* test with partial match at end */
|
|
"!child4\n"
|
|
/* test with partial match with '/' at end */
|
|
"!nested/child5\n"
|
|
/* test with complete match */
|
|
"!nested/child6\n"
|
|
/* test with trailing '/' */
|
|
"!child7/\n"
|
|
/* test with partial dir match */
|
|
"!_parent/child8\n");
|
|
|
|
refute_is_ignored("parent/child1/bar.txt");
|
|
assert_is_ignored("parent/child2/bar.txt");
|
|
assert_is_ignored("parent/child3/foo.txt");
|
|
refute_is_ignored("parent/child4/bar.txt");
|
|
assert_is_ignored("parent/nested/child5/bar.txt");
|
|
refute_is_ignored("parent/nested/child6/bar.txt");
|
|
refute_is_ignored("parent/nested/child7/bar.txt");
|
|
assert_is_ignored("padded_parent/child8/bar.txt");
|
|
}
|
|
|
|
void test_status_ignore__unignore_entry_in_ignored_dir(void)
|
|
{
|
|
static const char *test_files[] = {
|
|
"empty_standard_repo/bar.txt",
|
|
"empty_standard_repo/parent/bar.txt",
|
|
"empty_standard_repo/parent/child/bar.txt",
|
|
"empty_standard_repo/nested/parent/child/bar.txt",
|
|
NULL
|
|
};
|
|
|
|
make_test_data("empty_standard_repo", test_files);
|
|
cl_git_mkfile(
|
|
"empty_standard_repo/.gitignore",
|
|
"bar.txt\n"
|
|
"!parent/child/bar.txt\n");
|
|
|
|
assert_is_ignored("bar.txt");
|
|
assert_is_ignored("parent/bar.txt");
|
|
refute_is_ignored("parent/child/bar.txt");
|
|
assert_is_ignored("nested/parent/child/bar.txt");
|
|
}
|
|
|
|
void test_status_ignore__do_not_unignore_basename_prefix(void)
|
|
{
|
|
static const char *test_files[] = {
|
|
"empty_standard_repo/foo_bar.txt",
|
|
NULL
|
|
};
|
|
|
|
make_test_data("empty_standard_repo", test_files);
|
|
cl_git_mkfile(
|
|
"empty_standard_repo/.gitignore",
|
|
"foo_bar.txt\n"
|
|
"!bar.txt\n");
|
|
|
|
assert_is_ignored("foo_bar.txt");
|
|
}
|
|
|
|
void test_status_ignore__filename_with_cr(void)
|
|
{
|
|
int ignored;
|
|
|
|
g_repo = cl_git_sandbox_init("empty_standard_repo");
|
|
cl_git_mkfile("empty_standard_repo/.gitignore", "Icon\r\r\n");
|
|
|
|
cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Icon\r"));
|
|
cl_assert_equal_i(1, ignored);
|
|
|
|
cl_git_mkfile("empty_standard_repo/.gitignore", "Ico\rn\n");
|
|
cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Ico\rn"));
|
|
cl_assert_equal_i(1, ignored);
|
|
|
|
cl_git_mkfile("empty_standard_repo/.gitignore", "Ico\rn\r\n");
|
|
cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Ico\rn"));
|
|
cl_assert_equal_i(1, ignored);
|
|
cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Ico\rn\r"));
|
|
cl_assert_equal_i(0, ignored);
|
|
|
|
cl_git_mkfile("empty_standard_repo/.gitignore", "Ico\rn\r\r\n");
|
|
cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Ico\rn\r"));
|
|
cl_assert_equal_i(1, ignored);
|
|
cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Icon\r"));
|
|
cl_assert_equal_i(0, ignored);
|
|
|
|
cl_git_mkfile("empty_standard_repo/.gitignore", "Icon\r\n");
|
|
cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Icon\r"));
|
|
cl_assert_equal_i(0, ignored);
|
|
cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Icon"));
|
|
cl_assert_equal_i(1, ignored);
|
|
}
|
|
|
|
void test_status_ignore__subdir_doesnt_match_above(void)
|
|
{
|
|
int ignored, icase = 0, error;
|
|
git_config *cfg;
|
|
|
|
g_repo = cl_git_sandbox_init("empty_standard_repo");
|
|
|
|
cl_git_pass(git_repository_config_snapshot(&cfg, g_repo));
|
|
error = git_config_get_bool(&icase, cfg, "core.ignorecase");
|
|
git_config_free(cfg);
|
|
if (error == GIT_ENOTFOUND)
|
|
error = 0;
|
|
|
|
cl_git_pass(error);
|
|
|
|
cl_git_pass(p_mkdir("empty_standard_repo/src", 0777));
|
|
cl_git_pass(p_mkdir("empty_standard_repo/src/src", 0777));
|
|
cl_git_mkfile("empty_standard_repo/src/.gitignore", "src\n");
|
|
cl_git_mkfile("empty_standard_repo/.gitignore", "");
|
|
|
|
cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "src/test.txt"));
|
|
cl_assert_equal_i(0, ignored);
|
|
cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "src/src/test.txt"));
|
|
cl_assert_equal_i(1, ignored);
|
|
cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "src/foo/test.txt"));
|
|
cl_assert_equal_i(0, ignored);
|
|
|
|
cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "SRC/src/test.txt"));
|
|
cl_assert_equal_i(icase, ignored);
|
|
cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "src/SRC/test.txt"));
|
|
cl_assert_equal_i(icase, ignored);
|
|
}
|
|
|
|
void test_status_ignore__negate_exact_previous(void)
|
|
{
|
|
int ignored;
|
|
|
|
g_repo = cl_git_sandbox_init("empty_standard_repo");
|
|
|
|
cl_git_mkfile("empty_standard_repo/.gitignore", "*.com\ntags\n!tags/\n.buildpath");
|
|
cl_git_mkfile("empty_standard_repo/.buildpath", "");
|
|
cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, ".buildpath"));
|
|
cl_assert_equal_i(1, ignored);
|
|
}
|
|
|
|
void test_status_ignore__negate_starstar(void)
|
|
{
|
|
int ignored;
|
|
|
|
g_repo = cl_git_sandbox_init("empty_standard_repo");
|
|
|
|
cl_git_mkfile("empty_standard_repo/.gitignore",
|
|
"code/projects/**/packages/*\n"
|
|
"!code/projects/**/packages/repositories.config");
|
|
|
|
cl_git_pass(git_futils_mkdir_r("empty_standard_repo/code/projects/foo/bar/packages", 0777));
|
|
cl_git_mkfile("empty_standard_repo/code/projects/foo/bar/packages/repositories.config", "");
|
|
|
|
cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "code/projects/foo/bar/packages/repositories.config"));
|
|
cl_assert_equal_i(0, ignored);
|
|
}
|