Blame tests/status/ignore.c

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