| #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_relative("sm_unchanged", "submod2", 0755, 0, NULL)); |
| 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); |
| } |
| |
| void test_submodule_status__ignore_untracked(void) |
| { |
| unsigned int status; |
| git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_UNTRACKED; |
| |
| 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); |
| |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_index", ign)); |
| cl_assert((status & GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED) != 0); |
| |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_head", ign)); |
| cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0); |
| |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_file", ign)); |
| cl_assert((status & GIT_SUBMODULE_STATUS_WD_WD_MODIFIED) != 0); |
| |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_untracked_file", ign)); |
| cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); |
| |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_missing_commits", ign)); |
| cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0); |
| |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_added_and_uncommited", ign)); |
| cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_ADDED) != 0); |
| |
| /* removed sm_unchanged for deleted workdir */ |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_unchanged", ign)); |
| cl_assert((status & GIT_SUBMODULE_STATUS_WD_DELETED) != 0); |
| |
| /* now mkdir sm_unchanged to test uninitialized */ |
| cl_git_pass(git_futils_mkdir_relative("sm_unchanged", "submod2", 0755, 0, NULL)); |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_unchanged", ign)); |
| cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) != 0); |
| |
| /* update sm_changed_head in index */ |
| add_submodule_to_index("sm_changed_head"); |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_head", ign)); |
| 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"); |
| |
| 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); |
| |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_index", ign)); |
| cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); |
| |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_head", ign)); |
| cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0); |
| |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_file", ign)); |
| cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); |
| |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_untracked_file", ign)); |
| cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); |
| |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_missing_commits", ign)); |
| cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0); |
| |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_added_and_uncommited", ign)); |
| cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_ADDED) != 0); |
| |
| /* removed sm_unchanged for deleted workdir */ |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_unchanged", ign)); |
| cl_assert((status & GIT_SUBMODULE_STATUS_WD_DELETED) != 0); |
| |
| /* now mkdir sm_unchanged to test uninitialized */ |
| cl_git_pass(git_futils_mkdir_relative("sm_unchanged", "submod2", 0755, 0, NULL)); |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_unchanged", ign)); |
| cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) != 0); |
| |
| /* update sm_changed_head in index */ |
| add_submodule_to_index("sm_changed_head"); |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_head", ign)); |
| 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"); |
| |
| 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); |
| |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_index", ign)); |
| cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); |
| |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_head", ign)); |
| cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); |
| |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_file", ign)); |
| cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); |
| |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_untracked_file", ign)); |
| cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); |
| |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_missing_commits", ign)); |
| cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); |
| |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_added_and_uncommited", ign)); |
| cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); |
| |
| /* removed sm_unchanged for deleted workdir */ |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_unchanged", ign)); |
| cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); |
| |
| /* now mkdir sm_unchanged to test uninitialized */ |
| cl_git_pass(git_futils_mkdir_relative("sm_unchanged", "submod2", 0755, 0, NULL)); |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_unchanged", ign)); |
| cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); |
| |
| /* update sm_changed_head in index */ |
| add_submodule_to_index("sm_changed_head"); |
| cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_head", ign)); |
| 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; |
| git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT; |
| 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; |
| git_index *index; |
| |
| iter_opts.flags = GIT_ITERATOR_IGNORE_CASE | GIT_ITERATOR_INCLUDE_TREES; |
| |
| cl_git_pass(git_repository_index(&index, g_repo)); |
| cl_git_pass(git_iterator_for_workdir(&iter, g_repo, index, NULL, &iter_opts)); |
| |
| for (i = 0; !git_iterator_advance(&entry, iter); ++i) |
| cl_assert_equal_s(expected[i], entry->path); |
| |
| git_iterator_free(iter); |
| git_index_free(index); |
| |
| 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_relative("sm_unchanged/directory", "submod2", 0755, 0, NULL)); |
| 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); |
| } |