mirror of
				https://git.proxmox.com/git/libgit2
				synced 2025-10-31 05:54:20 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			361 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			361 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "clar_libgit2.h"
 | |
| #include "posix.h"
 | |
| #include "path.h"
 | |
| #include "submodule_helpers.h"
 | |
| #include "fileops.h"
 | |
| #include "iterator.h"
 | |
| 
 | |
| static git_repository *g_repo = NULL;
 | |
| 
 | |
| void test_submodule_status__initialize(void)
 | |
| {
 | |
| 	g_repo = setup_fixture_submod2();
 | |
| }
 | |
| 
 | |
| void test_submodule_status__cleanup(void)
 | |
| {
 | |
| }
 | |
| 
 | |
| void test_submodule_status__unchanged(void)
 | |
| {
 | |
| 	unsigned int status = get_submodule_status(g_repo, "sm_unchanged");
 | |
| 	unsigned int expected =
 | |
| 		GIT_SUBMODULE_STATUS_IN_HEAD |
 | |
| 		GIT_SUBMODULE_STATUS_IN_INDEX |
 | |
| 		GIT_SUBMODULE_STATUS_IN_CONFIG |
 | |
| 		GIT_SUBMODULE_STATUS_IN_WD;
 | |
| 
 | |
| 	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
 | |
| 	cl_assert(expected == status);
 | |
| }
 | |
| 
 | |
| static void rm_submodule(const char *name)
 | |
| {
 | |
| 	git_buf path = GIT_BUF_INIT;
 | |
| 	cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), name));
 | |
| 	cl_git_pass(git_futils_rmdir_r(path.ptr, NULL, GIT_RMDIR_REMOVE_FILES));
 | |
| 	git_buf_free(&path);
 | |
| }
 | |
| 
 | |
| static void add_submodule_to_index(const char *name)
 | |
| {
 | |
| 	git_submodule *sm;
 | |
| 	cl_git_pass(git_submodule_lookup(&sm, g_repo, name));
 | |
| 	cl_git_pass(git_submodule_add_to_index(sm, true));
 | |
| 	git_submodule_free(sm);
 | |
| }
 | |
| 
 | |
| static void rm_submodule_from_index(const char *name)
 | |
| {
 | |
| 	git_index *index;
 | |
| 	size_t pos;
 | |
| 
 | |
| 	cl_git_pass(git_repository_index(&index, g_repo));
 | |
| 	cl_assert(!git_index_find(&pos, index, name));
 | |
| 	cl_git_pass(git_index_remove(index, name, 0));
 | |
| 	cl_git_pass(git_index_write(index));
 | |
| 	git_index_free(index);
 | |
| }
 | |
| 
 | |
| /* 4 values of GIT_SUBMODULE_IGNORE to check */
 | |
| 
 | |
| void test_submodule_status__ignore_none(void)
 | |
| {
 | |
| 	unsigned int status;
 | |
| 
 | |
| 	rm_submodule("sm_unchanged");
 | |
| 
 | |
| 	refute_submodule_exists(g_repo, "just_a_dir", GIT_ENOTFOUND);
 | |
| 	refute_submodule_exists(g_repo, "not-submodule", GIT_EEXISTS);
 | |
| 	refute_submodule_exists(g_repo, "not", GIT_EEXISTS);
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_changed_index");
 | |
| 	cl_assert((status & GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED) != 0);
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_changed_head");
 | |
| 	cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_changed_file");
 | |
| 	cl_assert((status & GIT_SUBMODULE_STATUS_WD_WD_MODIFIED) != 0);
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_changed_untracked_file");
 | |
| 	cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNTRACKED) != 0);
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_missing_commits");
 | |
| 	cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_added_and_uncommited");
 | |
| 	cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_ADDED) != 0);
 | |
| 
 | |
| 	/* removed sm_unchanged for deleted workdir */
 | |
| 	status = get_submodule_status(g_repo, "sm_unchanged");
 | |
| 	cl_assert((status & GIT_SUBMODULE_STATUS_WD_DELETED) != 0);
 | |
| 
 | |
| 	/* now mkdir sm_unchanged to test uninitialized */
 | |
| 	cl_git_pass(git_futils_mkdir("sm_unchanged", "submod2", 0755, 0));
 | |
| 	status = get_submodule_status(g_repo, "sm_unchanged");
 | |
| 	cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) != 0);
 | |
| 
 | |
| 	/* update sm_changed_head in index */
 | |
| 	add_submodule_to_index("sm_changed_head");
 | |
| 	status = get_submodule_status(g_repo, "sm_changed_head");
 | |
| 	cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_MODIFIED) != 0);
 | |
| 
 | |
| 	/* remove sm_changed_head from index */
 | |
| 	rm_submodule_from_index("sm_changed_head");
 | |
| 	status = get_submodule_status(g_repo, "sm_changed_head");
 | |
| 	cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_DELETED) != 0);
 | |
| }
 | |
| 
 | |
| static int set_sm_ignore(git_submodule *sm, const char *name, void *payload)
 | |
| {
 | |
| 	git_submodule_ignore_t ignore = *(git_submodule_ignore_t *)payload;
 | |
| 	GIT_UNUSED(name);
 | |
| 	git_submodule_set_ignore(sm, ignore);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| void test_submodule_status__ignore_untracked(void)
 | |
| {
 | |
| 	unsigned int status;
 | |
| 	git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_UNTRACKED;
 | |
| 
 | |
| 	rm_submodule("sm_unchanged");
 | |
| 	cl_git_pass(git_submodule_foreach(g_repo, set_sm_ignore, &ign));
 | |
| 
 | |
| 	refute_submodule_exists(g_repo, "just_a_dir", GIT_ENOTFOUND);
 | |
| 	refute_submodule_exists(g_repo, "not-submodule", GIT_EEXISTS);
 | |
| 	refute_submodule_exists(g_repo, "not", GIT_EEXISTS);
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_changed_index");
 | |
| 	cl_assert((status & GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED) != 0);
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_changed_head");
 | |
| 	cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_changed_file");
 | |
| 	cl_assert((status & GIT_SUBMODULE_STATUS_WD_WD_MODIFIED) != 0);
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_changed_untracked_file");
 | |
| 	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_missing_commits");
 | |
| 	cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_added_and_uncommited");
 | |
| 	cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_ADDED) != 0);
 | |
| 
 | |
| 	/* removed sm_unchanged for deleted workdir */
 | |
| 	status = get_submodule_status(g_repo, "sm_unchanged");
 | |
| 	cl_assert((status & GIT_SUBMODULE_STATUS_WD_DELETED) != 0);
 | |
| 
 | |
| 	/* now mkdir sm_unchanged to test uninitialized */
 | |
| 	cl_git_pass(git_futils_mkdir("sm_unchanged", "submod2", 0755, 0));
 | |
| 	status = get_submodule_status(g_repo, "sm_unchanged");
 | |
| 	cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) != 0);
 | |
| 
 | |
| 	/* update sm_changed_head in index */
 | |
| 	add_submodule_to_index("sm_changed_head");
 | |
| 	status = get_submodule_status(g_repo, "sm_changed_head");
 | |
| 	cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_MODIFIED) != 0);
 | |
| }
 | |
| 
 | |
| void test_submodule_status__ignore_dirty(void)
 | |
| {
 | |
| 	unsigned int status;
 | |
| 	git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_DIRTY;
 | |
| 
 | |
| 	rm_submodule("sm_unchanged");
 | |
| 	cl_git_pass(git_submodule_foreach(g_repo, set_sm_ignore, &ign));
 | |
| 
 | |
| 	refute_submodule_exists(g_repo, "just_a_dir", GIT_ENOTFOUND);
 | |
| 	refute_submodule_exists(g_repo, "not-submodule", GIT_EEXISTS);
 | |
| 	refute_submodule_exists(g_repo, "not", GIT_EEXISTS);
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_changed_index");
 | |
| 	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_changed_head");
 | |
| 	cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_changed_file");
 | |
| 	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_changed_untracked_file");
 | |
| 	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_missing_commits");
 | |
| 	cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_added_and_uncommited");
 | |
| 	cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_ADDED) != 0);
 | |
| 
 | |
| 	/* removed sm_unchanged for deleted workdir */
 | |
| 	status = get_submodule_status(g_repo, "sm_unchanged");
 | |
| 	cl_assert((status & GIT_SUBMODULE_STATUS_WD_DELETED) != 0);
 | |
| 
 | |
| 	/* now mkdir sm_unchanged to test uninitialized */
 | |
| 	cl_git_pass(git_futils_mkdir("sm_unchanged", "submod2", 0755, 0));
 | |
| 	status = get_submodule_status(g_repo, "sm_unchanged");
 | |
| 	cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) != 0);
 | |
| 
 | |
| 	/* update sm_changed_head in index */
 | |
| 	add_submodule_to_index("sm_changed_head");
 | |
| 	status = get_submodule_status(g_repo, "sm_changed_head");
 | |
| 	cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_MODIFIED) != 0);
 | |
| }
 | |
| 
 | |
| void test_submodule_status__ignore_all(void)
 | |
| {
 | |
| 	unsigned int status;
 | |
| 	git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_ALL;
 | |
| 
 | |
| 	rm_submodule("sm_unchanged");
 | |
| 	cl_git_pass(git_submodule_foreach(g_repo, set_sm_ignore, &ign));
 | |
| 
 | |
| 	refute_submodule_exists(g_repo, "just_a_dir", GIT_ENOTFOUND);
 | |
| 	refute_submodule_exists(g_repo, "not-submodule", GIT_EEXISTS);
 | |
| 	refute_submodule_exists(g_repo, "not", GIT_EEXISTS);
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_changed_index");
 | |
| 	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_changed_head");
 | |
| 	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_changed_file");
 | |
| 	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_changed_untracked_file");
 | |
| 	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_missing_commits");
 | |
| 	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_added_and_uncommited");
 | |
| 	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
 | |
| 
 | |
| 	/* removed sm_unchanged for deleted workdir */
 | |
| 	status = get_submodule_status(g_repo, "sm_unchanged");
 | |
| 	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
 | |
| 
 | |
| 	/* now mkdir sm_unchanged to test uninitialized */
 | |
| 	cl_git_pass(git_futils_mkdir("sm_unchanged", "submod2", 0755, 0));
 | |
| 	status = get_submodule_status(g_repo, "sm_unchanged");
 | |
| 	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
 | |
| 
 | |
| 	/* update sm_changed_head in index */
 | |
| 	add_submodule_to_index("sm_changed_head");
 | |
| 	status = get_submodule_status(g_repo, "sm_changed_head");
 | |
| 	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
 | |
| }
 | |
| 
 | |
| typedef struct {
 | |
| 	size_t counter;
 | |
| 	const char **paths;
 | |
| 	int *statuses;
 | |
| } submodule_expectations;
 | |
| 
 | |
| static int confirm_submodule_status(
 | |
| 	const char *path, unsigned int status_flags, void *payload)
 | |
| {
 | |
| 	submodule_expectations *exp = payload;
 | |
| 
 | |
| 	while (exp->statuses[exp->counter] < 0)
 | |
| 		exp->counter++;
 | |
| 
 | |
| 	cl_assert_equal_i(exp->statuses[exp->counter], (int)status_flags);
 | |
| 	cl_assert_equal_s(exp->paths[exp->counter++], path);
 | |
| 
 | |
| 	GIT_UNUSED(status_flags);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| void test_submodule_status__iterator(void)
 | |
| {
 | |
| 	git_iterator *iter;
 | |
| 	const git_index_entry *entry;
 | |
| 	size_t i;
 | |
| 	static const char *expected[] = {
 | |
| 		".gitmodules",
 | |
| 		"just_a_dir/",
 | |
| 		"just_a_dir/contents",
 | |
| 		"just_a_file",
 | |
| 		"not-submodule/",
 | |
| 		"not-submodule/README.txt",
 | |
| 		"not/",
 | |
| 		"not/README.txt",
 | |
| 		"README.txt",
 | |
| 		"sm_added_and_uncommited",
 | |
| 		"sm_changed_file",
 | |
| 		"sm_changed_head",
 | |
| 		"sm_changed_index",
 | |
| 		"sm_changed_untracked_file",
 | |
| 		"sm_missing_commits",
 | |
| 		"sm_unchanged",
 | |
| 		NULL
 | |
| 	};
 | |
| 	static int expected_flags[] = {
 | |
| 		GIT_STATUS_INDEX_MODIFIED | GIT_STATUS_WT_MODIFIED, /* ".gitmodules" */
 | |
| 		-1,					    /* "just_a_dir/" will be skipped */
 | |
| 		GIT_STATUS_CURRENT,     /* "just_a_dir/contents" */
 | |
| 		GIT_STATUS_CURRENT,	    /* "just_a_file" */
 | |
| 		GIT_STATUS_WT_NEW,      /* "not-submodule/" untracked item */
 | |
| 		-1,                     /* "not-submodule/README.txt" */
 | |
| 		GIT_STATUS_WT_NEW,      /* "not/" untracked item */
 | |
| 		-1,                     /* "not/README.txt" */
 | |
| 		GIT_STATUS_CURRENT,     /* "README.txt */
 | |
| 		GIT_STATUS_INDEX_NEW,   /* "sm_added_and_uncommited" */
 | |
| 		GIT_STATUS_WT_MODIFIED, /* "sm_changed_file" */
 | |
| 		GIT_STATUS_WT_MODIFIED, /* "sm_changed_head" */
 | |
| 		GIT_STATUS_WT_MODIFIED, /* "sm_changed_index" */
 | |
| 		GIT_STATUS_WT_MODIFIED, /* "sm_changed_untracked_file" */
 | |
| 		GIT_STATUS_WT_MODIFIED, /* "sm_missing_commits" */
 | |
| 		GIT_STATUS_CURRENT,     /* "sm_unchanged" */
 | |
| 		0
 | |
| 	};
 | |
| 	submodule_expectations exp = { 0, expected, expected_flags };
 | |
| 	git_status_options opts = GIT_STATUS_OPTIONS_INIT;
 | |
| 
 | |
| 	cl_git_pass(git_iterator_for_workdir(&iter, g_repo,
 | |
| 		GIT_ITERATOR_IGNORE_CASE | GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
 | |
| 
 | |
| 	for (i = 0; !git_iterator_advance(&entry, iter); ++i)
 | |
| 		cl_assert_equal_s(expected[i], entry->path);
 | |
| 
 | |
| 	git_iterator_free(iter);
 | |
| 
 | |
| 	opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED |
 | |
| 		GIT_STATUS_OPT_INCLUDE_UNMODIFIED |
 | |
| 		GIT_STATUS_OPT_INCLUDE_IGNORED |
 | |
| 		GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS |
 | |
| 		GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY;
 | |
| 
 | |
| 	cl_git_pass(git_status_foreach_ext(
 | |
| 		g_repo, &opts, confirm_submodule_status, &exp));
 | |
| }
 | |
| 
 | |
| void test_submodule_status__untracked_dirs_containing_ignored_files(void)
 | |
| {
 | |
| 	unsigned int status, expected;
 | |
| 
 | |
| 	cl_git_append2file(
 | |
| 		"submod2/.git/modules/sm_unchanged/info/exclude", "\n*.ignored\n");
 | |
| 
 | |
| 	cl_git_pass(
 | |
| 		git_futils_mkdir("sm_unchanged/directory", "submod2", 0755, 0));
 | |
| 	cl_git_mkfile(
 | |
| 		"submod2/sm_unchanged/directory/i_am.ignored",
 | |
| 		"ignore this file, please\n");
 | |
| 
 | |
| 	status = get_submodule_status(g_repo, "sm_unchanged");
 | |
| 	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
 | |
| 
 | |
| 	expected = GIT_SUBMODULE_STATUS_IN_HEAD |
 | |
| 		GIT_SUBMODULE_STATUS_IN_INDEX |
 | |
| 		GIT_SUBMODULE_STATUS_IN_CONFIG |
 | |
| 		GIT_SUBMODULE_STATUS_IN_WD;
 | |
| 	cl_assert(status == expected);
 | |
| }
 | 
